FFmpeg与SDL双剑合璧之ubuntu
2015-09-17 16:50
246 查看
以前所做的工作,大多是把FFmpeg用在windows平台,采用D3D或者OpenGL的方式进行渲染呈现;
前面两篇文章中,已经做好了ubuntu平台下的ffmpeg编译与简单调试(ubuntu编译ffmpeg并且demo测试),以及windows平台下的ffmpeg解码SDL显示(FFmpeg与SDL双剑合璧之Windows
);
梳理一下手上已经具备的材料:
①ffmpeg解码,SDL播放的Demo(windows平台);
②ubuntu平台下编译好的ffmpeg库;
③ubuntu平台下编译好的SDL库;
第③份材料,没有写出来,因为太简单了,大致操作步骤是:
1.下载SDL源码(SDL),解压;
2.打开终端,切换到SDL源码解压后的目录,执行./configure
3.make
4.sudo make install
OVER;
接下来,就是把windows平台下的代码直接搬过来,没有多少需要修改的地方,主要是库的引用上下了点功夫
一个需要注意的,对于ffmpeg库的调用,需要在包含头文件之前,定义一下
下面上干货:
下面是调用的主函数
接下来是主菜,makefile
工作到此为止,收获的时间到了,cd到这些源代码所在的目录,make一下,
执行,看效果如何:
前面两篇文章中,已经做好了ubuntu平台下的ffmpeg编译与简单调试(ubuntu编译ffmpeg并且demo测试),以及windows平台下的ffmpeg解码SDL显示(FFmpeg与SDL双剑合璧之Windows
);
梳理一下手上已经具备的材料:
①ffmpeg解码,SDL播放的Demo(windows平台);
②ubuntu平台下编译好的ffmpeg库;
③ubuntu平台下编译好的SDL库;
第③份材料,没有写出来,因为太简单了,大致操作步骤是:
1.下载SDL源码(SDL),解压;
2.打开终端,切换到SDL源码解压后的目录,执行./configure
3.make
4.sudo make install
OVER;
接下来,就是把windows平台下的代码直接搬过来,没有多少需要修改的地方,主要是库的引用上下了点功夫
一个需要注意的,对于ffmpeg库的调用,需要在包含头文件之前,定义一下
#define __STDC_CONSTANT_MACROS
下面上干货:
//FFDecoder.h #pragma once #define __STDC_CONSTANT_MACROS extern "C" { #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" #include "libavutil/avutil.h" #include "libavutil/opt.h" #include "libswscale/swscale.h" } class CFFDecoder { public: CFFDecoder(); virtual ~CFFDecoder(); int OpenFile(const char *pFilePath); int GetMediaInfo(int &nFrameW,int &nFrameH); int GetOneFrame(AVFrame *pFrame); private: AVFormatContext *m_pFormatCxt; AVCodecContext *m_pCodecCtx; AVCodec *m_pCodec; AVPacket m_Packet; int m_nVideoIndex; int m_nAudioIndex; };
//FFDecoder.cpp #include "FFDecoder.h" CFFDecoder::CFFDecoder() { m_pFormatCxt = avformat_alloc_context(); m_pCodecCtx = NULL; m_pCodec = NULL; m_nVideoIndex = -1; m_nAudioIndex = -1; } CFFDecoder::~CFFDecoder() { } int CFFDecoder::OpenFile(const char *pFilePath) { av_register_all(); if(avformat_open_input(&m_pFormatCxt,pFilePath,NULL,NULL)<0) { return -1; } if (avformat_find_stream_info(m_pFormatCxt,NULL)<0) { return -2; } //ÕÒµœÒôÊÓƵ¶ÔÓŠµÄÁ÷ÍšµÀ for (int i=0;i<m_pFormatCxt->nb_streams;i++) { if (m_pFormatCxt->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { m_nVideoIndex = i; } else if (m_pFormatCxt->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) { m_nAudioIndex = i; } } if (m_nVideoIndex == -1) { return -3; } //Žò¿ªÏàÓŠµÄœâÂëÆ÷ m_pCodecCtx = m_pFormatCxt->streams[m_nVideoIndex]->codec; m_pCodec = avcodec_find_decoder(m_pCodecCtx->codec_id);; if(m_pCodec==NULL){ return -4; } if(avcodec_open2(m_pCodecCtx, m_pCodec,NULL)<0){ return -5; } return 0; } int CFFDecoder::GetMediaInfo(int &nFrameW,int &nFrameH) { if(m_pCodecCtx==NULL) return -1; nFrameW = m_pCodecCtx->width; nFrameH = m_pCodecCtx->height; return 0; } int CFFDecoder::GetOneFrame(AVFrame *pFrame) { if(m_pFormatCxt==NULL) return 0; int nGotPicture=-1; if(av_read_frame(m_pFormatCxt,&m_Packet)>=0) { //ÅжÏÊÇ·ñΪµ±Ç°ÊÓƵÁ÷Öеİü if (m_Packet.stream_index == m_nVideoIndex) { int nLen = avcodec_decode_video2(m_pCodecCtx,pFrame,&nGotPicture,&m_Packet); if (nLen<0) { return 0; } if (nGotPicture) { //³É¹ŠµÃµœÒ»Ö¡ÊýŸÝ return nLen; } } } return 0; }
//SDLPlayer.h #pragma once extern "C" { #include "SDL.h" } #define MSG_REFRESH_VIDEO (SDL_USEREVENT+10) class CSDLPlayer { public: CSDLPlayer(); virtual ~CSDLPlayer(); //³õÊŒ»¯²¥·ÅÆ÷£¬ÉèÖò¥·ÅÆ÷¿ížß int InitPlayer(int nWinW, int nWinH); //³õÊŒ»¯ÎÆÀí£¬ÉèÖÃÎÆÀí¿ížß int InitTexture(int nFrameW, int nFrameH); int InputFrame(unsigned char *pY, unsigned long Ylinesize, unsigned char *pU, unsigned long Ulinesize, unsigned char *pV, unsigned long Vlinesize); private: static int Thread2Refresh(void *opaque); private: SDL_Window *m_pPlayer; SDL_Rect m_rect; SDL_Renderer *m_pReader; SDL_Texture *m_pTexture; };
//SDLPlayer.cpp #include "SDLPlayer.h" CSDLPlayer::CSDLPlayer() { m_pPlayer = NULL; m_pReader = NULL; m_pTexture = NULL; } CSDLPlayer::~CSDLPlayer() { } int CSDLPlayer::Thread2Refresh(void *opaque) { while(1) { SDL_Event evt; evt.type = MSG_REFRESH_VIDEO; SDL_PushEvent(&evt); SDL_Delay(40); } return 0; } int CSDLPlayer::InitPlayer(int nWinW, int nWinH) { if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) { return -1; } m_pPlayer=SDL_CreateWindow("Hello SDL", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, nWinW,nWinH, SDL_WINDOW_RESIZABLE|SDL_WINDOW_OPENGL); SDL_Thread *refresh_thread = SDL_CreateThread(Thread2Refresh,NULL,NULL); return 0; } int CSDLPlayer::InitTexture(int nFrameW, int nFrameH) { if(m_pPlayer==NULL) return 0; m_pReader = SDL_CreateRenderer(m_pPlayer,-1,0); m_pTexture = SDL_CreateTexture(m_pReader,SDL_PIXELFORMAT_IYUV,SDL_TEXTUREACCESS_STREAMING,nFrameW,nFrameH); m_rect.x = 0; m_rect.y = 0; m_rect.w = nFrameW; m_rect.h = nFrameH; return 0; } int CSDLPlayer::InputFrame(unsigned char *pY, unsigned long Ylinesize, unsigned char *pU, unsigned long Ulinesize, unsigned char *pV, unsigned long Vlinesize) { if(m_pPlayer==NULL || m_pReader==NULL || m_pTexture==NULL) return -1; //ʵÏÖÏûÏ¢£¬ÊÇΪÁË¿ØÖƲ¥·ÅËÙ¶ÈÒÑŸ±ÜÃ⎰¿Ú³öÏÖÎŽÏìӊ׎̬ SDL_Event evt; SDL_WaitEvent(&evt); //SDL_Log("#####EVENT evt.type=0x%d\n",evt.type); if(evt.type == SDL_WINDOWEVENT) { SDL_Log("WINDOWEVENT evt.type=0x%x,evt.window.event=0x%d\n",evt.type,evt.window.event); if(evt.window.event==SDL_WINDOWEVENT_CLOSE) { SDL_Window *pWindow=SDL_GetWindowFromID(evt.window.windowID); if(pWindow == m_pPlayer) { SDL_DestroyWindow(pWindow); m_pPlayer = NULL; } } } if(evt.type!=MSG_REFRESH_VIDEO) return -1; SDL_Rect sdlRect; sdlRect.x = 0; sdlRect.y = 0; SDL_GetWindowSize(m_pPlayer,&sdlRect.w,&sdlRect.h); //SDL_UpdateTexture(m_pTexture,&m_rect,pYUVData,linesize); //¿ÉÒÔŽŠÀíÄÇЩyuvÄÚŽæÊýŸÝ²»Á¬ÐøµÄÇé¿ö SDL_UpdateYUVTexture(m_pTexture,&m_rect, pY,Ylinesize, pU,Ulinesize, pV,Vlinesize); SDL_RenderClear( m_pReader ); SDL_RenderCopy( m_pReader, m_pTexture, &m_rect, &sdlRect); SDL_RenderPresent( m_pReader ); SDL_Delay(10); return 0; }
下面是调用的主函数
//FFmpegSDL.cpp #include "FFDecoder.h" #include "SDLPlayer.h" int main(int argc, char* argv[]) { CFFDecoder dec; CSDLPlayer player[2]; dec.OpenFile("/home/xy/Videos/Wild.mp4"); int nFrameW=0,nFrameH=0; dec.GetMediaInfo(nFrameW,nFrameH); player[0].InitPlayer(800,600); player[0].InitTexture(nFrameW,nFrameH); player[1].InitPlayer(800,600); player[1].InitTexture(nFrameW,nFrameH); AVFrame *pFrame=av_frame_alloc(); while(1) { if(dec.GetOneFrame(pFrame)>0) { player[0].InputFrame(pFrame->data[0],pFrame->linesize[0], pFrame->data[1],pFrame->linesize[1], pFrame->data[2],pFrame->linesize[2]); player[1].InputFrame(pFrame->data[0],pFrame->linesize[0], pFrame->data[1],pFrame->linesize[1], pFrame->data[2],pFrame->linesize[2]); } } return 0; }
接下来是主菜,makefile
srcdir = . CC = g++ EXE = CFLAGS = -I/home/xy/soft/ffout/include -D_REENTRANT -I/usr/local/include/SDL2 -DHAVE_OPENGL LIBS = -L/home/xy/soft/ffout/lib -lpthread -lavutil -lavformat -lavcodec -lswscale -lm -lz \ -lSDL2_test -Wl,-rpath,/usr/local/lib -L/usr/local/lib -lSDL2 TARGETS = FFmpegSDL all: $(TARGETS) FFmpegSDL$(EXE): $(srcdir)/FFDecoder.cpp $(srcdir)/FFDecoder.h $(srcdir)/SDLPlayer.cpp $(srcdir)/SDLPlayer.h $(srcdir)/FFmpegSDL.cpp $(CC) $^ -o $(TARGETS) $(CFLAGS) $(LIBS) clean: rm -f $(TARGETS)
工作到此为止,收获的时间到了,cd到这些源代码所在的目录,make一下,
执行,看效果如何:
相关文章推荐
- html5预览上传图片缩略图
- HashMap的存储与实现
- Apache Camel读取配置文件
- WebRTC VideoEngine超详细教程(三)——集成X264编码和ffmpeg解码
- Java字符串转换为ASCII
- web.xml 配置中classpath: 与classpath*:的区别
- socket 设置阻塞和超时
- Third-party Modules Using Note
- 渲染和着色器
- Oracle笔记——分页查询
- hdu5437 优先级队列的应用
- MySQL通用优化技巧
- 【dp+优化】tyvj1013 FAreStorm教你找GF
- jni 转换
- NDK DEBUG方法
- Socket编程 socket连接设置超时的几种方法
- poi导出excel
- SpringMVC + Apache POI 实现WEB中Excel下载功能
- bindAppWidgetIdIfAllowed 老是返回false的原因
- 配置SDK时遇到的一系列问题