版ffmpeg解码流程.docx
- 文档编号:24195952
- 上传时间:2023-05-25
- 格式:DOCX
- 页数:22
- 大小:97.84KB
版ffmpeg解码流程.docx
《版ffmpeg解码流程.docx》由会员分享,可在线阅读,更多相关《版ffmpeg解码流程.docx(22页珍藏版)》请在冰豆网上搜索。
版ffmpeg解码流程
FFMPE解码流程:
1.注册所有容器格式和CODEC:
av_register_all()
2.打开文件:
av_open_input_file()
3.从文件中提取流信息:
av_find_stream_info()
4.穷举所有的流,查找其中种类为CODEC_TYPE_VIDEO
5.查找对应的解码器:
avcodec_find_decoder()
6.打开编解码器:
avcodec_open()
7.为解码帧分配内存:
avcodec_alloc_frame()
8.不停地从码流中提取出帧数据:
av_read_frame()
9.判断帧的类型,对于视频帧调用:
avcodec_decode_video()
10.解码完后,释放解码器:
avcodec_close()
11.关闭输入文件:
avformat_close_input_file()
主要数据结构:
AVFDimAlConteKt
*lfGPhnaL
*o^rrnai1
*卩•
^3trearn5(]
vTyTyi
createandmiliar弟yaurawndjaqrainsaitqliffyB>c«ini
基本概念:
编解码器、数据帧、媒体流和容器是数字媒体处理系统的四个基本概念。
首先需要统一术语:
容器/文件(Conainer/File):
即特定格式的多媒体文件。
媒体流(Stream):
指时间轴上的一段连续数据,如一段声音数据,一段视频数据或一
段字幕数据,可以是压缩的,也可以是非压缩的,压缩的数据需要关联特定的编解码器。
数据帧/数据包(Frame/Packet):
通常,一个媒体流由大量的数据帧组成,对于压缩
数据,帧对应着编解码器的最小处理单元。
通常,分属于不同媒体流的数据帧交错复用于容
器之中,参见交错。
编解码器:
编解码器以帧为单位实现压缩数据和原始数据之间的相互转换。
在FFMPEG中,使用AVFormatContext、AVStream、AVCodecContext、AVCodec及AVPacket等结构来抽象这些基本要素,它们的关系如上图所示:
AVCodecContext:
如下
这是一个描述编解码器上下文的数据结构,包含了众多编解码器需要的参数信息,
列出了部分比较重要的域:
typedefstructAVCodecContext{
/**
*一些编解码器需要/可以像使用extradataHuffman表。
*MJPEG:
Huffman表
*RV10其他标志
*MPEG4:
全球头(也可以是在比特流或这里)
*分配的内存应该是FF_INPUT_BUFFER_PADDING_SlZE节较大
*,比extradata_size避免比特流器,如果它与读prolems。
*extradata按字节的内容必须不依赖于架构或CPU的字节顺序。
*-编码:
设置/分配/释放由libavcodec的。
*-解码:
由用户设置/分配/释放。
*/
uint8_t*extradata;
intextradata_size;
F**
*这是时间的基本单位,在条件(以秒为单位)
*帧时间戳派代表出席了会议。
对于固定fps的内容,
*基应该1/framerate和时间戳的增量应该
*相同的1。
*-编码:
必须由用户设置。
*-解码:
libavcodec的设置。
*/
AVRationaltime_base;
/*视频*/
*图片宽度/高度。
*-编码:
必须由用户设置。
*-解码:
libavcodec的设置。
*请注意:
兼容性,它是可能的,而不是设置此
*coded_width/高解码之前。
*/
intwidth,height;
/*仅音频*/
intsample_rate;....
/**
*在解码器的帧重排序缓冲区的大小。
*对于MPEG-2这是IPB1或0低延时IP。
*-编码:
libavcodec的设置。
*-解码:
libavcodec的设置。
*/
inthas_b_frames;
*每包的字节数,如果常量和已知或0
*用于一些WAV勺音频编解码器。
*/
intblock_align;
*从分路器位每个样品/像素(huffyuv需要)。
*-编码:
libavcodec的设置。
*-解码:
由用户设置。
*/
intbits_per_coded_sample;
}AVCodecContext;
如果是单纯使用libavcodec,这部分信息需要调用者进行初始化;如果是使用整个FFMPEG
库,这部分信息在调用avformat_open_input和avformat_find_stream_info的过程中根据
文件的头信息及媒体流内的头部信息完成初始化。
其中几个主要域的释义如下:
extradata/extradata_size:
这个buffer中存放了解码器可能会用到的额外信息,在
av_read_frame中填充。
一般来说,首先,某种具体格式的demuxer在读取格式头信息的时
候会填充extradata,其次,如果demuxer没有做这个事情,比如可能在头部压根儿就没有相关的编解码信息,则相应的parser会继续从已经解复用出来的媒体流中继续寻找。
在没
有找到任何额外信息的情况下,这个buffer指针为空。
time_base:
width/height:
视频的宽和高。
sample_rate/channels:
音频的采样率和信道数目。
sample_fmt:
音频的原始采样格式。
codec_name/codec_type/codec_id/codec_tag:
编解码器的信息。
AVStream
该结构体描述一个媒体流,定义如下:
typedefstructAVStream{
intindex;/**<在AVFormatContext流的索引*/
intid;/**<特定格式的流ID*/
AVCodecContext*codec;/** 「** *流的实时帧率基地。 *这是所有时间戳可以最低帧率 *准确代表(它是所有的最小公倍数 *流的帧率)。 请注意,这个值只是一个猜测! *例如,如果时间基数为1/90000和所有帧 *约3600或1800计时器刻度,,然后r_frame_rate将是50/1。 */ AVRationalr_frame_rate; ! ** *这是时间的基本单位,在条件(以秒为单位) *帧时间戳派代表出席了会议。 对于固定fps的内容, *时基应该是1/framerate的时间戳的增量应为1。 */ AVRationaltime_base; 「** *解码流量的第一帧,在流量时-base分。 *如果你是绝对100%的把握,设定值 *它真的是第一帧点。 *这可能是未定义(AV_NOPTS_VALUE勺。 *@注意的业余头不弱者受制与正确的START_TIME勺业余 *分路器必须不设定此。 */ int64_tstart_time; /** 解码: 时间流流时基。 *如果源文件中没有指定的时间,但不指定 *比特率,这个值将被从码率和文件大小的估计。 */ int64_tduration; #ifLIBAVFORMAT_VERSION」NT<(53<<16) charIanguage[4];/**ISO639-2/B3-letterIanguagecode(emptystringif undefined)*/ #endif /*av_read_frame()支持*/ enumAVStreamParseTypeneed_parsing; structAVCodecParserContext*parser; /*函数av_seek_frame()支持*/ AVIndexEntry*index_entries;/**<仅用于如果格式不notsupport寻求本身。 */ intnb_index_entries; unsignedintindex_entries_allocated_size; int64_tnb_frames;.... }AVStream; 主要域的释义如下,其中大部分域的值可以由avformat_open_input根据文件头的信息确 定,缺少的信息需要通过调用avformat_find_stream」nfo读帧及软解码进一步获取: index/id: index对应流的索引,这个数字是自动生成的,根据index可以从 AVFormatContext: : streams表中索引到该流;而id则是流的标识,依赖于具体的容器格式。 比如对于MPEGTS格式,id就是pid。 time_base: 流的时间基准,是一个实数,该流中媒体数据的pts和dts都将以这个时 间基准为粒度。 通常,使用av_rescale/av_rescale_q可以实现不同时间基准的转换。 start_time: 流的起始时间,以流的时间基准为单位,通常是该流中第一个帧的pts。 duration: 流的总时间,以流的时间基准为单位。 need_parsing: 对该流parsing过程的控制域。 nb_frames: 流内的帧数目。 r_frame_rate/framerate/avg_frame_rate: 帧率相关。 codec: 指向该流对应的AVCodecContext结构,调用avformat_open」nput时生成。 parser: 指向该流对应的AVCodecParserContext结构,调用avformat_find_stream」nfo时生成。 。 AVFormatContext 这个结构体描述了一个媒体文件或媒体流的构成和基本信息,定义如下: typedefstructAVFormatContext{ constAVClass*av_class;/**<由avformat_alloc_context设置的。 */ /*只能是iFormat的,或在同一时间oformat,不是两个。 */ structAVInputFormat*iformat; structAVOutputFormat*oformat; void*priv_data; ByteIOContext*pb; unsignedintnb_streams; AVStream*streams[MAX_STREAMS]; charfilename[1024];/**<输入或输出的文件名*/ /*流信息*/ int64_ttimestamp; #ifLIBAVFORMAT_VERSION」NT<(53<<16) chartitle[512]; charauthor[512]; charcopyright[512]; charcomment[512]; charalbum[512]; intyear;/** inttrack;/** chargenre[32];/** #endif intctx_flags;/**<格式特定的标志,看到AVFMTCTX_xx*/ /*分处理的私人数据(不直接修改)。 */ /**此缓冲区只需要当数据包已经被缓冲,但 不解码,例如,在MPEG编解码器的参数 流。 */ structAVPacketList*packet_buffer; /**解码元件的第一帧的位置,在 AV_TIME_BASE分数秒。 从来没有设置这个值直接: 推导的AVStream值。 */ int64_tstart_time; /**解码流的时间,在AV_TIME_BAS分数 秒。 只设置这个值,如果你知道没有个人流 工期,也不要设置任何他们。 这是从推导 AVStream值如果没有设置。 int64_tduration; /**解码: 总的文件大小,如果未知0*/ int64_tfile_size; /**解码: 在比特/秒的总流率,如果不 可用。 从来没有直接设置它如果得到file_size和时间是已知的如FFmpeg的自动计算。 */intbit_rate; I*av_read_frame()支持*/ AVStream*cur_st; #ifLIBAVFORMAT_VERSION」NT<(53<<16) constuint8_t*cur_ptr_deprecated; intcur_len_deprecated; AVPacketcur_pkt_deprecated; #endif /*av_seek_frame()支持*/ int64_tdata_offset;/**第一包抵消*/ intindex_built; intmux_rate; unsignedintpacket_size; intpreload; intmax_delay; #defineAVFMT_NOOUTPUTLOOP-1 #defineAVFMT_INFINITEOUTPUTLOOP0 /**次循环输出的格式支持它的数量*/ intloop_output; intflags; #defineAVFMT_FLAG_GENPTS0x00011970年1月1日.IPP DTS: 0 1 2 3 4 5 6.. .100101 102 PTS: 0 1 2 3 4 5 6... 100101 102 有双向预测帧的情况: 图像类型: I P B B P B B...IP B DTS: 0 1 2 3 4 5 6. ■•100101 102 PTS: 0312645...100104102 对于存在双向预测帧的情况,通常要求解码器对图像重排序,以保证输出的图像顺序为 显示顺序: 解码器输入: IPBBPBB (DTS)0123456 (PTS)0312645 解码器输出: XIBBPBBP (PTS)X0123456 时间信息的获取: 通过调用avformat_find_stream_info,多媒体应用可以从AVFormatContext对象中拿 到媒体文件的时间信息: 主要是总时间长度和开始时间,此外还有与时间信息相关的比特率 和文件大小。 其中时间信息的单位是AV_TIME_BASE微秒。 typedefstructAVFormatContext{ /**解码元件的第一帧的位置,在 AV_TIME_BASE分数秒。 从来没有设置这个值直接: 推导的AVStream值。 */ int64_tstart_time; /**解码流的时间,在AV_TIME_BAS分数秒。 只设置这个值,如果你知道没有个人流工期,也不要设置任何他们。 这是从推导AVStream值如果没有设置。 */ int64_tduration; /**解码: 总的文件大小,如果未知=0*/ int64_tfile_size; /**解码: 在比特/秒的总流率,如果不可用。 从来没有直接设置它如果得到 file_size和时间是已知的如FFmpeg的自动计算。 */ intbit_rate; }AVFormatContext; 以上4个成员变量都是只读的,基于FFMpeg的中间件需要将其封装到某个接口中,如: LONGGetDuratioin(IntfX*); LONGGetStartTime(lntfX*); LONGGetFileSize(lntfX*); LONGGetBitRate(IntfX*); APIs avformat_open_input: intavformat_open_input(AVFormatContext**ic_ptr,constchar*filename, AVInputFormat*fmt,AVDictionary**options); avformat_open_input完成两个任务: 打开一个文件或URL基于字节流的底层输入模块得到初始化。 解析多媒体文件或多媒体流的头信息,创建AVFormatContext结构并填充其中的关 键字段,依次为各个原始流建立AVStream结构。 一个多媒体文件或多媒体流与其包含的原始流的关系如下: 多媒体文件/多媒体流 原始流1video) 原始流2(aacaudioforChinese) 原始流3(aacaudioforenglish) 原始流4(ChineseSubtitle) 原始流5(EnglishSubtitle) 关于输入参数: ic_ptr,这是一个指向指针的指针,用于返回avformat_open_input内部构造的一 个AVFormatContext结构体。 filename,指定文件名。 fmt,用于显式指定输入文件的格式,如果设为空则自动判断其输入格式。 options 这个函数通过解析多媒体文件或流的头信息及其他辅助数据,能够获取足够多的关于文 件、流和编解码器的信息,但由于任何一种多媒体格式提供的信息都是有限的,而且不同的 多媒体内容制作软件对头信息的设置不尽相同,此外这些软件在产生多媒体内容时难免会引 入一些错误,因此这个函数并不保证能够获取所有需要的信息,在这种情况下,则需要考虑 另一个函数: avformat_find_stream」nfo: intavformat_find_stream」nfo(AVFormatContext*ic,AVDictionary**options); 这个函数主要用于获取必要的编解码器参数,设置到ictstreams"]宀codec中。 首先必须得到各媒体流对应编解码器的类型和id,这是两个定义在和中的枚举: enumAVMediaType{ AVMEDIA_TYPE_UNKNOWN=-1, AVMEDIA_TYPE_VIDEO,AVMEDIA_TYPE_AUDIO, AVMEDIA_TYPE_DATA,AVMEDIA_TYPE_SUBTITLE, AVMEDIA_TYPE_ATTACHMENT, AVMEDIA_TYPE_NB }; enumCodecID{ CODEC_ID_NONE, /*videocodecs*/ CODEC_ID_MPEG1VIDEO, CODEC_ID_MPEG2VIDEO,. }; 通常,如果某种媒体格式具备完备而正确的头信息,调用avformat_open_input即可以 得到这两个参数,但若是因某种原因avformat_open_input无法获取它们,这一任务将由 avformat_find_stream」nfo完成。 其次还要获取各媒体流对应编解码器的时间基准。 此外,对于音频编解码器,还需要得到: 采样率, 声道数, 位宽, 帧长度(对于某些编解码器是必要的), 对于视频编解码器,则是: 图像大小, 色彩空间及格式, av_read_frame intav_read_frame(AVFormatContext*s,AVPacket*pkt); 这个函数用于从多媒体文件或多媒体流中读取媒体数据,获取的数据由AVPacket结构 pkt来存放。 对于音频数据,如果是固定比特率,则pkt中装载着一个或多个音频帧;如果 是可变比特率,则pkt中装载有一个音频帧。 对于视频数据,pkt中装载有一个视频帧。 需 要注意的是: 再次调用本函数之前,必须使用av_free_packet释放pkt所占用的资源。 通过pkttstream_index可以查到获取的媒体数据的类型,从而将数据送交相应的解码器进行后续处理。 av_seek_frame intav_seek_frame(AVFormatContext*s,intstream」ndex,int64_ttimestamp,int flags); 这个函数通过改变媒体文件的读写指针来实现对媒体文件的随机访问,支持以下三种方 式: 基于时间的随机访问: 具体而言就是将媒体文件读写指针定位到某个给定的时间点上,则之后调用av_read_frame时能够读到时间标签等于给定时间点的媒体数据,通常用于 实现媒体播放器的快进、快退等功能。 基于文件偏移的随机访问: 相当于普通文件的seek函数,timestamp也成为文件 的偏移量。 基于帧号的随机访问: timestamp为要访问的媒体数据的帧号。 关于参数: s: 是个AVFormatContext指针,就是avformat_open_input返回的那个结构。 stream」ndex: 指定媒体流,如果是基于时间的随机访问,则第三个参数timestamp 将以此媒体流的时间基准为单位;如果设为负数,则相当于不指定具体的媒体流,FFMPEG 会按照特定的算法寻找缺省的媒体流,此时,timestamp的单位为AV_TIME_BAS(微秒)。 timestamp: 时间标签,单位取决于其他参数。 flags: 定位方式,AVSEEK_FLAG_BYTE示基于字节偏移,AVSEEK_FLAG_FRAME 示基于帧号,其它表示基于时间。 av_close_input_file: voidav_close_input_file(AVFormatContext*s); 关闭一个媒体文件: 释放资源,关闭物理10。 avcodec_find_decoder: AVCodec*avcodec_find_decoder(enumCodecIDid); AVCodec*avcodec_find_decoder_by_name(constchar*name); 根据给定的codecid或解码器名称从系统中搜寻并返回一个AVCodec结构的指针。 avcodec_open: intavcodec_open(AVCodecCon
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- ffmpeg 解码 流程
![提示](https://static.bdocx.com/images/bang_tan.gif)