日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0)

發(fā)布時(shí)間:2024/4/11 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

=====================================================

最簡單的基于FFmpeg的視頻播放器系列文章列表:

100行代碼實(shí)現(xiàn)最簡單的基于FFMPEG+SDL的視頻播放器(SDL1.x)

最簡單的基于FFMPEG+SDL的視頻播放器 ver2 (采用SDL2.0)

最簡單的基于FFmpeg的解碼器-純凈版(不包含libavformat)

最簡單的基于FFMPEG+SDL的視頻播放器:拆分-解碼器和播放器

最簡單的基于FFMPEG的Helloworld程序

=====================================================


簡介

之前做過一個(gè)FFMPEG+SDL的簡單播放器:《100行代碼實(shí)現(xiàn)最簡單的基于FFMPEG+SDL的視頻播放器》。該播放器采用SDL1.2顯示視頻。最近有不少人反映SDL已經(jīng)升級到2.0版本了,甚至官網(wǎng)的Wiki上都只有SDL2.0的文檔了,因此下載了SDL 2.0 并且進(jìn)行了簡單的研究。隨后對此前的播放器進(jìn)行了修改,將SDL1.2換成了SDL2.0。

注:《100行代碼實(shí)現(xiàn)最簡單的基于FFMPEG+SDL的視頻播放器》文章中提到的很多知識這里不再重復(fù)記錄。本文重點(diǎn)記錄SDL1.2與SDL2.0的不同。


平臺使用了VC2010,FFmpeg類庫使用了最近的版本,SDL使用2.0版本。


Simplest FFmpeg Player 2


項(xiàng)目主頁

SourceForge:https://sourceforge.net/projects/simplestffmpegplayer/

Github:https://github.com/leixiaohua1020/simplest_ffmpeg_player

開源中國:http://git.oschina.net/leixiaohua1020/simplest_ffmpeg_player


流程圖


FFmpeg解碼一個(gè)視頻流程如下圖所示:


SDL2.0顯示YUV的流程圖:


對比SDL1.2的流程圖,發(fā)現(xiàn)變化還是很大的。幾乎所有的API都發(fā)生了變化。但是函數(shù)和變量有一定的對應(yīng)關(guān)系:

SDL_SetVideoMode()————SDL_CreateWindow()

SDL_Surface————SDL_Window

SDL_CreateYUVOverlay()————SDL_CreateTexture()

SDL_Overlay————SDL_Texture

不再一一例舉。

下圖為SDL1.x顯示YUV的流程圖。


簡單解釋各個(gè)變量的作用:

SDL_Window就是使用SDL的時(shí)候彈出的那個(gè)窗口。在SDL1.x版本中,只可以創(chuàng)建一個(gè)一個(gè)窗口。在SDL2.0版本中,可以創(chuàng)建多個(gè)窗口。
SDL_Texture用于顯示YUV數(shù)據(jù)。一個(gè)SDL_Texture對應(yīng)一幀YUV數(shù)據(jù)。
SDL_Renderer用于渲染SDL_Texture至SDL_Window。
SDL_Rect用于確定SDL_Texture顯示的位置。注意:一個(gè)SDL_Texture可以指定多個(gè)不同的SDL_Rect,這樣就可以在SDL_Window不同位置顯示相同的內(nèi)容(使用SDL_RenderCopy()函數(shù))。
它們的關(guān)系如下圖所示:


下圖舉了個(gè)例子,指定了4個(gè)SDL_Rect,可以實(shí)現(xiàn)4分屏的顯示。




simplest_ffmpeg_player(標(biāo)準(zhǔn)版)代碼

最基礎(chǔ)的版本,學(xué)習(xí)的開始。

