ffmpeg学习入门

2 篇文章 0 订阅

http://ffmpeg.org/doxygen/trunk/index.html       ffmpeg的api

我自己想写一个输入视频-》图像处理-》写视频的一个程序,首先自然是考虑使用opencv的视频处理的功能,但是如果纯粹使用opencv,处理出来的视频有个很大的缺点,那就是输出的文件中只有视频,而没有音频,所以最后选择使用opencv+ffmpeg的形式来写程序。但ffmpeg是面向过程的,编程很复杂,在参考我的另外一篇博文http://blog.csdn.net/jia_zhengshen/article/details/12994077的基础上编写了下面的程序。我认为我写的程序没有内存泄露,我使用到的东西最后都释放掉了,如果哪个人看到什么东西应该释放,而在程序中没有释放,请指出来,小弟不胜感激。

程序基本上按照:输入视频处理的初始化,opencv初始化,输出视频的初始化,处理视频,输入视频所用变量的释放,opencv的变量的释放、输出视频的变量的释放、程序结束。这几个步骤来写程序的,有什么错误还请指点。,。下面的程序还不能实现处理音频。

#ifdef  __cplusplus    
extern "C" {    
#endif  
#include<libavformat\avformat.h>
#include<libavcodec\avcodec.h>
#include<libswscale\swscale.h> 
#include<libavdevice\avdevice.h>
#include<libavfilter\avfilter.h>
//#include<avcodec.h>  
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

#include <libavutil/opt.h>
#include <libavutil/mathematics.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
//@author jia_zhengshen  http://blog.csdn.net/jia_zhengshen   版权所有。
#ifdef  __cplusplus    
}    
#endif    
#include<opencv\cv.h>
#include<opencv\highgui.h>
//input
int findStreamIndex(int *videoStreamIndex,int *audioStreamIndex ,AVFormatContext *pFormatCtx);
//output
int main()
{
	//ffmpeg init
	av_register_all();
	const char *inputFilename	= "testR.rmvb";//"input.avi";
	const char *outputFilename	= "output.avi";
	//input init
	AVFormatContext *iFormatCtx = NULL;
	if(avformat_open_input(&iFormatCtx,inputFilename,NULL,NULL)  !=0)//打开将要处理的视频文件。
		return 1;
	if(av_find_stream_info(iFormatCtx) <0)  //把
        return 2;  
    av_dump_format(iFormatCtx,0,inputFilename,0);
	int videoStreamIndex =-1;
	int audioStreamIndex = -1;
	if( findStreamIndex(&videoStreamIndex,&audioStreamIndex,iFormatCtx) == -1)//查找视频音频的号。。
		return 3;
	
	AVCodecContext *iVideoCodecCtx = iFormatCtx->streams[videoStreamIndex]->codec;
	AVCodecContext *iAudioCodecCtx = iFormatCtx->streams[audioStreamIndex]->codec;
	AVCodec *iVideoCodec		= avcodec_find_decoder(iVideoCodecCtx->codec_id);
	if(iVideoCodec == NULL)
		return 4;
	if( avcodec_open2(iVideoCodecCtx,iVideoCodec,NULL) <0)//打开视频解码器
		return 5;
	AVCodec *iAudioCodec = avcodec_find_decoder(iAudioCodecCtx->codec_id);//查找音频解码器。
	if(iAudioCodec == NULL)
		return 4;
	if(avcodec_open2(iAudioCodecCtx,iAudioCodec,NULL) <0) //打开音频解码器
		return 5;
	AVFrame *iFrame = avcodec_alloc_frame();//为输入视频的解码后的帧分配个帧头???????这里分配内存了吗、
	AVFrame *iFrameRGB = avcodec_alloc_frame();//写一个帧头
	int numBytes = avpicture_get_size(AV_PIX_FMT_RGB24,iVideoCodecCtx->width,iVideoCodecCtx->height);  
	uchar *iBufferRGB = (uchar *)av_malloc(numBytes*sizeof(uchar) );  
	avpicture_fill((AVPicture*)iFrameRGB,iBufferRGB,AV_PIX_FMT_RGB24,iVideoCodecCtx->width,iVideoCodecCtx->height); //为iFrame分配内存。
	//opencv init
	int width = iVideoCodecCtx->width;
	int height = iVideoCodecCtx->height;
	IplImage *vImg =cvCreateImageHeader(cvSize(width,height),8,3);  //待处理的帧存在的位置。
	IplImage *vDst = cvCreateImage(cvSize(width,height),8,3);//最终的处理结果。
	///
	/
	//no audio 
	//no audio

	//output init;
	AVFormatContext *oFormatCtx ;
	avformat_alloc_output_context2(&oFormatCtx,NULL,NULL,outputFilename);
	if(!oFormatCtx)//如果找不到默认的格式,就采用mepg格式来压缩。
	{
		avformat_alloc_output_context2(&oFormatCtx,NULL,"mpeg",outputFilename);
	}
	if(!oFormatCtx)
		return 6;
	AVOutputFormat *oof = oFormatCtx->oformat;
	AVStream *oVideoSt= NULL;//视频流
	AVStream *oAudioSt = NULL;//音频流
	AVCodecContext *oVideoCodecCtx = NULL;
	AVCodecContext *oAudioCodecCtx = NULL;
	AVCodec *oVideoCodec = NULL;
	AVCodec *oAudioCodec = NULL;
	oVideoCodec = avcodec_find_encoder(oof->video_codec);//视频编码器
	oAudioCodec = avcodec_find_encoder(oof->audio_codec);//音频编码器
	
	if(!oVideoCodec || !oAudioCodec )
		return 7;
	oVideoSt = avformat_new_stream(oFormatCtx,oVideoCodec);
	oAudioSt = avformat_new_stream(oFormatCtx,oAudioCodec);
	if(!oVideoSt || !oAudioSt)
		return 8;
	oVideoCodecCtx = oVideoSt->codec;
	oAudioCodecCtx = oAudioSt->codec;


	oVideoSt->id	= oFormatCtx->nb_streams-1;
	oAudioSt->id	= oFormatCtx->nb_streams-1;
	oVideoCodecCtx	= oVideoSt->codec;
	oAudioCodecCtx	= oAudioSt->codec;
	//initVideoCodecCtx();
	//oVideoCodecCtx->codec_id	= oof->video_codec;
	//oVideoCodecCtx->bit_rate	= 400000;/这里写成定值了。。。
	oVideoCodecCtx->width		= width;
	oVideoCodecCtx->height		= height;
	oVideoCodecCtx->time_base.den= 25;//iVideoCodecCtx->time_base.den;
	oVideoCodecCtx->time_base.num= 1;//iVideoCodecCtx->time_base.num;
	oVideoCodecCtx->pix_fmt		=AV_PIX_FMT_YUV420P;//iVideoCodecCtx->pix_fmt;
	//init output audioCodecContext ;
	oAudioCodecCtx->sample_rate = iAudioCodecCtx->sample_rate;
	oAudioCodecCtx->bit_rate	= iAudioCodecCtx->bit_rate;
	oAudioCodecCtx->sample_fmt	= iAudioCodecCtx->sample_fmt;
	oAudioCodecCtx->channels	= iAudioCodecCtx->channels;
	avcodec_open2(oVideoCodecCtx,oVideoCodec,NULL);//打开视频解码器。
	avcodec_open2(oAudioCodecCtx,oAudioCodec,NULL);//打开音频解码器。
	//*oVideoCodecCtx = *iVideoCodecCtx;
	//*oAudioCodecCtx = *iAudioCodecCtx;
	av_dump_format(oFormatCtx,0,outputFilename,1);
	if( !(oof->flags &AVFMT_NOFILE) )
	{
		int ret = avio_open(&oFormatCtx->pb,outputFilename,AVIO_FLAG_WRITE);
		if(ret<0)
			return 9;;
	}//现在打开了输出的文件。
	avformat_write_header(oFormatCtx,NULL);//写输出文件的文件头
	//初始化帧。
	AVFrame *oFrame = NULL;
	AVPicture oPicture ;
	oFrame = avcodec_alloc_frame();
	numBytes = avpicture_get_size(oVideoCodecCtx->pix_fmt,iVideoCodecCtx->width,iVideoCodecCtx->height);  
	uchar *oBufferFrame = (uchar *)av_malloc(numBytes*sizeof(uchar) );  
	avpicture_fill((AVPicture*)oFrame,oBufferFrame,oVideoCodecCtx->pix_fmt,iVideoCodecCtx->width,iVideoCodecCtx->height); 
	//avpicture_alloc(&oPicture,oVideoCodecCtx->pix_fmt,width,height);
	//*(AVPicture*)oFrame = oPicture;/这样就可以赋值了吗???????????
	oFrame->pts =0;
	

	//while 循环初始化。
	int frameFinished;  
    AVPacket iPacket;  
    int i =0;  
	double audioTime =0;
	double videoTime = 0;

	while(av_read_frame(iFormatCtx,&iPacket) >=0)
	{
		audioTime = oAudioSt ? oAudioSt->pts.val * av_q2d(oAudioSt->time_base) : 0.0;//似乎是画蛇添足的。。。。我认为可以直接:
        																			//audio_time = audio_st->pts.val*av_q2d(audio_st->time_base);
        videoTime = oVideoSt ? oVideoSt->pts.val * av_q2d(oVideoSt->time_base) : 0.0;
		
		if(videoTime>10)
			break;/测试用的终止条件。
		if(iPacket.stream_index == videoStreamIndex)
		{
			avcodec_decode_video2(iVideoCodecCtx,iFrame,&frameFinished,&iPacket);
			if(frameFinished)//成功解码。
			{
				SwsContext *pSwsCtx;
				pSwsCtx = sws_getContext(width,height,iVideoCodecCtx->pix_fmt,
					width,height,AV_PIX_FMT_RGB24,SWS_POINT,NULL,NULL,NULL
					);
				sws_scale(pSwsCtx,iFrame->data,iFrame->linesize
					,0,height,iFrameRGB->data,iFrameRGB->linesize
					);
				//free swsContext
				sws_freeContext(pSwsCtx);
				//opencv的图像处理。
				vImg->imageData= (char *)(*(iFrameRGB->data) );
				cvShowImage("hello",vImg);
				cvWaitKey(2);
				//ffmpeg输出。
				pSwsCtx = sws_getContext(width,height,AV_PIX_FMT_RGB24,width,height,
					oVideoCodecCtx->pix_fmt,SWS_POINT,NULL,NULL,NULL);
				sws_scale(pSwsCtx,iFrameRGB->data,iFrameRGB->linesize,0,height,oFrame->data,oFrame->linesize);//转换为ffmpeg格式。
				sws_freeContext(pSwsCtx);//因为又使用了一次,所以要再次释放掉,否则会产生内存泄露。
				//保存帧。
				AVPacket oPacket = {0};
				int gotPacket = 0;
				av_init_packet(&oPacket);
				int ret = avcodec_encode_video2(oVideoCodecCtx,&oPacket,oFrame,&gotPacket);
				if( !ret && gotPacket && oPacket.size)
				{
					oPacket.stream_index = oVideoSt->index;
					ret = av_interleaved_write_frame(oFormatCtx,&oPacket);
					//frame->pts += av_rescale_q(1, video_st->codec->time_base, video_st->time_base);;
					oFrame->pts += av_rescale_q(1,oVideoSt->codec->time_base,oVideoSt->time_base);///z这句话必须有,这是写frame的pts的。
				}

			}
		}//视频流处理过程。
		av_free_packet(&iPacket);
	}
	//while free
	av_write_trailer(oFormatCtx);
	//input  free
	avcodec_close(iVideoCodecCtx);
	avcodec_close(iAudioCodecCtx);
	avformat_free_context(iFormatCtx);
	av_free(iBufferRGB);
	av_free(iFrame);
	av_free(iFrameRGB);
	//opencv free 
	cvReleaseImage(&vImg);
	cvReleaseImage(&vDst);
	//output free 
	avio_close(oFormatCtx->pb);//关闭打开的文件。
	avcodec_close(oVideoCodecCtx);
	avcodec_close(oAudioCodecCtx);
	avformat_free_context(oFormatCtx);
	//av_free_packet(&oPacket);
	
	//end of the program ;
	return 0;
}
int findStreamIndex(int *videoStreamIndex,int *audioStreamIndex ,AVFormatContext *pFormatCtx)
{
	
    *videoStreamIndex = -1;  
	*audioStreamIndex = -1; 
    for(int i=0;i<pFormatCtx->nb_streams;i++)  
    {  
        if(pFormatCtx->streams[i]->codec->codec_type	== AVMEDIA_TYPE_VIDEO)  
        {  
            *videoStreamIndex  = i;  
            
        }  
		if(pFormatCtx->streams[i]->codec->codec_type	== AVMEDIA_TYPE_AUDIO)
		{
			*audioStreamIndex = i;
		}
    }//查找视频流 音频流
	if(*audioStreamIndex ==-1 || *videoStreamIndex == -1)
		return -1;
	else
		return 0;
}



