ffmpeg视频播放过程文档格式.docx

上传人:b****3 文档编号:7967340 上传时间:2023-05-09 格式:DOCX 页数:16 大小:117.69KB
下载 相关 举报
ffmpeg视频播放过程文档格式.docx_第1页
第1页 / 共16页
ffmpeg视频播放过程文档格式.docx_第2页
第2页 / 共16页
ffmpeg视频播放过程文档格式.docx_第3页
第3页 / 共16页
ffmpeg视频播放过程文档格式.docx_第4页
第4页 / 共16页
ffmpeg视频播放过程文档格式.docx_第5页
第5页 / 共16页
ffmpeg视频播放过程文档格式.docx_第6页
第6页 / 共16页
ffmpeg视频播放过程文档格式.docx_第7页
第7页 / 共16页
ffmpeg视频播放过程文档格式.docx_第8页
第8页 / 共16页
ffmpeg视频播放过程文档格式.docx_第9页
第9页 / 共16页
ffmpeg视频播放过程文档格式.docx_第10页
第10页 / 共16页
ffmpeg视频播放过程文档格式.docx_第11页
第11页 / 共16页
ffmpeg视频播放过程文档格式.docx_第12页
第12页 / 共16页
ffmpeg视频播放过程文档格式.docx_第13页
第13页 / 共16页
ffmpeg视频播放过程文档格式.docx_第14页
第14页 / 共16页
ffmpeg视频播放过程文档格式.docx_第15页
第15页 / 共16页
ffmpeg视频播放过程文档格式.docx_第16页
第16页 / 共16页
亲,该文档总共16页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

ffmpeg视频播放过程文档格式.docx

《ffmpeg视频播放过程文档格式.docx》由会员分享,可在线阅读,更多相关《ffmpeg视频播放过程文档格式.docx(16页珍藏版)》请在冰点文库上搜索。

ffmpeg视频播放过程文档格式.docx

解析文件时会将音/视频帧读入到packet中

打开文件

接下来我们打开一个视频文件。

av_register_all();

av_register_all定义在libavformat里,调用它用以注册所有支持的文件格式以及编解码器,从其实现代码里可以看到它会调用avcodec_register_all,因此之后就可以用所有ffmpeg支持的codec了。

if(avformat_open_input(&

pFormatCtx,argv[1],NULL,NULL)!

=0)

return-1;

使用新的APIavformat_open_input来打开一个文件,第一个参数是一个AVFormatContext指针变量的地址,它会根据打开的文件信息填充AVFormatContext,需要注意的是,此处的pFormatContext必须为NULL或由avformat_alloc_context分配得到,这也是上一节中将其初始化为NULL的原因,否则此函数调用会出问题。

第二个参数是打开的文件名,通过argv[1]指定,也就是命令行的第一个参数。

后两个参数分别用于指定特定的输入格式(AVInputFormat)以及指定文件打开额外参数的AVDictionary结构,这里均留作NULL。

if(avformat_find_stream_info(pFormatCtx,NULL)<

0)

av_dump_format(pFormatCtx,-1,argv[1],0);

avformat_open_input函数只是读文件头,并不会填充流信息,因此我们需要接下来调用avformat_find_stream_info获取文件中的流信息,此函数会读取packet,并确定文件中所有的流信息,设置pFormatCtx->

streams指向文件中的流,但此函数并不会改变文件指针,读取的packet会给后面的解码进行处理。

最后调用一个帮助函数av_dump_format,输出文件的信息,也就是我们在使用ffmpeg时能看到的文件详细信息。

第二个参数指定输出哪条流的信息,-1表示给ffmpeg自己选择。

最后一个参数用于指定dump的是不是输出文件,我们dump的是输入文件,因此一定要是0。

现在pFormatCtx->

streams中已经有所有流了,因此现在我们遍历它找到第一条视频流:

videoStream=-1;

for(i=0;

i<

pFormatCtx->

nb_streams;

i++)

