This blog is excerpted from the course “Production of Video Player Based on FFmpeg + SDL” by Master Lei Xiaohua. It is very suitable for beginners in audio and video. I would like to thank Lei Shen for his guidance!
Integration of FFmpeg and SDL to achieve video playback
Integration
? FFmpeg decoder implemented: video file->YUV
? SDL video display is implemented: YUV->Screen
? After the integration of FFmpeg + SDL, it is realized: video file->YUV->screen
Add processing events, such as moving video window, zooming, etc.
/** * The simplest FFmpeg-based video player 2 (SDL upgraded version) * Simplest FFmpeg Player 2(SDL Update) * * Lei Xiaohua *[email protected] * Communication University of China/Digital TV Technology * Communication University of China / Digital TV Technology * http://blog.csdn.net/leixiaohua1020 * * This program implements the decoding and display of video files (supports HEVC, H.264, MPEG2, etc.). * It is the simplest tutorial on FFmpeg video decoding. * By studying this example, you can understand the decoding process of FFmpeg. * This version uses the SDL message mechanism to refresh the video screen. * This software is a simplest video player based on FFmpeg. * Suitable for beginners of FFmpeg. * */ #include <stdio.h> #define __STDC_CONSTANT_MACROS #define SDL_MAIN_HANDLED extern "C" { #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" #include "libswscale/swscale.h" #include "libavutil/imgutils.h" #include "SDL.h" }; // Custom event // Refresh Event refresh video event #define SFM_REFRESH_EVENT (SDL_USEREVENT + 1) #define SFM_BREAK_EVENT (SDL_USEREVENT + 2) int thread_exit = 0; int sfp_refresh_thread(void* opaque) { thread_exit = 0; while (!thread_exit) { SDL_Event event; event.type = SFM_REFRESH_EVENT; SDL_PushEvent( & amp;event); SDL_Delay(40); } thread_exit = 0; //Break SDL_Event event; event.type = SFM_BREAK_EVENT; SDL_PushEvent( & amp;event); return 0; } int main(int argc, char* argv[]) { AVFormatContext* pFormatCtx; int i, videoindex; AVCodecContext* pCodecCtx; AVCodec* pCodec; AVFrame* pFrame, * pFrameYUV; uint8_t* out_buffer; AVPacket* packet; int ret, got_picture; //----------------SDL---------------- int screen_w, screen_h; SDL_Window* screen; SDL_Renderer* sdlRenderer; SDL_Texture* sdlTexture; SDL_Rect sdlRect; SDL_Thread* video_tid; SDL_Event event; struct SwsContext* img_convert_ctx; \t// file path char filepath[] = "test.avi"; //av_register_all(); avformat_network_init(); pFormatCtx = avformat_alloc_context(); if (avformat_open_input( & amp;pFormatCtx, filepath, NULL, NULL) != 0) { printf("Couldn't open input stream.\\ "); return -1; } if (avformat_find_stream_info(pFormatCtx, NULL) < 0) { printf("Couldn't find stream information.\\ "); return -1; } videoindex = -1; for (i = 0; i < pFormatCtx->nb_streams; i + + ) if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { videoindex = i; break; } if (videoindex == -1) { printf("Didn't find a video stream.\\ "); return -1; } AVCodecParameters* codecParameters = pFormatCtx->streams[videoindex]->codecpar; pCodecCtx = avcodec_alloc_context3(nullptr); avcodec_parameters_to_context(pCodecCtx, codecParameters); //pCodecCtx = pFormatCtx->streams[videoindex]->codec; pCodec = (AVCodec*)avcodec_find_decoder(pCodecCtx->codec_id); if (pCodec == NULL) { printf("Codec not found.\\ "); return -1; } if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) { printf("Could not open codec.\\ "); return -1; } packet = av_packet_alloc(); pFrame = av_frame_alloc(); pFrameYUV = av_frame_alloc(); out_buffer = (uint8_t*)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 1)); av_image_fill_arrays(pFrameYUV->data, pFrameYUV->linesize, out_buffer, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 1); img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL); if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER)) { printf("Could not initialize SDL - %s\\ ", SDL_GetError()); return -1; } //SDL 2.0 Support for multiple windows screen_w = pCodecCtx->width; screen_h = pCodecCtx->height; screen = SDL_CreateWindow("Simplest ffmpeg player's Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, screen_w, screen_h, SDL_WINDOW_OPENGL); if (!screen) { printf("SDL: could not create window - exiting:%s\\ ", SDL_GetError()); return -1; } sdlRenderer = SDL_CreateRenderer(screen, -1, 0); //IYUV: Y + U + V (3 planes) //YV12: Y + V + U (3 planes) sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, pCodecCtx->width, pCodecCtx->height); sdlRect.x = 0; sdlRect.y = 0; sdlRect.w = screen_w; sdlRect.h = screen_h; packet = (AVPacket*)av_malloc(sizeof(AVPacket)); //Create a thread video_tid = SDL_CreateThread(sfp_refresh_thread, NULL, NULL); //------------SDL End------------ //Event Loop for (;;) { //Wait SDL_WaitEvent( & amp;event); // Loop waiting for the custom event SFM_REFRESH_EVENT if (event.type == SFM_REFRESH_EVENT) { //--------------------------------- if (av_read_frame(pFormatCtx, packet) >= 0) { if (packet->stream_index == videoindex) { if (avcodec_send_packet(pCodecCtx, packet) < 0) { printf("avcodec_send_packet failed!.\\ "); continue; } while (1) { ret = avcodec_receive_frame(pCodecCtx, pFrame); if (ret != 0)break; sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize); //SDL-------------------------- SDL_UpdateTexture(sdlTexture, NULL, pFrameYUV->data[0], pFrameYUV->linesize[0]); SDL_RenderClear(sdlRenderer); //SDL_RenderCopy( sdlRenderer, sdlTexture, & amp;sdlRect, & amp;sdlRect ); SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL); SDL_RenderPresent(sdlRenderer); //SDL End---------------------- } } av_packet_unref(packet); } else { //Exit Thread thread_exit = 1; } } else if (event.type == SDL_WINDOWEVENT) { // Zoom to change the size of the video playback window SDL_GetWindowSize(screen, & amp;screen_w, & amp;screen_h); } else if (event.type == SDL_QUIT) { thread_exit = 1; } else if (event.type == SFM_BREAK_EVENT) { break; } } sws_freeContext(img_convert_ctx); SDL_Quit(); //------------- av_frame_free( & amp;pFrameYUV); av_frame_free( & amp;pFrame); avcodec_close(pCodecCtx); avformat_close_input( & amp;pFormatCtx); return 0; }