一、SCRIPTDATA
根据《video_file_format_spec_v10_1.pdf》第75页到76页,如果某个Tag的Tag header中的TagType值为18,表示该Tag为Script Tag(脚本Tag,又称Data Tag、SCRIPTDATA tag)。这时如果Filter的值不为1表示未加密,不需要预处理,则StreamID之后紧接着的就是SCRIPTDATA。也就是说这时Tag header之后的是SCRIPTDATA:
所以,未加密的情况下,一个Script Tag = Tag header + SCRIPTDATA。
根据《video_file_format_spec_v10_1.pdf》第80页,SCRIPTDATA包含可选的加密元数据和脚本有效负载。加密的情况下,SCRIPTDATA的Body为EncryptedBody;未加密的情况下,SCRIPTDATA的Body为ScriptTagBody。这里我们主要讲解未加密的情况:
所以,未加密的情况下,SCRIPTDATA = ScriptTagBody
二、ScriptTagBody
根据《video_file_format_spec_v10_1.pdf》第80页,ScriptTagBody包含以Action Message Format(AMF)编码的SCRIPTDATA。AMF是一种用于数据交换的开放标准,旨在简化数据传输和解析过程。ScriptTagBody由Name和Value组成,这两个属性都是SCRIPTDATAVALUE类型的:
所以,ScriptTagBody = Name + Value
三、SCRIPTDATAVALUE类型
根据《video_file_format_spec_v10_1.pdf》第80页到81页,SCRIPTDATAVALUE类型由一个8位(1字节)的Type和一个ScriptDataValue组成。其中Type属性用来指定ScriptDataValue的类型,根据Type值的不同,ScriptDataValue的类型也不同:
四、ScriptTagBody的Name属性
由上文我们可以知道,ScriptTagBody由Name和Value组成。 Name属性指定方法或对象名称,为SCRIPTDATAVALUE类型。Name对应的Type的值必为2,所以Name对应的ScriptDataValue属性必为SCRIPTDATASTRING类型:
根据《video_file_format_spec_v10_1.pdf》第83页,SCRIPTDATASTRING类型用来记录存贮不超过65535个字符的字符串数据。SCRIPTDATASTRING类型由一个16位(2字节)的StringLength属性和一个存贮字符数据的StringData属性组成。其中StringLength属性用来指定要存贮的字符串的长度,单位为字节;StringData属性存贮实际的字符串数据(不超过65535个字符):
所以,
ScriptTagBody的Name = 1字节的值为2的Type + 2字节的StringLength + 可变长的StringData
五、ScriptTagBody的Value属性
ScriptTagBody的Value属性指定了AMF参数或对象的属性,为SCRIPTDATAVALUE类型。Value对应的Type的值必为8,所以Value对应的ScriptDataValue属性必为SCRIPTDATAECMAARRAY类型:
根据《video_file_format_spec_v10_1.pdf》第81页,SCRIPTDATAECMAARRAY类型存储一个ECMA数组。SCRIPTDATAECMAARRAY类型由一个32位(4字节)的ECMAArrayLength、一个由每个元素都为SCRIPTDATAOBJECTPROPERTY类型的数组构成的Variables和一个SCRIPTDATAOBJECTEND类型的List Terminator组成:
所以,
ScriptTagBody的Value = 1字节的值为8的Type + 4字节的ECMAArrayLength + Variables数组 + List Terminator
(一)ECMAArrayLength属性
SCRIPTDATAECMAARRAY类型的ECMAArrayLength属性指定ECMA数组中的元素个数。
(二)Variables属性
SCRIPTDATAECMAARRAY类型的Variables属性是一个数组,该数组的每个元素都为SCRIPTDATAOBJECTPROPERTY类型。数组中的每个元素由变量名称(PropertyName)和变量的值(PropertyData)组成。根据《video_file_format_spec_v10_1.pdf》第82页,PropertyName为上文提到过的SCRIPTDATASTRING类型,而PropertyData为上文提到过的SCRIPTDATAVALUE类型:
所以,
Variables数组中某个元素 = PropertyName + PropertyData;
Variables数组中某个元素的PropertyName = 2字节的StringLength + 可变长的StringData;
Variables数组中某个元素的PropertyData = 1字节的值为0到12的Type + ScriptDataValue;
(三)List Terminator属性
List Terminator属性是SCRIPTDATAOBJECTEND类型,为终止符。根据《video_file_format_spec_v10_1.pdf》第82页,SCRIPTDATAOBJECTEND类型用来终止SCRIPTDATAOBJECTPROPERTY类型的数组。SCRIPTDATAOBJECTEND类型固定3字节,值必须为0,0,9:
所以,
ScriptTagBody的Value = 1字节的值为8的Type + 4字节的ECMAArrayLength + Variables数组 + List Terminator
= 1字节的值为8的Type + 4字节的ECMAArrayLength + Variables数组 + 3字节的终止符(值固定为0,0,9)
六、onMetaData
根据《video_file_format_spec_v10_1.pdf》第84页,FLV文件的元数据对象应该在名称为“onMetadata”的SCRIPTDATA tag(Script Tag)中携带。也就是说FLV文件中存在一个特殊的Script Tag,它的ScriptTagBody中的Name属性中的StringData属性存贮“onMetadata”字符串,而它的ScriptTagBody中的Value属性中的Variables数组中的每个元素都分别为一个元数据属性。用来存贮当前文件的一些基本信息,比如视频和音频的编解码器ID、视频的分辨率、文件大小、文件总时长、创建日期等:
根据上图,对于名称为“onMetadata”的Script Tag,其Variables数组中的元素(可用的属性)
根据创建FLV文件的软件而有所不同。典型的属性包括:
1.audiocodecid:音频编解码器ID。根据《video_file_format_spec_v10_1.pdf》第76页,可以看到FLV文件中的音频压缩编码格式可以为PCM、MP3......AAC等:
2.audiodatarate:音频码率,单位为kilobits per second,即Kbps。
3.audiodelay:音频编解码器引入的延迟,以秒为单位。
4.audiosamplerate:音频采样率,单位为Hz。
5.audiosamplesize:音频采样位数。
6.canSeekToEnd:表示最后一帧视频是否为关键帧,能否跳转到最后。
7.creationdate:该FLV文件的创建日期和时间。
8.duration:该FLV文件的总时长,以秒为单位。
9.filesize:该FLV文件的总大小,以字节为单位。
10.framerate:视频帧率。
11.height:视频分辨率的高,以像素为单位。
12.stereo:表示音频是否是立体声。
13.videocodecid:视频编解码器ID。根据《video_file_format_spec_v10_1.pdf》第78页,可以看到FLV文件中的视频压缩编码格式可以为H.263,VP6......AVC(即H.264)等:
14.videodatarate:视频码率,单位为kilobits per second,即Kbps。
15.width:视频分辨率的宽,以像素为单位。
除了《video_file_format_spec_v10_1.pdf》第84页表格中显示的属性外,某些软件(比如FFmpeg)生成的FLV文件中,其名称为“onMetadata”的Script Tag的Variables数组中的可用元素可能还有:
1.major_brand:表示“最好”基于哪种格式来解析当前的文件。
2.minor_version:提供 major_brand 的说明信息,比如版本号。
3.compatible_brands:文件兼容的brand列表。
4.encoder:编码器。
七、总结
1.如果某个Tag的Tag header中的TagType值为18,表示该Tag为Script Tag(脚本Tag,又称Data Tag、SCRIPTDATA tag)。
2.未加密的情况下,
一个Script Tag = Tag header + SCRIPTDATA;
SCRIPTDATA = ScriptTagBody;
ScriptTagBody = Name + Value;
ScriptTagBody的Name = 1字节的值为2的Type + 2字节的StringLength + 可变长的StringData;
ScriptTagBody的Value = 1字节的值为8的Type + 4字节的ECMAArrayLength + Variables数组 + 3字节的终止符(值固定为0,0,9);
Variables数组中某个元素 = PropertyName + PropertyData;
Variables数组中某个元素的PropertyName = 2字节的StringLength + 可变长的StringData;
Variables数组中某个元素的PropertyData = 1字节的值为0到12的Type + ScriptDataValue;
3.FLV文件中存在一个特殊的Script Tag,它的ScriptTagBody中的Name属性中的StringData属性存贮“onMetadata”字符串,而它的ScriptTagBody中的Value属性中的Variables数组中的每个元素都分别为一个元数据属性。用来存贮当前文件的一些基本信息,比如视频和音频的编解码器ID、视频的分辨率、文件大小、文件总时长、创建日期等。