火影 发表于 2024-8-21 16:56:30

以FLV解复用为例详解开源库FFmpeg中解复用器的源码逻辑及处置惩罚流程

目录
1、FFmpeg简介
2、FLV文件格式介绍
3、注册解复用器
4、解复用器的处置惩罚
4.1、AVFormatContext
4.1.1、AVClass
4.1.2、AVOption
4.1.3    AVDictionary—AV字典
4.1.4、AVIOContext
4.1.4.1、URLProtocol
4.1.4.2、AVIOContext的初始化及获取
4.1.5、AVInputFormat
4.1.6、AVStream
4.2、解复用器的获取
4.3、Flv解复用器处置惩罚流程分析
4.3.1、读取头信息--flv_read_header
4.3.2、AVStream的获取--flv_read_packet
5、总结
C++软件异常排查从入门到醒目系列教程(专栏文章列表,接待订阅,连续更新...)https://csdnimg.cn/release/blog_editor_html/release2.3.6/ckeditor/plugins/CsdnLink/icons/icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931C/C++实战专栏(专栏文章已更新400多篇,连续更新中...)https://csdnimg.cn/release/blog_editor_html/release2.3.6/ckeditor/plugins/CsdnLink/icons/icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_11931267.htmlC++ 软件开辟从入门到醒目(专栏文章,连续更新中...)https://csdnimg.cn/release/blog_editor_html/release2.3.6/ckeditor/plugins/CsdnLink/icons/icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_12695902.htmlVC++常用功能开辟汇总(专栏文章列表,接待订阅,连续更新...)https://csdnimg.cn/release/blog_editor_html/release2.3.6/ckeditor/plugins/CsdnLink/icons/icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124272585C++软件分析工具从入门到醒目案例集锦(专栏文章,连续更新中...)https://csdnimg.cn/release/blog_editor_html/release2.3.6/ckeditor/plugins/CsdnLink/icons/icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/131405795开源组件及数据库技能(专栏文章,连续更新中...)https://csdnimg.cn/release/blog_editor_html/release2.3.6/ckeditor/plugins/CsdnLink/icons/icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_12458859.html网络编程与网络问题分享(专栏文章,连续更新中...)https://csdnimg.cn/release/blog_editor_html/release2.3.6/ckeditor/plugins/CsdnLink/icons/icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_2276111.html一样平常音视频编解码器处置惩罚的是原始的裸音视频数据(编码器对原始音视频数据进行编码,解码器从编码后的音视频数据中分析出原始的音视频数据)。flv/avi/mp4等格式文件中包含的是编码后的音视频数据,解复用的目的就是从封装容器中分析出各音频流或视频流等。本文以FLV解复用器分析ffmpeg解复用的处置惩罚逻辑,介绍了ffmeg中解复用器的注册,并以FLV解复用器为例分析解复用器如何从封装格式中,分析出不同的视频、音频、数据流。
1、FFmpeg简介

https://i-blog.csdnimg.cn/direct/34f5b7c9c7724235810e29eae5b2f944.png
FFmpeg是一个开源的多媒体框架,广泛用于处置惩罚音视频处置惩罚范畴。它提供了一套丰富的工具和库,支持广泛的多媒体格式的解码、编码、转码、等功能。支持多种格式的音视频编码和解码,以及音视频的转换、剪辑、过滤、流处置惩罚等功能。
FFmpeg主要特性如下:
   1)音视频编解码


[*]FFmpeg包含了非常先进的音频/视频编解码库libavcodec,其中很多codec都是重新开辟的,以包管高可移植性和编解码质量。
[*]支持险些所有的音视频格式和编解码器,包罗常见的MP4、AVI、MOV、MKV、FLV、MP3、AAC等文件封装格式,以及H.264、H.265、AAC、VP9、AV1等音视频编解码器。
2)音视频处置惩罚


[*]提供了丰富的音视频处置惩罚功能,如去噪、含糊视频、色彩转换、视频旋转、提取帧、缩放视频尺寸等。
[*]可以通过其提供的滤镜库libavfilter对音视频数据进行各种处置惩罚,如缩放、裁剪、添加水印等。
3)流媒体处置惩罚


