音视频学习(十三)——flv详解

简介

全称FLASHVIDEO,是一种新的视频格式,主要的特点是文件小、加载速度快。

结构

flv的结构相对简单,可以通过下图来初步了解其组成:

在这里插入图片描述

flv = flv header(9字节) + flv body

flv header = Signature(3字节) + Version(1字节) + Flags(1字节) + DataOffset(4字节)

flv body = PreviousTagSize0 + Tag1 + PreviousTagSize1 + Tag2 + ... + PreviousTagSizeN-1 + TagN

flv header

  • Signature:固定字符(“flv”);
  • Version:flv的版本号;
  • Flags:标识。第0位和第2位分别表示视频和音频,若为0x05,则表示既有音频,也有视频;
  • DataOffset:flv header的长度;

示例:
在这里插入图片描述

flv body

flv body主要由PreviousTagSize和Tag组成,有以下约定:

  • PreviousTagSize0固定为0;
  • tag = tag header + tag data;
  • 若flv的版本为1,则tag header固定为11个字节;
  • PreviousTagSize(除第一个)= 11 + 前一个tag的tag data的大小;

flv tag分为3种类型:

  • vedio tag:存储视频数据;
  • audio tag:存储音频数据;
  • script tag:存储音视频元数据;

flv tag

tag header

字段 大小 含义
TagType 1字节 tag类型。
音频:0x08
视频:0x09
script data:0x12
Datasize 3字节 tag data的大小
Timestamp 3字节 该tag的时间戳
TimestampExtended 1字节 时间戳扩展字节。当24位数值不够时,该字节最高位将时间戳扩展为32位
StreamID 3字节 总为0
TagData 不定 取决于TagType

tag data

video tag data

FrameType + CodecID总共为1个字节。

字段 大小 含义
FrameType 前4位 帧类型
1:key frame (如h264的I帧)
2:inter frame(如h264普通帧)
3:disposable inter frame
4:generated keyframe
5:video info/command frame
CodecID 后四位 编码id
1:JPEG (currently unused)
2:Sorenson H.263
3:Screen video
4:On2 VP6
5:On2 VP6 with alpha channel 6: Screen video version 2
7:AVC
VideoData 不定 视频数据,与CodecID相关。
2:H263VIDEOPACKET
3:SCREENVIDEOPACKET
4:VP6FLVVIDEOPACKET
5:VP6FLVALPHAVIDEOPACKET
6:SCREENV2VIDEOPACKET
7:AVCVIDEOPACKE(h264媒体数据)

AVCVIDEOPACKE

当 CodecID 为 7 时,VideoData 为 AVCVIDEOPACKE,为H.264媒体数据。

AVCVIDEOPACKE 的定义如下:

字段 大小 含义
AVCPacketType 1字节 0:AVC sequence header
1:AVC NALU
2:AVC end of sequence
CompositionTime 3字节 如果AVCPacketType=1,则为时间cts偏移量;否则,为0
Data 不定 1)AVCPacketType=0,则为AVCDecoderConfigurationRecord
2)AVCPacketType=1,则为NALU(一个或多个)
3)AVCPacketType=2,则为空

示例:

在这里插入图片描述

audio tag data

SoundFormat + SoundRate + SoundSize + SoundType = 1字节

字段 大小 含义
SoundFormat 4 bits 音频格式。
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
SoundRate 2 bits 采样率,对AAC来说,永远等于3
0:5.5-kHz
1:11-kHz
2:22-kHz
3:44-kHz
SoundSize 1 bits 采样精度,对于压缩过的音频,永远是16位
0:snd8Bit
1:snd16Bit
SoundType 1 bits 声道类型,对Nellymoser来说,永远是单声道;对AAC来说,永远是双声道;
0:sndMono 单声道
1:sndStereo 双声道
SoundData 不定 如果是AAC,则为 AACAUDIODATA;

AACAUDIODATA

当 SoundFormat 为10时,表示音频采AAC进行编码,此时,SoundData的定义如下:

字段 大小 含义
AACPacketType 1 bits 0:AAC sequence header
1:AAC raw
Data 不定 如果AACPacketType为0,则为AudioSpecificConfig
如果AACPacketType为1,则为AAC帧数据

AudioSpecificConfig

字段 大小 含义
AudioObjectType 5 bits 编码器类型,比如2表示AAC-LC
SamplingFrequencyIndex 4 bits 采样率索引值,比如4表示44100
SamplingFrequencyIndex 4 bits 采样率索引值,比如4表示44100
ChannelConfiguration 4 bits 声道配置,比如2代表双声道,front-left, front-right

示例:

在这里插入图片描述

script tag data

定义