近期又开始整ffmpeg,参考http://blog.csdn.net/jia_zhengshen/article/details/10334313博文,自己写的程序。本博文只用于记录。。。。。。

如何基于FFMPEG和SDL写一个少于1000行代码的视频播放器》这篇博文写的和翻译的比较早,而SDL和ffmpeg的向下兼容性又不是很好,所以原博文的有很多代码都不能用了,经过我查阅资料,对原博文的部分代码做了更改,以适应新的接口。我使用的是ffmpeg1.1.3 sdl2.0

(1)指导1

#include<opencv\cv.h>
#include<opencv\highgui.h>
//uisng namespace cv;
#ifdef  __cplusplus  
extern "C" {  
#endif  
#include<avcodec.h>
#include<avformat.h>
#include<libswscale\swscale.h>
int main()
{
	av_register_all();
	AVFormatContext *pFormatCtx = NULL;
	if(avformat_open_input(&pFormatCtx,"testR.rmvb",NULL,NULL) !=0)
		return 1;
	if(av_find_stream_info(pFormatCtx) <0)
		return 2;
	av_dump_format(pFormatCtx,0,"testR.rmvb",0);

	
	AVCodecContext *pCodecCtx;//解码器的上下文
	int videoStream = -1;
	for(int i=0;i<pFormatCtx->nb_streams;i++)
	{
		if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
		{
			videoStream = i;
			break;
		}
	}//查找视频流
	if(videoStream  == -1)
		return 3;
	pCodecCtx = pFormatCtx->streams[videoStream]->codec;//现在它指向正确的视频流解码器上下文

	AVCodec *pCodec;
	pCodec = avcodec_find_decoder(pCodecCtx->codec_id);//现在pCodec指向正确的解码器
	if(pCodec == NULL)
		return 4;
	if(avcodec_open(pCodecCtx,pCodec) <0)
		return 5;

	AVFrame *pFrame;//将来用来指向原始帧数据。
	pFrame = avcodec_alloc_frame();

	AVFrame *pFrameRGB  = avcodec_alloc_frame();//转换成rgb帧的存储空间。
	int numBytes= avpicture_get_size(PIX_FMT_RGB24,pCodecCtx->width,pCodecCtx->height);
	uchar *buffer = (uchar *)av_malloc(numBytes*sizeof(uchar) );
	avpicture_fill((AVPicture*)pFrameRGB,buffer,PIX_FMT_RGB24,pCodecCtx->width,pCodecCtx->height);

	int frameFinished;
	AVPacket packet;
	int i =0;
	
	while(av_read_frame(pFormatCtx,&packet) >=0)
	{
		if(packet.stream_index == videoStream)
		{
			avcodec_decode_video2(pCodecCtx,pFrame,&frameFinished,&packet);
			if(frameFinished)
			{
				SwsContext *pSwsCtx;
				pSwsCtx = sws_getContext(pCodecCtx->width,
					pCodecCtx->height,pCodecCtx->pix_fmt,
					pCodecCtx->width,pCodecCtx->height,
					AV_PIX_FMT_BGR24,SWS_POINT,NULL,NULL,NULL
					);
				sws_scale(pSwsCtx,pFrame->data,pFrame->linesize,0,
					pCodecCtx->height,pFrameRGB->data,pFrameRGB->linesize
					);//ffmpeg的从yuv420格式转换到bgr24格式。
				cv::Mat rgbCv(pCodecCtx->height,pCodecCtx->width,CV_8UC3);
				rgbCv.data=(uchar*)*pFrameRGB->data;
				cv::imshow("rgb",rgbCv);//显示是否正确的读取了包。
				cvWaitKey(2);
			}//if finished ;
		}//c确定这是视频流
		av_free_packet(&packet);
	}//while




}


#ifdef  __cplusplus  
}  
#endif  

