ffmpeg examples -- demuxing_decoding

本文详细介绍了FFmpeg库中解复用(demuxing)和解码(decoding)的过程,包括av_register_all、avformat_open_input、avformat_find_stream_info、avcodec_find_decoder、avcodec_open2等关键步骤。通过mp4文件为例,展示了从打开文件到读取header信息的详细流程,解析了诸如stts和stco box等关键数据结构,有助于理解FFmpeg如何处理多媒体数据。
摘要由CSDN通过智能技术生成

demuxing_decoding

1 概要

样例Demo,主要展示解复用和解码。样例Demo的时序图如下,对于重点关注的接口,我用了实线箭头来做指向。
demuxing_decoding时序图

2 av_register_all

官方给定的接口解释如下,用于注册所有的formats和codecs。
针对这个接口分析,网上的资料较多,建议直接学习这篇Blog:ffmpeg 源代码简单分析 : av_register_all()

/**
 * Initialize libavformat and register all the muxers, demuxers and
 * protocols. If you do not call this function, then you can select
 * exactly which formats you want to support.
 *
 * @see av_register_input_format()
 * @see av_register_output_format()
 */
void av_register_all(void);

3 avformat_open_input

先看下官方给定的接口注释,该函数用于打开多媒体数据并且获得一些相关的信息。fmt参数不为NULL时,强制指定AVFormatContext中AVInputFormat的。样例Demo中设置成NULL,这里先从简分析下,利用av_find_input_format接口先查找指定的fmt,再用作入参提供给avformat_open_input接口。参考Blog如下:
1. 图解FFMPEG打开媒体的函数avformat_open_input
2. FFMPEG源码分析:avformat_open_input() 媒体打开函数
3. FFmpeg源代码简单分析:avformat_open_input()

/**
 * Open an input stream and read the header. The codecs are not opened.
 * The stream must be closed with avformat_close_input().
 *
 * @param ps Pointer to user-supplied AVFormatContext (allocated by avformat_alloc_context).
 *           May be a pointer to NULL, in which case an AVFormatContext is allocated by this
 *           function and written into ps.
 *           Note that a user-supplied AVFormatContext will be freed on failure.
 * @param url URL of the stream to open.
 * @param fmt If non-NULL, this parameter forces a specific input format.
 *            Otherwise the format is autodetected.
 * @param options  A dictionary filled with AVFormatContext and demuxer-private options.
 *                 On return this parameter will be destroyed and replaced with a dict containing
 *                 options that were not found. May be NULL.
 *
 * @return 0 on success, a negative AVERROR on failure.
 *
 * @note If you want to use custom IO, preallocate the format context and set its pb field.
 */
int avformat_open_input(AVFormatContext **ps, const char *url, AVInputFormat *fmt, AVDictionary **options);

这里分析的是mp4文件,所以指定的fmt是ff_mov_demuxer。由于这里指定了fmt,init_input接口内部处理变得简单多了,只剩下io_open处理。

正常情况下需要探测视频文件的格式,这个过程也比较有趣。如果感兴趣的话,可以单独拎出来看。
avformat_open_input大致的调用流程见下面的流程图:
avformat_open_input调用流程

3.1 io_open

参考Blog:FFmpeg源代码简单分析:avio_open2()
io_open调用流程

step3-5: 从代码中可以看出,ffurl_alloc()主要调用了2个函数:url_find_protocol()根据文件路径查找合适的URLProtocol,url_alloc_for_protocol()为查找到的URLProtocol创建URLContext。由于这里使用本地文件调试,所以匹配的URL是file.c。
step9: 指定read_packet和write_packet,这样就关联到protocol的url_read和url_write。
step8: 再回到ffio_fdopen(),会发现它初始化AVIOContext的结构体的时候,首先将自己分配的Buffer设置为该AVIOContext的Buffer;然后将URLContext作为用户自定义数据(对应AVIOContext的opaque变量)提供给该AVIOContext;最后分别将3个函数作为该AVIOContext的读,写,跳转函数:ffurl_read(),ffurl_write(),ffurl_seek()。

3.2 read_header

这里还是以mp4文件为例,所以read_header实际指向的是mov_read_header接口。参考内容:MPEG-4 Part 14; Elements of the H.264 Video/AAC Audio MP4 Movie.pdf。

下面内容是执行 ffplay -loglevel 56 VID_20180131_195311.mp4,读取到的header信息。需要关注的是stts和stco box,前者表示 Sample To Time映射关系,后者是Chunk Offset Table。具体的结构描述见Elements of the H.264 Video/AAC Audio MP4 Movie.pdf文档。

调用mov_read_trak接口解析trak box时,每调用一次,都会用avformat_new_stream创建一个AVStream,离开mov_read_trak接口前,nb_streams也会自增一。
read_header解析日志:(read_header读取到的内容填充到AVStream结构体内部的×priv_data变量)

[mov,mp4,m4a,3gp,3g2,mj2 @ 0x7f3b40000920] type:’ftyp’ parent:’root’ sz: 24 8 3705390
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x7f3b40000920] ISO: File Type Major Brand: mp42
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x7f3b40000920] type:’moov’ parent:’root’ sz: 1915 32 3705390
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x7f3b40000920] type:’mvhd’ parent:’moov’ sz: 108 8 1907
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x7f3b40000920] time scale = 1000
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x7f3b40000920] type:’udta’ parent:’moov’ sz: 38 116 1907
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x7f3b40000920] type:’[169]xyz’ parent:’udta’ sz: 30 8 30
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x7f3b40000920] type:’meta’ parent:’moov’ sz: 121 154 1907
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x7f3b40000920] type:’hdlr’ parent:’meta’ sz: 33 8 113
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x7f3b40000920] ctype=[0][0][0][0]
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x7f3b40000920] stype=mdta
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x7f3b40000920] type:’keys’ parent:’meta’ sz: 43 41 113
[mov,mp

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值