This article complements two examples from the simplest ffmpeg+sdl-based video player: the FFmpeg video decoder and the SDL pixel data player. These two sections are two examples that are split from the video player. The FFmpeg video decoder realizes the decoding of video data to YUV data, while the SDL pixel data player realizes the display of YUV data. In short, the original FFMPEG+SDL video player implemented:
Video Data->yuv-> display
The FFmpeg video decoder implements:
Video Data->yuv
The SDL pixel data player implements:
yuv-> Display
FFmpeg Video Decoder source code
/** * Simplest FFmpeg based video decoder * Simplest FFmpeg Decoder * * Lei hua Lei Xiaohua * [email protected] * Communication University/Digital TV Technology * Communic ation University of China/digital TV technology * http://blog.csdn.net/leixiaohua1020 * * * This program implements video file decoding for YUV data. It uses LIBAVCODEC and * Libavformat. Is the simplest ffmpeg video decoding aspect of the tutorial. * Learn this example to understand the decoding process of ffmpeg. * This software are a simplest decoder based on FFmpeg. * It decodes video to YUV pixel data. * It uses LIBAVCODEC and Libavformat. * Suitable for beginner of FFmpeg. * */#include <stdio.h> #define __STDC_CONSTANT_MACROS#IFDEF _win32//windowsextern "C" {#include "libavcodec/ Avcodec.h "#include" libavformat/avformat.h "#include" libswscale/swscale.h "} #else//linux ... #ifdef __ Cplusplusextern "C" {#endif # include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libswscale/swscale.h> #ifdef __cplusplus}; #endif #endifint main (int argc, char* argv[]) {avformatcontext* Pformatctx;inti, Videoindex; Avcodeccontext*pcodecctx; Avcodec*pcodec; Avframe*pframe,*pframeyuv;uint8_t *out_buffer; Avpacket *packet;int y_size;int ret, got_picture;struct swscontext *img_convert_ctx;char filepath[]= "Titanic.mkv"; FILE *fp_yuv=fopen ("Output.yuv", "wb+"); Av_register_all (); Avformat_network_init ();p formatctx = Avformat_alloc_context (); if (Avformat_open_input (& Pformatctx,filepath,null,null) {!=0) {printf ("couldn ' t open input stream.\n"); return-1;} if (Avformat_find_stream_info (pformatctx,null) <0) {printf ("couldn ' t find stream information.\n"); return-1;} Videoindex=-1;for (i=0; i<pformatctx->nb_streams; i++) if (pformatctx->streams[i]->codec->codec_type ==avmedia_type_video) {videoindex=i;break;} if (videoindex==-1) {printf ("didn ' t find a video stream.\n"); return-1;} Pcodecctx=pformatctx->streams[videoindex]->codec;pcodec=avcodec_find_decoder (pCodecCtx->codec_id); if ( Pcodec==null) {printf ("Codec not found.\n"); return-1;} if (Avcodec_open2 (Pcodecctx, Pcodec,null) <0) {printf ("Could not open codec.\n"); return-1;} Pframe=av_frame_alloc ();p Frameyuv=av_frame_alloc (); out_buffer= (uint8_t *) Av_malloc (avpicture_get_size (pix_fmt_yuv420p, Pcodecctx->width, Pcodecctx->height)); Avpicture_fill ((Avpicture *) PFRAMEYUV, Out_buffer, pix_fmt_yuv420p, PCodecCtx->width, Pcodecctx->height);p acket= (Avpacket *) av_malloc (sizeof (Avpacket));//output Info-----------------------------printf ("---------------File information----------------\ n"); Av_dump_format ( pformatctx,0,filepath,0);p rintf ("-------------------------------------------------\ n"); img_convert_ctx = Sws_ GetContext (Pcodecctx->width, Pcodecctx->height, Pcodecctx->pix_fmt, Pcodecctx->width, pCodecCtx-> Height, pix_fmt_yuv420p, sws_bicubic, NULL, NULL, NULL); while (Av_read_frame (pformatctx, packet) >=0) {if (packet->stream_index==videoindex) {ret = Avcodec_decode_ Video2 (Pcodecctx, Pframe, &got_picture, packet); if (Ret < 0) {printf ("Decode error.\n"); return-1;} if (got_picture) {Sws_scale (Img_convert_ctx, (const uint8_t* const*) Pframe->data, pframe->linesize, 0, Pcodecctx->height, Pframeyuv->data, pframeyuv->linesize);y_size=pcodecctx->width*pcodecctx-> Height Fwrite (PFRAMEYUV->DATA[0],1,Y_SIZE,FP_YUV); Y fwrite (PFRAMEYUV->DATA[1],1,Y_SIZE/4,FP_YUV); Ufwrite (PFRAMEYUV->DATA[2],1,Y_SIZE/4,FP_YUV); Vprintf ("Succeed to decode 1 frame!\n");}} Av_free_packet (packet);} Flush Decoder//fix:flush Frames remained in Codecwhile (1) {ret = Avcodec_decode_video2 (Pcodecctx, Pframe, &got_pic ture, packet); if (Ret < 0) break;if (!got_picture) Break;sws_scale (Img_convert_ctx, (const uint8_t* const*) pframe- >data, pframe->linesize, 0, Pcodecctx->height, Pframeyuv->data, pframeyuv->linesize); int y_size= pcodecctx->width*pcodecctx->height; Fwrite (PFRAMEYUV->DATA[0],1,Y_SIZE,FP_YUV); Y fwrite (PFRAMEYUV->DATA[1],1,Y_SIZE/4,FP_YUV); Ufwrite (PFRAMEYUV->DATA[2],1,Y_SIZE/4,FP_YUV); Vprintf ("Flush decoder:succeed to decode 1 frame!\n");} Sws_freecontext (IMG_CONVERT_CTX); Fclose (FP_YUV);Av_frame_free (&PFRAMEYUV); Av_frame_free (&pframe); Avcodec_close (PCODECCTX); Avformat_close_input (& PFORMATCTX); return 0;}
After running the resulting program, the following video files are decoded.
The decoded yuv420p data is saved as a file. You can view YUV content after you set the width height using the YUV player.
SDL pixel data player source code
/** * Simplest SDL2 Play video example (SDL2 play RGB/YUV) * Simplest video play SDL2 (SDL2 play RGB/YUV) * * Lei hua Lei xiaohua * [Email pro Tected] * Communication University/Digital TV Technology * Communication University of China/digital TV technology * http://blog.csdn.net/leixiaohua1020 * * This program uses SDL2 to play RGB/YUV video pixel data. SDL is actually an encapsulation of the underlying drawing * API (DIRECT3D,OPENGL), which is significantly easier to use than calling the underlying * API directly. * * Function call steps are as follows: * * [Initialize] * SDL_INIT (): Initialize SDL. * Sdl_createwindow (): Create window (Windows). * Sdl_createrenderer (): Creates a renderer (render) based on a window. * Sdl_createtexture (): Create texture (Texture). * * [Cyclic rendering data] * Sdl_updatetexture (): Sets the texture's data. * Sdl_rendercopy (): Textures are copied to the renderer. * Sdl_renderpresent (): Display. * * This software plays RGB/YUV raw video data using SDL2. * SDL is a wrapper of low-level API (Direct3D, OpenGL). * Use of SDL is much easier than directly call these low-level API. * The process is shown as follows: * * [init] * SDL_INIT (): Init SDL. * Sdl_createwindow (): Create a Window. * Sdl_createrenderer (): Create a Render. * Sdl_createtexture (): Create a Texture. * * [Loop to Render data] * Sdl_updatetexture (): Set Texture ' s data. * Sdl_rendercopy (): Copy Texture to Render. * Sdl_renderpresent (): Show. */#include <stdio.h>extern "C" {#include "sdl/sdl.h"};const int bpp=12;int screen_w=500,screen_h=500;const int pixel_w=320,pixel_h=180;unsigned Char Buffer[pixel_w*pixel_h*bpp/8];//refresh event#define REFRESH_EVENT (SDL_ Userevent + 1) #define Break_event (sdl_userevent + 2) int thread_exit=0;int refresh_video (void *opaque) {thread_exit=0; while (!thread_exit) {sdl_event event;event.type = refresh_event; Sdl_pushevent (&event); Sdl_delay (40);} Thread_exit=0;//breaksdl_event event;event.type = break_event; Sdl_pushevent (&event); return 0;} int main (int argc, char* argv[]) {if (Sdl_init (Sdl_init_video)) {printf ("Could not initialize SDL-%s\n", Sdl_geterror () ); return-1;} Sdl_window *screen; SDL 2.0 support for multiple Windowsscreen = Sdl_createwindow ("Simplest Video Play SDL2", sdl_windowpos_undefined, Sdl_w Indowpos_undefined,screen_w, Screen_h,sdl_window_opengl| sdl_window_resizable), if (!screen) {printf ("Sdl:could not create window-exiting:%s\n", Sdl_geterror ()); return-1;} sdl_renderer* sdlrenderer = sdl_createrenderer (screen,-1, 0); Uint32 pixformat=0;//iyuv:y + U + V (3 planes)//yv12:y + V + U (3 planes) pixformat= SDL_PIXELFORMAT_IYUV; sdl_texture* sdltexture = Sdl_createtexture (Sdlrenderer,pixformat, sdl_textureaccess_streaming,pixel_w,pixel_h); FILE *fp=null;fp=fopen ("Test_yuv420p_320x180.yuv", "rb+"), if (fp==null) {printf ("Cannot open this file\n"); return-1;} Sdl_rect Sdlrect; Sdl_thread *refresh_thread = Sdl_createthread (refresh_video,null,null); Sdl_event Event;while (1) {//waitsdl_waitevent (&event), if (event.type==refresh_event) {if (fread (buffer, 1, pixel_ W*PIXEL_H*BPP/8, fp)! = PIXEL_W*PIXEL_H*BPP/8) {//Loopfseek (FP, 0, Seek_set); fread (buffer, 1, PIXEL_W*PIXEL_H*BPP/8, FP );} Sdl_updatetexture (sdltexture, NULL, buffer, pixel_w); Fix:if window is resizesdlrect.x = 0; Sdlrect.y = 0; SDLRECT.W = Screen_w; SdlRect.h = SCReen_h; Sdl_renderclear (Sdlrenderer); Sdl_rendercopy (Sdlrenderer, Sdltexture, NULL, &sdlrect); Sdl_renderpresent (Sdlrenderer); }else if (event.type==sdl_windowevent) {//if resizesdl_getwindowsize (screen,&screen_w,&screen_h);} else if (event.type==sdl_quit) {thread_exit=1;} else if (event.type==break_event) {break;}} Sdl_quit (); return 0;}
After running the result program, it reads a yuv420p file under the program folder, as shown below.
The YUV content is then drawn in the popup window.
Download
simplest FFmpeg Player
Project Home
sourceforge:https://sourceforge.net/projects/simplestffmpegplayer/
Github:https://github.com/leixiaohua1020/simplest_ffmpeg_player
Open source China: Http://git.oschina.net/leixiaohua1020/simplest_ffmpeg_player
This program realizes the decoding and display of video files (support HEVC,H.264,MPEG2, etc.).
Is the simplest ffmpeg video decoding aspect of the tutorial.
You can learn about the decoding process of ffmpeg by studying this example.
The project consists of 6 projects:
Simplest_ffmpeg_player: Standard Edition, the beginning of ffmpeg learning.
SIMPLEST_FFMPEG_PLAYER_SU:SU (SDL Update), added a simple SDL event.
Simplest_ffmpeg_decoder: A decoder that contains the Encapsulation format processing function. Libavcodec and Libavformat are used.
Simplest_ffmpeg_decoder_pure: a pure decoder. Use only Libavcodec (no libavformat is used).
SIMPLEST_VIDEO_PLAY_SDL2: Example of using SDL2 to play YUV.
Simplest_ffmpeg_helloworld: Outputs the information for the FFmpeg class library.
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
The simplest ffmpeg+sdl-based video player: split-decoder and player