C++音视频

代码改变世界

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

0. 前言

FLV 是 flash video 的缩写,是 Adobe Flash payler 支持的一种流媒体播放格式。flv文件格式的官方文档 Adobe Flash Video File Format Specification Version 10.1 的附录E里。
flv文件格式由flv header和许多tag组成,一个flv文件只有一个flv header,tag 类型分为音频、视频、脚本,共三种类型,tag 由 tag 头和 tag 数据组成。

1. FLV Header

FLV header有 9 个字节,定义如下

字段 类型 描述
Signature UI8 总是'F', 0x46
Signature UI8 总是'L', 0x4C
Signature UI8 总是'V', 0x56
version UI8 文件版本号,总是1
保留字段 UB5 0
TypeFlagsAudio UB1 0-无音频;1-有音频
保留字段 UB1 0
TypeFlagsVideo UB1 0-无视频;1-有视频
DataOffset UI32 flv头的长度,version=1时,总是9

2. FLV File Body

flv 文件体由许多tag挨个存储组成,每个tag的前四个字节表示前一个tag的长度。

2.1 FLV tag 格式

tag 的格式如下

字段 类型 描述
Reserved UB2 保留字段,总是0
Filter UB1 表示包是否被处理过,如加密处理,0-未加密,1-加密
TagType UB5 tag类型,8 - audio,9 - video, 18 - script data
DataSize UI24 消息的长度。从StreamID到标签结束的字节数(等于tag的长度- 11)
Timestamp UI24 数据的时间戳,单位是ms
TimestampExtended UI8 扩展时间戳,这字节与前3字节组成SI32的时间戳,前三位是低24bit值
StreamID UI24 总是0
AudioTagHeader AudioTagHeader 如果TagType==8,接着就是音频tag头,AudioTagHeader定义在2.2.1小节
VideoTagHeader VideoTagHeader 如果TagType==9,接着就是视频tag头,VideoTagHeader定义在后面
EncryptionHeader EncryptionHeader 如果Filter==1,接着就是加密头,EncryptionHeader定义在后面
FilterParams FilterParams 如果Filter==1才有此字段
Data tag的数据,数据格式与TagType的类型有关,if TagType == 8,AUDIODATA; if TagType == 9,VIDEODATA;if TagType == 18,SCRIPTDATA

2.2 AUDIO DATA

音频数据由音频tag头和音频data构成。

2.2.1 音频tag头

音频tag头一个字节或者2个字节

字段 类型 描述
SoundFormat UB4 音频编码格式,定义入下:
0 = Linear PCM, platform endian
1 = ADPCM
2 = MP3
3 = Linear PCM, little endian
4 = Nellymoser 16 kHz mono
5 = Nellymoser 8 kHz mono
6 = Nellymoser
7 = G.711 A-law logarithmic PCM
8 = G.711 mu-law logarithmic PCM
9 = reserved
10 = AAC
11 = Speex
14 = MP3 8 kHz
15 = Device-specific sound
7, 8, 14, 15是保留值
SoundRate UB2 采样率
0 = 5.5 kHz
1 = 11 kHz
2 = 22 kHz
3 = 44 kHz
SoundSize UB1 采样位数
0 = 8-bit
1 = 16-bit
SoundType UB1 声道模式
0 = 单声道
1 = 双声道(立体声)
AACPacketType UI8 AAC包类型,如果SoundFormat = 10 才会有这个字段
0 = AAC sequence header
1 = AAC raw

2.2.2 AAC音频数据

字段 类型 描述
data IF AACPacketType == 0
AudioSpecificConfig
ELSE IF AACPacketType == 1
Raw AAC frame data in UI8 []
AudioSpecificConfig定义在 ISO/IEC 14496-3 2009 中第1.6.2.1小节。请注意,这与来自MP4/F4V文件的esds box的内容不同

ISO/IEC 14496-3 2009确实不好找,但是我还是找到了。https://csclub.uwaterloo.ca/~ehashman/ISO14496-3-2009.pdf,有可能这个地址会失效,也可以点这里下载 ISO-IEC-14496-3-2009.7z

AudioSpecificConfig

AudioSpecificConfig的结构在ISO/IEC 14496-3中描述得好复杂,wiki 的描述简洁一些。

