ffmpeg源码分析-decode_video

《FFmpeg原理》的社群来了,想加入社群的朋友请购买 VIP 版,VIP 版有更高级的内容与答疑服务。


本系列 以 ffmpeg4.2 源码为准,下载地址:链接:百度网盘 提取码:g3k8

ffmpeg 源码分析系列以一条简单的命令开始,ffmpeg -i a.mp4 b.flv,分析其内部逻辑。

a.mp4下载链接:百度网盘,提取码:nl0s 。


本文主要分析 decode_video() 跟 decode_audio() 的内部逻辑,流程图如下:

decode_video() 这个函数不仅仅要注意内部逻辑。函数返回值,函数传递的参数也相当有考究。下面贴一下 decode_video() 的形参与实参。

形参:decode_video(InputStream *ist, AVPacket *pkt, int *got_output, int64_t *duration_pts, int eof,int *decode_failed)
实参:decode_video(ist, repeating ? NULL : &avpkt, &got_output, &duration_pts, !pkt, &decode_failed)

返回值分析:

decode_video() 最后一行代码 是 return err < 0 ? err : ret; err 是 send_frame_to_filters() 的错误,ret 是解码返回的错误。跑到最后一行,ret肯定是 0。decode_video() 的返回值是 0 跟 非0 值,0代表没问题。

参数分析:

  1. decode_video() 第二个参数是 AVPacket *pkt,第二个参数其实有3种场景传值。
    • repeating 等于1,传NULL,传NULL主要控制 decode() 函数内部 不调用avcodec_send_packet(), 只调用avcodec_receive_frame() 来刷解码器frame。
    • 直接传 avpkt 变量,avpkt 实际上也有两种情况,avpkt.size 等于0 或者不等于 0。avpkt.size == 0 代表后续已经没有 正常pakcet 数据给解码器,是 flush 解码器。avpkt.size != 0 代表正常 pakcet 发送给解码器。
  2. got_output 代表解码器有没输出frame。有时候要输入多个 pakcet 才能解码出 frame

这里面最重要的就是 decode_video() , decode() 这两个函数的传参跟返回值,其他的代码都是一些参数赋值,数据统计,比较容易理解。

所以下面的流程图主要以 pkt 传参,repeating 分支为主。

从流程图可以看出,在处理文件末尾的时候, process_input_packet() 的参数 pkt = null,但只执行了一次 avcodec_receive_frame() 就跳出while循环,没有设置 reapting 继续,所以解码器可能还有frame未读出来,所以可能会调用多次 process_input_packet() 传递 pkt = null,直到avcodec_receive_frame() 返回 EOF,才算读完全部的 frame。


decode_video() 的函数调用流程图如下,下面开始讲解 send_frame_to_filters() 函数的内部实现。

send_frame_to_filters() 里面的代码,非常简单。就是往 InputStream 关联的多个 InputFilter 发送 frame,但是由于本文使用的命令 InputStream 没有多个 filter, 所以相当于直接执行 ifilter_send_frame()

ifilter_send_frame() 的内部逻辑也比较简单,通过对比 InputFilter 跟 AVFrame 的格式,采样率,宽高等参数,判断需不需要重新初始化 filtergraph。如果需要就执行 ifilter_parameters_from_frame() ,把 frame 的参数 赋值给 InputFilter。然后调用 configure_filtergraph() 初始出 filtergraph,没调用 ifilter_parameters_from_frame() 之前,InputFilter 大部分参数是空,所以 need_reinit 肯定是1。configure_filtergraph() 这个函数特别重要,就是在这里把 InputStream::filters 跟 OutputStream::filter LINK 起来的。


下面仔细 分析 configure_filtergraph() 的内部逻辑。贴上代码图,重点代码用红笔圈出来了,没有圈出来的是不会执行或者是检测类型的代码。

流程图跟代码相对比较容易理解,主要是 avfilter_graph_parse2() 函数后面的两个变量 inputs ,outputs。实际上这两个变量相当于一个filter头尾连接器。画个流程图便于理解。

可以看到 configure_filtergraph() 把 InputFilter 跟 OutputFilter 关联了在一起。

configure_input_filte() 的逻辑也相对简单,就是把 InputFilter::filter 初始化 为 buffer filter, 然后 Link 到 inputs[0]->filter_ctx

configure_output_filte()把 OutputFilter::filter 初始化 为 buffersink filter, 然后 Link 到 outputs[0]->filter_ctx


decode_audio() 的逻辑跟 decode_video() 类似,就不再分析了


©版权所属:弦外之音

由于笔者的水平有限, 加之编写的同时还要参与开发工作,文中难免会出现一些错误或者不准确的地方,恳请读者批评指正。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Loken2020

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值