😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
🤣本文内容🤣:🍭介绍Ogg封装格式🍭
😎金句分享😎:🍭子曰:君子坦荡荡,小人长戚戚。——《论语·述而篇》。意思是,君子心胸开阔,神定气安;小人斤斤计较,患得患失。🍭
目录
- 🎄一、介绍
- 🎄二、定义
- 🎄三、通用封装格式的要求
- 🎄四、Ogg比特流格式
- 🎄五、封装过程
- 🎄六、Ogg页面格式
🎄一、介绍
Ogg比特流格式是作为一个更大项目的一部分开发的,该项目旨在创建一组用于多媒体内容(编解码器)编码和解码的组件,这些组件将在软件和硬件方面免费提供并可免费重新实现,以供包括互联网社区在内的广大计算社区使用。以Xiph.Org为代表的Ogg开发人员的意图是,它可以在没有知识产权问题的情况下使用。
本文档描述了Ogg比特流格式,以及如何使用它来封装由一个或多个编码器创建的一个或几个媒体比特流。Ogg传输比特流旨在为由原始、未封装数据包组成的高级编解码器流提供成帧、错误保护和查找结构,例如Vorbis音频编解码器或即将推出的Tarkin和Theora视频编解码器。它能够交织不同的二进制媒体和其他时间连续的数据流,这些数据流由编码器准备为数据包序列。Ogg提供了足够的信息来在原始分包边界处将数据适当地分离回这样的编码器创建的数据分包,而不依赖于解码来找到分包边界(packet boundaries)。
请注意,MIME类型应用程序/ogg已在IANA注册。
🎄二、定义
为了描述Ogg封装过程,将使用一组术语,其含义需要充分理解。因此,在我们开始描述通用媒体流封装格式的要求、封装过程和Ogg比特流的具体格式之前,现在已经定义了一些最基本的术语。有关更完整的词汇表,请参阅附录。
Ogg封装的结果被称为“物理(Ogg)比特流”。它封装了一个或多个编码器创建的比特流,称为“逻辑比特流”。提供给Ogg封装过程的逻辑比特流具有一种结构,即它被拆分为一系列所谓的“数据包”。分包由该逻辑比特流的编码器创建,并且仅代表该编码器的有意义的实体(例如,未压缩流可以使用视频帧作为分包)。它们不包含边界信息——串在一起,看起来像是没有地标的随机字节流。
请注意,本文件中“数据包”(packet)一词并非用于表示通过网络传输的实体。
🎄三、通用封装格式的要求
Ogg背后的设计思想是提供一种通用的线性媒体传输格式,以实现独立于媒体数据的编码格式的一个或多个交织媒体流的基于文件的存储和基于流的传输。这种封装格式需要提供:
- 逻辑比特流的成帧。
- 不同逻辑比特流的交错。
- 腐败检测。( detection of corruption. )
- 解析错误后重新捕获
- 用于直接随机访问比特流中任意位置的标志.
- 流传输能力(即不需要寻找来构建100%完整的比特流)。
- 小开销(即,使用不超过比特流带宽的大约1-2%用于分包边界标记、高级成帧、同步和查找)。
- 实现快速解析的简单性。
- 几个物理比特流的简单连接机制。
Ogg考虑了所有这些设计因素。Ogg支持逻辑比特流的成帧和交织、寻找地标、检测损坏以及在解析错误后重新同步流,开销不超过1-2%。它是一个通用框架,用于对时间连续的比特流进行封装。它不知道它封装的编解码器数据的任何细节,因此独立于任何媒体编解码器。
🎄四、Ogg比特流格式
物理Ogg比特流由多个逻辑比特流组成,这些逻辑比特流交错在所谓的“页面”中。从在页面级别复用的多个逻辑比特流中按顺序获取整个页面。逻辑比特流由物理比特流的每个页面的报头中的唯一序列号来标识。这个唯一的序列号是随机创建的,与它所代表的逻辑比特流的内容或编码器没有任何连接。所有逻辑比特流的页面都是并发交错的,但它们不需要按规则顺序排列——它们只需要在逻辑比特流中是连续的。Ogg多路分解通过从物理比特流按顺序获取页面并将其重定向到适当的逻辑解码实体来从物理比特串流重构原始逻辑比特流。
每个Ogg页面(page)只包含一种类型的数据,因为它只属于一个逻辑位流。页面大小可变,并且具有包含封装和错误恢复信息的页头。物理Ogg比特流中的每个逻辑比特流都以一个特殊的起始页(bos=beginning of stream)开始,并以一个特定的页(eos=end of stream)结束。
bos页面包含唯一标识编解码器类型的信息,并且可能包含设置解码过程的信息。bos页面还应该包含有关编码媒体的信息——例如,对于音频,它应该包含采样率和通道数量。按照惯例,bos页面的第一个字节包含唯一标识所需编解码器的神奇数据(magic data)。任何部署新编解码器的人都有责任确保能够可靠地将他/她的编解码器与使用中的所有其他编解码器区分开来。没有固定的方法来检测编解码器识别标记的结束。bos页面的格式取决于编解码器,因此必须在该逻辑比特流类型的封装规范中给出。Ogg还允许但不要求逻辑比特流的bos页之后的辅助报头分包,并且这些报头分包还必须在任何逻辑比特流中的任何数据分包(data packets)之前。这些随后的报头分包(header packets)被添加到完整个数的页面(page)中,这些页面(page)将不包含任何数据分包。因此,物理比特流从所有逻辑比特流的每个页面包含一个初始报头分包的bos页面开始,然后是所有流的子报头分包,然后是包含数据分包的页面。
一个或多个逻辑比特流的封装规范称为“媒体映射”。媒体映射的一个例子是“Ogg Vorbis”,它使用Ogg框架来封装Vorbis编码的音频数据,用于基于流的存储(如文件)和传输(如TCP流或管道)。Ogg Vorbis提供了Vorbis编解码器的名称和版本,音频速率和音频质量在Ogg Vorpis的bos页面上。它还为每个逻辑位流使用两个额外的头页。Ogg Vorbis-bos页面以字节0x01开头,后跟“Vorbis”(标识符共7个字节)。
Ogg知道两种类型的多路复用:并发多路复用(所谓的“分组”(Grouping))和顺序多路复用(称为“链接”(Chaining))。分组(Grouping)定义了如何在同一物理比特流中逐页交错多个逻辑比特流。例如,使用不同逻辑比特流中的不同编解码器来将视频流与几个同步的音轨交织需要分组。另一方面,链接(Chaining)被定义为提供一种简单的机制来连接物理Ogg比特流,这是流应用程序经常需要的。
在分组(Grouping)中,所有逻辑位流的所有bos页必须一起出现在Ogg位流的开头。媒体映射指定初始页面的顺序。例如,特定Ogg视频和Ogg音频比特流的分组(grouping)可以指定物理比特流必须以逻辑视频比特流的bos页开始,然后是音频比特流。与bos页面不同,逻辑位流的eos页面不需要全部连续出现。eos页面可以是“nil”页面,也就是说,不包含任何内容,只包含一个具有位置信息的页头和在页头中设置的eos标志的页面。每个分组的逻辑比特流必须在物理比特流的范围内具有唯一的序列号(unique serial number)。
在链接(Chaining)中,完整的逻辑比特流被连接在一起。比特流不重叠,即给定逻辑比特流的eos页紧接着是下一个逻辑比特流。每个链接的逻辑比特流必须在物理比特流的范围内具有唯一的序列号(unique serial number)。
可以连续地将并行复用的比特流的组串接。当未绑定时,这些组必须作为有效的并发多路复用比特流独立存在。下图显示了这种物理比特流的示意性示例,该物理比特流遵守分组和链式复用比特流的所有规则。
physical bitstream with pages of
different logical bitstreams grouped and chained
-------------------------------------------------------------
|*A*|*B*|*C*|A|A|C|B|A|B|#A#|C|...|B|C|#B#|#C#|*D*|D|...|#D#|
-------------------------------------------------------------
bos bos bos eos eos eos bos eos
在这个例子中,有两个链接的物理比特流,第一个是由三个逻辑比特流A、B和C组成的分组流。第二个物理比特流D链接在分组比特流的末尾之后,分组比特流在其所有分组逻辑比特流的最后一个eos页之后结束。可以看出,分组的比特流从一起开始——所有的bos页面都必须出现在任何数据页面之前。还可以看出,并行复用的比特流的页面不需要符合规则的顺序。可以看出,一个分组的比特流可以在该组中的其他比特流结束之前很久结束。
Ogg不知道关于编解码器数据的任何细节,只是每个逻辑比特流都属于不同的编解码器,来自编解码器的数据按顺序排列,并有位置标记(所谓的“颗粒位置”)。Ogg没有“时间”的概念:它只知道顺序增加的、无单位的位置标记。应用程序只能通过更高层获得时间信息,这些高层可以访问编解码器API来分配和转换颗粒位置或时间。
使用Ogg的媒体映射的特定定义可以对其对Ogg比特流格式的特定使用施加进一步的约束。例如,特定的媒体映射可能要求所有分组比特流的所有eos页面都需要以直接顺序出现。介质映射的一个例子是“Ogg Vorbis”的规范。另一个例子是即将推出的“Ogg Theora”规范,该规范封装了Theora编码的视频数据,通常与包含同步音频和视频的Ogg的Vorbis流多路复用。由于Ogg没有指定封装的并发复用比特流之间的时间关系,因此音频和视频流之间的临时同步将在该媒体映射中指定。为了启用流式传输,来自各种逻辑位流的页面通常将按时间顺序交错。
🎄五、封装过程
多路复用不同逻辑比特流的过程发生在如上所述的页面级别。然而,编码器提供的比特流作为所谓的“分包”(Packets)移交给Ogg,分包边界(packet boundaries)取决于编码格式。现在将描述将数据包封装到页面中的过程。
从Ogg的角度来看,数据包(packet )可以是任意大小的。特定媒体映射将定义如何对来自特定媒体编码器的数据包进行分组或分解。由于Ogg页面(Ogg pages)的最大大小约为64kBytes,有时一个数据包必须分布在几个页面上。为了简化这个过程,Ogg将每个数据包划分为255字节长的块和最后一个较短的块。这些块被称为“Ogg分段”(Ogg Segments)。它们只是一个逻辑结构,本身没有分段的头部(header)。
一组连续的段(segments )被包装成一个可变长度的页面,页面前面有一个页头部(page)。页面头部(page header)中的分段表(segment table)告诉页面中包含的各个分段(segments)的“Lacing Value”(大小)。页面头部(page header)中的标志告诉一个页是否包含从前一页继续的数据包。注意,lacing value 值位255意味着第二个lacing value 跟随其后在同一数据包中,并且lacing value 值小于255标记在许多附加字节之后的数据包的结束。255个字节(或255个字节的倍数)的数据包以 lacing value 值为 0 终止。还要注意,“nil”(零长度)数据包不是错误;它只包括页头部中的一个值为零的lacing value。
编码针对速度和大多数数据包在50到200字节之间的预期情况进行了优化。这是一个设计理由,而不是一个建议。这种编码既避免了对小分包施加最大分包大小,又避免了对其施加最小开销。相反,例如,简单地在每个数据包的开头使用两个字节,并且具有32kBytes的最大数据包大小,将总是以两倍的分段开销惩罚小数据包(典型情况下<255字节)。使用建议的lacing value,小数据包可以看到最小可能的字节对齐开销(1字节),而大数据包(>512字节)在编码空间上看到相当恒定的~0.5%的开销。
The following diagram shows a schematic example of a media mapping
using Ogg and grouped logical bitstreams:
logical bitstream with packet boundaries
-----------------------------------------------------------------
> | packet_1 | packet_2 | packet_3 | <
-----------------------------------------------------------------
|segmentation (logically only)
v
packet_1 (5 segments) packet_2 (4 segs) p_3 (2 segs)
------------------------------ -------------------- ------------
.. |seg_1|seg_2|seg_3|seg_4|s_5 | |seg_1|seg_2|seg_3|| |seg_1|s_2 | ..
------------------------------ -------------------- ------------
| page encapsulation
v
page_1 (packet_1 data) page_2 (pket_1 data) page_3 (packet_2 data)
------------------------ ---------------- ------------------------
|H|------------------- | |H|----------- | |H|------------------- |
|D||seg_1|seg_2|seg_3| | |D|seg_4|s_5 | | |D||seg_1|seg_2|seg_3| | ...
|R|------------------- | |R|----------- | |R|------------------- |
------------------------ ---------------- ------------------------
|
pages of |
other --------| |
logical -------
bitstreams | MUX |
-------
|
v
page_1 page_2 page_3
------ ------ ------- ----- -------
... || | || | || | || | || | ...
------ ------ ------- ----- -------
physical Ogg bitstream
在本例中,我们对一个逻辑比特流的封装过程进行了快照。我们可以看到编解码器提供的部分比特流细分为数据包。Ogg封装过程将数据包分割成若干段。本例中的数据包相当大,因此数据包1被分为5个段,其中4个段有255个字节,最后一个较小。数据包2分为4个段,其中3个段有255个字节,最后一个非常小。数据包3分为两个段。然后,封装过程会创建页面,在本例中页面非常小。页面1由数据包1的前三个段组成,页面2包含数据包1中剩余的两个段,页面3包含数据包2的前三页。最后,该逻辑比特流的页面和其他逻辑比特流页面被混合组成一个物理Ogg比特流。
🎄六、Ogg页面格式
物理Ogg比特流由一系列连接的页面组成。页面大小可变,通常为4-8 kB,最大65307字节。页头包含将逻辑比特流从物理比特流中解复用出来以及执行基本错误恢复和用于查找的地标所需的所有信息。每个页面都是一个自包含的实体,因此页面解码机制可以一次识别、验证和处理单个页面,而不需要整个比特流。
The Ogg page header has the following format:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1| Byte
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| capture_pattern: Magic number for page start "OggS" | 0-3
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| version | header_type | granule_position | 4-7
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | 8-11
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | bitstream_serial_number | 12-15
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | page_sequence_number | 16-19
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | CRC_checksum | 20-23
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |page_segments | segment_table | 24-27
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ... | 28-
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The LSb (least significant bit) comes first in the Bytes. Fields
with more than one byte length are encoded LSB (least significant
byte) first.
LSb(最低有效位)位于字节中的第一位。长度超过一个字节的字段首先编码LSB(最低有效字节)。
页面头部(page header)中的字段具有以下含义:
1、capture_pattern:表示页面开始的4字节字段。它包含4个字符:O
、g
、g
、S
。它可以帮助解码器找到页面边界,并在解析损坏的流后重新获得同步。一旦发现捕获模式,解码器就通过计算和比较校验和来验证页面同步和完整性。
2、stream_structure_version:1字节,表示该流中使用的Ogg文件格式的版本号(本文档指定版本0)。
3、header_type_flag:这1字节字段中的位标识该页面的特定类型。
bit 0x01
被设置:页面包含从上一页继续的数据包的数据。
没设置: 页面包含新的数据包
bit 0x02
被设置:这是逻辑比特流(bos)的第一页
没设置:此页面不是首页
bit 0x04
被设置:这是逻辑比特流(eos)的最后一页
没设置:这一页不是最后一页
4、granule_position:包含位置信息的8字节字段。例如,对于音频流,它可能包含在包括此页面上完成的所有帧之后编码的PCM样本的总数。对于视频流,它可能包含在此页面之后编码的视频帧的总数。这是对解码器的提示,并给它一些定时和位置信息。其含义取决于该逻辑比特流的编解码器,并在特定媒体映射中指定。特殊值-1(以2的补码表示)表示此页上没有数据包结束。
5、bitstream_serial_number:包含唯一序列号的4字节字段,通过该唯一序列号来识别逻辑比特流。
6、page_sequence_number:包含页面序列号的4字节字段,使得解码器可以识别页面丢失。该序列号在每个逻辑比特流上分别增加。
7、CRC_checksum:包含页面的32位CRC校验和的4字节字段(包括具有零CRC字段的报头和页面内容)。生成多项式为0x04c11db7。
8、number_page_segments:1字节,给出分段表(segment table.)中编码的分段条目的数量。
9、segment_table:大小为 number_page_segments 个字节。包含此页中所有段的lacing value。每个字节包含一个 lacing value。
以字节为单位的页面头部大小(total header size)由下式给出:
header_size = number_page_segments + 27 [Byte]
以字节为单位的总页面大小由下式给出:页面头部大小
+ 所有lacing_values值之和
page_size = header_size + sum(lacing_values: 1..number_page_segments)[Byte]
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁
参考资料:
The Ogg Encapsulation Format Version 0