5 bits: object type                  #AudioObjectType
if (object type == 31)
    6 bits + 32: object type
4 bits: frequency index              #samplingFrequencyIndex
if (frequency index == 15)
    24 bits: frequency
4 bits: channel configuration        #channelConfiguration
var bits: AOT Specific Config

AudioObjectType定义在 ISO/IEC 14496-3 的 1.5.1.1 table 1.1

samplingFrequencyIndex对应表

samplingFrequencyIndex
0x0 96000
0x1 88200
0x2 64000
0x3 48000
0x4 44100
0x5 32000
0x6 24000
0x7 22050
0x8 16000
0x9 12000
0xa 11025
0xb 8000
0xc 7350
0xd reseverd
0xe reseverd
0xf escape value

channelConfiguration 定义在 ISO/IEC 14496-3 的 1.6.3.5

以上定义可以查看这里 MPEG-4 Audio wiki

2.3 VIDEO DATA

视频数据由视频tag头和视频data构成。

2.3.1 视频tag头

字段 类型 描述
Frame Type UB4 视频帧类型,定义如下:
1 = 关键帧
2 = 非关键帧(inter frame)
3 = disposable inter frame (H.263 only)
4 = generated key frame (reserved for server use only)
5 = video info/command frame
CodecID UB4 编码格式,定义如下:
2 = H.263
3 = Screen video
4 = On2 VP6
5 = On2 VP6 with alpha channel
6 = Screen video version 2
7 = AVC(H264)
AVCPacketType if CodecID == 7
UI8
0 = AVC sequence header(序列头)
1 = AVC NALU
2 = AVC end of sequence
CompositionTime IF CodecID == 7
SI24
IF AVCPacketType == 1
{Composition time offset}
ELSE
{0}
压缩时间定义在ISO 14496-12, 8.15.3,在FLV中时间偏移单位是ms

2.3.2 AVC视频packet

字段 类型 描述
Data IF AVCPacketType == 0
{AVCDecoderConfigurationRecord}
IF AVCPacketType == 1
如果AVCPacketType为0,data是AVC的编码配置信息,解码器需要使用,AVCDecoderConfigurationRecord定义在ISO/IEC 14496-15 5.2.4.1,此段和MP4/FLV中 avcc box 的内容一样;如果AVCPacketType为1,data是AVC的编码帧

ISO/IEC 14496-15确实不好下载,官方的需要买的,我找了好久找了到2010的第二版,我想第二版比第一版要好吧。我提供 ISO/IEC 14496-15 2010下载。

aligned(8) class AVCDecoderConfigurationRecord {
    unsigned int(8) configurationVersion = 1;
    unsigned int(8) AVCProfileIndication;
    unsigned int(8) profile_compatibility;
    unsigned int(8) AVCLevelIndication;
    bit(6) reserved = ‘111111’b;
    unsigned int(2) lengthSizeMinusOne;
    bit(3) reserved = ‘111’b;
    unsigned int(5) numOfSequenceParameterSets;
    for (i=0; i< numOfSequenceParameterSets; i++) {
        unsigned int(16) sequenceParameterSetLength ;
        bit(8*sequenceParameterSetLength) sequenceParameterSetNALUnit;
    }
    unsigned int(8) numOfPictureParameterSets;
    for (i=0; i< numOfPictureParameterSets; i++) {
        unsigned int(16) pictureParameterSetLength;
        bit(8*pictureParameterSetLength) pictureParameterSetNALUnit;
    }
    if( profile_idc == 100 || profile_idc == 110 ||
        profile_idc == 122 || profile_idc == 144 )
    {
        bit(6) reserved = ‘111111’b;
        unsigned int(2) chroma_format;
        bit(5) reserved = ‘11111’b;
        unsigned int(3) bit_depth_luma_minus8;
        bit(5) reserved = ‘11111’b;
        unsigned int(3) bit_depth_chroma_minus8;
        unsigned int(8) numOfSequenceParameterSetExt;
        for (i=0; i< numOfSequenceParameterSetExt; i++) {
            unsigned int(16) sequenceParameterSetExtLength;
            bit(8*sequenceParameterSetExtLength) sequenceParameterSetExtNALUnit;
        }
    }
}
posted on 2022-02-22 22:09  shunxiang  阅读(758)  评论(0编辑  收藏  举报