[*]FFmpeg支持将本地音视频文件转换为流媒体格式,并通过网络进行传输和播放。
[*]完全支持利用HLS和MPEG-DASH打包视频,并可以配置为利用RTMP或其他协议来传输视频。
4)封装与解封装


[*]提供了对各种音视频封装格式的读写支持,如MP4、FLV等。
[*]AVFormat模块封装了Protocol层和Demuxer、Muxer层,使得协议和格式对于开辟者来说是透明的。
5)高效稳定
FFmpeg在音视频处置惩罚方面表现出色,具有高效且稳定的性能,能够处置惩罚大量的音视频数据。
6)开源
FFmpeg采用LGPL或GPL许可证,其开源属性意味着任何人都能修改并利用它。
7)跨平台
FFmpeg可以在多种操纵体系上运行,包罗但不限于Linux、Windows、macOS等,这使其具有非常广泛的适用性。
8)社区支持
作为一个开源项目,FFmpeg拥有活泼的社区,用户可以从社区获得帮助和最新的开辟动态。
险些所有的视频播放器都利用到了FFmpeg的音视频解码功能,好比国内知名的暴风影音、QQ影音、腾讯视频、爱奇艺视频、优酷视频等。
FFmpeg内部支持多种音视频格式之间的相互转换,很多音视频转化软件都用到了FFmpeg的音视频转换功能,好比大家常用的格式工厂、暴风转码(暴风影音自带的工具)、QQ音影自带的视频格式转换工具、狸窝视频转换器、迅捷视频转换器等。    
2、FLV文件格式介绍

FLV视频格式是Adobe公司设计开辟的一种流媒体的封装格式,总体上看,FLV包罗文件头(Flv Header)和文件体(Flv Body)两部门,其中文件体由一系列的Tag及Tag Size对构成。Tag又可以分成三类:audio,video,script,分别代表音频流,视频流,脚本流(关键字大概文件信息之类)。
header部门记载了flv的类型、版本等信息,是flv的开头,一样平常都差不多,占9bytes。具体格式如下:
https://img-blog.csdnimg.cn/direct/6681b7d9602a410892f5874a3bcaeb31.png
body部门由一个个Tag构成,每个Tag的下面有一块4bytes的空间,用来记载这个tag的长度,这个后置用于逆向读取处置惩罚。 每个Tag由也是由两部门构成的:Tag Header和Tag Data。Tag Header里存放的是当前Tag的类型、数据区(Tag Data)长度等信息,具体如下:
https://img-blog.csdnimg.cn/direct/d5a4133059c44ee5905f8b6944e59002.png
3、注册解复用器

调用av_register_all()接口注册所有格式的编解码器和复用/解复用器、硬件加速器、分析等。调用关系图如下:
https://img-blog.csdnimg.cn/direct/18174deba5744336ba7d7049ed8e6aad.png
所有的注册逻辑都是相同的,注册解复用也一样,其链表头为first_iformat:
Ffmpeg/libavformat/allformats.c
https://img-blog.csdnimg.cn/direct/68d37a89f4904c3eb030046184f01d19.png
 真正实现注册解复用器的函数是av_register_input_format(),如下:
Ffmpeg/libavformat/formats.c
https://img-blog.csdnimg.cn/direct/943ec74e22b54997bdb69804e16e5a53.png
由此可以看出,所有解复用器按注册的先后次序以链表布局存储起来,链表头为first_iformat。以注册flv、avi为例:
https://img-blog.csdnimg.cn/direct/d27e0673c0c3494e96f03fac1f198701.png
First_iformat是AVInputFormat*类型指针,指向第一个注册的flv解复用器ff_flv_demuxer,flv解复用器对象的next变量(AVInputFormat*类型)指向avi解复用器对象ff_avi_demuxer,依次向后。
需要留意的是,ff_flv_demuxer、ff_avi_demuxer都是按AVInputFormat布局定义好的解复用器对象,以flv为例:
Flv解复用:Ffmpeg/libavformat/flvdec.c
https://img-blog.csdnimg.cn/direct/2fca96691d9048c1803c1b41e10de774.png
通过上面的分析,向ffmpeg注册新的解码器的步调如下:
   1)在/libavformat下,创建源文件,在该源文件中按AVInputFormat类型接口定义该算法处置惩罚。
