FFmpeg 从入门到出家(FLV 文件结构解析) - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
KSClive
V2EX    推广

FFmpeg 从入门到出家(FLV 文件结构解析)

  •  
  •   KSClive 2018-01-08 18:21:51 +08:00 2419 次点击
    这是一个创建于 2835 天前的主题,其中的信息可能已经有所发展或是发生改变。

    金山云多媒体 SDK 团队在移动直播、短视频等项目中遇到了许多 FFmpeg 问题,特设立《 FFmpeg 从入门到出家》系列文稿,希望博君一笑的同时,能让大家对 FFmpeg 有更深入的了解。

    FLV(FLASH VIDEO),是一种常用的文件封装格式,目前国内外大部分视频分享网站都是采用的这种格式。其标准定义为《 Adobe Flash Video File Format Specification 》。RTMP 协议也是基于 FLV 视频格式的。

    FLV 的文件格式在该规范中已阐述清楚,本章节不再重复描述,而是结合下面的示例具体阐述如何分析 FLV 文件。

    FLV 文件的分析工具有很多,这里给大家推荐 FLV Parser 这个小软件,通过它可以很容易的看到文件的组成结构。

    3.1 文件结构

    从整个文件上看,FLV 是由 Header 和 File Body 组成,如下图所示:

    1.FLV Header - 长度为 9,其结构的标准定义参见标准定义见 E.2 The FLV header ;

    1. 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,结构如下:

    以图 3. FLV 文件结构示例 1 为例分析 Tag 结构:

    1.位置 0x0000020E : 0x08, 二进制为 0000 1000,第 5 位为 0, 表示为非加扰文件;低 5 位 01000 为 8,说明这个 Tag 包含的数据类型为 Audio ;

    1. 位置 0x0000020F - 0x00000211 : 0x00 0x00 0x04,转十进制为 4,说明 Tag 的内容长度为 4,与该 tag 后面的 previousTagSize(15) - 11 相同;

    2. 位置 0x00000212 - 0x00000214 : 0x00 0x00 0x00,转十进制为 0,说明当前 Audio 数据的时间戳为 0 ;

    5.位置 0x00000215 : 0x00,扩展时间戳为 0,如果扩展时间戳不为 0,那么该 Tag 的时间戳应为:Timestamp | TimestampExtended<<24 ;

    1. 位置 0x00000216 - 0x00000218 : 0x00 0x00 0x00,StreamID,总是 0 ;

    2. 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 结构:

    1. 位置 0x00000219 : 0xAF, 二进制表示为 1010 1111:

    高 4 位为 1010,转十进制为 10,表示 Audio 的编码格式为 AAC ;

    第 3、2 位为 11,转十进制为 3,表示该音频的采样率为 44KHZ ;

    第 1 位为 1,表示该音频采样点位宽为 16bits ;

    第 0 位为 1,表示该音频为立体声。

    1. 位置 0x0000021A : 0x00,十进制为 0,并且 Audio 的编码格式为 AAC,说明 AACAUDIODATA 中存放的是 AAC sequence header ;

    2. 位置 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 结构:

    1. 位置 0x0000022C : 0x17, 二进制表示为 0001 0111:

    高 4 位为 0001,转十进制为 1,表示当前帧为关键帧;

    低 4 位为 0111,转十进制为 7,说明当前视频的编码格式为 AVC。

    1. 位置 0x0000022D : 0x00,十进制为 0,并且 Video 的编码格式为 AVC,说明 VideoTagBody 中存放的是 AVC sequence header ;

    2. 位置 0x0000022E - 0x00000230 : 转十进制为 0,表示相对时间戳为 0 ;

    3. 位置 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、视频的宽和高、文件大小、视频长度、创建日期等。

    目前尚无回复
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2769 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 23ms UTC 15:07 PVG 23:07 LAX 08:07 JFK 11:07
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86