热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

ffmpeg源码分析open_output_file

推荐一个零声学院免费公开课程,个人觉得老师讲得不错,分享给大家:Linux,Nginx,ZeroMQÿ

推荐一个零声学院免费公开课程,个人觉得老师讲得不错,分享给大家: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 。


本文章主要分析 open_output_file() 的内部逻辑。

简单转码命令 的 open_output_file() 流程图如下,一些参数赋值的内容没有画出来,只有主干。

理解 open_output_file(),必须先了解 2个新的数据结构,OutputFile,OutputStream,请先看源码自行阅读这两个结构体的声明。跑完 open_output_file() 之后形成的数据关系图如下,跟上一章的输入非常类似。

下面再贴一个 open_output_file() 的代码图,因为 open_output_file() 里面的逻辑分支比较多,在 ffmpeg -i a.mp4 b.flv 下并不会跑进去某些 if 条件,所以代码图为了简洁,会删减一些if,有一些参数赋值也会删掉。

接下来会逐行代码分析 open_output_file() 的内部逻辑。

  1. 图片1873~1894 行,申明一个 OutputFile 结构 ,丢进去全局变量数组 outpur_files[],然后把 OptionsContext 的一些值赋值给 of
  2. 图片1914~2083 行,这个代码块是比较重要的,首先根据算法,选出输入流里最好的 video 流 idx,然后调用 new_video_stream(o, oc, idx) 来创建输出流。new_video_stream() 函数比较复杂,这里简单介绍,下一段再仔细分析。 audio流类似 video流,也是根据算法选出最好 idx,然后调 new_audio_stream(o, oc, idx);
  3. 图片2090~2132 行,这部分代码主要对命令行参数做些检测,检测哪些option 没有用到,命令行写错了,给提示。不是主要逻辑。
  4. 图片2133~2213 行,这部分代码就是遍历输出流,然后调 init_simple_filtergraph(ist, ost) 初始化Filter,这块比较重要,要细看。
  5. 后面的代码都不重要,都是一些检测,参数赋值,处理metadata,处理chapter,后面的代码最重要的是调了 avio_open2() 打开输出文件

如此看来,open_output_file() 的内部逻辑就变得极其简单了,创建 OutputFile,用OptionsContext来赋值,调new_video_stream() ,new_audio_stream() 创建输出流,最后初始化 filter,然后avio_open2()打开输出文件。


上面有两个函数没有仔细介绍 new_video_stream() new_audio_stream() ,接下来仔细分析。

new_video_stream()的逻辑相对简单。如下面的流程图所示,new_video_stream() 里面有个 new_output_stream(),

new_output_stream() 主要创建 stream,编码器context,然后做一些初始化。

new_output_stream() 是一个公共函数,音频流,数据流,字幕流都用了它,所以 ffmpeg 把他分出来。video_stream 的一些初始化会在调用 new_output_stream() 后执行。

比较注意的一点是,new_video_stream() 跟 new_output_stream() 里面用了大量的 MATCH_PER_STREAM_OPT(),把 OptionsContex 的参数提取出来,赋值给 stream参数,或者赋值给编码器参数。所以一定要理解 MATCH_PER_STREAM_OPT() 的实现。

new_audio_stream()跟 new_video_stream() 类似,只是 new_audio_stream() 调了 new_output_stream() ,对音频流或编码器的某些参数赋值。


最后还有一个重要函数没有分析,init_simple_filtergraph(),即使是简单的转码命令,ffmpeg 为了通用性,也是会创建 filter 的,只不过是 null filter 跟 anull filter。空的视频流 filter,空的音频流filter

init_simple_filtergraph() 的逻辑比较简单,只是看 init_simple_filtergraph() ,不太容易看出filter的整体逻辑跟关系结构,需要后面分析 transcode()转码函数 ,ifilter_send_frame() 调用了 configure_filtergraph() 才能形成完整的关系结构体。这里尽量简单介绍,有个印象。

init_simple_filtergraph() 跑完之后形成的关系结构如下。

