接着上一篇继续分析Video Tag和Audio Tag相关内容。
Video Tag 视频Tag:
Flv Parse 解析的结果如下:
previous tag1:
十六机制:0x00 00 01 37
十进制:311
因表示了前一个Metadata Tag的长度是311字节,这跟上篇分析结果是一致的;
Video tag header:
十六进制:0x09 00 00 2C 00 00 00 00 00 00 00
Tagtype:
十六进制:0x09
二进制:0000 1001
通过前1-2bit即知道非加密,后面4-8bit10010即十进制为9则为Video Tag类型;
DataSize:
十六进制:0x 00 00 2C
十进制:44
说明这个Video Tag的data字段长度为44字节;
Timestamp:
十六进制:0x 00 00 00
由于是第一个Video Tag该字段一般就是默认为0;
TimeStampExtended:
十六进制:0x 00 00 00
时间戳扩展字段也是默认为0;
Stream ID:
十六进制:0x 00 00 00
无论那种类型的Tag,一般默认为0;
Video Tag Data:
视频头:
在Video tag的Header后面按道理就是视频裸数据了,但是这里我们需要分析下第一个字节,判断视频数据的编码格式等信息,然后才知道视频裸数据是怎么打包进Video Tag的Data字段的,第一个Video Tag的Data部分如图所示:
视频头字段格式:
字段 | 占位 | 含义 |
---|---|---|
Frame type帧类型 | 第一字节1-4bit位 | 十进制1: keyframe (for AVC, a seekable frame)——h264的IDR,关键帧,可重入。该关键帧时进行视频拖动 seek的关键;2: inter frame (for AVC, a non- seekable frame)——h264的普通幀 ,比如P帧,B帧等3: disposable inter frame (H.263 only)4: generated keyframe (reserved for server use only)5: video info/command frame |
Code ID编码ID | 第一字节4-8bit位 | 视频的编码类型:1: JPEG (currently unused) 2: Sorenson H.2633: Screen video4: On2 VP65: On2 VP6 with alpha channel 6: Screen video version 27: AVC也就是说的H264 |
待分析数据第一字节:
十六进制:0x17 我们先分析Video Tag数据部分的第一个字节即视频头
Frame type:
十六进制:0x17
二进制:0001 0111
十进制:1
通过前面1-4bit位发现十进制为1,即认为是key frame;
CodeID:
十六进制:0x17
二进制:0001 0111
十进制:7
说明这个Video的编码格式AVC也就是常说的H264;
特别注意:
分析到这里,我们发现这个Video Tag的承载数据是AVC即H264编码格式的数据,一般情况下Flv承载的数据格式都是这种。那么就需要继续向下面分析后面的Packet Type字段。
Packet Typ数据格式:
字段 | type | Comment |
---|---|---|
AVC packet Type 类型 | 1字节 | 0:AVC序列头1:AVC NALU单元2:AVC序列结束。低级别AVC不需要。 |
CTS CompositionTime 字段 | 3字节 | 如果AVC packet类型是1,則为cts偏移;如果AVC packet为0則为0; |
数据 | 后面部分 | 如果AVC packet类型是0,則是编码器配置,sps,pps;如果AVC packet类型是1,則是nalu单元,可以是多个,具体格式见下面分析; |
对各个字段解释:
CTS:这个字段需要结合PTS和DTS一块来理解,至于还不知道PTS和DTS参考以前的文章,我这里的理解就是编码延时,有更深理解的可以留言交流。
CTS的大小:cts = pts - dts/90,CTS的单位是毫秒,除以90是因为H264的采样率是90KHz,这里是为了将时间戳单位转化为毫秒;
同时H264编码时有编码级别和规范的说法,一般而言profile级别是没有B帧的,这就意味着pts等于dts,那cts直接为0即可;如果是profile main级别,说明有B帧则需要根据公式计算,B帧时双向预测帧,则有编码延时大部分情况不启用这边级别编码方式;
待分析数据第2-5字节:
十六进制:0x00 00 00 00
Avc packet:
十六进制:0x00
十进制:0
通过说明后面承载的数据是H264的序列头也就是编码器配置SPS PPS而不是裸数据Nalu;
CTS:
十六进制:0x00 00 00
十进制:0
由于Av Packet是0,则这里的cts肯定是0,因为不是真正的视频帧所以没有cts的概念;
后面我们会分析Avc Packet是Nalu的数据部分,现在先分析Avc Packet是Avc序列头的数据部分。
AVCDecoderConfigurationRecord部分:
分析完视频数据前五个字节,后面就是Video Tag Data字段对SPS PPS的封装:
待分析数据:
十六机制:0x 01 64 00 28 FF E1
Configuration version:
十六进制:0x01
一般默认固定为0x01;
Avc Profile Indication:
十六进制:0x64
这是提取来自SPS的字段值,表示编码级别,表示的profile high这种级别。
Profile compatibility:
十六进制:0x00
Avc Level Indication:
十六进制:0x28
这是也是提取来自SPS的字段值,表示编码能力,跟分辨率、帧率、码率有关系;
Reserved:
十六进制:0xFF
二进制:0x1111 1111
Length size minus one:
十六进制:0xFF
二进制:0x1111 1111
十进制:3,暂时没用字段;
Reserved:
十六进制:0xE1
二进制:0x1110 0001
Num sequence parmeter sets:
十六进制:0xE1
二进制:0x1110 0001
紧接着的后面只有一个SPS;
接下来就很容易分析了:
0x00 18表示SPS的开始部分,长度为24;
0x67-0xA8 的24个字节就是SPS数据部分;
0x01 表示PPS的个数
0x00 0x04表示PPS的长度
0x68-0xB0 表示PPS的数据部分;
看到这里大家肯定想知道SPS PPS的具体字段,这里就不详细解释了,会在后面的文章详细讲解。作用就是初始化播放器,没有这个值播放器拿不到编码器编码H264数据的参数信息也就没办法进行解码和渲染播放。SPS PPS值很关键,跟首屏秒开、拖动随机播放等功能有密切功能,后面帮大家分析分析。同样为了交叉验证,我用程序将这个flv的音视频裸数据进行了分离,然后用Stream Eye工具分析了其中的SPS PPS,结果如下:
分析到这里,分析了Video Tag的视频编码格式为H264即AVC的AVCDecoderConfigurationRecord数据类型,下面再分析一个NALU类型的Video Tag数据部分:
刚才我们分析的Video Tag1,Data部分承载的SPS PPS 部分,现在我们分析的Video Tag3,中间是音频,先跳过,等下分析。对于Video Tag3也是直接跳过11字节的Tag Header前面已经分析,不再赘述,直接分析Tag Data部分:
待分析数据第一字节:
十六进制:0x17 我们先分析Video Tag数据部分的第一个字节即视频头
Frame type:
十六进制:0x17
二进制:0001 0111
十进制:1
通过前面1-4bit位发现十进制为1,即认为是key frame;
CodeID:
十六进制0x17
二进制:0001 0111
十进制:7
说明这个Video的编码格式AVC也就是常说的H264;
待分析数据第2-5字节:
十六进制:0x00 00 00 00
Avc packet:
十六进制0x00
十进制:0
通过说明后面承载的数据是H264即AVC的NALU单元;
CTS:
十六进制0x00 00 00
十进制:0
由于此AVC的编码级别显示没有B帧,则PTS=DTS,所以这里的CTS一直为0;
NALU Legth:
十六机制:0x00 00 01 EF
十进制:495
表示这个NALU的长度为495字节,同时我们分析这个Video Tag的头中显示长度为504,也就很快发现Data部分就是前面分析的这9个字节,剩余的495则为NALU的真实数据,这就是NALU的裸数据,非常关键。
接下来的0x65-0x29都是NALU的数据,NALU也是有不同的类型,后面文章会详细介绍。
这里0x65就是NALU的类型,二进制为0110 0101,其中红色显示的5bit就是NALU类型,这里是IDR帧类型。
至此我们分析完了Flv的Video Tag部分,基本也分析了H264的Nalu打包方法。
Audio Tag Header部分:
这里基本参考Script Tag的头部分析即可,这里简单说明下:
待分析数据:
十六进制:0x08 00 00 04 00 00 00 00 00 00 00
Tagtype:
十六进制:0x08
二进制:0000 1000
通过前1-2bit即知道非加密,后面4-8bit10010即十进制为8 则Tag类型Audio tag;
DataSize:
十六进制:0x 00 00 04
十进制:4
说明这个Audio Tag的data字段长度为4字节;
Timestamp:
十六进制:0x 00 00 00
第一个Audio Tag该字段一般就是默认为0;
TimeStampExtended:
十六进制:0x 00 00 00
时间戳扩展字段也是默认为0;
Stream ID:
十六进制:0x 00 00 00
默认为0,该字段暂时未启用;
Audio Tag Data部分:
音频头格式:
字段 | 占位 | 含义 |
---|---|---|
SoundFormat音频格式 | 第一字节1-4bit位 | 音频编码:十进制0 = Linear PCM, platform endian1 = ADPCM2 = MP33 = Linear PCM, little endian4 = Nellymoser 16 kHz mono5 = Nellymoser 8 kHz mono6 = Nellymoser7 = G.711 A-law logarithmic PCM , reserved8 = G.711 mu-law logarithmic PCM , reserved 9 = reserved10 = AAC (supported in Flash Player 9,0,115,0 and higher)11 = Speex (supported in Flash Player 10 and higher)14 = MP3 8 kHz , reserved15 = Device-specific sound , reserved 说明:这里面一般就是10和14会用到,对于G711系列其实是不支持的,只是保留位而已; |
SoundRate音频采样率 | 第一字节5-6bit位 | 采样率:0 = 5.5kHz1 = 11kHz2 = 22kHz3 = 44kHz注意:这里是不支持48HKz的,对于音频AAC而言,基本就是3即44KHz; |
SoundSize采样位宽 | 第一字节第7bit位 | 采样位宽也就会说采样精度:0 = 8bit samples1= 16bit samples 对于AAC而言就是1即16位表示一个采样点的大小; |
SoundType 音频通道 | 第一字节第8bit位 | 通道个数:0 = Mono,单通道1 = Stereo,双通道对于AAC一般就是双通道; |
AAC Packet Type 音频数据 | 第二字节 | 0 则表示的是AAC sequence header1 则表示的AAC Raw码流可选字段,只有是AAC音频有该字段。 |
我们先分析数据部分第一字节弄清楚音频的编码格式等基本信息:
待分析数据:
十六进制:0xAF
二进制:1010 1111
SoundFormat:
十六进制:0xAF
二进制:1010 1111
通过前4个bit,则表示的A即12,所以音频编码为AAC;
SoundRate:
十六进制:0xAF
二进制:1010 1111
说明AAC采样频率用的44KHz
SoundSize:
十六进制:0xAF
二进制:1010 1111
说明AAC采样精度是16bit即2字节;
SoundType:
十六进制:0xAF
二进制:1010 1111
说明AAC的声道数是2;
其实对于AAC音频来说,一般Audio Tag的音频头字段都是0xAF,这里变化不大。由于是AAC,接
下来需要继续分析一个字节。
AAC Packet Type:
待分析数据:
十六机制数据:0x00
AAC Packet Type:
十六进制:0x00
十进制:0
这里为0则说明下面的真实数据是AAC Sequence Header,这个字段有点类似H264的编码配置SPS或者PPS,一般只在整个Flv文件出现一次。
那么下面分析AAC Sequence Header字段,这个值需要解析AAC的裸数据得到,同时它起到的作用和AAC的ADTS一样,但是这里并不是ADTS,可以认为是AAC裸数据的另外一种封装格式。
AAC Sequence Header:
这个字段也被称为是AudioSpecificConfig,AudioSpecificConfig包含着一些更加详细的音频信息,它的定义在ISO14496-3中1.6.2.1。
格式如下:
字段 | 占位 | 含义 |
---|---|---|
AAC Profile编码级别 | 第一字节1-5bit | 编码级别:AAC Main 0x01AAC LC 0x02AAC SSR 0x03 |
AAC Sample Frequence采样率 | 第一字节6-8bit第二字节1-1bit | 0x00 960000x01 882000x02 640000x03 480000x04 441000x05 320000x06 240000x07 220500x08 160000x09 120000x0A 110250x0B 80000x0C reserved0x0D reserved0x0E reserved0x0F escape value |
AAC Channel config通道数 | 第二字节2-5bit | 0x00 - defined in audioDecderSpecificConfig0x01 单声道(center front speaker)0x02 双声道(left, right front speakers)0x03 三声道(center, left, right front speakers)0x04 四声道(center, left, right front speakers, rear surround speakers)0x05 五声道(center, left, right front speakers, left surround, right surround rear speakers)0x06 5.1声道(center, left, right front speakers, left surround, right surround rear speakers, front low frequency effects speaker)0x07 7.1声道(center, left, right center front speakers, left, right outside front speakers, left surround, right surround rear speakers, front low frequency effects speaker)0x08-0x0F - reserved |
AAC Reserve | 第二字节6-8bit | 保留位 |
待分析数据:
十六机制数据:0x12 10
二进制数据:0001 0010 0001 0000
AAC Profile:
十六进制:0x12
二进制:0001 0010
十进制:2
这里为2,则说明编码方式是AAC LC
AAC Sample Frequence:
十六进制:0x12 0x10
二进制:0001 0010 0001 0000
十进制:4
这里为4,则说明采样频率是44KHz,对于AAC基本都是这个值;
AAC Channel Config:
十六进制:0x12 0x10
二进制:0001 0010 0001 0000
十进制:4
这里为2,则说明AAC的音频通道是2;
AAC Reserve:
十六进制:0x12 0x10
二进制:0001 0010 0001 0000
这里三个bit保留位都是0;
综上所述,对于音频编码格式是AAC的,则第一个Audio Tag基本是四字节的固定值:
0xAF 00 12 10,这可以作为判断音频为AAC的快速方法。当然有时会有点出入。
我们分析了Audio的第一个Tag值为AudioSpecificConfig类型的,再分析一个是裸数据的Tag Data字段如下图:
说明:
1. 第一部分红框11字节还是Audio Tag的Header字段,上面已经分析不再赘述;
2. 第二部分承载数据的蓝框1字节是音频编码类型等信息,前面分析AAC Sequence Header已经分析了,一般只有一路音频,所以该字段固定不再变化;
3. 绿框决定了该Audi Tag的数据部分是AAC Sequence Header还是 AAC Raw Data,这里值为0x01,则说明该Audio承载的AAC Raw裸数据;
4. 后面的粉框9字节即为AAC Raw Data,关于AAC的编码方式和裸数据含义以后再讲。
FLV总结:
这篇文章首先讲解了Flv的基本概念、目前现状以及在直播方案中的应用。后面在我本地通过Flv Parse专门分析了Flv文件的封装格式。其中Audio Tag和Video Tag已经分析到AAC和H264的数据帧如何封装到Tag的Data字段,基本按照分析的方法就能很简单的将Flv里面的音频和视频裸数据提取出来,当然也能将H264和AAC数据打包封装成Flv。
下面说解装的操作步骤:
1. 分析Flv的头字段,一般9字节作为开头,主要是根据头字段判断是不是FLV格式,其次判断是否有音视频。因为Flv只封装视频,没有音频是可以传输和播放的,这个我在本地做了实验,VLC是可以播放的,甚至没有Script Tag也是可以的;
2. 接着分析第一个Tag,一般是Script Tag。这个Tag前面是11字节的Tag Header头数据,后面AMF0和AMF1包,严格按照这两个包的定义分析即可,上文已经详细说明;
3. 分析视频的第一个Video Tag,还是11字节的Tag Header头,紧接着分析Data的第一字节,分析帧类型和编码方式。帧类型能找出关键帧,这是很多特殊操作的关键。
4. 如果3分析出来的编码方式不是AVC即H264,那么直接走5.如果是AVC,则继续分析下一个字节AVC packet类型,一般不是AVC的编码配置就是NALU字段。第一个是AVC的编码配置,则提取出SPS PPS等信息,如果是NALU则根据NALU的类型分析出裸码流;
5. 直接按照指定的编码方式分析裸数据即可;
6. 分析第一个音频Video Tag,同样分析Tag Data字段的第一字节分析音频编码方式和基本信息,如果不是AAC则直接走7;如果是再分析第二字节,判断AAC的Packet类型是AAC Sequence Header还是AAV Law裸数据。是AAC Sequence Header就进一步分析AAC相关信息,如果裸数据,则解析出AAC音频帧即可;
7. 分析AAC Sequence Header即可,参考上文;
8. 后面交替分析Video Tag和Audio Tag的裸数据即可,直到分析结束;
封装步骤跟解装步骤相反即可;
今天就说这么多,祝您心情愉快,工作顺利!
如果有疑问,你可以在公众号后台发消息咨询我。
参考文章:
flv.js相关:
https://mp.weixin.qq.com/s/M97Krog9VS2C2QqSld9o9w
分析工具下载:
https://github.com/ty6815/AvStackDocs