收藏 分享(赏)

最新版FFMPEG解码流程(欢迎愿意分享资料群友下载载).doc

上传人:HR专家 文档编号:11421734 上传时间:2020-04-19 格式:DOC 页数:30 大小:270KB
下载 相关 举报
最新版FFMPEG解码流程(欢迎愿意分享资料群友下载载).doc_第1页
第1页 / 共30页
最新版FFMPEG解码流程(欢迎愿意分享资料群友下载载).doc_第2页
第2页 / 共30页
最新版FFMPEG解码流程(欢迎愿意分享资料群友下载载).doc_第3页
第3页 / 共30页
最新版FFMPEG解码流程(欢迎愿意分享资料群友下载载).doc_第4页
第4页 / 共30页
最新版FFMPEG解码流程(欢迎愿意分享资料群友下载载).doc_第5页
第5页 / 共30页
点击查看更多>>
资源描述

1、 FFMPEG解码流程: 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. 判断帧的类型,对于视频帧调用:

2、avcodec_decode_video() 10. 解码完后,释放解码器: avcodec_close() 11. 关闭输入文件: avformat_close_input_file()主要数据结构:基本概念: 编解码器、数据帧、媒体流和容器是数字媒体处理系统的四个基本概念。首先需要统一术语: 容器文件(Conainer/File):即特定格式的多媒体文件。 媒体流(Stream):指时间轴上的一段连续数据,如一段声音数据,一段视频数据或一段字幕数据,可以是压缩的,也可以是非压缩的,压缩的数据需要关联特定的编解码器。 数据帧数据包(Frame/Packet):通常,一个媒体流由大量的数据帧组

3、成,对于压缩数据,帧对应着编解码器的最小处理单元。通常,分属于不同媒体流的数据帧交错复用于容器之中,参见交错。 编解码器:编解码器以帧为单位实现压缩数据和原始数据之间的相互转换。在FFMPEG中,使用AVFormatContext、AVStream、AVCodecContext、AVCodec及AVPacket等结构来抽象这些基本要素,它们的关系如上图所示: AVCodecContext: 这是一个描述编解码器上下文的数据结构,包含了众多编解码器需要的参数信息,如下列出了部分比较重要的域:typedef struct AVCodecContext / * *一些编解码器需要/可以像使用extr

