FLV视频封装格式详细解析

FLV的定义:

Flash Video(简称FLV),是一种流行的网络格式,是Adobe推出的。目前大部分视频网站都支持这种格式。

FLV的文件结构

FLV文件由FLV Header 和 FLV Body构成。

FLV Header 头部信息

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

image

FLV Body 文件内容部分

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

image

FLV Tag

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

image

Tag Data

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

Audio Tag Data

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

image

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编码

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

AudioSpecificConfig

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 Raw frame data

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

AAC头部数据 ADTS

ADTS包括采样频率、帧长度等信息,共7个字节,分为两部分:
adts_fixed_header 、adts_variable_header

adts_fixed_header 排布如下:

adts_fixed_header() {
    syncword                  12bits    always 0xFFF
    ID                        1bit      0--MPEG-4   1--MPEG-2
    layer                     2bits     always '00'
    protection_absent         1bit
    profile                   2bits     0--Main profile     1--Low Complexity profile(LC) 
                                        2--Scalable Sampling Rate profile(SSR) 3--reserved
    sampling_frequency_index  4bits     音频采样率索引值
    private_bit               1bit
    channel_configuration     3bits     音频声道数
    original_copy             1bit
    home                      1bit
}

channel_configuration 对应关系如下:

0 bit : Defined in AOT Specific Config
1 bit : 1 channel:front-center
2 bit : 2 channels:front-left,front-right  
3 bit : 3 channels:front-center,front-left,front-right  
4 bit : 4 channels:front-center,front-left,front-right,back-center
5 bit : 5 channels:front-center,front-left,front-right,back-left,back-right  
6 bit : 6 channels:front-center,front-left,front-right,back-left,back-right,LFE-channel 
7 bit : 8 channels:front-center,front-left,front-right,side-left,side-right,back-left,back-right,LFE-channel 
8-15 bit:Reserved

adts_variable_header排布如下:

adts_variable_header() {
    copyright_identification_bit        1bit
    copyright_identification_start      1bit
    aac_frame_length                    13bits  ADTS头 + AAC原始流     
    adts_buffer_fullness                11bits  0x7FF表示码率可变的码流
    number_of_raw_data_blocks_in_frame  2bits 
}

MP3编码

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

MP3 头部格式如下:

MP3FrameHeader
{
    sync                11bits  同步信息always 0xFFF     
    version             2bits   版本 00--MPEG 2.5  01--未定义 10--MPEG 2  11--MPEG 1    
    layer               2bits   层 00--未定义 01--Layer 3  10--Layer 2  11--Layer 1    
    error_protection    1bit    CRC校验0--校验  1--不校验    
    bitrate_index       4bits   位率 
    sampling_frequency  2bits   采样率索引值   
    padding             1bit    帧长调节    
    private             1bit    保留字    
    mode                2bits   声道模式    
    mode_extension      2bits   扩充模式    
    copyright           1bit    版权     
    original            1bit    原版标志    
    emphasis            2bits   强调模式 
}

sampling_frequency对应关系如下:

version   00--MPEG 2.5    01--未定义  10--MPEG 2    11--MPEG 1 
MPEG 1:   00--44.1kHz     01--48kHz   10--32kHz     11--未定义 
MPEG 2:   00--22.05kHz    01--24kHz   10--16kHz     11--未定义 
MPEG 2.5: 00--11.025kHz   01--12kHz   10--8kHz      11--未定义

mode对应关系如下:

00--立体声Stereo   01--Joint Stereo   10--双声道   11--单声道

Video Tag Data

如果Tag 包中的TagType = 9时,这个Tag就表示video数据。则StreamID之后紧跟着 VideoTagHeader 和 Video Data 数据区。
Video Tag 有一个字节的VideoTagHeader 和 Video数据区部分组成

VideoTagHeader

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

image

Video数据区

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

image

其中,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长度字段所占字节数

Script Tag

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

image

其中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   不定长

类型在FLV的官方文档中有详细的介绍。

onMeteData

onMeteData 是FLV文件中的第一个Tag,是ScriptData中对我们来说十分重要的信息,结构如下:

image

audiocodecid

音频编码类型id,跟AudioTagHeader中的SoundFormat是对应的。

videocodecid

视频编码类型id,跟VideoTagHeader 的 CodecID是对应的

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容