音视频 FLV格式解析

格式介绍

概览

FLV是流媒体封装格式,我们可以将其数据看为二进制字节流。

总体上看,FLV包括文件头(File Header)和文件体(File Body)两部分,其中文件体由一系列的Tag及Tag Size对组成。FLV文件格式

  • 用UltraEdit打开FLV文件,如下图
    二进制文件

1. 文件头File Header

FLV header

46 4C 56 01 05 00 00 00 09
头部分由一下几部分组成
Signature(3 Byte)+Version(1 Byte)+Flags(1 Bypte)+DataOffset(4 Byte)

  • signature :占3个字节,固定FLV三个字符作为标示。
    一般发现前三个字符为FLV时就认为他是flv文件。
    图中0x46 0x4C 0x56,代表FLV。
  • Version:占1个字节 标示FLV的版本号。这里我们看到是1。
  • Flags:占1个字节 内容标示。
    第0位和第2位,分别表示 video 与 audio 存在的情况.(1表示存在,0表示不存在)。
    截图看到是0x05,也就是00000101,代表既有视频,也有音频。
  • DataOffset:
    4个字节 表示FLV的header长度。这里可以看到固定是9。

2.文件体File Body

FLV文件格式
FLV的body部分是一系列的back-pointers+tag构成的

  • back-pointers
    固定4个字节,表示前一个tag的size。第一个back-pointers数据为0。

  • tag
    音视频数据,其中tag内部又分为flv_tag_header + video_header/audio_header+data,详见如下Tag详解部分。文件体File Body

3. Tag详解

Tag数据结构

Tag分为:
flv_tag_header + video_header/audio_header+data;
其中flv_tag_header占11个字节,video_header5个字节,audio_header2个字节,剩余为H264数据。

flv_tag_header如下:

长度11个字节,type+tag data size+Timestamp+TimestampExtended+stream id+ tag data

  • type 1个字节。
    Tag分三种类型:
    scripts 0x12 18
    audio 0x08 8
    video 0x09 9

  • tag data size 3个字节。
    表示tag data的长度。从streamd id 后算起。

  • Timestreamp 3个字节。
    时间戳

  • TimestampExtended 1个字节。
    时间戳扩展字段

  • stream id 3个字节。
    总是0

video_header/audio_header

  • video_header,长度5个字节
    4bit Frame Type,帧类型
    4bit CodecID,视频编码类型
    8 bit AVCPacketType,是sequence header(0)还是NALU(1)
    24 bit CompositionTime,如果为NALU 则为时间间隔,否则为0

  • audio_header,长度为2个字节
    4bit 表示音频格式
    第5、6bit 表示采样率
    第7bit 表示采用的长度
    第8bit 表示音频类型
    8 bit AVCPacketType,是AAC sequence header(0)还是 AAC raw(1)

data 数据部分

为H264编码后帧数据

脚本Tag,script tag,18,0x12

脚本Tag一般只有一个,是flv的第一个Tag,用于存放flv的信息,比如duration、audiodatarate、creator、width等。

  • 一般来说,该Tag Data结构包含两个AMF包。
    AMF(Action Message Format)是Adobe设计的一种通用数据封装格式,在Adobe的很多产品中应用,简单来说,AMF将不同类型的数据用统一的格式来描述。

    • 第一个AMF包封装字符串类型数据
      第1个字节表示AMF包类型,一般总是0x02,表示字符串,其他值表示意义请查阅文档。
      第2-3个字节为UI16类型值,表示字符串的长度,一般总是0x000A(“onMetaData”长度)。
      后面字节为字符串数据,一般总为“onMetaData”。

    • 第二个AMF包封装一个数组类型,这个数组中包含了音视频信息项的名称和值。
      第1个字节表示AMF包类型,一般总是0x08,表示数组。
      第2-5个字节为UI32类型值,表示数组元素的个数。
      后面即为各数组元素的封装,数组元素为元素名称和值组成的对。表示方法如下:
      第1-2个字节表示元素名称的长度,假设为L。
      后面跟着为长度为L的字符串。
      第L+3个字节表示元素值的类型。
      后面跟着为对应值,占用字节数取决于值的类型。

  • 脚本的数据类型。
    所有数据都是以数据类型+(数据长度)+数据的格式出现的。
    数据类型占1byte,数据长度看数据类型是否存在,后面才是数据。数据类型

视频Tag,FLV Video Tag,9,0x09

FLV Video Tag
根据Tag Header读取VideoData数据后,videoData的部分分为 视频信息Video_Header+AVC_Video_Header+数据

  • 视频信息,1字节

    • 前4位表示帧类型Frame Type
      视频信息

    • 后4位为编码ID (CodecID)
      CodecID

  • 视频的格式(CodecID)是AVC(H.264)的话,VideoTagHeader会多出4个字节的信息,AVCPacketType和CompositionTime,所以是H264编码的情况下VideoHeader长度是5个字节。

    • AVCPacketType,1个字节
      AVCPacketType

    • AVCDecoderConfigurationRecord
      包含着是H.264解码相关比较重要的sps和pps信息,再给AVC解码器送数据流之前一定要把sps和pps信息送出,否则的话解码器不能正常解码。
      而且在解码器stop之后再次start之前,如seek、快进快退状态切换等,都需要重新送一遍sps和pps的信息。
      AVCDecoderConfigurationRecord在FLV文件中一般情况也是出现1次,也就是第一个video tag.

    • CompositionTime,3个字节
      CompositionTime

  • sps pps
    第一个video 一般存放的是sps和pps。
    存储的格式: 0x01+sps[1]+sps[2]+sps[3]+0xFF+0xE1+sps size+sps+01+pps size+pps
    其中sps size和pps size各占两个字节,所以videoData部分长度是11个字节 + sps.length + pps.length;再加上videoHeader的5个字节。