如图所示,有一个全局变量数组 filtergraphs[],一个 FilterGraph 里有一个InputFilter 跟一个 OutputFilter 。InputFilter 跟 OutputFilter 又各自有输入跟输出流,所以代码跑到这里,已经确定把输入输出流关联在一起了。

只要在输入流读数据,然后往输入流关联的输出流丢数据就完成转码了。其实之前 OutputStream 里面有个 source_index 成员本身已经关联了输入流,还要把 输入输出流 关联到 filter ,然后丢进去 FilterGraph 是因为 输入输出流虽然关联了,但他们的filter 还没关联起来。

FilterGraph::InputFilter 跟 FilterGraph::OutputFilter 在 init_simple_filtergraph() 里面也还没开始关联,关联之后就可以 发送 frame 到 buffersrc ,从 buffersink 出口读frame,不了解filter的,请先自己了解filter的基本用法。

关联 FilterGraph::InputFilter 跟 FilterGraph::OutputFilter 是在后面的 configure_filtergraph() 里完成的。

至此,open_output_file() 内部逻辑已经分析完毕


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

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


推荐阅读
  • 本文详细解析了JavaScript中相称性推断的知识点,包括严厉相称和宽松相称的区别,以及范例转换的规则。针对不同类型的范例值,如差别范例值、统一类的原始范例值和统一类的复合范例值,都给出了具体的比较方法。对于宽松相称的情况,也解释了原始范例值和对象之间的比较规则。通过本文的学习,读者可以更好地理解JavaScript中相称性推断的概念和应用。 ... [详细]
  • 本文介绍了Swing组件的用法,重点讲解了图标接口的定义和创建方法。图标接口用来将图标与各种组件相关联,可以是简单的绘画或使用磁盘上的GIF格式图像。文章详细介绍了图标接口的属性和绘制方法,并给出了一个菱形图标的实现示例。该示例可以配置图标的尺寸、颜色和填充状态。 ... [详细]
  • 2021最新总结网易/腾讯/CVTE/字节面经分享(附答案解析)
    本文分享作者在2021年面试网易、腾讯、CVTE和字节等大型互联网企业的经历和问题,包括稳定性设计、数据库优化、分布式锁的设计等内容。同时提供了大厂最新面试真题笔记,并附带答案解析。 ... [详细]
  • 一面自我介绍对象相等的判断,equals方法实现。可以简单描述挫折,并说明自己如何克服,最终有哪些收获。职业规划表明自己决心,首先自己不准备继续求学了,必须招工作了。希望去哪 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • ***byte(字节)根据长度转成kb(千字节)和mb(兆字节)**parambytes*return*publicstaticStringbytes2kb(longbytes){ ... [详细]
  • {moduleinfo:{card_count:[{count_phone:1,count:1}],search_count:[{count_phone:4 ... [详细]
  • Vue基础一、什么是Vue1.1概念Vue(读音vjuː,类似于view)是一套用于构建用户界面的渐进式JavaScript框架,与其它大型框架不 ... [详细]
  • 有意向可以发简历到邮箱内推.简历直达组内Leader.能做同事的话,内推奖励全给你. ... [详细]
  • 抖音服务器带宽有多大,才能供上亿人同时刷?
    最近看到一个有意思的提问:抖音服务器带宽有多大,为什么能够供那么多人同时刷?今天来给大家科普一下。 ... [详细]
  • 腾讯T3大牛亲自教你!2021大厂Android面试经验,经典好文
    本篇将由环境搭建、实现原理、编程开发、插件开发、编译运行、性能稳定、发展未来等七个方面,对当前的ReactNative和Flutter进行全面的分析对比, ... [详细]
  • Java工程师书单(初级,中级,高级)
    简介怎样学习才能从一名Java初级程序员成长为一名合格的架构师,或者说一名合格的架构师应该有怎样的技术知识体系,这是不仅一个刚刚踏入职场的初级程序员也是工作一两年之后开始迷茫的程序 ... [详细]
  • 小白的Python 学习笔记(八)推导式详解
    大家好,今天我总结一下Python的推导式,首先让我们来看定义推导式(comprehensions)是Python的一种独有特性,是可以从一个数据序列构建另一个新的数据序列的结构体 ... [详细]
author-avatar
农大军乐团_697
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有