2)调用REGISTER_DEMUXER宏,注册该解码器。
       在这里,给大家重点保举一下我的几个热门畅销专栏,接待订阅:(博客主页另有其他专栏,可以去查看)
专栏1:(该佳构技能专栏的订阅量已达到510多个,专栏中包含大量项目实战分析案例,有很强的实战参考价值,广受好评!专栏文章连续更新中,预计更新到200篇以上!接待订阅!)
C++软件调试与异常排查从入门到醒目系列文章汇总https://csdnimg.cn/release/blog_editor_html/release2.3.6/ckeditor/plugins/CsdnLink/icons/icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931
   本专栏根据多年C++软件异常排查的项目实践,体系地总结了引发C++软件异常的常见缘故原由以及排查C++软件异常的常用思路与方法,具体讲述了C++软件的调试方法与本领,以图文并茂的方式给出具体的项目问题实战分析实例(很有实战参考价值),带领大家逐步掌握C++软件调试与异常排查的相关技能,得当底子进阶和想做技能提升的相关C++开辟人员!
考察一个开辟人员的程度,一是看其编码及设计能力,二是要看其软件调试能力!所以软件调试能力(排查软件异常的能力)很重要,必须重视起来!能解决一样平常人解决不了的问题,既能提升个人能力及价值,也能表现对团队及公司的贡献!
专栏中的文章都是通过项目实战总结出来的,包含大量项目问题实战分析案例,有很强的实战参考价值!专栏文章还在连续更新中,预计文章篇数能更新到200篇以上!
专栏2:  
C++常用软件分析工具从入门到醒目案例集锦汇总(专栏文章,连续更新中...)https://csdnimg.cn/release/blog_editor_html/release2.3.6/ckeditor/plugins/CsdnLink/icons/icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/131405795
   常用的C++软件辅助分析工具有SPY++、PE工具、Dependency Walker、GDIView、Process Explorer、Process Monitor、API Monitor、Clumsy、Windbg、IDA Pro等,本专栏具体介绍如何利用这些工具去巧妙地分析和解决一样平常工作中遇到的问题,很有实战参考价值!
专栏3:(本专栏涵盖了C++多方面的内容,是当前重点打造的专栏,专栏文章已经更新到400多篇,连续更新中...)
C/C++实战进阶(专栏文章,连续更新中...)https://csdnimg.cn/release/blog_editor_html/release2.3.6/ckeditor/plugins/CsdnLink/icons/icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_11931267.html
   以多年的开辟实战为底子,总结并讲解一些的C/C++底子与项目实战进阶内容,以图文并茂的方式对相关知识点进行具体地展开与阐述!专栏涉及了C/C++范畴多个方面的内容,包罗C++底子及编程要点(模版泛型编程、STL容器及算法函数的利用等)、C++11及以上新特性(不仅看开源代码会用到,一样平常编码中也会用到部门新特性,面试时也会涉及到)、常用C++开源库的介绍与利用、代码分享(调用体系API、利用开源库)、常用编程技能(动态库、多线程、多历程、数据库及网络编程等)、软件UI编程(Win32/duilib/QT/MFC)、C++软件调试技能(排查软件异常的本领与方法、分析C++软件异常的底子知识、常用软件分析工具利用、实战问题分析案例等)、设计模式、网络底子知识与网络问题分析进阶内容等。
专栏4:   
VC++常用功能开辟汇总(专栏文章,连续更新中...)https://csdnimg.cn/release/blog_editor_html/release2.3.6/ckeditor/plugins/CsdnLink/icons/icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124272585
   将10多年C++开辟实践中常用的功能,以高质量的代码展现出来。这些常用的高质量规范代码,可以直接拿到项目中利用,能有用地解决软件开辟过程中遇到的问题。