if(pFormatCtx->

streams[i]->

codec->

codec_type==AVMEDIA_TYPE_VIDEO){

videoStream=i;

break;

}

if(videoStream==-1)

codec_type的宏定义已经由以前的CODEC_TYPE_VIDEO改为AVMEDIA_TYPE_VIDEO了。

接下来我们通过这条videostream的编解码信息打开相应的解码器:

pCodecCtx=pFormatCtx->

streams[videoStream]->

codec;

pCodec=avcodec_find_decoder(pCodecCtx->

codec_id);

if(pCodec==NULL)

if(avcodec_open2(pCodecCtx,pCodec,NULL)<

分配图像缓存

接下来我们准备给即将解码的图片分配内存空间。

pFrame=avcodec_alloc_frame();

if(pFrame==NULL)

pFrameRGB=avcodec_alloc_frame();

if(pFrameRGB==NULL)

调用avcodec_alloc_frame分配帧,因为最后我们会将图像写成24-bitsRGB的PPM文件,因此这里需要两个AVFrame,pFrame用于存储解码后的数据,pFrameRGB用于存储转换后的数据。

numBytes=avpicture_get_size(PIX_FMT_RGB24,pCodecCtx->

width,

pCodecCtx->

height);

这里调用avpicture_get_size,根据pCodecCtx中原始图像的宽高计算RGB24格式的图像需要占用的空间大小,这是为了之后给pFrameRGB分配空间。

buffer=av_malloc(numBytes);

avpicture_fill((AVPicture*)pFrameRGB,buffer,PIX_FMT_RGB24,

pCodecCtx->

width,pCodecCtx->

接着上面的,首先是用av_malloc分配上面计算大小的内存空间,然后调用avpicture_fill将pFrameRGB跟buffer指向的内存关联起来。

获取图像

OK,一切准备好就可以开始从文件中读取视频帧并解码得到图像了。

i=0;

while(av_read_frame(pFormatCtx,&

packet)>

=0){

if(packet.stream_index==videoStream){

avcodec_decode_video2(pCodecCtx,pFrame,&

frameFinished,&

packet);

if(frameFinished){

structSwsContext*img_convert_ctx=NULL;

img_convert_ctx=

sws_getCachedContext(img_convert_ctx,pCodecCtx->

pCodecCtx->

height,pCodecCtx->

pix_fmt,

height,

PIX_FMT_RGB24,SWS_BICUBIC,

NULL,NULL,NULL);

if(!

img_convert_ctx){

fprintf(stderr,"

Cannotinitializeswsconversioncontext\n"

);

exit

(1);

sws_scale(img_convert_ctx,(constuint8_t*const*)pFrame->

data,

pFrame->

linesize,0,pCodecCtx->

height,pFrameRGB->

pFrameRGB->

linesize);

if(i++<

50)

SaveFrame(pFrameRGB,pCodecCtx->

height,i);

av_free_packet(&

av_read_frame从文件中读取一个packet,对于视频来说一个packet里面包含一帧图像数据,音频可能包含多个帧(当音频帧长度固定时),读到这一帧后,如果是视频帧,则使用avcodec_decode_video2对packet中的帧进行解码,有时候解码器并不能从一个packet中解码得到一帧图像数据(比如在需要其他参考帧的情况下),因此会设置frameFinished,如果已经得到下一帧图像则设置frameFinished非零,否则为零。

所以这里我们判断frameFinished是否为零来确定pFrame中是否已经得到解码的图像。

注意在每次处理完后需要调用av_free_packet释放读取的packet。

解码得到图像后,很有可能不是我们想要的RGB24格式,因此需要使用swscale来做转换,调用sws_getCachedContext得到转换上下文,使用sws_scale将图形从解码后的格式转换为RGB24,最后将前50帧写人ppm文件。

最后释放图像以及关闭文件:

av_free(buffer);

av_free(pFrameRGB);

av_free(pFrame);

avcodec_close(pCodecCtx);

avformat_close_input(&

pFormatCtx);

return0;

}

staticvoidSaveFrame(AVFrame*pFrame,intwidth,intheight,intiFrame)

FILE*pFile;

charszFilename[32];

inty;

sprintf(szFilename,"

frame%d.ppm"

iFrame);

pFile=fopen(szFilename,"

wb"

pFile)

return;

fprintf(pFile,"

P6\n%d%d\n255\n"

width,height);

for(y=0;

y<

height;

y++)

fwrite(pFrame->

data[0]+y*pFrame->

linesize[0],1,width*3,pFile);

fclose(pFile);

重点分析AVCodec/AVCodecContext/MsrleContext这几个数据结构,这几个数据结构定义了编解码

器的核心架构,相当于Directshow中的各种音视频解码器decoder。

typedefstructAVCodec

{

constchar*name;

//标示Codec的名字,比如,"

msrle"

"

truespeech"

等。

enumCodecTypetype;

//标示Codec的类型,有Video,Audio,Data等类型

enumCodecIDid;

//标示Codec的ID,有CODEC_ID_MSRLE,CODEC_ID_TRUESPEECH等

intpriv_data_size;

//标示具体的Codec对应的Context的大小,在本例中是MsrleContext//或TSContext的大小。

int(*init)(AVCodecContext*);

//标示Codec对外提供的操作

int(*encode)(AVCodecContext*,uint8_t*buf,intbuf_size,void*data);

int(*close)(AVCodecContext*);

int(*decode)(AVCodecContext*,void*outdata,int*outdata_size,uint8_t*buf,intbuf_size);

intcapabilities;

//标示Codec的能力,在瘦身后的ffplay中没太大作用,可忽略

structAVCodec*next;

//用于把所有Codec串成一个链表,便于遍历

}AVCodec;

AVCodec是类似COM接口的数据结构,表示音视频编解码器,着重于功能函数,一种媒体类型对应一个

AVCodec结构,在程序运行时有多个实例。

next变量用于把所有支持的编解码器连接成链表,便于遍历查找;

id

确定了唯一编解码器;

priv_data_size表示具体的Codec对应的Context结构大小,比如MsrleContext或

TSContext,这些具体的结够定义散落于各个.c文件中,为避免太多的ifelse类语句判断类型再计算大小,这里

就直接指明大小,因为这是一个编译时静态确定的字段,所以放在AVCodec而不是AVCodecContext中。

typedefstructAVCodecContext

{

intbit_rate;

intframe_number;

unsignedchar*extradata;

//Codec的私有数据,对Audio是WAVEFORMATEX结构扩展字节。

intextradata_size;

//对Video是BITMAPINFOHEADER后的扩展字节

intwidth,height;

//此逻辑段仅针对视频

enumPixelFormatpix_fmt;

intsample_rate;

//此逻辑段仅针对音频

intchannels;

intbits_per_sample;

intblock_align;

structAVCodec*codec;

//指向当前AVCodec的指针,

void*priv_data;

//指向当前具体编解码器Codec的上下文Context。

enumCodecTypecodec_type;

//seeCODEC_TYPE_xxx

enumCodecIDcodec_id;

//seeCODEC_ID_xxx

int(*get_buffer)(structAVCodecContext*c,AVFrame*pic);

void(*release_buffer)(structAVCodecContext*c,AVFrame*pic);

int(*reget_buffer)(structAVCodecContext*c,AVFrame*pic);

intinternal_buffer_count;

void*internal_buffer;

structAVPaletteControl*palctrl;

}AVCodecContext;

AVCodecContext结构表示程序运行的当前Codec使用的上下文,着重于所有Codec共有的属性(并且是在程

序运行时才能确定其值)和关联其他结构的字段。

extradata和extradata_size两个字段表述了相应Codec使用的私

有数据,对Codec全局有效,通常是一些标志信息;

codec字段关联相应的编解码器;

priv_data字段关联各个具

体编解码器独有的属性上下文,和AVCodec结构中的priv_data_size配对使用。

typedefstructMsrleContext

AVCodecContext*avctx;

AVFrameframe;

unsignedchar*buf;

intsize;

}MsrleContext;

MsrleContext结构着重于RLE行程长度压缩算法独有的属性值和关联AVCodecContext的avctx字段。

因为

RLE行程长度算法足够简单,属性值相对较少。

接着来重点分析AVInputFormat/AVFormatContext/AVIContext这几个数据结构,这几个数据结构定义了识别文件容器格式的核心架构,相当于Directshow中的各种解复用demuxer。

typedefstructAVInputFormat

//标示具体的文件容器格式对应的Context的大小,在本例中是AVIContext

int(*read_probe)(AVProbeData*);

int(*read_header)(structAVFormatContext*,AVFormatParameters*ap);

int(*read_packet)(structAVFormatContext*,AVPacket*pkt);

int(*read_close)(structAVFormatContext*);

constchar*extensions;

//文件扩展名

structAVInputFormat*next;

}AVInputFormat;

AVInputFormat是类似COM接口的数据结构,表示输入文件容器格式,着重于功能函数,一种文件容器格

式对应一个AVInputFormat结构,在程序运行时有多个实例。

next变量用于把所有支持的输入文件容器格式连接

成链表,便于遍历查找;

priv_data_size标示具体的文件容器格式对应的Context的大小,在本例中是AVIContext,

这些具体的结够定义散落于各个.c文件中,为避免太多的ifelse类语句判断类型再计算大小,这里就直接指明大小,因为这是一个编译时静态确定的字段,所以放在AVInputFormat而不是AVFormatContext中。

typedefstructAVFormatContext//formatI/Ocontext

structAVInputFormat*iformat;

//指向具体的文件容器格式的上下文Context,在本例中是AVIContext

ByteIOContextpb;

//广泛意义的输入文件

intnb_streams;

AVStream*streams[MAX_STREAMS];

}AVFormatContext;

AVFormatContext结构表示程序运行的当前文件容器格式使用的上下文,着重于所有文件容器共有的属性(并且是在程序运行时才能确定其值)和关联其他结构的字段。

iformat字段关联相应的文件容器格式;

pb关联广义的

输入文件;

streams关联音视频流;

priv_data字段关联各个具体文件容器独有的属性上下文,和priv_data_size配

对使用。

typedefstructAVIContext

int64_triff_end;

int64_tmovi_end;

offset_tmovi_list;

intnon_interleaved;

intstream_index_2;

//为了和AVPacket中的stream_index相区别,添加后缀标记。

}AVIContext;

AVIContext定义了AVI中流的一些属性,其中stream_index_2定义了当前应该读取流的索引。

接着我们来重点分析URLProtocol/URLContext(ByteIOContext)/FILE(Socket)这几个数据结构,这几个数据结

构定义了读取文件的核心架构,相当于Directshow中的文件源filesourcefilter。

typedefstructURLProtocol

//便于人性化的识别理解

int(*url_open)(URLContext*h,constchar*filename,intflags);

int(*url_read)(URLContext*h,unsignedchar*buf,intsize);

int(*url_write)(URLContext*h,unsignedchar*buf,intsize);

offset_t(*url_seek)(URLContext*h,offset_tpos,intwhence);

int(*url_close)(URLContext*h);

structURLProtocol*next;

}URLProtocol;

URLProtocol是类似COM接口的数据结构,表示广义的输入文件,着重于功能函数,一种广义的输入文件

对应一个URLProtocol结构,比如file,pipe,tcp等等,但瘦身后的ffplay只支持file一种输入文件。

next变量

用于把所有支持的广义的输入文件连接成链表,便于遍历查找。

typedefstructURLContext

structURLProtocol*prot;

intflags;

intmax_packet_size;

//ifnonzero,thestreamispacketizedwiththismaxpacketsize

//文件句柄fd,网络通信Scoket等

charfilename[1];

//specifiedfilename

}URLContext;

URLCon

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 小学教育 > 语文

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2