本人对这个程序的理解:


(2)指导2:

#include<opencv\cv.h>
#include<opencv\highgui.h>
#include<SDL.h>
#include<SDL_thread.h>
//uisng namespace cv;
#ifdef  __cplusplus  
extern "C" {  
#endif  
#include<avcodec.h>
#include<avformat.h>
#include<libswscale\swscale.h>
int main()
{
	av_register_all();
	AVFormatContext *pFormatCtx = NULL;
	if(avformat_open_input(&pFormatCtx,"testR.rmvb",NULL,NULL) !=0)
		return 1;
	if(av_find_stream_info(pFormatCtx) <0)
		return 2;
	av_dump_format(pFormatCtx,0,"testR.rmvb",0);

	
	AVCodecContext *pCodecCtx;//解码器的上下文
	int videoStream = -1;
	for(int i=0;i<pFormatCtx->nb_streams;i++)
	{
		if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
		{
			videoStream = i;
			break;
		}
	}//查找视频流
	if(videoStream  == -1)
		return 3;
	pCodecCtx = pFormatCtx->streams[videoStream]->codec;//现在它指向正确的视频流解码器上下文

	AVCodec *pCodec;
	pCodec = avcodec_find_decoder(pCodecCtx->codec_id);//现在pCodec指向正确的解码器
	if(pCodec == NULL)
		return 4;
	if(avcodec_open(pCodecCtx,pCodec) <0)
		return 5;

	AVFrame *pFrame;//将来用来指向原始帧数据。
	pFrame = avcodec_alloc_frame();

	AVFrame *pFrameRGB  = avcodec_alloc_frame();//转换成rgb帧的存储空间。
	int numBytes= avpicture_get_size(PIX_FMT_RGB24,pCodecCtx->width,pCodecCtx->height);
	uchar *buffer = (uchar *)av_malloc(numBytes*sizeof(uchar) );
	avpicture_fill((AVPicture*)pFrameRGB,buffer,PIX_FMT_RGB24,pCodecCtx->width,pCodecCtx->height);

	//sdl_init
	if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO|SDL_INIT_TIMER) )
	{
		return 6;
	}
	
	SDL_Surface *screen  = SDL_SetVideoMode(pCodecCtx->width,pCodecCtx->height,0,0);
	if(!screen)
		return 7;
	SDL_Overlay  *bmp ;

	bmp = SDL_CreateYUVOverlay(pCodecCtx->width,pCodecCtx->height,
		SDL_YV12_OVERLAY,screen);

	int frameFinished;
	AVPacket packet;
	int i =0;
	SDL_Event event;
	while(av_read_frame(pFormatCtx,&packet) >=0)
	{
		if(packet.stream_index == videoStream)
		{
			avcodec_decode_video2(pCodecCtx,pFrame,&frameFinished,&packet);
			SDL_Rect rect ;
			if(frameFinished)
			{
				SDL_LockYUVOverlay(bmp);
				AVPicture pict;
				pict.data[0] = bmp->pixels[0];
				pict.data[1] = bmp->pixels[1];
				pict.data[2] = bmp->pixels[2];
				
				pict.linesize[0] = bmp->pitches[0];
				pict.linesize[1] = bmp->pitches[1];
				pict.linesize[2] = bmp->pitches[2];
				SwsContext *pSwsCtx;
				pSwsCtx = sws_getContext(pCodecCtx->width,
					pCodecCtx->height,pCodecCtx->pix_fmt,
					pCodecCtx->width,pCodecCtx->height,
					AV_PIX_FMT_YUV420P,SWS_POINT,NULL,NULL,NULL
					);
				sws_scale(pSwsCtx,pFrame->data,pFrame->linesize,0,
					pCodecCtx->height,pict.data,pict.linesize
					);//ffmpeg的从yuv420格式转换到bgr24格式。
				SDL_UnlockYUVOverlay(bmp);
				rect.x = 0;
				rect.y = 0;
				rect.w = pCodecCtx->width;
				rect.h = pCodecCtx->height;
				SDL_DisplayYUVOverlay(bmp,&rect);

				//SwsContext *pSwsCtx;
				//pSwsCtx = sws_getContext(pCodecCtx->width,
				//	pCodecCtx->height,pCodecCtx->pix_fmt,
				//	pCodecCtx->width,pCodecCtx->height,
				//	AV_PIX_FMT_BGR24,SWS_POINT,NULL,NULL,NULL
				//	);
				//sws_scale(pSwsCtx,pFrame->data,pFrame->linesize,0,
				//	pCodecCtx->height,pFrameRGB->data,pFrameRGB->linesize
				//	);//ffmpeg的从yuv420格式转换到bgr24格式。
				//cv::Mat rgbCv(pCodecCtx->height,pCodecCtx->width,CV_8UC3);
				//rgbCv.data=(uchar*)*pFrameRGB->data;
				//cv::imshow("rgb",rgbCv);//显示是否正确的读取了包。
				//cvWaitKey(2);
			}//if finished ;
		}//c确定这是视频流
		av_free_packet(&packet);
		SDL_PollEvent(&event);
		switch(event.type)
		{
		case SDL_QUIT:
			SDL_Quit();
			exit(0);
			break;
		default:
			break;
		}//eventtype
	}//while
	av_free(buffer);
	av_free(pFrameRGB);
	av_free(pFrame);
	avcodec_close(pCodecCtx);
	av_close_input_file(pFormatCtx);
	return 0;	
}