专栏5: 
C++ 软件开辟从入门到醒目(专栏文章,连续更新中...)https://csdnimg.cn/release/blog_editor_html/release2.3.6/ckeditor/plugins/CsdnLink/icons/icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_12695902.html
   根据多年C++软件开辟实践,具体地总结了C/C++软件开辟相关技能实现细节,分享了大量的实战案例,很有实战参考价值。
4、解复用器的处置惩罚

解复用器处置惩罚过程中,涉及到多少布局体类型,这里先介绍下。
4.1、AVFormatContext

媒体封装上下文,包含如下成员,下面我们分析这几个布局体类型:
https://img-blog.csdnimg.cn/direct/ffbc63de978b4ff8b70156478ebb412c.png
4.1.1、AVClass

AVClass是一个成员管理体系,记载了其关联类的类名、并通过其AVOption对象设置关联类的成员变量等,AVFormatContext、AVIOContext、AVCodecContext等都有其对应的AVClass成员管理对象AVFormatContext对象调用avformat_get_context_defaults()接口初始化默认值时,将其av_class对象指向全局的AVClass对象av_format_context_class, av_format_context_class的AVOption成员option指向全局的avformat_options数组,这里列出一部门如下:
/ffmpeg/libavformat/options.c
https://img-blog.csdnimg.cn/direct/dbede7d3ef3840a6b64924b401ce56e8.png
 /ffmpeg/libavformat/options_table.h
https://img-blog.csdnimg.cn/direct/1a49aedb6d794d568a3946dac26dcea8.png
AVFormatContext、AVClass与AVOption之间的关系如下:
https://img-blog.csdnimg.cn/direct/64cc3ae843fc4d05a3e060a6cc134202.png
图中AVFormatContext布局体的第一个变量为AVClass类型的指针av_class,它在AVFormatContext布局体初始化的时间,被赋值指向了全局静态变量av_format_context_class布局体(定义位于libavformat\options.c)。而AVClass类型的av_format_context_class布局体中的option变量指向了全局静态数组avformat_options(定义位于libavformat\options_table.h)。
Ps:应该也可以自定义一个AVClass及AVOption对象,赋给AVFormatContext。
4.1.2、AVOption

AVClass中存储了AVOption类型的option数组,用于存储AVClass关联类的成员变量信息,每一个成员变量对应一个AVOption。可以利用av_opt_set()函数通过字符串的方式(传入参数为变量名称的字符串和变量值的字符串)设置AVOption的值。
/ffmpeg/libavutil/opt.c
https://img-blog.csdnimg.cn/direct/bab35ae7ebe9484595666634fd4dbeb7.png
该函数首先通过av_opt_find2()在**(AVClass**)obj中查找到与name匹配的AVOption对象o,然后根据该对象的类型o->type调用相应的类型设置函数(如set_string_bool、set_string、set_string_image_size等),将字符串val转换为相应type的数据并对该AVOption对象o进行赋值。
Ps: av_opt_get通过字符串获取变量值:
https://img-blog.csdnimg.cn/direct/c8150f38b1f2432fa06bb43b5204795b.png
4.1.3    AVDictionary—AV字典

AVDictionary键值对类型,布局体定义如下:
/ffmpeg/libavutil/dict.c
https://img-blog.csdnimg.cn/direct/7586150476c2465b820e81ead96b28de.png
/ffmpeg/libavutil/dict.h
https://img-blog.csdnimg.cn/direct/d1070260a6884e4f9ab72edcceb5f989.png
这里介绍设置键值和获取键值的两个接口
/ffmpeg/libavutil/dict.h
https://img-blog.csdnimg.cn/direct/b51895fd029647999c0eb459f2835ca7.png
功能:将键值对(key, value)添加到pm中,如果pm为*pm为NULL,将会创建一个新的AVDictionaryEntry对象并将该对象地址赋值给*pm
/ffmpeg/libavutil/dict.h
https://img-blog.csdnimg.cn/direct/b539286cc04741139a36f4004ead4212.png
功能:在m中遍历,获得匹配key值的AVDictionaryEntry对象(即返回值)。
4.1.4、AVIOContext