4、adata Huffman表。 * MJPEG:Huffman表 * RV10其他标志 * MPEG4:全球头(也可以是在比特流或这里) *分配的内存应该是FF_INPUT_BUFFER_PADDING_SIZE字节较大 *,比extradata_size避免比特流器,如果它与读prolems。 * extradata按字节的内容必须不依赖于架构或CPU的字节顺序。 * - 编码:设置/分配/释放由libavcodec的。 * - 解码:由用户设置/分配/释放。 * / uint8_t *extradata; int extradata_size; / * *这是时间的基本单位,在条件(以秒为

5、单位) *帧时间戳派代表出席了会议。对于固定fps的内容, *基应该1/framerate和时间戳的增量应该 *相同的1。 * - 编码:必须由用户设置。 * - 解码:libavcodec的设置。 * / AVRational time_base; /*视频* / / * *图片宽度/高度。 * - 编码:必须由用户设置。 * - 解码:libavcodec的设置。 *请注意:兼容性,它是可能的,而不是设置此 * coded_width/高解码之前。 * / int width, height; . / *仅音频* / int sample_rate; / 每秒采样 int channels

6、; / 音频通道数 / * *音频采样格式 * - 编码:由用户设置。 * - 解码:libavcodec的设置。 * / enum SampleFormat sample_fmt; / 样本格式 / *下面的数据不应该被初始化。* / / * *每包样品,初始化时调用“init”。 * / int frame_size; int frame_number; /(“D” 24)(“C” 16)(“B” 8)+“A”)。 *这是用来解决一些编码错误。 *分路器应设置什么是编解码器用于识别领域中。 *如果有分路器等多个领域,在一个容器,然后选择一个 *最大化使用的编解码器有关的信息。 *如果在容器

7、中的编解码器标记字段然后32位大分路器应该 *重新映射到一个表或其他结构的32位编号。也可选择新 * extra_codec_tag+大小可以添加,但必须证明这是一个明显的优势 *第一。 * - 编码:由用户设置,如果没有则默认基础上codec_id将使用。 * - 解码:由用户设置,将被转换成在初始化libavcodec的大写。 * / unsigned int codec_tag; . / * *在解码器的帧重排序缓冲区的大小。 *对于MPEG-2,这是IPB1或0低延时IP。 * - 编码:libavcodec的设置。 * - 解码:libavcodec的设置。 * / int has_

8、b_frames; / * *每包的字节数,如果常量和已知或0 *用于一些WAV的音频编解码器。 * / int block_align; / * *从分路器位每个样品/像素(huffyuv需要)。 * - 编码:libavcodec的设置。 * - 解码:由用户设置。 * / int bits_per_coded_sample; . AVCodecContext;如果是单纯使用libavcodec,这部分信息需要调用者进行初始化;如果是使用整个FFMPEG库,这部分信息在调用avformat_open_input和avformat_find_stream_info的过程中根据文件的头信息及媒

9、体流内的头部信息完成初始化。其中几个主要域的释义如下: extradata/extradata_size:这个buffer中存放了解码器可能会用到的额外信息,在av_read_frame中填充。一般来说,首先,某种具体格式的demuxer在读取格式头信息的时候会填充extradata,其次,如果demuxer没有做这个事情,比如可能在头部压根儿就没有相关的编解码信息,则相应的parser会继续从已经解复用出来的媒体流中继续寻找。在没有找到任何额外信息的情况下,这个buffer指针为空。 time_base: width/height:视频的宽和高。 sample_rate/channels:音

10、频的采样率和信道数目。 sample_fmt: 音频的原始采样格式。codec_name/codec_type/codec_id/codec_tag:编解码器的信息。AVStream 该结构体描述一个媒体流,定义如下:typedef struct AVStream int index; /* 在AVFormatContext流的索引* / int id; /* 特定格式的流ID */ AVCodecContext *codec; /* codec context */ / * *流的实时帧率基地。 *这是所有时间戳可以最低帧率 *准确代表(它是所有的最小公倍数 *流的帧率)。请注意,这个值只是

11、一个猜测! *例如,如果时间基数为1/90000和所有帧 *约3600或1800计时器刻度,然后r_frame_rate将是50/1。 * / AVRational r_frame_rate; / * *这是时间的基本单位,在条件(以秒为单位) *帧时间戳派代表出席了会议。对于固定fps的内容, *时基应该是1/framerate的时间戳的增量应为1。 * / AVRational time_base; . / * *解码流量的第一帧,在流量时-base分。 *如果你是绝对100的把握,设定值 *它真的是第一帧点。 *这可能是未定义(AV_NOPTS_VALUE)的。 *注意的业余头不弱者受制

12、与正确的START_TIME的业余 *分路器必须不设定此。 * / int64_t start_time; / * *解码:时间流流时基。 *如果源文件中没有指定的时间,但不指定 *比特率,这个值将被从码率和文件大小的估计。 * / int64_t duration;#if LIBAVFORMAT_VERSION_INT (5316) char language4; /* ISO 639-2/B 3-letter language code (empty string if undefined) */#endif /* av_read_frame()支持* / enum AVStreamPar

