[时间:2016-06] [状态:Open]
ASF,全称Advanced Systems Format,是由微软提出的开放封装格式标准。ASF是微软公司Windows Media的核心。这是一种包含音频、视频、图像、控制命令脚本、JPEG、二进制文件的数据格式。
目前常见遵循这种标准的数据封装格式化的后缀是.asf、.wma、.wmv。
详细介绍建议参考
- Overview of the ASF Format https://msdn.microsoft.com/en-us/library/windows/desktop/dd757562\v=vs.85).aspx
- Advanced Systems Format-wiki
- ASF-百度百科
学习ASF容器格式的目标
读完本文,你应该能够回答下面问题:
- ASF中数据是如何组织的?
- 该容器包含哪些编码格式的数据?这些数据是如何存储的?
- 该容器包含哪些元数据信息?包含哪些节目信息?
- 对于支持多节目的容器格式,如何找到对应的音频流、视频流、字幕流?
- 如何确定该容器的节目播放时长?
- 如何从该容器中提取音频、视频、字幕数据,并交给解码器解码,有时间戳否?
- 该容器是否支持seek?有哪些辅助信息?
- 是否支持直接流化?
- 哪里可以找到该容器格式最标准的文档资料?
- 有哪些可用的工具,方便分析容器格式异常或者错误?
1. ASF文件整体结构
ASF Object
ASF文件是有多个ASF Object构成,换个说法,ASF Object是ASF的最小组成单元。其结构如下:
Field | Size(byte) |
---|---|
Object GUID | 16 |
Object Size | 8 |
Payload | varies |
ASF object 是16个字节的GUID代表这个Object的类型,Object的类型有很多种。8个字节的 Size 代表这个Object的大小(=24+负载长度),紧接着就是Object的内容(负载)。
所有ASF Object和结构都是以小端字节序存储的。
ASF文件顶层视图
ASF文件通常包含三类ASF Object: Header Object、Data Object和Index Object。
- Header Object是必须位于ASF文件起始位置,一个ASF文件中有且仅有一个Header Object。
- Data Object必须紧跟在Header Object之后,有且仅有一个。
- Index Object是可选的,该对象主要提供了基于时间点的ASF随机访问机制(快速seek);如果Index Object存在必须是ASF文件最后一个Object。
实际结构类似下图:
==================
Header Object
------------------
Data Object
------------------
------------------
Index Object
===================
ASF文件的解析过程中可以忽略任何无法识别的ASF Object。所有新定义或添加的ASF Object必须位于Data Object之后,Index Object之前(即上面的Other Object)。
Header Object
Header Object以ASF_Header_Object GUID object开头,是唯一可以包含ASF Ojbect的顶层结构。它包含着一系列的ASF object,分别代表着不同类型的ASF object,由GUID区分;它们提供了关于ASF DATA 的一些解释信息,如音视频类型及详细信息等, Header Object通常包含如下类型的object:
- File Properties Object:包含整个文件属性,如文件大小、时长等
- Stream Properties Object:包含Stream特性,如音视频格式、类型、PID等
- Header Extension Object:包含用于ASF后向兼容的机制
- Content Description Object:包含内容目录信息
- Script Command Object:包含用于回放时执行的脚本命令
- Marker Object:Provides named jump points within a file
一般情况, Header Object必须包含1个File Properties Object, 1个Header Extension Object, 和至少一个Stream Properties Object。
并且Header Object中Object出现的顺序是不固定的。
一类比较简单的Header Object构成如下(音视频Stream各一个):
========================
File Properties Object
------------------------
Header Extenstion Object
------------------------
Stream Properties Object
------------------------
Stream Properties Object
========================
Index Objects
Index Objects包含两种变体:Simple Index Object和Index Object。在ASF文件中Index Object可以有多个。
Simple Index Object包含视频流的基于时间的索引序列,其中索引之间的间隔是固定的,通常是1s。标准规定,对于ASF文件中的任意视频流必须有一个对应的Simple Index Object,而且顺序是必须以stream number出现。
Index Object指的是Index Object,Media Object Index Object和Timecode Index Object。Index Object类似Simple Index Object,保存固定时间间隔的索引序列,但可以包括非视频流;Media Object Index Object是逐帧的索引机制,支持逐帧seek。Timecode Index Object是基于时间码(timecode)的seek机制,主要针对有时间码的内容。
更具体的内容建议参考“ASF Specification” section 7.3。
2. 如何解析ASF Data Object?
Data Object(GUID:ASF_Data_Object)是由多个Data Packet构成。这些Data Packet是按照发送时间顺序排列的,并且可以来自多个不同的stream。
Data Object包含64位的Total Data Packets字段,用于说明当前文件包含的Data Packet数目。
Data Packet通常是等长的,长度固定(具体长度在File Properties Object中的Data Packet Size字段)。
一个Data Packet中可以包含一个或多个Payload。
Data Packet结构
ASF Data Packet的结构如下图:
============================
Error Correction Data
----------------------------
Payload Parsing Info
----------------------------
Playload Data
----------------------------
Padding Data
============================
or
============================
Error Correction Data
----------------------------
Opaque Data
----------------------------
Padding Data
============================
其中Error Correction Data和Padding Data都是可选的,不一定每一个Data Packet都存在这些数据。
由于Error Correction Data是可选的,如何区分ASF Data Packet开始位置是Error Correction Data还是Payload Parsing Info呢?主要区分在于Data Packet中第一个字节的最高位是否的值(Error Correction Present),如果为1,则是Error Correction Data,否则是Playload Parsing Info。不管是那种数据,其中都存储了数据长度,可以按照ASF Specification中的section 5.2解析。
其中Error Correction Data中有一个字段Opaque Data Present,表示当前Data Packet结构是第二种,负载中有Opaque Data。
Payload Parsing & data解析
Payload Parsing Info段的长度不是固定的,需要按照其实际字段含义解析。其中需要特别关注的是Multiple Payloads Present、Padding Length、Send Time字段。在解析Payload data时会参考这些字段。
一个Playload Data可以包含一个或多个Payload,需要根据Multiple Payloads Present的值判断,如果该值为1,表示包含多个Payload。
Payload结构
ASF中定义Payload如下:
Field name | Filed Type | Size(bits) |
---|---|---|
Stream Number | BYTE | 8 |
Media Object Number | BYTE/WORD/DWORD | 0/8/16/32 |
Offset Into Media Object | BYTE/WORD/DWORD | 0/8/16/32 |
Relicated Data Length | BYTE/WORD/DWORD | 0/8/16/32 |
Replicated Data | BYTE | varies |
Payload Data | BYTE | varies |
其中Stream Number的最高位表示是否是关键帧(key frame),这也就限制了ASF最大能支持128个Stream Media。
另外,如果Replicated Data Length长度为1,表示payload是压缩格式的,具体建议参考ASF Specification的section 5.2.3。
Replicated Data中包含一个DWORD用于标识Payload长度,紧跟一个DWORD表示时间戳信息(以毫秒为单位),其他数据是附加的media sample信息。
对于Multiple Payloads Present为0的情况,可以直接通过Payload的结构解析出负载数据信息。
多个Payload数据解析
理解单个Payload解析之后,多Payload解析是参考Payload Data第一个字节的信息来解析的。其定义如下:
Filed name | Field type | Size(bits) |
---|---|---|
Playload Flags | BYTE | 8 |
==Number of Payloads | - | 6(LSDB) |
==Payload Length Type | - | 2 |
Payloads | - | varies |
这里的Payload的定义包含了Payload Length字段,定义结构如下:
Field name | Filed Type | Size(bits) |
---|---|---|
Stream Number | BYTE | 8 |
Media Object Number | BYTE/WORD/DWORD | 0/8/16/32 |
Offset Into Media Object | BYTE/WORD/DWORD | 0/8/16/32 |
Relicated Data Length | BYTE/WORD/DWORD | 0/8/16/32 |
Replicated Data | BYTE | varies |
Payload Length | BYTE/WORD/DWORD | 8/16/32 |
Payload Data | BYTE | varies |
填充字节主要为了保证ASF Data Packet的定长,通常填充0数据。
3. 如何解析ASF MetaData?
ASF中有五种Object用于存储Metadata,每个Metadata属性存储的顺序按照下面规则选择:
- Content Description Object:可用于存储长度小于65535字节、与Stream无关、与语言无关的属性值,包括:Title, Author, Copyright, Description, and Rating
- Content Branding Object:可用于存储与Stream无关、与语言无关的以下属性值:Banner Image Type, Banner Image Data, Banner Image URL, and Copyright URL
- Extended Content Description Object:可用于存储任意命名的属性值,该属性值需要是下列类型的一种,并且长度小于65535,与Stream无关、与语言无关:WCHAR strings, BYTE arrays, Boolean values, DWORDs, QWORDs, or WORDs
- Metadata Object:可用于存储与语言无关的任意名称的属性。允许数据按照Extended Content Description Object格式存储。属性可以用于描述特定stream,但长度必须不超过65535字节。
- Metadata Library Object:可用于存储任意名称的属性。允许数据按照Extended Content Description Object格式或者GUID数据类型存储。属性可以用于描述特定stream,并支持指定特定语言,并且其长度可以超过65535字节(DWORD)。
至于这五种Object如何解析,建议参考ASF Specification的相关内容。
4. ASF中的节目选择
ASF文件中用StreamID唯一的标识一个stream(音频或者视频,当然也支持其他数据,比如字幕、脚本命令等,目前不需要关心这个,按照传统的音视频处理即可,后续需要可以自己按照标准处理下),这些信息可以在Header Object中的Stream Properties Object找到。比如说音频的声道数、采样率、量化位数、编码方式,视频的编码宽高、编码方式、量化位数。
如果ASF文件中只有一个音频或者一个视频,这是很容易选择,但是如果存在多个音频、视频文件该如何选择呢?
ASF中提供了Bitrate Mutual Exclusion Object、Advanced Mutual Exclusion Object、Group Mutual Exclusion Object,用于说明不能同时播放的视频流。
Stream Prioritization Object用于给出流播放的优先级。
stream选择在流媒体推流,及带宽变化时用的比较多,正常播放文件的话,通常默认选择最大分辨率、最大码率的视频,最大采样率、最多声道数的音频。
具体选择策略建议参考ASF Specification的section 7.2。
5. ASF如何实现seek?
第一部分介绍了ASF中提供的四种不同的Index Object。对于文件,比较常见的是Simple Index Object。多数seek操作时可以通过这个对象实现的。
Simple Index Object中存储的是按照固定时间间隔seek point。先了解下Simple Index Object的结构:
Field name | Field type | Size (bits) |
---|---|---|
Object ID | GUID | 128 |
Object Size | QWORD | 64 |
File ID | GUID | 128 |
Index Entry Time Interval | QWORD | 64 |
Maximum Packet Count | DWORD | 32 |
Index Entries Count | DWORD | 32 |
Index Entries | See below | varies |
其中Index Entry Time Interval表示相邻seek point之间的时间间隔,单位是100纳秒。最常用的是10000000,表示1s。
Maximum Packet Count中存储的是Index Entries中最大的Packet数目。
Index Entries的定义如下:
Field name | Field type | Size (bits) |
---|---|---|
Packet Number | DWORD | 32 |
Packet Count | WORD | 16 |
其中Packet Number指的是与当前时间有关的Data Packet的编号。对于视频stream,该域总是指向具当前时间最近的关键帧所在的Data packet.
Packet Count表示在当前时间间隔内需要发送的Data Packet数目。
举个例子,下面数据是一个wmv文件的Simple Index Object的二进制数据:
0000: 90 08 00 33 B1 E5 CF 11-89 F4 00 A0 C9 03 49 CB
0010: CE 00 00 00 00 00 00 00-B6 FA 97 93 D3 CB E3 4B
0020: 81 D0 F0 6B 24 96 98 A2-80 96 98 00 00 00 00 00
0030: 0F 00 00 00 19 00 00 00-01 00 00 00 01 00 01 00
0040: 00 00 01 00 01 00 00 00-01 00 01 00 00 00 01 00
0050: 38 00 00 00 08 00 38 00-00 00 08 00 38 00 00 00
0060: 08 00 77 01 00 00 0A 00-77 01 00 00 0A 00 77 01
0070: 00 00 0A 00 B2 02 00 00-0D 00 B2 02 00 00 0D 00
0080: B2 02 00 00 0D 00 E8 03-00 00 07 00 E8 03 00 00
0090: 07 00 E8 03 00 00 07 00-26 05 00 00 08 00 26 05
00A0: 00 00 08 00 26 05 00 00-08 00 66 06 00 00 0F 00
00B0: 66 06 00 00 0F 00 66 06-00 00 0F 00 69 07 00 00
00C0: 0A 00 69 07 00 00 0A 00-69 07 00 00 0A 00
解析之后的数据如下:
Simple Index Object (206 bytes) |
---|
Property |
File Position |
Object ID |
Object Size |
MMS ID |
Interval |
Max. Packets in Entry |
Index Entries |
Entry |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
这样我们就可以通过这张表查到需要seek到的时间点对应的Data Packet的索引号,然后通过ASF Data Packet的定长逻辑跳转到指定位置。(注意其他三种Index Object给出的是相对第一个ASF Data Packet的偏移位置)
上面表格中的Packet SCR是Packet Send Time。
6. 其他
读到这里,相信对ASF文件格式有一定的了解了,那么剩下的就回答下没有覆盖的问题。
如何确定该容器的节目播放时长?
在Header Object中的File Properties Object中有一个字段Duration,可以通过这个直接读出节目时长(有时候不准确,这就是文件生成方的责任了)。哪里可以找到该容器格式最标准的文档资料?
通常在微软的官网上是可以下载到ASF标准文档的,但是不行的话可以谷歌(百度基本找不到)。
我现在参考的是“Advanced Systems Format (ASF) Specification Revision 01.20.05 Microsoft Corporation June 2010”有哪些可用的工具,方便分析容器格式异常或者错误?
比较经典的分析ASF、wmv、wma文件的工具是ASFViewer,也是微软提供的码流辅助分析工具,当然你也可以使用开源的demuxer分析(比如ffmpeg asf_demuxer)。
小结
本文主要是参考:
- “Advanced Systems Format (ASF) Specification Revision 01.20.05 Microsoft Corporation June 2010”
- 【多媒体封装格式详解】---ASF(WMV/WMA)
这里主要整理我对于ASF文件格式一些疑惑的地方。算是基本上可以解析了。了解了基本的文件结构,清楚了如何选择音频、视频,时间戳信息、seek索引文件的使用。