栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

ffmpeg源码分析-decode

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

ffmpeg源码分析-decode

推荐一个零声学院免费公开课程,个人觉得老师讲得不错,分享给大家:Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,立即学习


本系列 以 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代表没问题。

参数分析:

    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 发送给解码器。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() 类似,就不再分析了


©版权所属:知识星球:弦外之音,QQ:2338195090。

由于笔者的水平有限, 加之编写的同时还要参与开发工作,文中难免会出现一些错误或者不准确的地方,恳请读者批评指正。如果读者有任何宝贵意见,可以加我微信 Loken1。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/748483.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号