├── README.md ├── StreamVideo ├── StreamVideo.c ├── StreamVideo.h ├── StreamYoutube.sh ├── compile.sh └── sketch_aug05c.ino /README.md: -------------------------------------------------------------------------------- 1 | # Stream-video-esp32 2 | For it to work you will need to install ffmpeg www.ffmpeg.org 3 | the StreamVideo has been compile on Mac OS x to recompile it use compile.sh 4 | 5 | USAGE: 6 | ./StreamVideo -i 'inputfile' -a 'address_to_stream_to' -d 'dimension of the panel width x height' 7 | example: 8 | ./StreamVideo -i test.mp4 -a 192.168.1.23 -d 120x34 9 | 10 | To modifify the rotation of the image in regards to your panel use the option -w 11 | 12 | OPTIONS ARE: 13 | TOP_LEFT,TOP_RIGHT,DOWN_RIGHT,DOWN_LEFT by default it is set as DOWN_LEFT 14 | 15 | example: 16 | ./StreamVideo -i test.mp4 -a 192.168.1.23 -d 120x34 -w TOP_LEFT 17 | 18 | you can also set the brigthness using the -b option 19 | example: 20 | ./StreamVideo -i test.mp4 -a 192.168.1.23 -d 120x34 -w TOP_LEFT -b 120 21 | 22 | The input file can also be a URL to an online video. 23 | 24 | If you want to stream Youtube video you need to install youtube-dl 25 | brew install youtube-dl 26 | and then do: 27 | ./StreamVideo -i $(youtube-dl -f bestvideo -g https://youtu.be/CZ9Pu9Usk5o) -d 123x48 -a 192.168.1.22 28 | 29 | OTHER OPTIONS: 30 | By default the program will resize the video to match you led panel to change this you can use -s scalewidthxscaleheight 31 | For instance you could stream a image double the size of your panel by: 32 | ./StreamVideo -i test.mp4 -a 192.168.1.23 -d 120x34 -s 240x68 33 | 34 | then you can move around the picture using the option -o 35 | 36 | ./StreamVideo -i test.mp4 -a 192.168.1.23 -d 120x34 -s 240x68 -o 100x20 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /StreamVideo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hpwit/Stream-video-esp32/e69731511f2b0b28a1abb946701f326ee528a172/StreamVideo -------------------------------------------------------------------------------- /StreamVideo.c: -------------------------------------------------------------------------------- 1 | // 2 | // StreamVideo.c 3 | // 4 | // 5 | // Created by Yves BAZIN on 5/08/18. 6 | // 7 | 8 | #include "StreamVideo.h" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | // compatibility with newer API 22 | #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1) 23 | #define av_frame_alloc avcodec_alloc_frame 24 | #define av_frame_free avcodec_free_frame 25 | #endif 26 | 27 | 28 | #define TOP_LEFT 2 29 | #define TOP_RIGHT 3 30 | #define DOWN_LEFT 0 31 | #define DOWN_RIGHT 1 32 | void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame) { 33 | FILE *pFile; 34 | char szFilename[32]; 35 | int y; 36 | 37 | // Open file 38 | sprintf(szFilename, "frame%d.ppm", iFrame); 39 | pFile=fopen(szFilename, "wb"); 40 | if(pFile==NULL) 41 | return; 42 | 43 | // Write header 44 | fprintf(pFile, "P6\n%d %d\n255\n", width, height); 45 | 46 | // Write pixel data 47 | for(y=0; ydata[0]+y*pFrame->linesize[0], 1, width*3, pFile); 49 | 50 | // Close file 51 | fclose(pFile); 52 | } 53 | 54 | int main(int argc, char *argv[]) { 55 | //= //{ 56 | //0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,3,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,8,8,8,9,9,9,10,10,10,11,11,11,12,12,13,13,14,14,14,15,15,16,16,17,17,18,18,19,19,20,21,21,22,22,23,23,24,25,25,26,27,27,28,29,29,30,31,31,32,33,34,34,35,36,37,37,38,39,40,41,42,42,43,44,45,46,47,48,49,50,51,52,52,53,54,55,56,57,59,60,61,62,63,64,65,66,67,68,69,71,72,73,74,75,77,78,79,80,82,83,84,85,87,88,89,91,92,93,95,96,98,99,100,102,103,105,106,108,109,111,112,114,115,117,119,120,122,123,125,127,128,130,132,133,135,137,138,140,142,144,145,147,149,151,153,155,156,158,160,162,164,166,168,170,172,174,176,178,180,182,184,186,188,190,192,194,197,199,201,203,205,207,210,212,214,216,219,221,223,226,228,230,233,235,237,240,242,245,247,250,252,255, 57 | 58 | 59 | // }; 60 | char gammared[260]; 61 | char gamma8[260];// = { 62 | //0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,3,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,7,7,7,8,8,8,9,9,9,10,10,10,11,11,11,12,12,13,13,14,14,14,15,15,16,16,17,17,18,18,19,19,20,21,21,22,22,23,23,24,25,25,26,27,27,28,29,29,30,31,31,32,33,34,34,35,36,37,37,38,39,40,41,42,42,43,44,45,46,47,48,49,50,51,52,52,53,54,55,56,57,59,60,61,62,63,64,65,66,67,68,69,71,72,73,74,75,77,78,79,80,82,83,84,85,87,88,89,91,92,93,95,96,98,99,100,102,103,105,106,108,109,111,112,114,115,117,119,120,122,123,125,127,128,130,132,133,135,137,138,140,142,144,145,147,149,151,153,155,156,158,160,162,164,166,168,170,172,174,176,178,180,182,184,186,188,190,192,194,197,199,201,203,205,207,210,212,214,216,219,221,223,226,228,230,233,235,237,240,242,245,247,250,252,255, 63 | 64 | // }; 65 | 66 | 67 | double gammaCorrection=2; 68 | double redgammaCorrection=2.2; 69 | float correctGamma=1;//Math.pow(tableBrightness/255,1/gammaCorrection); 70 | 71 | correctGamma=1; 72 | for (int i=0;i<256;i++) 73 | { 74 | 75 | char newValue=(uint8_t)255*powf((float)i/255,correctGamma*gammaCorrection); 76 | //Serial.println(newValue); 77 | gamma8[i]=newValue; 78 | //printf("%d\n",gamma8[i]); 79 | newValue=(uint8_t)255*powf((float)i/255,correctGamma*redgammaCorrection); 80 | gammared[i]=(short)newValue; 81 | //Serial.println(gamma8[i]); 82 | } 83 | // Initalizing these to NULL prevents segfaults! 84 | AVFormatContext *pFormatCtx = NULL; 85 | int i, videoStream; 86 | AVCodecContext *pCodecCtxOrig = NULL; 87 | AVCodecContext *pCodecCtx = NULL; 88 | AVCodec *pCodec = NULL; 89 | AVFrame *pFrame = NULL; 90 | AVFrame *pFrameRGB = NULL; 91 | AVPacket packet; 92 | int frameFinished; 93 | int numBytes; 94 | uint8_t *buffer = NULL; 95 | struct SwsContext *sws_ctx = NULL; 96 | 97 | int socket_info; 98 | struct sockaddr_in server; 99 | char message[369*2+1]; 100 | char incoming_message[100]; 101 | 102 | 103 | int opt = 0; 104 | char *input= NULL; 105 | char *ipaddress = NULL; 106 | char *dimension=NULL; 107 | char *in_fname= NULL; 108 | char *out_fname = NULL; 109 | char *paneldirection=NULL; 110 | int panel_direction=DOWN_LEFT; //DOWN_LEFT 111 | 112 | int width,height,scalew,scaleh,decalagex,decalagey,offsety,offsetx=0; 113 | int brightness=100; 114 | 115 | while ((opt = getopt(argc, argv, "i:d:a:s:o:w:b:")) != -1) { 116 | switch(opt) { 117 | case 'b': 118 | dimension=optarg; 119 | sscanf(optarg, "%d", &brightness); 120 | brightness=brightness%256; 121 | break; 122 | case 'w': 123 | paneldirection=optarg; 124 | break; 125 | case 'i': 126 | input = optarg; 127 | //printf("\nInput option value=%s", in_fname); 128 | /* int val=0; 129 | sscanf(optarg, "%d", &val); 130 | printf("\nThe value of x : %d\n ", val+23); 131 | char *token = strtok(optarg, "x"); 132 | 133 | // Keep printing tokens while one of the 134 | // delimiters present in str[]. 135 | while (token != NULL) 136 | { 137 | printf("%s\n", token); 138 | token = strtok(NULL, "x"); 139 | }*/ 140 | break; 141 | case 'a': 142 | ipaddress = optarg; 143 | //printf("\nOutput option value=%s", out_fname); 144 | break; 145 | case 'd': 146 | dimension=optarg; 147 | int val=0; 148 | char *token = strtok(optarg, "x"); 149 | 150 | // Keep printing tokens while one of the 151 | // delimiters present in str[]. 152 | // while (token != NULL) 153 | //{ 154 | sscanf(token, "%d", &width); 155 | //printf("%s\n", token); 156 | token = strtok(NULL, "x"); 157 | sscanf(token, "%d", &height); 158 | //} 159 | break; 160 | case 's': 161 | dimension=optarg; 162 | //int val=0; 163 | char *token2 = strtok(optarg, "x"); 164 | 165 | // Keep printing tokens while one of the 166 | // delimiters present in str[]. 167 | // while (token != NULL) 168 | //{ 169 | sscanf(token2, "%d", &scalew); 170 | //printf("%s\n", token); 171 | token2 = strtok(NULL, "x"); 172 | sscanf(token2, "%d", &scaleh); 173 | //} 174 | break; 175 | case 'o': 176 | dimension=optarg; 177 | //int val=0; 178 | char *token3 = strtok(optarg, "x"); 179 | 180 | // Keep printing tokens while one of the 181 | // delimiters present in str[]. 182 | // while (token != NULL) 183 | //{ 184 | sscanf(token3, "%d", &offsetx); 185 | //printf("%s\n", token); 186 | token3 = strtok(NULL, "x"); 187 | sscanf(token3, "%d", &offsety); 188 | //} 189 | break; 190 | case '?': 191 | /* Case when user enters the command as 192 | * $ ./cmd_exe -i 193 | */ 194 | if (optopt == 'i') { 195 | printf("Missing mandatory input stream name -i inputfile\n"); 196 | /* Case when user enters the command as 197 | * # ./cmd_exe -o 198 | */ 199 | } else if (optopt == 'd') { 200 | printf("Missing mandatory input led panel size -d widthxheight\n"); 201 | } else if (optopt =='a'){ 202 | printf("Missing mandatory input led streaminf address -a xx.xx.xx.xx\n"); 203 | } 204 | else { 205 | printf("\nInvalid option received"); 206 | } 207 | break; 208 | } 209 | } 210 | 211 | if(input==NULL) 212 | { 213 | printf("Missing mandatory input stream name -i inputfile\n"); 214 | return 0; 215 | } 216 | if(ipaddress==NULL) 217 | { 218 | printf("Missing mandatory input led streaminf address -a xx.xx.xx.xx\n"); 219 | return 0; 220 | } 221 | if(width==0 | height==0) 222 | { 223 | printf("Missing mandatory input led panel size -d widthxheight\n"); 224 | return 0; 225 | } 226 | /* 227 | #define TOP_LEFT 2 228 | #define TOP_RIGHT 3 229 | #define DOWN_LEFT 0 230 | #define DOWN_RIGHT 1 231 | */ 232 | if(paneldirection!=NULL) 233 | { 234 | 235 | if( strcmp(paneldirection,"TOP_LEFT")==0 ) 236 | panel_direction=TOP_LEFT; 237 | 238 | if( strcmp(paneldirection,"TOP_RIGHT")==0 ) 239 | panel_direction=TOP_RIGHT; 240 | if( strcmp(paneldirection,"DOWN_RIGHT")==0 ) 241 | panel_direction=DOWN_RIGHT; 242 | if( strcmp(paneldirection,"DOWN_LEFT")==0 ) 243 | panel_direction=DOWN_LEFT; 244 | } 245 | 246 | 247 | if(scaleh==0) 248 | scaleh=height; 249 | if(scalew==0) 250 | scalew=width; 251 | 252 | printf("input :%s \naddress:%s \nwidth :%d \nheight :%d \nscalex :%d \nscaley :%d \noffsetx:%d\noffsety:%d\nPannel direction:%d\nBrightness:%d\n",input,ipaddress,width,height,scalew,scaleh,offsetx,offsety,panel_direction,brightness); 253 | 254 | 255 | clock_t temps; 256 | socket_info = socket(AF_INET, SOCK_DGRAM, 0); 257 | if (socket_info == -1) { 258 | printf("Could not create socket"); 259 | } 260 | 261 | //assign local values 262 | server.sin_addr.s_addr = inet_addr(ipaddress); 263 | server.sin_family = AF_INET; 264 | server.sin_port = htons( 100 ); 265 | 266 | 267 | if (connect(socket_info, (struct sockaddr *)&server, sizeof(server)) < 0) { 268 | perror("Connection error"); 269 | return 1; 270 | } 271 | puts("Connected"); 272 | 273 | 274 | /*if(argc < 2) { 275 | printf("Please provide a movie file\n"); 276 | return -1; 277 | }*/ 278 | // Register all formats and codecs 279 | av_register_all(); 280 | 281 | // Open video file 282 | if(avformat_open_input(&pFormatCtx, input, NULL, NULL)!=0) 283 | return -1; // Couldn't open file 284 | 285 | // Retrieve stream information 286 | if(avformat_find_stream_info(pFormatCtx, NULL)<0) 287 | return -1; // Couldn't find stream information 288 | 289 | // Dump information about file onto standard error 290 | av_dump_format(pFormatCtx, 0,input, 0); 291 | 292 | 293 | // Find the first video stream 294 | videoStream=-1; 295 | for(i=0; inb_streams; i++) 296 | if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO) { 297 | videoStream=i; 298 | break; 299 | } 300 | if(videoStream==-1) 301 | return -1; // Didn't find a video stream 302 | 303 | // Get a pointer to the codec context for the video stream 304 | pCodecCtxOrig=pFormatCtx->streams[videoStream]->codec; 305 | // Find the decoder for the video stream 306 | int numrate=pFormatCtx->streams[videoStream]->avg_frame_rate.num; 307 | int denumreate=pFormatCtx->streams[videoStream]->avg_frame_rate.den; 308 | printf("%f\n",(float)((float)numrate/(float)denumreate)); 309 | //return 0; 310 | pCodec=avcodec_find_decoder(pCodecCtxOrig->codec_id); 311 | if(pCodec==NULL) { 312 | fprintf(stderr, "Unsupported codec!\n"); 313 | return -1; // Codec not found 314 | } 315 | // Copy context 316 | pCodecCtx = avcodec_alloc_context3(pCodec); 317 | if(avcodec_copy_context(pCodecCtx, pCodecCtxOrig) != 0) { 318 | fprintf(stderr, "Couldn't copy codec context"); 319 | return -1; // Error copying codec context 320 | } 321 | 322 | // Open codec 323 | if(avcodec_open2(pCodecCtx, pCodec, NULL)<0) 324 | return -1; // Could not open codec 325 | 326 | // Allocate video frame 327 | pFrame=av_frame_alloc(); 328 | 329 | // Allocate an AVFrame structure 330 | pFrameRGB=av_frame_alloc(); 331 | if(pFrameRGB==NULL) 332 | return -1; 333 | 334 | // Determine required buffer size and allocate buffer 335 | numBytes=avpicture_get_size(AV_PIX_FMT_RGB24, pCodecCtx->width, 336 | pCodecCtx->height); 337 | buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t)); 338 | 339 | // Assign appropriate parts of buffer to image planes in pFrameRGB 340 | // Note that pFrameRGB is an AVFrame, but AVFrame is a superset 341 | // of AVPicture 342 | avpicture_fill((AVPicture *)pFrameRGB, buffer, AV_PIX_FMT_RGB24, 343 | pCodecCtx->width, pCodecCtx->height); 344 | 345 | // initialize SWS context for software scaling 346 | sws_ctx = sws_getContext(pCodecCtx->width, 347 | pCodecCtx->height, 348 | pCodecCtx->pix_fmt, 349 | scalew,//pCodecCtx->width, 350 | scaleh,//pCodecCtx->height, 351 | AV_PIX_FMT_RGB24, 352 | SWS_BILINEAR, 353 | NULL, 354 | NULL, 355 | NULL 356 | ); 357 | 358 | // Read frames and save first five frames to disk 359 | i=0; 360 | temps=clock(); 361 | 362 | message[0]=255; 363 | message[1]=brightness; 364 | int off=0; 365 | if(send(socket_info, message, 2, 0) <0) { 366 | perror("Send failed"); 367 | return 1; 368 | } 369 | while(av_read_frame(pFormatCtx, &packet)>=0) { 370 | 371 | // Is this a packet from the video stream? 372 | if(packet.stream_index==videoStream) { 373 | 374 | // Decode video frame 375 | avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet); 376 | 377 | // Did we get a video frame? 378 | if(frameFinished) { 379 | 380 | // Convert the image from its native format to RGB 381 | sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data, 382 | pFrame->linesize, 0, pCodecCtx->height, 383 | pFrameRGB->data, pFrameRGB->linesize); 384 | 385 | // Save the frame to disk 386 | /* if(++i<=200) 387 | SaveFrame(pFrameRGB, 123,48,//pCodecCtx->width, pCodecCtx->height, 388 | i);*/ 389 | int m=1000000*(double)denumreate*9/(double)numrate/10-(double)(((clock()-temps)*1000000)/CLOCKS_PER_SEC); 390 | // printf("%d\n",m); 391 | if(m>0) 392 | usleep(m) ; 393 | temps=clock(); 394 | int nbpacket=height/2; 395 | for(uint16_t s=0;sdata[0]+2*123*3*s); 407 | //printf("address:%d\n",&(pFrame->data[0])); 408 | memcpy(&b,pFrameRGB->data[0]+offsetx*3+((nbpacket-1-s)*2+1+offsety)*pFrameRGB->linesize[0]+3*g,1); 409 | 410 | message[g*3+1]=gammared[(uint8_t)b]; 411 | 412 | 413 | memcpy(&b,pFrameRGB->data[0]+offsetx*3+((nbpacket-1-s)*2+1+offsety)*pFrameRGB->linesize[0]+3*g+1,1); 414 | message[g*3+1+1]=gamma8[(uint8_t)b]; 415 | 416 | memcpy(&b,pFrameRGB->data[0]+offsetx*3+((nbpacket-1-s)*2+1+offsety)*pFrameRGB->linesize[0]+3*g+2,1); 417 | message[g*3+2+1]=gamma8[(uint8_t)b]; 418 | 419 | } 420 | //memcpy(&message[1],pFrame->data[0]+s*pFrame->linesize[0],123*3); 421 | for(int g=0;gdata[0]+2*123*3*s); 426 | //printf("address:%ld\n",&(pFrame->data[0])); 427 | memcpy(&b,pFrameRGB->data[0]+offsetx*3+((nbpacket-1-s)*2+offsety)*pFrameRGB->linesize[0]+3*g,1); 428 | message[(width*2-g-1)*3+1]=gammared[(uint8_t)b]; 429 | 430 | memcpy(&b,pFrameRGB->data[0]+offsetx*3+((nbpacket-1-s)*2+offsety)*pFrameRGB->linesize[0]+3*g+1,1); 431 | message[(width*2-g-1)*3+1+1]=gamma8[(uint8_t)b]; 432 | 433 | memcpy(&b,pFrameRGB->data[0]+offsetx*3+((nbpacket-1-s)*2+offsety)*pFrameRGB->linesize[0]+3*g+2,1); 434 | message[(width*2-g-1)*3+2+1]=gamma8[(uint8_t)b]; 435 | 436 | } 437 | 438 | break; 439 | case TOP_RIGHT: 440 | for(uint16_t g=0;gdata[0]+2*123*3*s); 445 | //printf("address:%d\n",&(pFrame->data[0])); 446 | memcpy(&b,pFrameRGB->data[0]+offsetx*3+((s)*2+offsety)*pFrameRGB->linesize[0]+3*g,1); 447 | 448 | message[g*3+1]=gammared[(uint8_t)b]; 449 | 450 | 451 | memcpy(&b,pFrameRGB->data[0]+offsetx*3+((s)*2+offsety)*pFrameRGB->linesize[0]+3*g+1,1); 452 | message[g*3+1+1]=gamma8[(uint8_t)b]; 453 | 454 | memcpy(&b,pFrameRGB->data[0]+offsetx*3+((s)*2+offsety)*pFrameRGB->linesize[0]+3*g+2,1); 455 | message[g*3+2+1]=gamma8[(uint8_t)b]; 456 | 457 | } 458 | //memcpy(&message[1],pFrame->data[0]+s*pFrame->linesize[0],123*3); 459 | for(int g=0;gdata[0]+2*123*3*s); 464 | //printf("address:%ld\n",&(pFrame->data[0])); 465 | memcpy(&b,pFrameRGB->data[0]+offsetx*3+((s)*2+1+offsety)*pFrameRGB->linesize[0]+3*g,1); 466 | message[(width*2-g-1)*3+1]=gammared[(uint8_t)b]; 467 | 468 | memcpy(&b,pFrameRGB->data[0]+offsetx*3+((s)*2+1+offsety)*pFrameRGB->linesize[0]+3*g+1,1); 469 | message[(width*2-g-1)*3+1+1]=gamma8[(uint8_t)b]; 470 | 471 | memcpy(&b,pFrameRGB->data[0]+offsetx*3+((s)*2+1+offsety)*pFrameRGB->linesize[0]+3*g+2,1); 472 | message[(width*2-g-1)*3+2+1]=gamma8[(uint8_t)b]; 473 | 474 | } 475 | break; 476 | case TOP_LEFT: 477 | for(uint16_t g=0;gdata[0]+2*123*3*s); 482 | //printf("address:%d\n",&(pFrame->data[0])); 483 | memcpy(&b,pFrameRGB->data[0]+offsetx*3+((s)*2+offsety)*pFrameRGB->linesize[0]+3*g,1); 484 | 485 | message[(width-g-1)*3+1]=gammared[(uint8_t)b]; 486 | 487 | 488 | memcpy(&b,pFrameRGB->data[0]+offsetx*3+((s)*2+offsety)*pFrameRGB->linesize[0]+3*g+1,1); 489 | message[(width-g-1)*3+1+1]=gamma8[(uint8_t)b]; 490 | 491 | memcpy(&b,pFrameRGB->data[0]+offsetx*3+((s)*2+offsety)*pFrameRGB->linesize[0]+3*g+2,1); 492 | message[(width-g-1)*3+2+1]=gamma8[(uint8_t)b]; 493 | 494 | } 495 | //memcpy(&message[1],pFrame->data[0]+s*pFrame->linesize[0],123*3); 496 | for(int g=0;gdata[0]+2*123*3*s); 501 | //printf("address:%ld\n",&(pFrame->data[0])); 502 | memcpy(&b,pFrameRGB->data[0]+offsetx*3+((s)*2+1+offsety)*pFrameRGB->linesize[0]+3*g,1); 503 | message[(width+g)*3+1]=gammared[(uint8_t)b]; 504 | 505 | memcpy(&b,pFrameRGB->data[0]+offsetx*3+((s)*2+1+offsety)*pFrameRGB->linesize[0]+3*g+1,1); 506 | message[(width+g)*3+1+1]=gamma8[(uint8_t)b]; 507 | 508 | memcpy(&b,pFrameRGB->data[0]+offsetx*3+((s)*2+1+offsety)*pFrameRGB->linesize[0]+3*g+2,1); 509 | message[(width+g)*3+2+1]=gamma8[(uint8_t)b]; 510 | 511 | } 512 | 513 | break; 514 | case DOWN_RIGHT: 515 | for(uint16_t g=0;gdata[0]+2*123*3*s); 520 | //printf("address:%d\n",&(pFrame->data[0])); 521 | memcpy(&b,pFrameRGB->data[0]+offsetx*3+((nbpacket-1-s)*2+1+offsety)*pFrameRGB->linesize[0]+3*g,1); 522 | 523 | message[(width-g-1)*3+1]=gammared[(uint8_t)b]; 524 | 525 | 526 | memcpy(&b,pFrameRGB->data[0]+offsetx*3+((nbpacket-1-s)*2+1+offsety)*pFrameRGB->linesize[0]+3*g+1,1); 527 | message[(width-g-1)*3+1+1]=gamma8[(uint8_t)b]; 528 | 529 | memcpy(&b,pFrameRGB->data[0]+offsetx*3+((nbpacket-1-s)*2+1+offsety)*pFrameRGB->linesize[0]+3*g+2,1); 530 | message[(width-g-1)*3+2+1]=gamma8[(uint8_t)b]; 531 | 532 | } 533 | //memcpy(&message[1],pFrame->data[0]+s*pFrame->linesize[0],123*3); 534 | for(int g=0;gdata[0]+2*123*3*s); 539 | //printf("address:%ld\n",&(pFrame->data[0])); 540 | memcpy(&b,pFrameRGB->data[0]+offsetx*3+((nbpacket-1-s)*2+offsety)*pFrameRGB->linesize[0]+3*g,1); 541 | message[(width+g)*3+1]=gammared[(uint8_t)b]; 542 | 543 | memcpy(&b,pFrameRGB->data[0]+offsetx*3+((nbpacket-1-s)*2+offsety)*pFrameRGB->linesize[0]+3*g+1,1); 544 | message[(width+g)*3+1+1]=gamma8[(uint8_t)b]; 545 | 546 | memcpy(&b,pFrameRGB->data[0]+offsetx*3+((nbpacket-1-s)*2+offsety)*pFrameRGB->linesize[0]+3*g+2,1); 547 | message[(width+g)*3+2+1]=gamma8[(uint8_t)b]; 548 | 549 | } 550 | 551 | break; 552 | } 553 | 554 | if(send(socket_info, message, width*3*2+1, 0) <0) { 555 | perror("Send failed"); 556 | // return 1; 557 | } 558 | //usleep(600); 559 | } 560 | 561 | } 562 | 563 | 564 | 565 | } 566 | 567 | av_free_packet(&packet); 568 | /* for (int skip=0;i<20;i++) 569 | { 570 | if(av_read_frame(pFormatCtx, &packet)<0) 571 | return 0; 572 | av_free_packet(&packet); 573 | }*/ 574 | // Free the packet that was allocated by av_read_frame 575 | 576 | } 577 | 578 | close(socket_info); 579 | // Free the RGB image 580 | av_free(buffer); 581 | av_frame_free(&pFrameRGB); 582 | 583 | // Free the YUV frame 584 | av_frame_free(&pFrame); 585 | 586 | // Close the codecs 587 | avcodec_close(pCodecCtx); 588 | avcodec_close(pCodecCtxOrig); 589 | 590 | // Close the video file 591 | avformat_close_input(&pFormatCtx); 592 | 593 | return 0; 594 | } 595 | -------------------------------------------------------------------------------- /StreamVideo.h: -------------------------------------------------------------------------------- 1 | // 2 | // StreamVideo.h 3 | // 4 | // 5 | // Created by Yves BAZIN on 5/08/18. 6 | // 7 | 8 | #ifndef StreamVideo_h 9 | #define StreamVideo_h 10 | 11 | #include 12 | 13 | #endif /* StreamVideo_h */ 14 | -------------------------------------------------------------------------------- /StreamYoutube.sh: -------------------------------------------------------------------------------- 1 | ./StreamVideo -i $(youtube-dl -f bestvideo -g $1) -d 123x48 -a 192.168.1.22 2 | -------------------------------------------------------------------------------- /compile.sh: -------------------------------------------------------------------------------- 1 | cc StreamVideo.c -o StreamVideo -lavutil -lavformat -lavcodec -lz -lavutil -lm -lavresample -lswresample -lswscale 2 | 3 | -------------------------------------------------------------------------------- /sketch_aug05c.ino: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #define USE_SPI 1 11 | #define FASTLED_ALLOW_INTERRUPTS 0 12 | #define INTERRUPT_THRESHOLD 1 13 | #include "FastLED.h" 14 | FASTLED_USING_NAMESPACE 15 | #define FASTLED_SHOW_CORE 0 16 | 17 | 18 | 19 | 20 | 21 | WiFiUDP Udp2; 22 | 23 | 24 | 25 | #define LED_WIDTH 123 26 | #define LED_HEIGHT 48 27 | #define NUM_LEDS LED_WIDTH*LED_HEIGHT 28 | 29 | CRGB leds[NUM_LEDS]; 30 | CRGB Tpic[NUM_LEDS]; 31 | 32 | char *artnetPacket2; 33 | 34 | 35 | 36 | // Artnet settings 37 | //Artnet artnet; 38 | 39 | 40 | 41 | 42 | CRGB artnetled[32*32]; 43 | 44 | 45 | 46 | 47 | 48 | //manage the the core0 49 | 50 | 51 | // -- Task handles for use in the notifications 52 | 53 | static TaskHandle_t FastLEDshowTaskHandle2 = 0; 54 | static TaskHandle_t userTaskHandle = 0; 55 | 56 | 57 | 58 | 59 | 60 | void FastLEDshowESP322() 61 | { 62 | if (userTaskHandle == 0) { 63 | const TickType_t xMaxBlockTime = pdMS_TO_TICKS( 200 ); 64 | // -- Store the handle of the current task, so that the show task can 65 | // notify it when it's done 66 | // noInterrupts(); 67 | userTaskHandle = xTaskGetCurrentTaskHandle(); 68 | 69 | // -- Trigger the show task 70 | xTaskNotifyGive(FastLEDshowTaskHandle2); 71 | //to thge contrary to the other one we do not wait for the display task to come back 72 | } 73 | } 74 | 75 | 76 | 77 | void FastLEDshowTask2(void *pvParameters) 78 | { 79 | const TickType_t xMaxBlockTime = pdMS_TO_TICKS( 500 ); 80 | // -- Run forever... 81 | for(;;) { 82 | // -- Wait for the trigger 83 | ulTaskNotifyTake(pdTRUE,portMAX_DELAY); 84 | 85 | 86 | 87 | memcpy(leds,Tpic,LED_WIDTH*LED_HEIGHT*sizeof(CRGB)); 88 | 89 | 90 | FastLED.show(); 91 | 92 | userTaskHandle=0; //so we can't have two display tasks at the same time 93 | 94 | } 95 | } 96 | 97 | 98 | 99 | 100 | void fill(CRGB color) 101 | { 102 | fill_solid(leds, NUM_LEDS, color); 103 | fill_solid(Tpic, NUM_LEDS, color); 104 | } 105 | 106 | 107 | bool firsttime=true; 108 | 109 | 110 | uint32_t syncmax1=0; 111 | uint32_t syncmax2=0; 112 | void setup() { 113 | Serial.begin(115200); 114 | 115 | 116 | 117 | 118 | xTaskCreatePinnedToCore(FastLEDshowTask2, "FastLEDshowTask2", 1000, NULL,3, &FastLEDshowTaskHandle2, FASTLED_SHOW_CORE); 119 | 120 | FastLED.addLeds(leds, 0, NUM_LEDS); 121 | //or your way of calling the led 122 | 123 | FastLED.setBrightness(64); 124 | 125 | fill(CRGB::Black); 126 | FastLED.show(); 127 | FastLED.delay(2000); 128 | 129 | 130 | 131 | 132 | WiFi.mode(WIFI_STA); 133 | Serial.printf("Connecting to %s\n", ""); 134 | Serial.printf("Connecting "); 135 | WiFi.begin("xxxxx", "xxxx"); 136 | //WiFi.begin("DomainePutterie", "Jeremyyves"); 137 | while (WiFi.status() != WL_CONNECTED) { 138 | Serial.println(WiFi.status()); 139 | 140 | delay(500); 141 | Serial.print("."); 142 | } 143 | 144 | Serial.println(""); 145 | Serial.println("WiFi connected."); 146 | Serial.println("IP address: "); 147 | Serial.println(WiFi.localIP()); 148 | 149 | //server.begin(); 150 | 151 | int nbNeededUniverses=LED_HEIGHT/2; 152 | if(nbNeededUniverses<=32) 153 | { 154 | if(nbNeededUniverses<32) 155 | syncmax1=(1<0) 197 | { 198 | 199 | 200 | Udp2.read(artnetPacket2, packetSize); 201 | memcpy(&Tpic[LED_WIDTH*2*(artnetPacket2[0])],artnetPacket2 + 1,LED_WIDTH*3*2); 202 | //Serial.printf("univers:%d\n",artnetPacket2[0]); 203 | if(artnetPacket2[0]==255) 204 | { 205 | Serial.printf("new value bru:%d\n",artnetPacket2[1]); 206 | FastLED.setBrightness(artnetPacket2[1]); 207 | } 208 | else 209 | { 210 | if (artnetPacket2[0]==0) 211 | { 212 | sync=1; 213 | sync2=0; 214 | } 215 | else 216 | { 217 | if(artnetPacket2[0]<32) 218 | sync=sync | (1<