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更熟悉了,然后更改。