FFmpeg与SDL双剑合璧之ubuntu

以前所做的工作,大多是把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库的调用,需要在包含头文件之前,定义一下

#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一下,



执行,看效果如何:


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值