13、seType need_parsing; struct AVCodecParserContext *parser; . /*函数av_seek_frame()支持* / AVIndexEntry *index_entries; / *仅用于如果格式不notsupport寻求本身。* / int nb_index_entries; unsigned int index_entries_allocated_size; int64_t nb_frames; / 在此流的帧,如果已知或0 . /*平均帧率 AVRational avg_frame_rate; . AVStream;主要域的释义如下,其

14、中大部分域的值可以由avformat_open_input根据文件头的信息确定,缺少的信息需要通过调用avformat_find_stream_info读帧及软解码进一步获取: index/id:index对应流的索引,这个数字是自动生成的,根据index可以从AVFormatContext:streams表中索引到该流;而id则是流的标识,依赖于具体的容器格式。比如对于MPEG TS格式,id就是pid。 time_base:流的时间基准,是一个实数,该流中媒体数据的pts和dts都将以这个时间基准为粒度。通常,使用av_rescale/av_rescale_q可以实现不同时间基准的转换。

15、start_time:流的起始时间,以流的时间基准为单位,通常是该流中第一个帧的pts。 duration:流的总时间,以流的时间基准为单位。 need_parsing:对该流parsing过程的控制域。 nb_frames:流内的帧数目。 r_frame_rate/framerate/avg_frame_rate:帧率相关。 codec:指向该流对应的AVCodecContext结构,调用avformat_open_input时生成。parser:指向该流对应的AVCodecParserContext结构,调用avformat_find_stream_info时生成。AVFormatCont

16、ext这个结构体描述了一个媒体文件或媒体流的构成和基本信息,定义如下:typedef struct AVFormatContext const AVClass *av_class; /*由avformat_alloc_context设置的。* / / *只能是iFormat的,或在同一时间oformat,不是两个。* / struct AVInputFormat *iformat; struct AVOutputFormat *oformat; void *priv_data; ByteIOContext *pb; unsigned int nb_streams; AVStream *stre

17、amsMAX_STREAMS; char filename1024; / *输入或输出的文件名*/ / *流信息* / int64_t timestamp;#if LIBAVFORMAT_VERSION_INT (5316) char title512; char author512; char copyright512; char comment512; char album512; int year; /* ID3 year, 0 if none */ int track; /* track number, 0 if none */ char genre32; /* ID3 genre *

18、/#endif int ctx_flags; /* 格式特定的标志,看到AVFMTCTX_xx* / /*分处理的私人数据(不直接修改)。* / / *此缓冲区只需要当数据包已经被缓冲,但 不解码,例如,在MPEG编解码器的参数 流。 * / struct AVPacketList *packet_buffer; / *解码元件的第一帧的位置,在 AV_TIME_BASE分数秒。从来没有设置这个值直接: 推导的AVStream值。 * / int64_t start_time; / *解码流的时间,在AV_TIME_BASE分数 秒。只设置这个值,如果你知道没有个人流 工期,也不要设置任何他们

19、。这是从推导 AVStream值如果没有设置。 int64_t duration; / *解码:总的文件大小,如果未知0* / int64_t file_size; / *解码:在比特/秒的总流率,如果不 可用。从来没有直接设置它如果得到file_size和 时间是已知的如FFmpeg的自动计算。 * / int bit_rate; /* av_read_frame()支持* / AVStream *cur_st;#if LIBAVFORMAT_VERSION_INT (5316) const uint8_t *cur_ptr_deprecated; int cur_len_deprecate

20、d; AVPacket cur_pkt_deprecated;#endif /* av_seek_frame() 支持 */ int64_t data_offset; /* 第一包抵消 */ int index_built; int mux_rate; unsigned int packet_size; int preload; int max_delay;#define AVFMT_NOOUTPUTLOOP -1#define AVFMT_INFINITEOUTPUTLOOP 0 /* 次循环输出的格式支持它的数量 */ int loop_output; int flags;#define

21、AVFMT_FLAG_GENPTS 0x0001 / 生成失踪分,即使它需要解析未来框架。#define AVFMT_FLAG_IGNIDX 0x0002 / 忽略指数。#define AVFMT_FLAG_NONBLOCK 0x0004 /从输入中读取数据包时,不要阻止。#define AVFMT_FLAG_IGNDTS 0x0008 / 忽略帧的DTS包含DTS与PTS#define AVFMT_FLAG_NOFILLIN 0x0010 / 不要从任何其他值推断值,只是返回存储在容器中#define AVFMT_FLAG_NOPARSE 0x0020 /无帧。也在寻求框架不能工作,如果找到

