43.FFmpeg学习笔记 - flv格式解析

一、flv文件结构

flv文件由flv header 和flv body组成。

二、flv header

Header 部分记录了FLV的类型、版本、流信息、Header 长度等。一般整个Header占用9个字节,大于9个字节则表示头部信息在这基础之上还存在扩展数据。Header 的头部信息排布如下所示:

三、flv body

Body 是由一个个Tag组成的,每个Tag下面有一块4个字节的空间,用来记录这个Tag 的长度。这个后置的PreviousTagSize用于逆向读取处理,表示的是前面的Tag的大小,对于FLV版本0x01来说,数值等于 11 + Tag的DataSize(tag header总是11个字节)。其结构排布如下:

1.tag

每个Tag 也是由两部分组成的:Tag Header 和 Tag Data。Tag Header 存放了当前Tag的类型,数据长度、时间戳、时间戳扩展、StreamsID等信息,然后再接着数据区Tag Data。

2.tag header

tag header的排布如下:

3.tag data

Tag Data分成 Audio,Video,Script 三种。

1)Audio Tag Data

音频的Tag Data又分为 Audio Tag Header 和 Data 数据区,其排布结构如下图所示:

AudioTagHeader通常占用1个字节,AAC编码则会多出一个AACPacketType的字节,用于表示AAC的序列头还是裸数据。
其中,前4bits表示SoundFormat,其数值对应声音格式,如下:
0 - Linear PCM, platform endian
1 - ADPCM
2 - MP3
3 - LinearPCM,little endian
4 - Nellymoser 16-kHz mono
5 - Nellymoser 8-kHZ mono
6 - Nellymoser
7 - G.711 A-law logarithmic PCM
8 - G.711 U-law logarithmic PCM
9 - reserved
10 - AAC
11 - Speex
14 - MP3 8-kHz
15 - Device-specific sound

第5、6bit 表示SoundRate,数值对应采样率,对于AAC来说,总是3:
0 - 5.5kHz
1 - 11kHz
2 - 22kHz
3 - 44kHz

第7bit 表示采样大小:
0 - snd 8 bit
1 - snd 16 bit

第8bit 表示音频声道数,对于AAC来说,总是1:
0 - sndMono
1 - sndStereo

audio Data数据区,根据SoundFormat的数值来确定,如果SoundFormat = 10,则Data数据区是AAC编码部分,其他声音类型,则根据具体格式进行解析。

针对AAC编码,音频Data数据区的定义如下:
AACPacketType = 0 时,表示AAC序列头,也就是AudioSpecificConfig, AACPacketType = 1 时,表示AAC的裸流,也就是AAC Raw frame data。

AudioSpecificConfig 只出现在第一个Audio Tag中,结构如下:

AudioSpecificConfig() {     
    audioObjectType;                              5bits
    samplingFrequencyIndex;                 4bits
    if  ( samplingFrequencyIndex == 0xf ) {
        samplingFrequency;                         24bits
    }
    channelConfiguration;                           4bits
    sbrPresentFlag = -1;
    if  ( audioObjectType == 5 ) {
        extensionAudioObjectType = audioObjectType;
        sbrPresentFlag = 1;
        extensionSamplingFrequencyIndex;            4bits
        if ( extensionSamplingFrequencyIndex == 0xf )  {
            extensionSamplingFrequency;             24bits
        }
        audioObjectType;                            5bits
    } else {
         extensionAudioObjectType = 0;
    }
    
    if ( audioObjectType == 1 || audioObjectType == 2 ||
         audioObjectType == 3 || audioObjectType == 4 ||
         audioObjectType == 6 || audioObjectType == 7 ) {
        GASpecificConfig();
    }
    if ( audioObjectType == 8 )  {
        CelpSpecificConfig();
    }
    if ( audioObjectType == 9 ) {
        HvxcSpecificConfig();
    }
    if ( audioObjectType == 12 ) {
        TTSSpecificConfig();
    }
    if ( audioObjectType == 13 || audioObjectType == 14 ||
        audioObjectType == 15 || audioObjectType == 16 ) {
        StructureAudioSpecificConfig();
    }
    if ( audioObjectType == 17 || audioObjectType == 19 ||
        audioObjectType == 20 || audioObjectType == 21 ||
        audioObjectType == 22 || audioObjectType == 23 ) {
        GASpecificConfig();
    }
    if ( audioObjectType == 24 ) {
        ErrorResilientCelpSpecificConfig();
    }
    if ( audioObjectType == 25 ) {
        ErrorResilientHvxcSpecificConfig();
    }
    if ( audioObjectType == 26 || audioObjectType == 27 ) {
        ParametricSpecificConfig();
    }
    if ( audioObjectType == 17 || audioObjectType == 19 ||
        audioObjectType == 20 || audioObjectType == 21 ||
        audioObjectType == 22 || audioObjectType == 23 ||
        audioObjectType == 24 || audioObjectType == 25 ||
        audioObjectType == 26 || audioObjectType == 27 )  {
        epConfig;                                      2bits
        if ( epConfig == 2 || epConfig == 3 ) {
            ErrorProtectionSpecificConfig();
        }
        if ( epConfig == 3 ) {
            directMapping;                               1bit
            if ( ! directMapping ) {
              /* tbd */
            }
        }
    }
    if ( audioObjectType == 28 ) {
        SSCSpecificConfig();
    }
    if ( extensionAudioObjectType != 5 && bits_to_decode() >= 16 ) { 
        syncExtensionType;                                          11bits
        if ( syncExtensionType == 0x2b7 ) {
            extensionAudioObjectType;                                 5bits
            if ( extensionAudioObjectType == 5 ) {
                sbrPresentFlag;                                        1bit
                if ( sbrPresentFlag == 1 ) {
                    extensionSamplingFrequencyIndex;                     4bits
                    if ( extensionSamplingFrequencyIndex == 0xf ) {
                        extensionSamplingFrequency;                      24bits
                    }
                }
            }
        }
    }
}