[cpp]?view plaincopy
  • /**?
  • ?*?最簡單的基于FFmpeg的視頻播放器?2?
  • ?*?Simplest?FFmpeg?Player?2?
  • ?*?
  • ?*?雷霄驊?Lei?Xiaohua?
  • ?*?leixiaohua1020@126.com?
  • ?*?中國傳媒大學(xué)/數(shù)字電視技術(shù)?
  • ?*?Communication?University?of?China?/?Digital?TV?Technology?
  • ?*?http://blog.csdn.net/leixiaohua1020?
  • ?*?
  • ?*?第2版使用SDL2.0取代了第一版中的SDL1.2?
  • ?*?Version?2?use?SDL?2.0?instead?of?SDL?1.2?in?version?1.?
  • ?*?
  • ?*?本程序?qū)崿F(xiàn)了視頻文件的解碼和顯示(支持HEVC,H.264,MPEG2等)。?
  • ?*?是最簡單的FFmpeg視頻解碼方面的教程。?
  • ?*?通過學(xué)習(xí)本例子可以了解FFmpeg的解碼流程。?
  • ?*?This?software?is?a?simplest?video?player?based?on?FFmpeg.?
  • ?*?Suitable?for?beginner?of?FFmpeg.?
  • ?*?
  • ?*/??
  • ??
  • ??
  • ??
  • #include?<stdio.h>??
  • ??
  • #define?__STDC_CONSTANT_MACROS??
  • ??
  • #ifdef?_WIN32??
  • //Windows??
  • extern?"C"??
  • {??
  • #include?"libavcodec/avcodec.h"??
  • #include?"libavformat/avformat.h"??
  • #include?"libswscale/swscale.h"??
  • #include?"libavutil/imgutils.h"??
  • #include?"SDL2/SDL.h"??
  • };??
  • #else??
  • //Linux...??
  • #ifdef?__cplusplus??
  • extern?"C"??
  • {??
  • #endif??
  • #include?<libavcodec/avcodec.h>??
  • #include?<libavformat/avformat.h>??
  • #include?<libswscale/swscale.h>??
  • #include?<SDL2/SDL.h>??
  • #include?<libavutil/imgutils.h>??
  • #ifdef?__cplusplus??
  • };??
  • #endif??
  • #endif??
  • ??
  • //Output?YUV420P?data?as?a?file???
  • #define?OUTPUT_YUV420P?0??
  • ??
  • int?main(int?argc,?char*?argv[])??
  • {??
  • ????AVFormatContext?*pFormatCtx;??
  • ????int?????????????i,?videoindex;??
  • ????AVCodecContext??*pCodecCtx;??
  • ????AVCodec?????????*pCodec;??
  • ????AVFrame?*pFrame,*pFrameYUV;??
  • ????unsigned?char?*out_buffer;??
  • ????AVPacket?*packet;??
  • ????int?y_size;??
  • ????int?ret,?got_picture;??
  • ????struct?SwsContext?*img_convert_ctx;??
  • ??
  • ????char?filepath[]="bigbuckbunny_480x272.h265";??
  • ????//SDL---------------------------??
  • ????int?screen_w=0,screen_h=0;??
  • ????SDL_Window?*screen;???
  • ????SDL_Renderer*?sdlRenderer;??
  • ????SDL_Texture*?sdlTexture;??
  • ????SDL_Rect?sdlRect;??
  • ??
  • ????FILE?*fp_yuv;??
  • ??
  • ????av_register_all();??
  • ????avformat_network_init();??
  • ????pFormatCtx?=?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();??
  • ????pFrameYUV=av_frame_alloc();??
  • ????out_buffer=(unsigned?char?*)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);??
  • ??????
  • ????packet=(AVPacket?*)av_malloc(sizeof(AVPacket));??
  • ????//Output?Info-----------------------------??
  • ????printf("---------------?File?Information?----------------\n");??
  • ????av_dump_format(pFormatCtx,0,filepath,0);??
  • ????printf("-------------------------------------------------\n");??
  • ????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?OUTPUT_YUV420P???
  • ????fp_yuv=fopen("output.yuv","wb+");????
  • #endif????
  • ??????
  • ????if(SDL_Init(SDL_INIT_VIDEO?|?SDL_INIT_AUDIO?|?SDL_INIT_TIMER))?{????
  • ????????printf(?"Could?not?initialize?SDL?-?%s\n",?SDL_GetError());???
  • ????????return?-1;??
  • ????}???
  • ??
  • ????screen_w?=?pCodecCtx->width;??
  • ????screen_h?=?pCodecCtx->height;??
  • ????//SDL?2.0?Support?for?multiple?windows??
  • ????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\n",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;??
  • ??
  • ????//SDL?End----------------------??
  • ????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?unsigned?char*?const*)pFrame->data,?pFrame->linesize,?0,?pCodecCtx->height,???
  • ????????????????????pFrameYUV->data,?pFrameYUV->linesize);??
  • ??????????????????
  • #if?OUTPUT_YUV420P??
  • ????????????????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);??//U??
  • ????????????????fwrite(pFrameYUV->data[2],1,y_size/4,fp_yuv);??//V??
  • #endif??
  • ????????????????//SDL---------------------------??
  • #if?0??
  • ????????????????SDL_UpdateTexture(?sdlTexture,?NULL,?pFrameYUV->data[0],?pFrameYUV->linesize[0]?);????
  • #else??
  • ????????????????SDL_UpdateYUVTexture(sdlTexture,?&sdlRect,??
  • ????????????????pFrameYUV->data[0],?pFrameYUV->linesize[0],??
  • ????????????????pFrameYUV->data[1],?pFrameYUV->linesize[1],??
  • ????????????????pFrameYUV->data[2],?pFrameYUV->linesize[2]);??
  • #endif????
  • ??????????????????
  • ????????????????SDL_RenderClear(?sdlRenderer?);????
  • ????????????????SDL_RenderCopy(?sdlRenderer,?sdlTexture,??NULL,?&sdlRect);????
  • ????????????????SDL_RenderPresent(?sdlRenderer?);????
  • ????????????????//SDL?End-----------------------??
  • ????????????????//Delay?40ms??
  • ????????????????SDL_Delay(40);??
  • ????????????}??
  • ????????}??
  • ????????av_free_packet(packet);??
  • ????}??
  • ????//flush?decoder??
  • ????//FIX:?Flush?Frames?remained?in?Codec??
  • ????while?(1)?{??
  • ????????ret?=?avcodec_decode_video2(pCodecCtx,?pFrame,?&got_picture,?packet);??
  • ????????if?(ret?<?0)??
  • ????????????break;??
  • ????????if?(!got_picture)??
  • ????????????break;??
  • ????????sws_scale(img_convert_ctx,?(const?unsigned?char*?const*)pFrame->data,?pFrame->linesize,?0,?pCodecCtx->height,???
  • ????????????pFrameYUV->data,?pFrameYUV->linesize);??
  • #if?OUTPUT_YUV420P??
  • ????????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);??//U??
  • ????????fwrite(pFrameYUV->data[2],1,y_size/4,fp_yuv);??//V??
  • #endif??
  • ????????//SDL---------------------------??
  • ????????SDL_UpdateTexture(?sdlTexture,?&sdlRect,?pFrameYUV->data[0],?pFrameYUV->linesize[0]?);????
  • ????????SDL_RenderClear(?sdlRenderer?);????
  • ????????SDL_RenderCopy(?sdlRenderer,?sdlTexture,??NULL,?&sdlRect);????
  • ????????SDL_RenderPresent(?sdlRenderer?);????
  • ????????//SDL?End-----------------------??
  • ????????//Delay?40ms??
  • ????????SDL_Delay(40);??
  • ????}??
  • ??
  • ????sws_freeContext(img_convert_ctx);??
  • ??
  • #if?OUTPUT_YUV420P???
  • ????fclose(fp_yuv);??
  • #endif???
  • ??
  • ????SDL_Quit();??
  • ??
  • ????av_frame_free(&pFrameYUV);??
  • ????av_frame_free(&pFrame);??
  • ????avcodec_close(pCodecCtx);??
  • ????avformat_close_input(&pFormatCtx);??
  • ??
  • ????return?0;??
  • }??



  • simplest_ffmpeg_player_su(SU版)代碼

    標(biāo)準(zhǔn)版的基礎(chǔ)之上引入了SDL的Event。

    效果如下:

    (1)SDL彈出的窗口可以移動了
    (2)畫面顯示是嚴(yán)格的40ms一幀

    [cpp]?view plaincopy
  • /**?
  • ?*?最簡單的基于FFmpeg的視頻播放器2(SDL升級版)?
  • ?*?Simplest?FFmpeg?Player?2(SDL?Update)?
  • ?*?
  • ?*?雷霄驊?Lei?Xiaohua?
  • ?*?leixiaohua1020@126.com?
  • ?*?中國傳媒大學(xué)/數(shù)字電視技術(shù)?
  • ?*?Communication?University?of?China?/?Digital?TV?Technology?
  • ?*?http://blog.csdn.net/leixiaohua1020?
  • ?*?
  • ?*?第2版使用SDL2.0取代了第一版中的SDL1.2?
  • ?*?Version?2?use?SDL?2.0?instead?of?SDL?1.2?in?version?1.?
  • ?*?
  • ?*?本程序?qū)崿F(xiàn)了視頻文件的解碼和顯示(支持HEVC,H.264,MPEG2等)。?
  • ?*?是最簡單的FFmpeg視頻解碼方面的教程。?
  • ?*?通過學(xué)習(xí)本例子可以了解FFmpeg的解碼流程。?
  • ?*?本版本中使用SDL消息機(jī)制刷新視頻畫面。?
  • ?*?This?software?is?a?simplest?video?player?based?on?FFmpeg.?
  • ?*?Suitable?for?beginner?of?FFmpeg.?
  • ?*?
  • ?*?備注:?
  • ?*?標(biāo)準(zhǔn)版在播放視頻的時(shí)候,畫面顯示使用延時(shí)40ms的方式。這么做有兩個(gè)后果:?
  • ?*?(1)SDL彈出的窗口無法移動,一直顯示是忙碌狀態(tài)?
  • ?*?(2)畫面顯示并不是嚴(yán)格的40ms一幀,因?yàn)檫€沒有考慮解碼的時(shí)間。?
  • ?*?SU(SDL?Update)版在視頻解碼的過程中,不再使用延時(shí)40ms的方式,而是創(chuàng)建了?
  • ?*?一個(gè)線程,每隔40ms發(fā)送一個(gè)自定義的消息,告知主函數(shù)進(jìn)行解碼顯示。這樣做之后:?
  • ?*?(1)SDL彈出的窗口可以移動了?
  • ?*?(2)畫面顯示是嚴(yán)格的40ms一幀?
  • ?*?Remark:?
  • ?*?Standard?Version?use's?SDL_Delay()?to?control?video's?frame?rate,?it?has?2?
  • ?*?disadvantages:?
  • ?*?(1)SDL's?Screen?can't?be?moved?and?always?"Busy".?
  • ?*?(2)Frame?rate?can't?be?accurate?because?it?doesn't?consider?the?time?consumed??
  • ?*?by?avcodec_decode_video2()?
  • ?*?SU(SDL?Update)Version?solved?2?problems?above.?It?create?a?thread?to?send?SDL??
  • ?*?Event?every?40ms?to?tell?the?main?loop?to?decode?and?show?video?frames.?
  • ?*/??
  • ??
  • #include?<stdio.h>??
  • ??
  • #define?__STDC_CONSTANT_MACROS??
  • ??
  • #ifdef?_WIN32??
  • //Windows??
  • extern?"C"??
  • {??
  • #include?"libavcodec/avcodec.h"??
  • #include?"libavformat/avformat.h"??
  • #include?"libswscale/swscale.h"??
  • #include?"libavutil/imgutils.h"??
  • #include?"SDL2/SDL.h"??
  • };??
  • #else??
  • //Linux...??
  • #ifdef?__cplusplus??
  • extern?"C"??
  • {??
  • #endif??
  • #include?<libavcodec/avcodec.h>??
  • #include?<libavformat/avformat.h>??
  • #include?<libswscale/swscale.h>??
  • #include?<libavutil/imgutils.h>??
  • #include?<SDL2/SDL.h>??
  • #ifdef?__cplusplus??
  • };??
  • #endif??
  • #endif??
  • ??
  • //Refresh?Event??
  • #define?SFM_REFRESH_EVENT??(SDL_USEREVENT?+?1)??
  • ??
  • #define?SFM_BREAK_EVENT??(SDL_USEREVENT?+?2)??
  • ??
  • int?thread_exit=0;??
  • int?thread_pause=0;??
  • ??
  • int?sfp_refresh_thread(void?*opaque){??
  • ????thread_exit=0;??
  • ????thread_pause=0;??
  • ??
  • ????while?(!thread_exit)?{??
  • ????????if(!thread_pause){??
  • ????????????SDL_Event?event;??
  • ????????????event.type?=?SFM_REFRESH_EVENT;??
  • ????????????SDL_PushEvent(&event);??
  • ????????}??
  • ????????SDL_Delay(40);??
  • ????}??
  • ????thread_exit=0;??
  • ????thread_pause=0;??
  • ????//Break??
  • ????SDL_Event?event;??
  • ????event.type?=?SFM_BREAK_EVENT;??
  • ????SDL_PushEvent(&event);??
  • ??
  • ????return?0;??
  • }??
  • ??
  • ??
  • int?main(int?argc,?char*?argv[])??
  • {??
  • ??
  • ????AVFormatContext?*pFormatCtx;??
  • ????int?????????????i,?videoindex;??
  • ????AVCodecContext??*pCodecCtx;??
  • ????AVCodec?????????*pCodec;??
  • ????AVFrame?*pFrame,*pFrameYUV;??
  • ????unsigned?char?*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;??
  • ??
  • ????//char?filepath[]="bigbuckbunny_480x272.h265";??
  • ????char?filepath[]="Titanic.ts";??
  • ??
  • ????av_register_all();??
  • ????avformat_network_init();??
  • ????pFormatCtx?=?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();??
  • ????pFrameYUV=av_frame_alloc();??
  • ??
  • ????out_buffer=(unsigned?char?*)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);??
  • ??
  • ????//Output?Info-----------------------------??
  • ????printf("----------------?File?Information?---------------\n");??
  • ????av_dump_format(pFormatCtx,0,filepath,0);??
  • ????printf("-------------------------------------------------\n");??
  • ??????
  • ????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_AUDIO?|?SDL_INIT_TIMER))?{????
  • ????????printf(?"Could?not?initialize?SDL?-?%s\n",?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\n",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));??
  • ??
  • ????video_tid?=?SDL_CreateThread(sfp_refresh_thread,NULL,NULL);??
  • ????//------------SDL?End------------??
  • ????//Event?Loop??
  • ??????
  • ????for?(;;)?{??
  • ????????//Wait??
  • ????????SDL_WaitEvent(&event);??
  • ????????if(event.type==SFM_REFRESH_EVENT){??
  • ????????????while(1){??
  • ????????????????if(av_read_frame(pFormatCtx,?packet)<0)??
  • ????????????????????thread_exit=1;??
  • ??
  • ????????????????if(packet->stream_index==videoindex)??
  • ????????????????????break;??
  • ????????????}??
  • ????????????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?unsigned?char*?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,?&sdlRect,?&sdlRect?);????
  • ????????????????SDL_RenderCopy(?sdlRenderer,?sdlTexture,?NULL,?NULL);????
  • ????????????????SDL_RenderPresent(?sdlRenderer?);????
  • ????????????????//SDL?End-----------------------??
  • ????????????}??
  • ????????????av_free_packet(packet);??
  • ????????}else?if(event.type==SDL_KEYDOWN){??
  • ????????????//Pause??
  • ????????????if(event.key.keysym.sym==SDLK_SPACE)??
  • ????????????????thread_pause=!thread_pause;??
  • ????????}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(&pFrameYUV);??
  • ????av_frame_free(&pFrame);??
  • ????avcodec_close(pCodecCtx);??
  • ????avformat_close_input(&pFormatCtx);??
  • ??
  • ????return?0;??
  • }??



  • 運(yùn)行結(jié)果

    程序運(yùn)行后,會在命令行窗口打印一些視頻信息,同時(shí)會彈出一個(gè)窗口播放視頻內(nèi)容。



    下載

    CSDN完整工程下載地址:

    http://download.csdn.net/detail/leixiaohua1020/7826277

    更新(2014.10.5)==============================

    版本升級至2.2。

    1.新版本在原版本的基礎(chǔ)上增加了“flush_decoder”功能。當(dāng)av_read_frame()循環(huán)退出的時(shí)候,實(shí)際上解碼器中可能還包含剩余的幾幀數(shù)據(jù)。因此需要通過“flush_decoder”將這幾幀數(shù)據(jù)輸出。“flush_decoder”功能簡而言之即直接調(diào)用avcodec_decode_video2()獲得AVFrame,而不再向解碼器傳遞AVPacket。參考代碼如下:

    [cpp]?view plaincopy
  • //FIX:?Flush?Frames?remained?in?Codec??
  • while?(1)?{??
  • ????ret?=?avcodec_decode_video2(pCodecCtx,?pFrame,?&got_picture,?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);??
  • ????//處理...??
  • }??

  • 2.為了更好地適應(yīng)Linux等其他操作系統(tǒng),做到可以跨平臺,去除掉了VC特有的一些函數(shù)。比如“#include "stdafx.h"”,“_tmain()”等等。

    具體信息參見文章:avcodec_decode_video2()解碼視頻后丟幀的問題解決

    2.2版下載地址: http://download.csdn.net/detail/leixiaohua1020/8002337


    更新-2.3(2015.1.03)==============================

    新增一個(gè)工程:最簡單的基于FFmpeg的解碼器-純凈版(不包含libavformat)

    2.3版CSDN下載地址: http://download.csdn.net/detail/leixiaohua1020/8322307


    更新-2.4(2015.2.13)==============================

    這次考慮到了跨平臺的要求,調(diào)整了源代碼。經(jīng)過這次調(diào)整之后,源代碼可以在以下平臺編譯通過:

    VC++:打開sln文件即可編譯,無需配置。

    cl.exe:打開compile_cl.bat即可命令行下使用cl.exe進(jìn)行編譯,注意可能需要按照VC的安裝路徑調(diào)整腳本里面的參數(shù)。編譯命令如下。

    [plain]?view plaincopy
  • ::VS2010?Environment??
  • call?"D:\Program?Files\Microsoft?Visual?Studio?10.0\VC\vcvarsall.bat"??
  • ::include??
  • @set?INCLUDE=include;%INCLUDE%??
  • ::lib??
  • @set?LIB=lib;%LIB%??
  • ::compile?and?link??
  • cl?simplest_ffmpeg_player.cpp?/MD?/link?SDL2.lib?SDL2main.lib?avcodec.lib?^??
  • avformat.lib?avutil.lib?avdevice.lib?avfilter.lib?postproc.lib?swresample.lib?swscale.lib?^??
  • /SUBSYSTEM:WINDOWS?/OPT:NOREF??
  • MinGW:MinGW命令行下運(yùn)行compile_mingw.sh即可使用MinGW的g++進(jìn)行編譯。編譯命令如下。

    [plain]?view plaincopy
  • g++?simplest_ffmpeg_player.cpp?-g?-o?simplest_ffmpeg_player.exe?\??
  • -I?/usr/local/include?-L?/usr/local/lib?\??
  • -lmingw32?-lSDL2main?-lSDL2?-lavformat?-lavcodec?-lavutil?-lswscale??
  • GCC:Linux或者M(jìn)acOS命令行下運(yùn)行compile_gcc.sh即可使用GCC進(jìn)行編譯。編譯命令如下。

    [plain]?view plaincopy
  • gcc?simplest_ffmpeg_player.cpp?-g?-o?simplest_ffmpeg_player.out?\??
  • -I?/usr/local/include?-L?/usr/local/lib?-lSDL2main?-lSDL2?-lavformat?-lavcodec?-lavutil?-lswscale??
  • PS:相關(guān)的編譯命令已經(jīng)保存到了工程文件夾中

    CSDN項(xiàng)目下載地址:http://download.csdn.net/detail/leixiaohua1020/8443943 SourceForge、Github等上面已經(jīng)更新。
    更新-2.5(2015.7.17)==============================
    增加了下列工程: simplest_ffmpeg_decoder:一個(gè)包含了封裝格式處理功能的解碼器。使用了libavcodec和libavformat。simplest_video_play_sdl2:使用SDL2播放YUV的例子。simplest_ffmpeg_helloworld:輸出FFmpeg類庫的信息。
    CSDN項(xiàng)目下載地址:http://download.csdn.net/detail/leixiaohua1020/8924321
    SourceForge、Github等上面已經(jīng)更新。

    總結(jié)

    以上是生活随笔為你收集整理的最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。