22、帧边界的解析已被禁用#define AVFMT_FLAG_RTP_HINT 0x0040 /基time_base单位介绍时间戳的时间 *解压缩包将被提交给用户。 *可AV_NOPTS_VALUE如果没有存储在文件中。 *分必须大于或等于DTS作为演示不能发生之前 *减压,除非要查看十六进制转储。有些格式滥用 * DTS和PTS/ CTS的条款意味着不同的东西。如时间戳 *必须转换为真正的PTS / DTS之前,他们在AVPacket存储。 * / int64_t pts; / * AVStream-基time_base单位时间的减压时间戳记; *包解压。 *可AV_NOPTS_VALUE如果没

23、有存储在文件中。 * / int64_t dts; uint8_t *data; int size; int stream_index; int flags; / * *这个包的时间AVStream-基time_base单位,如果未知。 *等于next_pts - 在呈现顺序this_pts。* / int duration; void (*destruct)(struct AVPacket *); void *priv; int64_t pos; /基time_base单位的时差,这点 *包从解码器输出的已融合在哪个点 *独立的前一帧的情况下。也就是说, *框架几乎是一致的,没有问题,如果解

24、码开始从 *第一帧或从这个关键帧。 * AV_NOPTS_VALUE如果不明。 *此字段是不是当前数据包的显示时间。 * *这一领域的目的是允许在流,没有寻求 *在传统意义上的关键帧。它所对应的 *恢复点SEI的H.264和match_time_delta在螺母。这也是 *必不可少的一些类型的字幕流,以确保所有 *后寻求正确显示字幕。* / int64_t convergence_duration; AVPacket;FFMPEG使用AVPacket来暂存解复用之后、解码之前的媒体数据(一个音/视频帧、一个字幕包等)及附加信息(解码时间戳、显示时间戳、时长等)。其中: dts表示解码时间戳,p

25、ts表示显示时间戳,它们的单位是所属媒体流的时间基准。 stream_index给出所属媒体流的索引; data为数据缓冲区指针,size为长度; duration为数据的时长,也是以所属媒体流的时间基准为单位; pos表示该数据在媒体流中的字节偏移量; destruct为用于释放数据缓冲区的函数指针; flags为标志域,其中,最低为置1表示该数据是一个关键帧。AVPacket结构本身只是个容器,它使用data成员引用实际的数据缓冲区。这个缓冲区通常是由av_new_packet创建的,但也可能由FFMPEG的API创建(如av_read_frame)。当某个AVPacket结构的数据缓冲区

26、不再被使用时,要需要通过调用av_free_packet释放。av_free_packet调用的是结构体本身的destruct函数,它的值有两种情况:1)av_destruct_packet_nofree或0;2)av_destruct_packet,其中,情况1)仅仅是将data和size的值清0而已,情况2)才会真正地释放缓冲区。FFMPEG内部使用AVPacket结构建立缓冲区装载数据,同时提供destruct函数,如果FFMPEG打算自己维护缓冲区,则将destruct设为av_destruct_packet_nofree,用户调用av_free_packet清理缓冲区时并不能够将其释

27、放;如果FFMPEG打算将该缓冲区彻底交给调用者,则将destruct设为av_destruct_packet,表示它能够被释放。安全起见,如果用户希望自由地使用一个FFMPEG内部创建的AVPacket结构,最好调用av_dup_packet进行缓冲区的克隆,将其转化为缓冲区能够被释放的AVPacket,以免对缓冲区的不当占用造成异常错误。av_dup_packet会为destruct指针为av_destruct_packet_nofree的AVPacket新建一个缓冲区,然后将原缓冲区的数据拷贝至新缓冲区,置data的值为新缓冲区的地址,同时设destruct指针为av_destruct_