AudioSpecificConfig 简化格式如下:

audioObjectType               5bits    编码结构类型,AAC-LC为2
samplingFreguencyIndex        4bits    音频采样率索引值
channelConfiguration          4bits    音频声道数
GASpecificConfig
    frameLengthFlag           1bits    标志位,用于表明IMDCT窗口长度,为0
    dependsOnCoreCoder        1bits    标志位,用于表明是否依赖corecoder,为0
    extensionFlag             1bits    扩展标志位,选择了AAC-LC,这里必须为0

其中,samplingFreguencyIndex 对应关系如下:

0 - 96000
1 - 88200
2 - 64000
3 - 48000
4 - 44100
5 - 32000
6 - 24000
7 - 22050
8 - 16000
9 - 12000
10 - 11025
11 - 8000
12 - 7350
13 - Reserved
14 - Reserved
15 - frequency is written explictly

AAC裸流AAC Raw frame data,即AAC音频原始数据,不包括AAC头数据ADTS。

如果是MP3 编码部分,audio 数据区直接为 MP3 头 + MP3 原始数据。

2)Video Tag Data

Video Tag 由一个字节的Video Tag Header 和 Video数据区部分组成。

Video Tag Header

Video Tag Header通常由一个字节构成,前4bit表示类型,后4bit表示编码器Id。

Video Tag Data

Video数据区部分格式不确定。对于H264/AVC编码部分,Video数据区排布如下:

其中,AVCsequenceheader只有出现在第一个Video Tag,只有一个。为了能够从FLV中获取NALU,必须知道前面的NALU长度所占的字节数,通常是1、2、4个字节,这个内容则必须从AVCDecoderConfigurationRecord中获取,这个遵从标准ISO/IEC 14496-15的5.2.4小节。AVCDecoderConfigurationRecord 的结构如下:

aligned(8) class AVCDecoderConfigurationRecord {
    unsigned int(8) configurationVersion = 1;  //版本号
    unsigned int(8) AVCProfileIndication;     //sps[1],即0x67后面那个字节
    unsigned int(8) profile_compatibility;     //sps[2]
    unsigned int(8) AVCLevelIndication;      //sps[3]
    bit(6) reserved = '111111'b;
    unsigned int(2) lengthSizeMinusOne;     //NALUnitLength的长度减1,一般为3  
    bit(3) reserved = '111'b;
    unsigned int(5) numOfSequenceParameterSets;    //sps个数,一般为1
    for ( i=0; i<numOfSequenceParameterSets; i++ ) {
        unsigned int(16) sequenceParameterSetLength;  //sps的长度      
        bit(8*sequenceParameterSetLength) sequenceParameterSetNALUnit;
    }
    unsigned int(8) numOfPictureParameterSets;      //pps个数,一般为1
    for ( i=0; i<numOfPictureParameterSets; i++) {
        unsigned int(16) pictureParameterSetLength;   //pps长度   
        bit(8*pictureParameterSetLength) pictureParameterSetNALUnit;
   }
}

其中,lengthSizeMinusOne + 1 = NALU长度字段所占字节数。

3)Script Tag Data

当TagType = 0x12时, 这个Tag就是Script tag。Script Tag一般只有一个,是FLV文件的第一个Tag,用于存放FLV文件信息,比如时长、分辨率、音频采样率等。所有的数据都是以数据类型 + (数据长度) + 数据格式出现,数据类型占1个字节,数据长度看数据类型是否存在,后面才是数据。数据排布如下:

 

其中SCRIPTDATAOBJECTEND和SCRIPTDATAVARIABLEEND为0x000009,用于标记对象和数组类型的结尾。

SCRIPTDATASTRING结构为:

StringLength    2bytes  
StringData      String 

SCRIPTDATALONGSTRING结构为:

StringLength  4bytes  
StringData    String  

ECMA array type结构为:

ECMAArrayLength   4bytes 
StringLength      2bytes 
StringData        String 
DataType          1byte 
Data              不定长 
SCRIPTDATAVARIABLEEND

Object type结构为:

StringLength  2bytes 
StringData    String 
DataType      1byte  
DataVale      不定长 
SCRIPTDATAOBJECTEND  

Strict array type结构为:

ArrayNum    4bytes 
DataType    byte 
DataValue   不定长

如果类型为String,后面的2bytes为字符串的长度(Long String是4bytes),再后面才是字符串数据;如果是Number类型,后面的8bytes为Double类型的数据;Boolean类型,后面1byte为Bool类型。

知道了这些后再来看看flv中的脚本,一般开头是0x02,表示String类型,后面的2bytes为字符串长度,一般是0x000a(“onMetaData”的长度),再后面就是字符串“onMetaData”。好像flv格式的文件都有onMetaData标记,在运行ActionScript的时候会用到它。后面跟的是0x08,表示ECMA Array类型,这个和Map比较相似,一个键跟着一个值。键都是String类型的,所以开头的0x02被省略了,直接跟着的是字符串的长度,然后是字符串,再是值的类型,也就是上面介绍的那些了。

onMetaData标签中包含的是流的信息,一般的信息包括:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值