{"id":56,"date":"2025-05-19T17:37:51","date_gmt":"2025-05-19T09:37:51","guid":{"rendered":"http:\/\/112.74.48.51\/?p=56"},"modified":"2025-05-22T14:33:14","modified_gmt":"2025-05-22T06:33:14","slug":"ffmpeg_player%e5%ad%a6%e4%b9%a0","status":"publish","type":"post","link":"https:\/\/look123.top\/index.php\/2025\/05\/19\/ffmpeg_player%e5%ad%a6%e4%b9%a0\/","title":{"rendered":"ffmpeg_player\u5b66\u4e60"},"content":{"rendered":"\n<pre class=\"wp-block-code\"><code>\/**\n * \u6700\u7b80\u5355\u7684\u57fa\u4e8eFFmpeg\u7684\u89c6\u9891\u64ad\u653e\u5668 2\n * Simplest FFmpeg Player 2\n *\n * \u96f7\u9704\u9a85 Lei Xiaohua\n * leixiaohua1020@126.com\n * \u4e2d\u56fd\u4f20\u5a92\u5927\u5b66\/\u6570\u5b57\u7535\u89c6\u6280\u672f\n * Communication University of China \/ Digital TV Technology\n * http:\/\/blog.csdn.net\/leixiaohua1020\n *\n * \u7b2c2\u7248\u4f7f\u7528SDL2.0\u53d6\u4ee3\u4e86\u7b2c\u4e00\u7248\u4e2d\u7684SDL1.2\n * Version 2 use SDL 2.0 instead of SDL 1.2 in version 1.\n *\n * \u672c\u7a0b\u5e8f\u5b9e\u73b0\u4e86\u89c6\u9891\u6587\u4ef6\u7684\u89e3\u7801\u548c\u663e\u793a(\u652f\u6301HEVC\uff0cH.264\uff0cMPEG2\u7b49)\u3002\n * \u662f\u6700\u7b80\u5355\u7684FFmpeg\u89c6\u9891\u89e3\u7801\u65b9\u9762\u7684\u6559\u7a0b\u3002\n * \u901a\u8fc7\u5b66\u4e60\u672c\u4f8b\u5b50\u53ef\u4ee5\u4e86\u89e3FFmpeg\u7684\u89e3\u7801\u6d41\u7a0b\u3002\n * This software is a simplest video player based on FFmpeg.\n * Suitable for beginner of FFmpeg.\n *\n * Version:2.1\n * \u589e\u52a0\u4e86\u4f7f\u7528SDL\u6d88\u606f\u673a\u5236\u7684\u9879\u76ee\n * Add a Project \"simplest_ffmpeg_player2_su\" that use SDL Events.\n *\n * Version:2.2\n * \u589e\u52a0\u4e86\u201cflush_decoder\u201d\u529f\u80fd\uff0c\u53ef\u4ee5\u5728av_read_frame()\u5faa\u73af\u7ed3\u675f\u540e\uff0c\n * \u8f93\u51fa\u89e3\u7801\u5668\u4e2d\u7684\u6700\u540e\u51e0\u5e27\u6570\u636e\u3002\n * Add Code about \"flush_decoder\". It can output frames remained\n * in Codec after the loop of av_read_frame().\n *\/\n\n\n#pragma comment(lib, \"legacy_stdio_definitions.lib\")\n#if _MSC_VER&gt;=1900\n#include \"stdio.h\" \n_ACRTIMP_ALT FILE* __cdecl __acrt_iob_func(unsigned);\n#ifdef __cplusplus \nextern \"C\"\n#endif \nFILE * __cdecl __iob_func(unsigned i) {\n\treturn __acrt_iob_func(i);\n}\n#endif \/* _MSC_VER&gt;=1900 *\/\n\n#include &lt;stdio.h&gt;\n\nextern \"C\"\n{\n#include \"libavcodec\/avcodec.h\"\n#include \"libavformat\/avformat.h\"\n#include \"libswscale\/swscale.h\"\n#include \"libavutil\/log.h\"\n\t\/\/SDL\n#include \"sdl\/SDL.h\"\n\n};\n\n\/\/Output YUV420P data as a file \n#define OUTPUT_YUV420P 0\n\nint main(int argc, char* argv&#91;])\n{\n\tAVFormatContext\t*pFormatCtx;\n\tint\t\t\t\ti, videoindex;\n\tAVCodecContext\t*pCodecCtx;\n\tAVCodec\t\t\t*pCodec;\n\tAVFrame\t*pFrame,*pFrameYUV;\n\tuint8_t *out_buffer;\n\tAVPacket *packet;\n\tint y_size;\n\tint ret, got_picture;\n\tstruct SwsContext *img_convert_ctx;\n\n\tchar filepath&#91;]=\"bigbuckbunny_480x272.h265\";\n\t\n\n\tav_register_all();\n\tavformat_network_init();\n\tpFormatCtx = avformat_alloc_context();\n\n\tif(avformat_open_input(&amp;pFormatCtx,filepath,NULL,NULL)!=0){\n\t\tprintf(\"Couldn't open input stream.(\u65e0\u6cd5\u6253\u5f00\u8f93\u5165\u6d41)\\n\");\n\t\treturn -1;\n\t}\n\tif(avformat_find_stream_info(pFormatCtx,NULL)&lt;0){\n\t\tprintf(\"Couldn't find stream information.(\u65e0\u6cd5\u83b7\u53d6\u6d41\u4fe1\u606f)\\n\");\n\t\treturn -1;\n\t}\n\tvideoindex=-1;\n\tfor(i=0; i&lt;pFormatCtx-&gt;nb_streams; i++) \n\t\tif(pFormatCtx-&gt;streams&#91;i]-&gt;codec-&gt;codec_type==AVMEDIA_TYPE_VIDEO){\n\t\t\tvideoindex=i;\n\t\t\tbreak;\n\t\t}\n\tif(videoindex==-1){\n\t\tprintf(\"Didn't find a video stream.(\u6ca1\u6709\u627e\u5230\u89c6\u9891\u6d41)\\n\");\n\t\treturn -1;\n\t}\n\tpCodecCtx=pFormatCtx-&gt;streams&#91;videoindex]-&gt;codec;\n\tpCodec=avcodec_find_decoder(pCodecCtx-&gt;codec_id);\n\tif(pCodec==NULL){\n\t\tprintf(\"Codec not found.(\u6ca1\u6709\u627e\u5230\u89e3\u7801\u5668)\\n\");\n\t\treturn -1;\n\t}\n\tif(avcodec_open2(pCodecCtx, pCodec,NULL)&lt;0){\n\t\tprintf(\"Could not open codec.(\u65e0\u6cd5\u6253\u5f00\u89e3\u7801\u5668)\\n\");\n\t\treturn -1;\n\t}\n\t\n\tpFrame=avcodec_alloc_frame();\n\tpFrameYUV=avcodec_alloc_frame();\n\tout_buffer=(uint8_t *)av_malloc(avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx-&gt;width, pCodecCtx-&gt;height));\n\tavpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_YUV420P, pCodecCtx-&gt;width, pCodecCtx-&gt;height);\n\tpacket=(AVPacket *)av_malloc(sizeof(AVPacket));\n\t\/\/Output Info-----------------------------\n\tprintf(\"File Information --------------------------------\\n\");\n\tav_dump_format(pFormatCtx,0,filepath,0);\n\tprintf(\"-------------------------------------------------\\n\");\n\timg_convert_ctx = sws_getContext(pCodecCtx-&gt;width, pCodecCtx-&gt;height, pCodecCtx-&gt;pix_fmt, \n\t\tpCodecCtx-&gt;width, pCodecCtx-&gt;height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL); \n\n#if OUTPUT_YUV420P \n    FILE *fp_yuv=fopen(\"output.yuv\",\"wb+\");  \n#endif  \n\t\n\t\/\/SDL---------------------------\n\tint screen_w=0,screen_h=0;\n\tSDL_Window *screen; \n\tSDL_Renderer* sdlRenderer;\n\tSDL_Texture* sdlTexture;\n\tSDL_Rect sdlRect;\n\n\tif(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {  \n\t\tprintf( \"Could not initialize SDL - %s\\n\", SDL_GetError()); \n\t\treturn -1;\n\t} \n\n\tscreen_w = pCodecCtx-&gt;width;\n\tscreen_h = pCodecCtx-&gt;height;\n\t\/\/SDL 2.0 Support for multiple windows\n\tscreen = SDL_CreateWindow(\"Simplest ffmpeg player's Window\", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,\n\t\tscreen_w, screen_h,\n\t\tSDL_WINDOW_OPENGL);\n\n\tif(!screen) {  \n\t\tprintf(\"SDL: could not create window - exiting:%s\\n\",SDL_GetError());  \n\t\treturn -1;\n\t}\n\n\tsdlRenderer = SDL_CreateRenderer(screen, -1, 0);  \n\t\/\/IYUV: Y + U + V  (3 planes)\n\t\/\/YV12: Y + V + U  (3 planes)\n\tsdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING,pCodecCtx-&gt;width,pCodecCtx-&gt;height);  \n\n\tsdlRect.x=0;\n\tsdlRect.y=0;\n\tsdlRect.w=screen_w;\n\tsdlRect.h=screen_h;\n\n\t\/\/SDL End----------------------\n\twhile(av_read_frame(pFormatCtx, packet)&gt;=0){\n\t\tif(packet-&gt;stream_index==videoindex){\n\t\t\tret = avcodec_decode_video2(pCodecCtx, pFrame, &amp;got_picture, packet);\n\t\t\tif(ret &lt; 0){\n\t\t\t\tprintf(\"Decode Error.(\u89e3\u7801\u9519\u8bef)\\n\");\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\tif(got_picture){\n\t\t\t\tsws_scale(img_convert_ctx, (const uint8_t* const*)pFrame-&gt;data, pFrame-&gt;linesize, 0, pCodecCtx-&gt;height, \n\t\t\t\t\tpFrameYUV-&gt;data, pFrameYUV-&gt;linesize);\n\t\t\t\t\n#if OUTPUT_YUV420P\n\t\t\t\ty_size=pCodecCtx-&gt;width*pCodecCtx-&gt;height;  \n\t\t\t\tfwrite(pFrameYUV-&gt;data&#91;0],1,y_size,fp_yuv); \/\/Y \n\t\t\t\tfwrite(pFrameYUV-&gt;data&#91;1],1,y_size\/4,fp_yuv);  \/\/U\n\t\t\t\tfwrite(pFrameYUV-&gt;data&#91;2],1,y_size\/4,fp_yuv);  \/\/V\n#endif\n\t\t\t\t\/\/SDL---------------------------\n\t\t\t\tSDL_UpdateTexture( sdlTexture, NULL, pFrameYUV-&gt;data&#91;0], pFrameYUV-&gt;linesize&#91;0] );  \n\t\t\t\tSDL_RenderClear( sdlRenderer );  \n\t\t\t\tSDL_RenderCopy( sdlRenderer, sdlTexture,  NULL, &amp;sdlRect);  \n\t\t\t\tSDL_RenderPresent( sdlRenderer );  \n\t\t\t\t\/\/SDL End-----------------------\n\t\t\t\t\/\/Delay 40ms\n\t\t\t\tSDL_Delay(40);\n\t\t\t}\n\t\t}\n\t\tav_free_packet(packet);\n\t}\n\t\/\/flush decoder\n\t\/\/FIX: Flush Frames remained in Codec\n\twhile (1) {\n\t\tret = avcodec_decode_video2(pCodecCtx, pFrame, &amp;got_picture, packet);\n\t\tif (ret &lt; 0)\n\t\t\tbreak;\n\t\tif (!got_picture)\n\t\t\tbreak;\n\t\tsws_scale(img_convert_ctx, (const uint8_t* const*)pFrame-&gt;data, pFrame-&gt;linesize, 0, pCodecCtx-&gt;height, \n\t\t\tpFrameYUV-&gt;data, pFrameYUV-&gt;linesize);\n#if OUTPUT_YUV420P\n\t\tint y_size=pCodecCtx-&gt;width*pCodecCtx-&gt;height;  \n\t\tfwrite(pFrameYUV-&gt;data&#91;0],1,y_size,fp_yuv);    \/\/Y \n\t\tfwrite(pFrameYUV-&gt;data&#91;1],1,y_size\/4,fp_yuv);  \/\/U\n\t\tfwrite(pFrameYUV-&gt;data&#91;2],1,y_size\/4,fp_yuv);  \/\/V\n#endif\n\t\t\/\/SDL---------------------------\n\t\tSDL_UpdateTexture( sdlTexture, &amp;sdlRect, pFrameYUV-&gt;data&#91;0], pFrameYUV-&gt;linesize&#91;0] );  \n\t\tSDL_RenderClear( sdlRenderer );  \n\t\tSDL_RenderCopy( sdlRenderer, sdlTexture,  NULL, &amp;sdlRect);  \n\t\tSDL_RenderPresent( sdlRenderer );  \n\t\t\/\/SDL End-----------------------\n\t\t\/\/Delay 40ms\n\t\tSDL_Delay(40);\n\t}\n\n\tsws_freeContext(img_convert_ctx);\n\n#if OUTPUT_YUV420P \n    fclose(fp_yuv);\n#endif \n\n\tSDL_Quit();\n\n\tav_frame_free(&amp;pFrameYUV);\n\tav_frame_free(&amp;pFrame);\n\tavcodec_close(pCodecCtx);\n\tavformat_close_input(&amp;pFormatCtx);\n\n\treturn 0;\n}<\/code><\/pre>\n\n\n\n<p>\u81f4\u656c\u96f7\u795e<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u81f4\u656c\u96f7\u795e<\/p>\n","protected":false},"author":1,"featured_media":127,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-56","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cpp_qt"],"_links":{"self":[{"href":"https:\/\/look123.top\/index.php\/wp-json\/wp\/v2\/posts\/56","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/look123.top\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/look123.top\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/look123.top\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/look123.top\/index.php\/wp-json\/wp\/v2\/comments?post=56"}],"version-history":[{"count":4,"href":"https:\/\/look123.top\/index.php\/wp-json\/wp\/v2\/posts\/56\/revisions"}],"predecessor-version":[{"id":63,"href":"https:\/\/look123.top\/index.php\/wp-json\/wp\/v2\/posts\/56\/revisions\/63"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/look123.top\/index.php\/wp-json\/wp\/v2\/media\/127"}],"wp:attachment":[{"href":"https:\/\/look123.top\/index.php\/wp-json\/wp\/v2\/media?parent=56"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/look123.top\/index.php\/wp-json\/wp\/v2\/categories?post=56"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/look123.top\/index.php\/wp-json\/wp\/v2\/tags?post=56"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}