28、packet。时间信息时间信息用于实现多媒体同步。同步的目的在于展示多媒体信息时,能够保持媒体对象之间固有的时间关系。同步有两类,一类是流内同步,其主要任务是保证单个媒体流内的时间关系,以满足感知要求,如按照规定的帧率播放一段视频;另一类是流间同步,主要任务是保证不同媒体流之间的时间关系,如音频和视频之间的关系(lipsync)。对于固定速率的媒体,如固定帧率的视频或固定比特率的音频,可以将时间信息(帧率或比特率)置于文件首部(header),如AVI的hdrl List、MP4的moov box,还有一种相对复杂的方案是将时间信息嵌入媒体流的内部,如MPEG TS和Real video,这种

29、方案可以处理变速率的媒体,亦可有效避免同步过程中的时间漂移。FFMPEG会为每一个数据包打上时间标签,以更有效地支持上层应用的同步机制。时间标签有两种,一种是DTS,称为解码时间标签,另一种是PTS,称为显示时间标签。对于声音来说 ,这两个时间标签是相同的,但对于某些视频编码格式,由于采用了双向预测技术,会造成DTS和PTS的不一致。无双向预测帧的情况:图像类型: I P P P P P P . I P PDTS: 0 1 2 3 4 5 6. 100 101 102PTS: 0 1 2 3 4 5 6. 100 101 102有双向预测帧的情况:图像类型: I P B B P B B . I

30、 P BDTS: 0 1 2 3 4 5 6 . 100 101 102PTS: 0 3 1 2 6 4 5 . 100 104 102对于存在双向预测帧的情况,通常要求解码器对图像重排序,以保证输出的图像顺序为显示顺序:解码器输入:I P B B P B B (DTS) 0 1 2 3 4 5 6 (PTS) 0 3 1 2 6 4 5解码器输出:X I B B P B B P (PTS) X 0 1 2 3 4 5 6时间信息的获取:通过调用avformat_find_stream_info,多媒体应用可以从AVFormatContext对象中拿到媒体文件的时间信息:主要是总时间长度和开始

31、时间,此外还有与时间信息相关的比特率和文件大小。其中时间信息的单位是AV_TIME_BASE:微秒。typedef struct AVFormatContext / *解码元件的第一帧的位置,在 AV_TIME_BASE分数秒。从来没有设置这个值直接: 推导的AVStream值。 * / int64_t start_time; / *解码流的时间,在AV_TIME_BASE分数秒。只设置这个值,如果你知道没有个人流工期,也不要设置任何他们。这是从推导AVStream值如果没有设置。 * / int64_t duration; / *解码:总的文件大小,如果未知=0* / int64_t fil

32、e_size; / *解码:在比特/秒的总流率,如果不可用。从来没有直接设置它如果得到file_size和时间是已知的如FFmpeg的自动计算。 * / int bit_rate; . AVFormatContext;以上4个成员变量都是只读的,基于FFMpeg的中间件需要将其封装到某个接口中,如:LONG GetDuratioin(IntfX*);LONG GetStartTime(IntfX*);LONG GetFileSize(IntfX*);LONG GetBitRate(IntfX*); APIs avformat_open_input:int avformat_open_input

33、(AVFormatContext *ic_ptr, const char *filename, AVInputFormat *fmt, AVDictionary *options);avformat_open_input完成两个任务: 打开一个文件或URL,基于字节流的底层输入模块得到初始化。 解析多媒体文件或多媒体流的头信息,创建AVFormatContext结构并填充其中的关键字段,依次为各个原始流建立AVStream结构。一个多媒体文件或多媒体流与其包含的原始流的关系如下:多媒体文件/多媒体流 (movie.mkv) 原始流 1 (h.264 video) 原始流 2 (aac audio for Chinese) 原始流 3 (aac audio for english) 原始流 4 (Chinese Subtitle) 原始流 5 (English Subtitle) .关于输入参数: ic_ptr,这是一个指向指针的指针,用于返回avformat_open_input内部构造的一个AVFormatContext结构体。 filename,指定文件名。 fmt,用于显式指定输入文件的格式,如果设为空则自动判断其输入格式。 options这个函数通过解析多媒体文件

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

当前位置:首页 > 实用文档 > 往来文书

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报