https://img-blog.csdnimg.cn/direct/cfdf72aea61c43d0988d0f1ad3c9966e.png
协议(文件)操纵的顶层布局是AVIOContext,这个对象实现了带缓冲的读写操纵;FFMPEG的输入对象AVFormat的pb字段指向一个AVIOContext。
AVIOContext的opaque现实指向一个URLContext对象,这个对象封装了协议对象及协议操纵对象,其中prot指向具体的协议操纵对象,priv_data指向具体的协议对象。
URLProtocol为协议操纵对象,针对每种协议,会有一个这样的对象,每个协议操纵对象和一个协议对象关联,好比,文件操纵对象为ff_file_protocol,它关联的布局体是FileContext。
4.1.4.1、URLProtocol

URLProtocol是FFMPEG操纵文件的布局(包罗文件,网络数据流等等),包罗open、close、read、write、seek等操纵。
在在av_register_all()函数中,通过调用REGISTER_PROTOCOL()宏,所有的URLProtocol都保存在以first_protocol为链表头的链表中
/ffmpeg/libavformat/url.h
https://img-blog.csdnimg.cn/direct/8be1aa23cad54be6a883047d87e71293.png
以file文件为例:
https://img-blog.csdnimg.cn/direct/538031fe1db1411d9a09ee89b0fcbe99.png
查看file_open发现, ff_file_protocol操纵的FileContext数据就是URLContext的priv_data
4.1.4.2、AVIOContext的初始化及获取

/ffmpeg/libavformat/aviobuf.c
https://img-blog.csdnimg.cn/direct/a12c7d33603549eab6bc08ee6b709a0a.png
从上图发现,最终实现AVIOContext初始化并获取对文件对象的是ffio_open_whitelist。
4.1.5、AVInputFormat

从前文了解到AVInputFormat现实上就是解复用器布局类型,各类型的解复用器已经在av_register_all()是注册玉成局的链表,表头为first_iformat。以flv为例:
/ffmpeg/libavformat/flvdec.c
https://img-blog.csdnimg.cn/direct/b69e4e45225a4caf9950f85c289255e8.png
   

[*].name:解复用器名称
[*].long_name:对应的文件格式
[*].priv_date_size:该解复用器关联的文件布局体类型
[*].read_probe:检测输入AVProbeData文件名数据与该解复用器的匹配度
[*].read_header:
[*].read_packet:
[*].read_seek:
[*].extensions:后缀名
后边几个函数分别为探测、读取头信息、读取包信息、搜刮、关闭,从这几个函数的源代码可以看出,解复用器处置惩罚的FLVContext数据指针保存在其关联AVFormatContext->priv_data中。
4.1.6、AVStream

AVStream是存储媒体流信息的布局体,其初始化函数avformat_new_stream(),解复用器负责把不同媒体流从容器(媒体文件)中分析出来并保存到不同的AVStream中。
4.2、解复用器的获取

AVInputFormat解复用器对象的获取有两种方法:
1)由文件名获取:/ffmpeg/libavformat/utils.cinit_input()
   https://img-blog.csdnimg.cn/direct/68a7872366b84e53a265c7cb9955e124.png
​Pd中包含了文件名,由文件名检测出对应的解复用器。
av_probe_input_format2调用av_probe_input_format3,在av_probe_input_format3中,遍历所有注册的解复用器fmt1(AVInputFormat),对于每个解复用器fmt1,调用fmt1的检测函数read_probe检测其与文件名的匹配度,如果没有该函数,则通过fmt1的后缀名extensions匹配。
    https://img-blog.csdnimg.cn/direct/3e924d2833f84648b33ac93d7017a03b.png
    https://img-blog.csdnimg.cn/direct/4c26fbcdf2b5427e9c9e113985624bec.png
​2)如果文件名检测不出来,则通过AVIOContext获取:/ffmpeg/libavformat/utils.cinit_input()
    https://img-blog.csdnimg.cn/direct/75decd74e1a146cfbaf0f8915fcd37f9.png
