FFmpeg从入门到出家(FLV文件结构解析)
FLV(FLASH VIDEO),是一种常用的文件封装格式,目前国内外大部分视频分享网站都是采用的这种格式。其标准定义为《Adobe Flash Video File Format Specification》。RTMP协议也是基于FLV视频格式的。
FLV的文件格式在该规范中已阐述清楚,本章节不再重复描述,而是结合下面的示例具体阐述如何分析FLV文件。
图3. FLV文件结构示例1
图4. FLV文件结构示例2
FLV文件的分析工具有很多,这里给大家推荐FLV Parser这个小软件,通过它可以很容易的看到文件的组成结构。
3.1 文件结构
从整个文件上看,FLV是由Header和File Body组成,如下图所示:
图5. FLV文件总体结构
1.FLV Header - 长度为9,其结构的标准定义参见标准定义见E.2 The FLV header;
FLV File Body - 由一连串的PreviousTagSize + Tag构成。previousTagSize是4个字节的数据,表示前一个tag的size。标准定义参见E.3 The FLV File Body。
以图3. FLV文件结构示例1为例分析整体结构:
1.位置0x00000000 - 0x00000008, 共9个字节,为FLV Header,其中:
◦0x00000000 - 0x00000002 : 0x46 0x4C 0x56分别表示字符'F''L''V',用来标识这个文件是FLV格式的。在做格式探测的时候,如果发现前3个字节为“FLV”,就认为它是FLV文件;
◦0x00000003 : 0x01, 表示FLV版本号;
◦0x00000004 : 0x05, 转换为2进制是0000 0101,其中第0位为1,表示存在video,第2位为1,表示存在audio;
◦0x00000005 - 0x00000008 : 0x00 0x00 0x00 0x09,转十进制为9,表示FLV header的长度,当FLV 版本号为1时,该值通常为9。
2.位置0x00000009 - ,为FLV File Body:
◦0x00000009 - 0x0000000C : 0x00 0x00 0x00 0x00 PreviousTagSize0,转十进制为0,该值永远为0;
◦0x0000000D - 0x00000209 : 0x12 ... 0x09,共509个字节,为Tag1的具体内容;
◦0x0000020A - 0x0000020D : 0x00 0x00 0x01 0xFD,转十进制为509,表示它前面的Tag,即Tag1的长度为509;
◦0x0000020E - :按照Tag + PreviousTagSize的结构依次递推,此处不再举例说明。
3.2 Tag定义
FLV File Body是由一系列的PreviousTagSize + Tag组成,其中PreviousTagSize的长度为4个字节,用来表示前一个Tag的长度;Tag里面的数据可能是video、audio或者scripts,其定义参见E.4.1 FLV Tag,结构如下:
图6. FLV Tag 结构
以图3. FLV文件结构示例1为例分析Tag结构:
1.位置0x0000020E : 0x08, 二进制为0000 1000,第5位为0, 表示为非加扰文件;低5位01000为8,说明这个Tag包含的数据类型为Audio;
位置0x0000020F - 0x00000211 : 0x00 0x00 0x04,转十进制为4,说明Tag的内容长度为4,与该tag后面的previousTagSize(15) - 11相同;
位置0x00000212 - 0x00000214 : 0x00 0x00 0x00,转十进制为0,说明当前Audio数据的时间戳为0;
位置0x00000215 : 0x00,扩展时间戳为0,如果扩展时间戳不为0,那么该Tag的时间戳应为:Timestamp | TimestampExtended<<24;
位置0x00000216 - 0x00000218 : 0x00 0x00 0x00,StreamID,总是0;
StreamID之后的数据每种格式的情况都不一样,下面会依次进行详细解读。
3.3 Audio Tags
如果TAG包中的TagType等于8,表示该Tag中包含的数据类型为Audio。StreamID之后的数据就是AudioTagHeader,其定义详见E.4.2.1 AUDIODATA。结构如下:
图7. FLV Audio Tag结构
需要说明的是,通常情况下AudioTagHeader之后跟着的就是AUDIODATA数据了,但有个特例,如果音频编码格式为AAC,AudioTagHeader中会多出1个字节的数据AACPacketType,这个字段来表示AACAUDIODATA的类型:
•0 = AAC sequence header
•1 = AAC raw。
以图3. FLV文件结构示例为例分析AudioTag结构:
位置0x00000219 : 0xAF, 二进制表示为1010 1111:
◦高4位为1010,转十进制为10,表示Audio的编码格式为AAC;
◦第3、2位为11,转十进制为3,表示该音频的采样率为44KHZ;
◦第1位为1,表示该音频采样点位宽为16bits;
◦第0位为1,表示该音频为立体声。
位置0x0000021A : 0x00,十进制为0,并且Audio的编码格式为AAC,说明AACAUDIODATA中存放的是AAC sequence header;
位置0x0000021B - 0x0000021C : AUDIODATA数据,即AAC sequence header。
3.3.1 AudioSpecificConfig
AAC sequence header中存放的是AudioSpecificConfig,该结构包含了更加详细的音频信息,《ISO-14496-3 Audio》中的1.6.2.1 章节对此作了详细定义。
通常情况下,AAC sequence header这种Tag在FLV文件中只出现1次,并且是第一个Audio Tag,它存放了解码AAC音频所需要的详细信息。
有关AudioSpecificConfig结构的代码解析,可以参考ffmpeg/libavcodec/mpeg4audio.c中的avpriv_mpeg4audio_get_config方法。
为什么AudioTagHeader中定义了音频的相关参数,我们还需要传递AudioSpecificConfig呢?
因为当SoundFormat为AAC时,SoundType须设置为1(立体声),SoundRate须设置为3(44KHZ),但这并不意味着FLV文件中AAC编码的音频必须是44KHZ的立体声。播放器在播放AAC音频时,应忽略AudioTagHeader中的参数,并根据AudioSpecificConfig来配置正确的解码参数。
3.4 Video Tag
如果TAG包中的TagType等于9,表示该Tag中包含的数据类型为Video。StreamID之后的数据就是VideoTagHeader,其定义详见E.4.3.1 VIDEODATA,结构如下:
图8. FLV Video Tag结构
VideoTagHeader之后跟着的就是VIDEODATA数据了,但是和AAC音频一样,它也存在一个特例,就是当视频编码格式为H.264的时候,VideoTagHeader会多出4个字节的信息,AVCPacketType和CompositionTime。
•AVCPacketType用来表示VIDEODATA的内容
•CompositonTime相对时间戳,如果AVCPacketType=0x01,为相对时间戳,其它均为0;
以图4. FLV文件结构示例2为例分析VideoTagHeader结构:
位置0x0000022C : 0x17, 二进制表示为0001 0111:
◦高4位为0001,转十进制为1,表示当前帧为关键帧;
◦低4位为0111,转十进制为7,说明当前视频的编码格式为AVC。
位置0x0000022D : 0x00,十进制为0,并且Video的编码格式为AVC,说明VideoTagBody中存放的是AVC sequence header;
位置0x0000022E - 0x00000230 : 转十进制为0,表示相对时间戳为0;
位置0x00000231 - 0x0000021C : VIDEODATA数据,即AVC sequence header。
3.4.1 AVCDecoderConfigurationRecord
AVC sequence header中存放的是AVCDecoderConfigurationRecord,《ISO-14496-15 AVC file format》对此作了详细定义。它存放的是AVC的编码参数,解码时需设置给解码器后方可正确解码。
通常情况下,AVC sequence header这种Tag在FLV文件中只出现1次,并且第一个Video Tag。
有关AVCDecoderConfigurationRecord结构的代码解析,可以参考中的ff_isom_write_avcc方法。
3.4.2 CompositionTime(相对时间戳)
相对时间戳的概念需要和PTS、DTS一起理解:
DTS : Decode Time Stamp,解码时间戳,用于告知解码器该视频帧的解码时间;
PTS : Presentation Time Stamp,显示时间戳,用于告知播放器该视频帧的显示时间;
CTS : Composition Time Stamp,相对时间戳,用来表示PTS与DTS的差值。
如果视频里各帧的编码是按输入顺序依次进行的,则解码和显示时间相同,应该是一致的。但在编码后的视频类型中,如果存在B帧,输入顺序和编码顺序并不一致,所以才需要PTS和DTS这两种时间戳。视频帧的解码一定是发生在显示前,所以视频帧的PTS,一定是大于等于DTS的,因此CTS=PTS-DTS。
FLV Video Tag中的TimeStamp,不是PTS,而是DTS,视频帧的PTS需要我们通过DTS + CTS计算得到。
为什么Audio Tag不需要CompositionTime呢?
因为Audio的编码顺序和输入顺序一致,即PTS=DTS,所以它没有CompositionTime的概念。
3.5 Script Data Tags
如果TAG包中的TagType等于18,表示该Tag中包含的数据类型为SCRIPT。
SCRIPTDATA 结构十分复杂,定义了很多格式类型,每个类型对应一种结构,详细可参考E.4.4 Data Tags
onMetaData是SCRIPTDATA中一个非常重要的信息,其结构定义可参考E.5 onMetaData。它通常是FLV文件中的第一个Tag,用来表示当前文件的一些基本信息: 比如视音频的编码类型id、视频的宽和高、文件大小、视频长度、创建日期等。
来自:金山云视频云团队
FFmpeg从入门到出家(FLV文件结构解析)的更多相关文章
- FFmpeg从入门到出家(HEVC在RTMP中的扩展)
由金山云视频云技术团队提供:FFmpeg从入门到出家第三季: 为推进HEVC视频编码格式在直播方案中的落地,经过CDN联盟讨论,并和主流云服务厂商达成一致,规范了HEVC在RTMP/FLV中的扩展,具 ...
- Windows下FFmpeg快速入门
本系列文章导航 Windows下FFmpeg快速入门 ffmpeg参数解释 mencoder和ffmpeg参数详解(Java处理视频) Java 生成视频缩略图(ffmpeg) 使用ffmpeg进行视 ...
- Windows下FFmpeg高速入门
本系列文章导航 Windows下FFmpeg高速入门 ffmpeg參数解释 mencoder和ffmpeg參数具体解释(Java处理视频) Java 生成视频缩略图(ffmpeg) 使用ffmpeg进 ...
- Windows下FFmpeg快速入门 <第二篇>
FFmpeg简介 FFmpeg是什么? FFmpeg是用于录制.转换和流化音频和视频的完整解决方案, 包括 libavcodec ,一套领先的音/视频编解码类库.FFmpeg 在Linux上开发,当可 ...
- 【爬虫入门手记03】爬虫解析利器beautifulSoup模块的基本应用
[爬虫入门手记03]爬虫解析利器beautifulSoup模块的基本应用 1.引言 网络爬虫最终的目的就是过滤选取网络信息,因此最重要的就是解析器了,其性能的优劣直接决定这网络爬虫的速度和效率.Bea ...
- MP3文件结构解析(超详细)
转自:http://blog.csdn.net/u010650845/article/details/53520426 MP3文件结构解析(超详细) 1. MP3文件结构解析 1.1. 概述 1.1. ...
- Shiro官方快速入门10min例子源码解析框架2-Session
Shiro自身维护了一套session管理组件,它可以独立使用,并不单纯依赖WEB/Servlet/EJB容器等环境,使得它的session可以任何应用中使用. 2-Session)主要介绍在quic ...
- labview从入门到出家6(进阶篇)--移位寄存器的使用
前面介绍了如何熟悉和使用Labview自带的库函数以及调试方式,大家后期基本可以凭借这两个方式从入门到出家了,哈哈,后面就靠各位同仁99%的努力了.这篇为啥要讲移位寄存器呢,主要是之前做的项目和经验告 ...
- labview从入门到出家5(进阶篇)--程序调试以及labview函数库的运用
跟了前面几章的操作流程,相信大家对labview有了一定的认识.其实只要了解了labview的编程思路,再熟悉地运用各个变量,函数以及属性,那么我们就可以打开labview的大门了.跟其他编程语言一样 ...
随机推荐
- echart--如何在折线图上添加矩形背景(可以借用bar柱状图的实现效果)
当鼠标滑过,如何在折线图上添加矩形背景图呢? 具体如下: 上面的dataShadow的来源
- docker for windows 中挂载文件到容器
docker for windows版本: 宿主机:windows10 场景: 容器是基于microsoft/donet的webapi 想把宿主机的文件挂载到容器中,比方说:a.txt 命令如下: d ...
- Comet OJ - Contest #7 D 机器学习题 斜率优化 + 未调完
Code: #include <cstdio> #include <algorithm> #include <cstring> #define setIO(s) f ...
- 约数定理(two)
筛约数个数和 理论基础: 1.对n质因数分解,n=p1^k1 * p2^k2 * p3^k3 …… 则n的约数个数为(k1+1)*(k2+1)*(k3+1)…… 2.线性筛素数时,用i和素数pj来筛掉 ...
- OpenCV Machine Learning (C++)
/*M/////////////////////////////////////////////////////////////////////////////////////////// IMPOR ...
- eclipse配置Maven——菜鸟篇
首先解释关于webservice: Web service是一个平台独立的,低耦合的,自包含的.基于可编程的web的应用程序, 可使用开放的XML(标准通用标记语言下的一个子集)标准来描述.发布.发现 ...
- 利用Javascript解决HTML大数据列表引起的网页加载慢/卡死问题。
在一些网页应用中,有时会碰到一个超级巨大的列表,成千上万行,这时大部份浏览器解析起来就非常痛苦了(有可能直接卡死). 也许你们会说可以分页或动态加载啊?但是有可能需求不允许分页,动态加载?网络的延迟也 ...
- MyISAM、InnoDB、Memory这3个常用引擎支持的索引类型
表格对比了MyISAM.InnoDB.Memory这3个常用引擎支持的索引类型: 索引 MyISAM引擎 InnoDB引擎 Memory引擎 B-Tree索引 支持 支持 支持 HASH索引 不支持 ...
- vscode-常用插件介绍(10大插件)
https://www.cnblogs.com/zhaoshujie/p/9834654.html 本文介绍了目前前端开发最受欢迎的开发工具 VSCode 必装的 10 个开发插件,用于大大提高软件开 ...
- python-网络编程requests模块
urllib模块去请求的确比较麻烦,需要不断的encode和decode:而requests模块就比较方便了,它是基于requests模块开发的第三方模块,安装简单只需要 pip install r ...