• 音视频学习(十三)——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
    
    • 1
    • 2
    • 3
    • 4
    • 5

    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

    字段大小含义
    TagType1字节tag类型。
    音频:0x08
    视频:0x09
    script data:0x12
    Datasize3字节tag data的大小
    Timestamp3字节该tag的时间戳
    TimestampExtended1字节时间戳扩展字节。当24位数值不够时,该字节最高位将时间戳扩展为32位
    StreamID3字节总为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 的定义如下:

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

    示例:

    在这里插入图片描述

    audio tag data

    SoundFormat + SoundRate + SoundSize + SoundType = 1字节

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

    AACAUDIODATA

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

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

    AudioSpecificConfig

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

    示例:

    在这里插入图片描述

    script tag data
    定义

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

    字段大小含义
    ObjectsSCRIPTDATAOBJECT[]任意数目的 SCRIPTDATAOBJECT
    SCRIPTDATAOBJECTEND3字节永远是9,标识着Script Data的结束
    SCRIPTDATAOBJECT
    字段大小含义
    ObjectNameSCRIPTDATASTRING对象的名字
    ObjectDataSCRIPTDATAVALUE对象的值
    SCRIPTDATAVALUE
    字段字段类型字段含义
    TypeSCRIPTDATASTRING变量类型: 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数组长度
    ScriptDataValueIf Type == 0 DOUBLE If Type == 1 UI8 If Type == 2 SCRIPTDATASTRING …(有点长,可以参考规范)变量的值
    ScriptDataValueTerminator如果Type3,则为SCRIPTDATAOBJECTEND 如果 Type8,则为SCRIPTDATAVARIABLEENDObject、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…,表示具体的时长;
    字段大小含义
    durationDOUBLE文件的时长
    widthDOUBLE视频宽度(px)
    heightDOUBLE视频高度(px)
    videodatarateDOUBLE视频比特率(kb/s)
    framerateDOUBLE视频帧率(帧/s)
    videocodecidDOUBLE视频编解码器ID(参考Video Tag)
    audiosamplerateDOUBLE音频采样率
    audiosamplesizeDOUBLE音频采样精度(参考Audio Tag)
    stereoBOOL是否立体声
    audiocodecidDOUBLE音频编解码器ID(参考Audio Tag)
    filesizeDOUBLE文件总得大小(字节)
    示例

    在这里插入图片描述

    示例

    解析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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    其他解析可参考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

  • 相关阅读:
    曲线艺术编程 coding curves 第十二章 玑镂(扭索)纹
    数据湖技术之 Hudi 集成 Flink
    [学习记录] SpringBoot 17. 数据访问 Mybatis
    centos7中安装mongoDB4
    k8s教程(10)-pod生命周期、重启策略及健康检查
    权限管理系统-0.4.0
    Ubuntu22.04启用root账户 2208120941
    Python 全栈系列183 元数据的规划与命名
    Spring Boot自动装配原理超详细解析
    详细介绍数据结构-堆
  • 原文地址:https://blog.csdn.net/www_dong/article/details/128166528