音频Tag,FLV Audio Tag,8,0x08

FLV Audio Tag
根据Tag Header读取AudioData数据后,AudioData的部分分为 音频信息Audio_Header+AACPacketType+数据

  • 音频信息,1字节

    • 前4位表示音频格式
      音频格式
    • 第5、6位表示采样率
      采样率
    • 第7位表示采用的长度
      采样长度
    • 第8位表示音频类型
      音频类型
  • 其中如果音频格式为10,即是AAC格式的,AudioTagHeader中会多出一个字节AACPacketType,这个字段来表示AACAUDIODATA的类型:0 = AAC sequence header,1 = AAC raw。

    • AAC sequence header也就是包含了AudioSpecificConfig,AudioSpecificConfig包含着一些更加详细音频的信息,AudioSpecificConfig的定义在ISO14496-3中1.6.2.1 AudioSpecificConfig,这里就不详细贴了。而且在ffmpeg中有对AudioSpecificConfig解析的函数,ff_mpeg4audio_get_config(),可以对比的看一下,理解更深刻。
    • AAC raw 这种包含的就是音频ES流了,也就是audio payload.
      image.png

举个例子

拿个flv文件对照着看一看

FLV Header

  • 46 4C 56 01 05 00 00 00 09
    表示FLV Header ,音视频都有

  • 0x 00 00 00 00
    第一个back-pointers(表示前一个tag的size)。他前面没有tag,所以是0。

脚本Tag

12 00 00 B6 00 00 00 00 00 00 00
0x12表示这是一个scripts tag,00 00 B6三个字节表示tag data长度为182个字节,Timestreamp、TimestampExtended、stream id 均为0。
下一个back-pointers,表示该整个tag的size,即182 + 11(tag data前面的长度) = 193 = 0xc1,即 00 00 00 c1,在工具中查找即可。

image.png

  • 02 00 0A 6F 6E 4D 65 65 74 61 44 61 74 61 表示第一个AMF包。
    02表示类型为string type,后面两个字节00 00A 表示长度是10,值onMetaData。

  • 03 00 00 00 08
    03表示ObjectType,此处应该一般是08才对,表示数组类型;表示有8个键值对。
    接下来就是解析键值对了。

  • 解析键值对
    0005表示键长度,77 69 64 74 68表示width,00表示类型为Number,后面8字节表示值。
    0006表示键长度,68 65 69 67 68 74表示height,00表示类型为Number,后面8字节表示值。
    以此类推解析到最后end marker 00 00 09,表示解析完毕。

第一个videoTag,一般包含sps和pps

09 00 00 25 00 00 00 00 00 00 00
09表示视频Tag;
00 00 25表示长度为0x25=37;加上头部长度11,为48,下一个back-pointers是00 00 00 30
Timestreamp、TimestampExtended、stream id均为0;
接下来是数据部分tag data。如下图所示:
image.png

  • 0x17,即0b00010111
    前4位表示帧类型,1表示为关键帧; 后4位表示编码ID,7表示是AVC。
    视频格式是AVC(H.264)类型的话,后面1个字节表示AVCPacketType,再后三个字节表示CompositionTime。

  • 00
    AVCPacketType为0,表示是AVCDecoderConfigurationRecord。就表示包含着sps和pps了。这个东西要第一个发给解码器,要不然不能正常解码。

  • 00 00 00
    CompositionTime为0。接下来就是sps和pps的信息了。

  • 0x01+sps[1]+sps[2]+sps[3]+0xFF+0xE1+sps size+sps+01+pps size+pps,对照着二进制看一下
    sps[1] = 42
    sps[2] = 80
    sps[3] = 20
    sps size = 00 11,表示sps长度为17,17字节的sps数据读取完;读到01
    pps size = 00 04,表示pps长度为4,
    读取完后该tag结束。下一个back-pointers。

第一个audioTag,包含AAC sequence header

08 00 00 04 00 00 00 00 00 00 00
08表示音频;
00 00 04表示长度为4;加上头部长度11,为15,下一个back-pointers是00 00 00 0F
接下来是tag data。如下图所示:
image.png

AF,即0b10101111
前4个字节为1010,十进制10,表示音频格式是AAC;10会多一个字节AACPacketType,表示该AACAUDIODATA的类型。
第5、6位为11,十进制3,表示采样率为44kHz;
第7位为1,表示16位采用;
第8位为1,表示stereo;

00,表示AACPacketType,为0表示该Tag是AAC sequence header。
接下来两个字节表示AudioSpecificConfig,包含更加详细音频的信息。
读取完后该tag结束。下一个back-pointers。

之后的videoTag、videoTag

  • 下一个video
    长度为35525的视频数据,时间戳为23。
    0x17后一位AVCPacketType 01,表示NALU数据。三个CompositionTime字节过后,就是NALU数据了。
    image.png

  • 下一个audio
    长度为1538的音频数据,时间戳为36;
    0xAF后一位AACPacketType为01,表示ACC raw,即音频NALU数据。
    image.png

总结

至此我们把FLV格式梳理了一遍,就能更好理解FLV部分代码了。

参考:
FLV视频封装格式详解
flv格式详解+实例剖析
将h.264视频流封装成flv格式文件
FLV(AAC/AVC)学习笔记

猜你喜欢

转载自blog.csdn.net/u014099894/article/details/108442904