#ifdef  __cplusplus  
}  
#endif  

我对SDL显示的理解:


(3);:;;指导3:播放声音

#include<opencv\cv.h>
#include<opencv\highgui.h>
#include<SDL.h>
#include<SDL_thread.h>
//uisng namespace cv;
#ifdef  __cplusplus  
extern "C" {  
#endif  
#include<avcodec.h>
#include<avformat.h>
#include<libswscale\swscale.h>


typedef struct PacketQueue{
	AVPacketList *first_pkt,*last_pkt;
	int nb_packets;
	int size;
	SDL_mutex *mutex;
	SDL_cond  *cond;
}PacketQueue;
//
PacketQueue audioq;
int quit = 0;
void packet_queue_init(PacketQueue *q)
{
	memset(q,0,sizeof(PacketQueue) );
	q->mutex= SDL_CreateMutex();
	q->cond	= SDL_CreateCond();
}
int packet_queue_put(PacketQueue *q ,AVPacket *pkt)//放入队列中。
{
	AVPacketList  *pktl;
	if(av_dup_packet(pkt) <0)
		return 10;
	pktl = (AVPacketList *)av_malloc(sizeof(AVPacketList) );
	if(!pktl)
		return 11;
	pktl->pkt = *pkt;
	pktl->next = NULL;
	SDL_LockMutex(q->mutex);
	if(!q->last_pkt)
		q->first_pkt = pktl;
	else
		q->last_pkt->next = pktl;
	q->last_pkt = pktl;
	q->nb_packets++;
	q->size += pktl->pkt.size;
	SDL_CondSignal(q->cond);
	SDL_UnlockMutex(q->mutex);

	return 0;
}
int packet_queue_get(PacketQueue *q ,AVPacket *pkt ,int block)
{
	AVPacketList *pktl;
	int ret;
	SDL_LockMutex(q->mutex);
	for(;;)
	{
		if(quit)
		{
			ret = -1;
			break;
		}
		pktl = q->first_pkt;
		if(pktl )//队列中存在数据
		{
			q->first_pkt = pktl->next;
			if(!q->first_pkt)//下面不存在数据了
			{
				q->last_pkt = NULL;
			}
			q->nb_packets--;
			q->size -= pktl->pkt.size;
			*pkt = pktl->pkt;
			av_free(pktl);
			ret = 1;
			break;
		}
		else
		{
			if(!block)//是否阻塞
			{
				ret = 0;
				break;
			}else
			{
				SDL_CondWait(q->cond,q->mutex);
			}
		}
	}//for
	SDL_UnlockMutex(q->mutex);
	return ret;
}
int audio_decode_frame(AVCodecContext *aCodecCtx,uint8_t*audio_buffer,int buf_size)
{
	static AVPacket pkt;
	static uint8_t *audio_pkt_data = NULL;
	static int audio_pkt_size = 0;
	int lenl, data_size;
	for(;;)
	{
		while(audio_pkt_size >0)
		{
			data_size = buf_size;
			lenl = avcodec_decode_audio3(aCodecCtx,(int16_t*)audio_buffer,&data_size,&pkt);
			if(lenl<0)
			{
				audio_pkt_size = 0;
				break;
			}
			audio_pkt_data +=lenl;
			audio_pkt_size -=lenl;
			if(data_size<=0)
			{
				continue;
			}
			return data_size;
		}
		if(pkt.data)
			av_free_packet(&pkt);
		if(quit)
			return -1;
		if(packet_queue_get(&audioq,&pkt,1) <0)
			return -1;
		audio_pkt_data = pkt.data;
		audio_pkt_size = pkt.size;
	}//for
}
void audio_callback(void *userdata,Uint8 *stream ,int len)
{
	AVCodecContext *aCodecCtx = (AVCodecContext *)userdata;
	int lenl ,audio_size;
	static uint8_t audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE *3)/2];
	static unsigned int audio_buf_size = 0;
	static unsigned int audio_buf_index = 0;
	while(len >0)
	{
		if(audio_buf_index>= audio_buf_size)
		{
			audio_size  = audio_decode_frame(aCodecCtx,audio_buf,sizeof(audio_buf) );
			if(audio_size<0)
			{
				audio_buf_size = 1024;
				memset(audio_buf,0,audio_buf_size);
			}else
			{
				audio_buf_size = audio_size;
			}
			audio_buf_index =0;
		}
		lenl = audio_buf_size -audio_buf_index;
		if(lenl >len  )
			lenl = len ;
		memcpy(stream,(uint8_t*)audio_buf+audio_buf_index,lenl);
		len -=lenl;
		stream +=lenl;
		audio_buf_index += lenl;
		
	}//while
}
int main()
{
	av_register_all();
	AVFormatContext *pFormatCtx = NULL;
	if(avformat_open_input(&pFormatCtx,"testR.rmvb",NULL,NULL) !=0)
		return 1;
	if(av_find_stream_info(pFormatCtx) <0)
		return 2;
	av_dump_format(pFormatCtx,0,"testR.rmvb",0);

	
	AVCodecContext *pCodecCtx;//解码器的上下文
	int videoStream = -1;
	int audioStream = -1;
	for(int i=0;i<pFormatCtx->nb_streams;i++)
	{
		if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO
			&& videoStream <0)
		{
			videoStream = i;
			//break;
		}
		if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO
			&& audioStream <0)
		{
			audioStream = i;
		}//
	}//查找视频流
	if(videoStream  == -1)
		return 3;
	if(audioStream  == -1)
		return 3;
	pCodecCtx = pFormatCtx->streams[videoStream]->codec;//现在它指向正确的视频流解码器上下文
	AVCodecContext *aCodecCtx = pFormatCtx->streams[audioStream]->codec;
	

	AVCodec *pCodec;
	pCodec = avcodec_find_decoder(pCodecCtx->codec_id);//现在pCodec指向正确的解码器
	if(pCodec == NULL)
		return 4;
	if(avcodec_open(pCodecCtx,pCodec) <0)
		return 5;

	AVFrame *pFrame;//将来用来指向原始帧数据。
	pFrame = avcodec_alloc_frame();

	AVFrame *pFrameRGB  = avcodec_alloc_frame();//转换成rgb帧的存储空间。
	int numBytes= avpicture_get_size(PIX_FMT_RGB24,pCodecCtx->width,pCodecCtx->height);
	uchar *buffer = (uchar *)av_malloc(numBytes*sizeof(uchar) );
	avpicture_fill((AVPicture*)pFrameRGB,buffer,PIX_FMT_RGB24,pCodecCtx->width,pCodecCtx->height);

	//sdl_init
	if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO|SDL_INIT_TIMER) )
	{
		return 6;
	}
	SDL_AudioSpec wanted_spec ,spec;
	wanted_spec.freq = aCodecCtx->sample_rate;
	wanted_spec.channels = aCodecCtx->channels;
	wanted_spec.format  = AUDIO_S16;//AUDIO_S16SYS;
	wanted_spec.silence = 0;
	wanted_spec.samples = 1024;//SDL_AUDIO_BUFFER_SIZE;
	wanted_spec.callback = audio_callback;
	wanted_spec.userdata = aCodecCtx;
	//if( SDL_OpenAudio(&wanted_spec,&spec) <0)
	if( SDL_OpenAudio(&wanted_spec,NULL) <0)
	{
		fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError());
		return 8;
	}
	AVCodec *aCodec = avcodec_find_decoder(aCodecCtx->codec_id);
	if(!aCodec)
		return 9;
	avcodec_open(aCodecCtx,aCodec);
	packet_queue_init(&audioq);
	SDL_PauseAudio(0);





	SDL_Surface *screen  = SDL_SetVideoMode(pCodecCtx->width,pCodecCtx->height,24,0);
	if(!screen)
		return 7;
	SDL_Overlay  *bmp ;

	bmp = SDL_CreateYUVOverlay(pCodecCtx->width,pCodecCtx->height,
		SDL_YV12_OVERLAY,screen);

	int frameFinished;
	AVPacket packet;
	int i =0;
	SDL_Event event;
	while(av_read_frame(pFormatCtx,&packet) >=0)
	{
		if(packet.stream_index == videoStream)
		{
			avcodec_decode_video2(pCodecCtx,pFrame,&frameFinished,&packet);
			SDL_Rect rect ;
			if(frameFinished)
			{
				SDL_LockYUVOverlay(bmp);
				AVPicture pict;
				pict.data[0] = bmp->pixels[0];
				pict.data[1] = bmp->pixels[1];
				pict.data[2] = bmp->pixels[2];
				
				pict.linesize[0] = bmp->pitches[0];
				pict.linesize[1] = bmp->pitches[1];
				pict.linesize[2] = bmp->pitches[2];
				SwsContext *pSwsCtx;
				pSwsCtx = sws_getContext(pCodecCtx->width,
					pCodecCtx->height,pCodecCtx->pix_fmt,
					pCodecCtx->width,pCodecCtx->height,
					AV_PIX_FMT_YUV420P,SWS_POINT,NULL,NULL,NULL
					);
				sws_scale(pSwsCtx,pFrame->data,pFrame->linesize,0,
					pCodecCtx->height,pict.data,pict.linesize
					);//ffmpeg的从yuv420格式转换到bgr24格式。
				SDL_UnlockYUVOverlay(bmp);
				rect.x = 0;
				rect.y = 0;
				rect.w = pCodecCtx->width;
				rect.h = pCodecCtx->height;
				SDL_DisplayYUVOverlay(bmp,&rect);

				//SwsContext *pSwsCtx;
				//pSwsCtx = sws_getContext(pCodecCtx->width,
				//	pCodecCtx->height,pCodecCtx->pix_fmt,
				//	pCodecCtx->width,pCodecCtx->height,
				//	AV_PIX_FMT_BGR24,SWS_POINT,NULL,NULL,NULL
				//	);
				//sws_scale(pSwsCtx,pFrame->data,pFrame->linesize,0,
				//	pCodecCtx->height,pFrameRGB->data,pFrameRGB->linesize
				//	);//ffmpeg的从yuv420格式转换到bgr24格式。
				//cv::Mat rgbCv(pCodecCtx->height,pCodecCtx->width,CV_8UC3);
				//rgbCv.data=(uchar*)*pFrameRGB->data;
				//cv::imshow("rgb",rgbCv);//显示是否正确的读取了包。
				//cvWaitKey(2);
			}//if finished ;
			av_free_packet(&packet);
		}//c确定这是视频流
		else//音频流
		{
			if(packet.stream_index == audioStream)
			{
				packet_queue_put(&audioq,&packet);
			}
			else
			{
				av_free_packet(&packet);
			}
		}
		
		SDL_PollEvent(&event);
		switch(event.type)
		{
		case SDL_QUIT:
			SDL_Quit();
			exit(0);
			break;
		default:
			break;
		}//eventtype
	}//while
	av_free(buffer);
	av_free(pFrameRGB);
	av_free(pFrame);
	avcodec_close(pCodecCtx);
	av_close_input_file(pFormatCtx);
	return 0;	
}


#ifdef  __cplusplus  
}  
#endif  


上面的代码还有问题,播放声音时发出“”zzzzz”的声音,并没有像原博文说的效果一样。留到以后对sdl更熟悉了,然后更改。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值