// gcc -o testDrone2_video testDrone2_video.c -lavcodec -lavformat -lswscale -lSDL2
// g++ -o testDrone2_video testDrone2_video.c -lavcodec -lavformat -lswscale -lSDL2#ifdef __cplusplusextern "C" { #endif#include "libavcodec/avcodec.h"#include "libavformat/avformat.h"#include "libswscale/swscale.h"#ifdef __cplusplus}#endif#include "SDL2/SDL.h"int main(int argc, char* argv[]) { // 3.0. Initializes the video subsystem *must be done before anything other!! if (SDL_Init(SDL_INIT_VIDEO) < 0) { fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError()); return -1; } // prepare variables // decoding char *drone_addr = "http://192.168.1.1:5555"; AVFormatContext *pFormatCtx = NULL; AVCodecContext *pCodecCtx; AVCodec *pCodec; AVPacket packet; AVFrame *pFrame; int terminate, frameDecoded; // converting AVFrame *pFrame_YUV420P; uint8_t *buffer_YUV420P; struct SwsContext *pConvertCtx_YUV420P; AVFrame *pFrame_BGR24; uint8_t *buffer_BGR24; struct SwsContext *pConvertCtx_BGR24; // displaying SDL_Window *pWindow1; SDL_Renderer *pRenderer1; SDL_Texture *bmpTex1; uint8_t *pixels1; int pitch1, size1; SDL_Window *pWindow2; SDL_Renderer *pRenderer2; SDL_Texture *bmpTex2; uint8_t *pixels2; int pitch2, size2; // SDL event handling SDL_Event event; // 1.1 Register all formats and codecs av_register_all(); avcodec_register_all(); avformat_network_init(); // 1.2. Open video file while(avformat_open_input(&pFormatCtx, drone_addr, NULL, NULL) != 0) printf("Could not open the video file\nRetrying...\n"); // 1.3. Retrieve stream information avformat_find_stream_info(pFormatCtx, NULL); // Dump information about file to standard output av_dump_format(pFormatCtx, 0, drone_addr, 0); // 1.4. Get a pointer to the codec context for the video stream // and find the decoder for the video stream pCodecCtx = pFormatCtx->streams[0]->codec; pCodec = avcodec_find_decoder(pCodecCtx->codec_id); // 1.5. Open Codec avcodec_open2(pCodecCtx, pCodec, NULL); // 2.1.1. Prepare format conversion for diplaying with SDL // Allocate an AVFrame structure pFrame_YUV420P = avcodec_alloc_frame(); if(pFrame_YUV420P == NULL) { fprintf(stderr, "Could not allocate pFrame_YUV420P\n"); return -1; } // Determine required buffer size and allocate buffer buffer_YUV420P = (uint8_t *)av_malloc(avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height)); // Assign buffer to image planes avpicture_fill((AVPicture *)pFrame_YUV420P, buffer_YUV420P, PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height); // format conversion context pConvertCtx_YUV420P = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_SPLINE, NULL, NULL, NULL); // 2.2.1. Prepare format conversion for OpenCV // Allocate an AVFrame structure pFrame_BGR24 = avcodec_alloc_frame(); if(pFrame_BGR24 == NULL) { fprintf(stderr, "Could not allocate pFrame_YUV420P\n"); return -1; } // Determine required buffer size and allocate buffer buffer_BGR24 = (uint8_t *)av_malloc(avpicture_get_size(PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height)); // Assign buffer to image planes avpicture_fill((AVPicture *)pFrame_BGR24, buffer_BGR24, PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height); // format conversion context pConvertCtx_BGR24 = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_BGR24, SWS_SPLINE, NULL, NULL, NULL); // 3.1.1 prepare SDL for YUV // allocate window, renderer, texture pWindow1 = SDL_CreateWindow( "YUV", 0, 0, pCodecCtx->width, pCodecCtx->height, SDL_WINDOW_SHOWN); pRenderer1 = SDL_CreateRenderer(pWindow1, -1, SDL_RENDERER_ACCELERATED); bmpTex1 = SDL_CreateTexture(pRenderer1, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING, pCodecCtx->width, pCodecCtx->height); size1 = pCodecCtx->width * pCodecCtx->height; if(pWindow1==NULL | pRenderer1==NULL | bmpTex1==NULL) { fprintf(stderr, "Could not open window1\n%s\n", SDL_GetError()); return -1; } // 3.2.1 prepare SDL for BGR // allocate window, renderer, texture pWindow2 = SDL_CreateWindow( "BGR", pCodecCtx->width+5, 0, pCodecCtx->width, pCodecCtx->height, SDL_WINDOW_SHOWN); pRenderer2 = SDL_CreateRenderer(pWindow2, -1, SDL_RENDERER_ACCELERATED); bmpTex2 = SDL_CreateTexture(pRenderer2, SDL_PIXELFORMAT_BGR24, SDL_TEXTUREACCESS_STREAMING, pCodecCtx->width, pCodecCtx->height); size2 = pCodecCtx->width * pCodecCtx->height * 3; if(pWindow2==NULL | pRenderer2==NULL | bmpTex2==NULL) { fprintf(stderr, "Could not open window2\n%s\n", SDL_GetError()); return -1; } // 1.6. get video frames pFrame = avcodec_alloc_frame(); terminate = 0; while(!terminate) { // read frame if(av_read_frame(pFormatCtx, &packet)<0) { fprintf(stderr, "Could not read frame!\n"); continue; } // decode the frame if(avcodec_decode_video2(pCodecCtx, pFrame, &frameDecoded, &packet) < 0) { fprintf(stderr, "Could not decode frame!\n"); continue; } if (frameDecoded) { // 2.1.2. convert frame to YUV for Displaying sws_scale(pConvertCtx_YUV420P, (const uint8_t * const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrame_YUV420P->data, pFrame_YUV420P->linesize); // 2.2.2. convert frame to GRAYSCALE [or BGR] for OpenCV sws_scale(pConvertCtx_BGR24, (const uint8_t * const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrame_BGR24->data, pFrame_BGR24->linesize); // 3.1.2. copy converted YUV to SDL 2.0 texture SDL_LockTexture(bmpTex1, NULL, (void **)&pixels1, &pitch1); memcpy(pixels1, pFrame_YUV420P->data[0], size1 ); memcpy(pixels1 + size1, pFrame_YUV420P->data[2], size1/4); memcpy(pixels1 + size1*5/4, pFrame_YUV420P->data[1], size1/4); SDL_UnlockTexture(bmpTex1); SDL_UpdateTexture(bmpTex1, NULL, pixels1, pitch1); // refresh screen SDL_RenderClear(pRenderer1); SDL_RenderCopy(pRenderer1, bmpTex1, NULL, NULL); SDL_RenderPresent(pRenderer1); // 3.2.2. copy converted BGR to SDL 2.0 texture SDL_LockTexture(bmpTex2, NULL, (void **)&pixels2, &pitch2); memcpy(pixels2, pFrame_BGR24->data[0], size2); SDL_UnlockTexture(bmpTex2); SDL_UpdateTexture(bmpTex2, NULL, pixels2, pitch2); // refresh screen SDL_RenderClear(pRenderer2); SDL_RenderCopy(pRenderer2, bmpTex2, NULL, NULL); SDL_RenderPresent(pRenderer2); } SDL_PollEvent(&event); switch (event.type) { case SDL_KEYDOWN: terminate = 1; break; } } // release // *note SDL objects have to be freed before closing avcodec. // otherwise it causes segmentation fault for some reason. SDL_DestroyTexture(bmpTex1); SDL_DestroyTexture(bmpTex2); SDL_DestroyRenderer(pRenderer1); SDL_DestroyRenderer(pRenderer2); SDL_DestroyWindow(pWindow1); SDL_DestroyWindow(pWindow2); av_free(pFrame_YUV420P); av_free(buffer_YUV420P); sws_freeContext(pConvertCtx_YUV420P); av_free(pFrame_BGR24); av_free(buffer_BGR24); sws_freeContext(pConvertCtx_BGR24); av_free(pFrame); avcodec_close(pCodecCtx); // <- before freeing this, all other objects, allocated after this, must be freed avformat_close_input(&pFormatCtx); SDL_Quit(); return 0; }