​s->pb为解复用器AVInputFormat对象地点AVFormatContext对象的AVIOContext成员,其获取方法如下:
    https://img-blog.csdnimg.cn/direct/a3af61aebf774f408918e7c4c2c48109.png
在av_probe_input_buffer2函数中,现实上也是通过avio_read接口从s->pb中得到媒体相关的AVProbeData数据,然后再调用av_probe_input_format2接口(即方法一),获得解复用器。需要留意的是:
i)s->io_open在s(AVFormatContext类型)初始化时构建
/ffmpeg/libavformat/options.c
   https://img-blog.csdnimg.cn/direct/ace1bd469eec436e9712e18e450a2744.png
​查看io_open_default发现,该函数调用的是ffio_open_whitelist函数,由3.1.4.2可知正是该函数根据文件名获取了其对应的AVIOContext对象pb。
ii)方法一和方法二固然最终都调用av_probe_input_format2检测,但在该函数中看,方法一、二的参数和处置惩罚流程是不一样的。
   https://img-blog.csdnimg.cn/direct/86d24a868d284efd939828cdd39a9d30.png
​/ffmpeg/libavformat/avformat.h 
    https://img-blog.csdnimg.cn/direct/01e4b571a54b4dccbce715fc11cd7977.png
​方法一中,pd = {filename, NULL, 0} 由于pd->buf = NULL,所以调用fmt1->read_probe是检测不到对应的解复用器的,只能通过pd->filename和fmt1->extensions比较得到效果。
方法二中,pd = {filename, buf, 0} ,其中buf是在av_probe_input_buffer2中调用avio_read获取的。由于pd->buf不为NULL,所以在fmt1->read_probe可检测到其对应的解复用器。
4.3、Flv解复用器处置惩罚流程分析

Flv解复用器按照flv文件格式分析出数据,根据不同的音频、视频数据,创建出对应的AVStream并记载到AVFormatContext中。这里介绍主要的两个函数
4.3.1、读取头信息--flv_read_header

/ffmpeg/libavformat/flvdec.c
   https://img-blog.csdnimg.cn/direct/a8328eed2bec44f4804bd5dcc9c60e11.png
​首先我们要知道s->pb是AVIOContext,该布局体中存在一个读写指针buf_ptr记载当前文件的读写位置。下面我们对每行代码进行分析:
    line632:s->priv_data在avformat_open_input函数中被指向ff_flv_demuxer.priv_class即flv_class(参           看ff_flv_demuxer定义),显然这里flv_class应该是在初始化FLVContext对象时,被赋值给FLVContext成员管理对象的,但是我没有找到FLVContext初始化的地方。
/ffmpeg/libavformat/utils.c
   https://img-blog.csdnimg.cn/direct/64dba3156e5f43cd97684b11228081c5.png
    Line635:跳过4个字节
Line636:读取1个字节,也就是第5个字节,对照FLV文件格式,我们发现改字节记载了流信息
Line640:读取4个字节,获取header长度
Line641:从文件开始,跳过文件头Header,到FLV body部门
Line642:跳过4个字节,这4个字节记载上一个Tag的大小即表中的PreTagSize0
到这里flv_read_header就竣事了,我们发现该函数的作用仅仅是把读写指针buf_ptr指向flv的第一个有用媒体数据部门即Tag0。
需要说明的是,不同媒体格式的处置惩罚都不一样,avi的avi_read_header函数,就实现了AVStream的创建即参数设置,而FLV的AVStream则是在flv_read_packet()中创建的。
4.3.2、AVStream的获取--flv_read_packet

该函数代码较多,这里分析主要代码行
/ffmpeg/libavformat/flvdec.c
   https://img-blog.csdnimg.cn/direct/8a5f804244824cf994697157610e2331.png
    Line850:获取AVIOContext当前读写位置