主要用来存放音视频数据的元数据信息(MetaData)。采用AMF(Action Message Format)封装了一系列数据类型,比如字符串、数值、数组等。

字段 大小 含义
Objects SCRIPTDATAOBJECT[] 任意数目的 SCRIPTDATAOBJECT
SCRIPTDATAOBJECTEND 3字节 永远是9,标识着Script Data的结束
SCRIPTDATAOBJECT
字段 大小 含义
ObjectName SCRIPTDATASTRING 对象的名字
ObjectData SCRIPTDATAVALUE 对象的值
SCRIPTDATAVALUE
字段 字段类型 字段含义
Type SCRIPTDATASTRING 变量类型: 0 = Number type 1 = Boolean type 2 = String type 3 = Object type 4 = MovieClip type 5 = Null type 6 = Undefined type 7 = Reference type 8 = ECMA array type 10 = Strict array type 11 = Date type 12 = Long string type
ECMAArrayLength 如果Type为8(数组),则为UI32 数组长度
ScriptDataValue If Type == 0 DOUBLE If Type == 1 UI8 If Type == 2 SCRIPTDATASTRING …(有点长,可以参考规范) 变量的值
ScriptDataValueTerminator 如果Type3,则为SCRIPTDATAOBJECTEND 如果 Type8,则为SCRIPTDATAVARIABLEEND Object、Array的结束符
MetaData

MetaData中包含了音视频相关的元数据,封装在Script Data Tag中,它包含了两个AMF。

第一个AMF:

  • 第1个字节:0x02,表示字符串类型;
  • 第2-3个字节:值为0x000A,表示字符串的长度为10(MetaData的长度);
  • 第4-13个字节:字符串MetaData对应的16进制数字(0x6F 0x6E 0x4D 0x65 0x74 0x61 0x44 0x61 0x74 0x61);

第二个AMF:

  • 第1个字节:0x08,表示数组类型;
  • 第2-5个字节:表示数组的长度,onMetaData中具体包含哪些属性是不固定的。
  • 第6个字节+:比如duration,则:
    • 第6-9个字节:0x0008,表示长度为8个字节;
    • 第10-17个字节:0x6475 7261 7469,表示 duration 这个字符串;
    • 第18个字节:0x00,表示为数值类型;
    • 第19-26个字节:0x…,表示具体的时长;
字段 大小 含义
duration DOUBLE 文件的时长
width DOUBLE 视频宽度(px)
height DOUBLE 视频高度(px)
videodatarate DOUBLE 视频比特率(kb/s)
framerate DOUBLE 视频帧率(帧/s)
videocodecid DOUBLE 视频编解码器ID(参考Video Tag)
audiosamplerate DOUBLE 音频采样率
audiosamplesize DOUBLE 音频采样精度(参考Audio Tag)
stereo BOOL 是否立体声
audiocodecid DOUBLE 音频编解码器ID(参考Audio Tag)
filesize DOUBLE 文件总得大小(字节)
示例

在这里插入图片描述

示例

解析flv header

struct flv_header_t
{
	unsigned char FLV[3];
	unsigned char version;
	unsigned char audio;
	unsigned char video;
	unsigned int  offset; // data offset
};

static inline uint32_t be_read_uint32(const uint8_t* ptr)
{
	return (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3];
}

static inline void be_write_uint32(uint8_t* ptr, uint32_t val)
{
	ptr[0] = (uint8_t)((val >> 24) & 0xFF);
	ptr[1] = (uint8_t)((val >> 16) & 0xFF);
	ptr[2] = (uint8_t)((val >> 8) & 0xFF);
	ptr[3] = (uint8_t)(val & 0xFF);
}

int flv_header_read(struct flv_header_t* flv, const uint8_t* buf, size_t len)
{
	if (len < 9 || 'F' != buf[0] || 'L' != buf[1] || 'V' != buf[2])
	{
		assert(0);
		return -1;
	}

	flv->FLV[0] = buf[0];
	flv->FLV[1] = buf[1];
	flv->FLV[2] = buf[2];
	flv->version = buf[3];

	assert(0x00 == (buf[4] & 0xF8) && 0x00 == (buf[4] & 0x20));
	flv->audio = (buf[4] >> 2) & 0x01;
	flv->video = buf[4] & 0x01;
	flv->offset = be_read_uint32(buf + 5);

	return FLV_HEADER_SIZE;
}

其他解析可参考ireader开源库,github: https://github.com/ireader

解析工具

推荐一款解析flv格式码流的工具:FlvAnalyzer.exe,解析效果如图所示:

在这里插入图片描述

部分参考:

https://www.cnblogs.com/chyingp/p/flv-getting-started.html

https://blog.51cto.com/u_13861442/5169955

猜你喜欢

转载自blog.csdn.net/www_dong/article/details/128166528