Line851:读1字节,该字节标识当前tag是音频流(8)/视频流(9)/脚本数据(18)
Line853:3字节,记载数据区长度
Line854:记载已经读取的所有tag总长度
Line855:获取时间戳(3字节)
Line856:获取扩展时间戳(1字节)并和line855行获取的时间戳组合成完整的时间戳
Line860:跳过3个字节(这3个字节为streamid),读写指针指向数据区TagData
    https://img-blog.csdnimg.cn/direct/373d877dcc364074b696f80c9bde6c30.png
    Line886:根据Line851获取的type,判断该tag是否为音频数据
Line888:读1个字节flags,该字节高4位标识音频格式、2-3两位标识采样率,最后两位分别标识位宽和声道
Line890:根据type判断该tag是否为视频数据
Line892:读1字节flags,该字节高4位标识帧类型(I/P/B),低四位标识视频格式
Line896-901:脚本数据,flv_read_metabody函数获取码流宽高等信息,并保持到AVFormatContext
通过以上两段代码的分析,我们发现flv解复用器所做的操纵都是按照flv语法获取数据,很显然其他解复用器也是同样的原理。
   https://img-blog.csdnimg.cn/direct/e7b8eeac94604de7bdaecbe2a3415ff4.png
    Line936-950:遍历已有的AVStream队列,查找和当前tag数据类型相同的AVStream流,显然从tag1开始处置惩罚时,是没有AVStream队列的,应该跳转到Line951行
Line940:根据Line888得到的flags,获取音频解码器id(st->codecpar->codec_id),如AV_CODEC_ID_AAC
Line944:根据Line892得到的flags,获取视频解码器id(st->codecpar->codec_id),如AV_CODEC_ID_H264
Line954:根据Line887/891的stream_type创建并初始化AVStream流。查看create_stream函数发现,该函数就是通过avformat_new_stream创建的AVStream对象。
    https://img-blog.csdnimg.cn/direct/62907558ed82454183ebfe2c03217964.png
    Line1009-1012:根据flags获取音频通道数channels、采样率sample_rate和位宽bits_per_coded_sample
Line1015-1025:更新创建的AVStream流的解码器参数信息
    https://img-blog.csdnimg.cn/direct/c67d580f63eb42208650b59ce55e9460.png
    Line1042:设置AVStream的视频解码器信息
    https://img-blog.csdnimg.cn/direct/5897109ac915461eb028e91779cdbb8c.png
     
Line1112:读取tagData数据到AVPacktet
Line1115:设置解码时间戳dts
Line1116:设置表现时间戳pts
Line1117:设置该AVPacket地点的AVStream队列
flv_read_header()和flv_read_packet()两个函数根本完成了flv媒体的解复用功能,这两个函数分别在avformat_open_input()和avformat_find_stream_info()两个接口中用到,并完成对AVFormatContext和AVStream信息的赋值。
调用avformat_open_input()获取的信息如下:通过之前的分析,我们知道flv_read_header没有获取信息,仅仅是移动了读写指针。
   https://img-blog.csdnimg.cn/direct/8d4aed25fe1e4bd5b09eeb4290ed4b25.png
​调用avformat_find_stream_info()获取的信息如下,该函数中会调用flv_read_packet(),并分析相关数据,可以完整添补AVFormatContext和AVStream信息:
    https://img-blog.csdnimg.cn/direct/6367b7248ba448438062fde7d67459bd.png
​至此,解复用器逻辑分析竣事。
       以上代码截图中的代码查看工具是Source Insight,该工具是轻量级的代码查看与编辑工具,虽不能编译代码,但查看和编辑代码很方便,我们经常利用该工具去查看开源代码。关于如何利用Source Insight工具,可以查看我之前写的文章:
如何利用 Source Insight 查看编辑C/C++源代码?https://csdnimg.cn/release/blog_editor_html/release2.3.6/ckeditor/plugins/CsdnLink/icons/icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124347857
5、总结

简单来讲,解复用器功能就是获取音视频码流所需解码器,在读取包AVPacket后,根据数据包AVPacket地点流AVStream,找到对应的解码器进行解码。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 以FLV解复用为例详解开源库FFmpeg中解复用器的源码逻辑及处置惩罚流程