ogg格式解析

 HTML5 规定了一种通过 video 元素来包含视频的标准方法。当前,video 元素支持三种视频格式:
Ogg = 带有 Theora 视频编码和 Vorbis 音频编码的 Ogg 文件
MPEG4 = 带有 H.264 视频编码和 AAC 音频编码的 MPEG 4 文件
WebM = 带有 VP8 视频编码和 Vorbis 音频编码的 WebM 文件

Internet Explorer 8 不支持 video 元素。在 IE 9 中,将提供对使用 MPEG4 的 video 元素的支持。

官网资料:https://www.xiph.org/

注意theora只有I 和 P帧,没有B帧。

最近的任务是做ogg的demux,一直在研究ogg格式,积累了一些资料和知识,在这里做一记录。

ogg是一种多媒体容器,可以包含很多种音视频格式,他是xiph提供的免费开源的音视频格式,官网可以看看http://www.xiph.org/!

        大家可能所见的.ogg的文件大都ogg的vorbis音频格式,是一种效果和MP3相媲美的音频,我最初接触ogg的时候,以为是纯音频,看过官网的介绍发现他是一个很强大的容器结构,xiph提供的免费的视频Theora和音频vorbis都是开源免费的,都包含在ogg的容器中,此外ogg也能包含很多其他音视频,如:flac,MP3等,大家可以看看我官网链接,便豁然开朗。

<一>ogg的标准容器格式

       ogg是以页(page)为单位将逻辑流组织链接起来,每个页都有pageheader和pagedata。页头中有如下的定义:

       1>页标识:ASCII字符,0x4f  'O'   0x67  'g'   0x67  'g'  0x53 'S',4个字节大小,它标识着一个页的开始。

       2>版本id:一般当前版本默认为0,1个字节

       3> 类型标识:标识当前的页的类型,1个字节

              0x01:本页媒体编码数据与前一页属于同一个逻辑流的同一个packet,若此位没有设,表示本页是以一个新的packet开始的;

              0x02:表示该页为逻辑流的第一页,bos标识,如果此位未设置,那表示不是第一页;

              0x04:表示该页位逻辑流的最后一页,eos标识,如果此位未设置,那表示本页不是最后一页。

      4>granule_position:媒体编码相关的参数信息,8个字节,对于音频流来说,它存储着到本页为止逻辑流在PCM输出中采样码的数目,可以由它来算得时间戳。对于视频流来说,它存储着到本页为止视频帧编码的数目。若此值为-1,那表示截止到本页,逻辑流的packet未结束。(小端)

      5> serial_number:当前页中的流的id,4个字节,它是区分本页所属逻辑流与其他逻辑流的序号,我们可以通过这个值来划分流。(小端)

      6>page_seguence_number:本页在逻辑流的序号,4个字节

      7>CRC_cbecksum:循环冗余效验码效验,4个字节,用来效验每页的有效性。

      8>number_page_segments:给定本页在segment_table域中出现的segement个数,1个字节

      9>segment_table:从字面看它就是一个表,表示着每个segment的长度,取值范围是0~255

          由segment(1个segment就是1个字节)可以得到packet的值,每个packet的大小是以最后一个不等于255的segment结束的,从页头中的segment_table可以得到每个packet长度,举例:如果一组segment依次顺序为FF 45 FF FF FF 40FF 05FF FF FF 66(共4个packet,含12个segment,每个packet的长度是:FF 45【324】;FF FF FF 40【829】;FF 05【260】;FF FF FF 66【847】,那么第一个packet的长度为255+69 = 324,第二个packet大小829,同理。

        页头基本上就是由上述的参数组成,由此我们可以得到页头的长度和整个页的长度:

       header_size  = 27+number_page_segments ;(byet)

       page_size = header_size +segment_table中每个segment的大小;



3  Ogg 文件格式结构

3.1 文件格式在流媒体系统中的重要性

     逻辑流以页(page)为单位组织链接成物理流,如图3所示:
 

图3   Ogg 文件的组织形式
    图3中的文件链接了两个物理流,A、B和C三个逻辑流组成一个物理流,逻辑流D单独是一个物理流。一个物理流中的所有逻辑流的bos_page都必须在物理位置上相邻,如图3所示*A*、*B*、*C*三个bos_page的位置。
    bos:beginning of stream;    eos:end of stream
    映射到Ogg格式的媒体(如vorbis音频,Theora视频)有相关详细定义,这些定义使得这些媒体之间有更具体的约束关系。Ogg 本身并没详细说明多个并发媒体流之间的时间关系,这需要并发媒体流在映射到Ogg格式的时刻来指定,通常他们之间的交错关系是按他们产生的时间先后顺序来排列。

3.2 Ogg page 页结构

    每个页之间相互独立,都包含了各自应有的信息,页的大小是可变的,通常为4K-8KB,最大值不能超过65307bytes(27+255+255*255=65307)。页头部格式如图4。
    页头部各字段域详细说明参见文献[4]:(小端字节序列格式LSB)。
    ⑴ capture_pattern: 模式捕获域,4个字节,表示页的开始,其作用是分离Ogg封装格式还原媒体编码时识别新页的作用,它包含了四个幻数(ASCII字符集):
0x4f 'O'    0x67 'g'    0x67 'g'     0x53 'S'
    ⑵ stream_structure_version:1个字节,表示当前Ogg文件格式的版本,目前为0。

图4 Ogg页头部结构
    ⑶ header_type_flag:头部类型标识,1个字节。标识当前页具体类型。其设置分三种情况:
    *  bit 0x01  若已设置,页包含的媒体编码数据于前一页同属于一个逻辑流的同一packet。若未设置,本页是一个新的packet。
    *  bit 0x02   设置,表示逻辑流的第一个页bos。未设,不是第一个页。
    *  bit 0x04   设置,表示逻辑流的最后一页eos。未设,不是最后一页。
    ⑷ granule_position:8个字节(字节6-字节13),包含了媒体编码相关参数信息。对于音频流,包含了到本页为止逻辑流在PCM中采样编码的总次数。对于视频流,包含了逻辑流到本页为止视频帧编码的总次数。其值若为-1,则说明到此页为止,逻辑流的packet还未结束。
    ⑸ bitstream_serial_number:流序列号,4字节,表示本页所属逻辑流与其他逻辑流相区别的序号。
    ⑹ page_sequence_number: 表明了本页在逻辑流中的序列号,Ogg解码器能据此识别有无页丢失。
    ⑺ CRC_checksum: 循环冗余校验码校验和,4字节域,包含页的32bit CRC校验和(包括页头部零CRC校验和页数据校验),它的产生多项式为:0x04c11db7。
    ⑻ number_page_segments:1字节,给定了在本页的segment_tabale域中所出现的segement个数 1个segment就是1个字节,其number_page_segments的值,就表示segment_table所占的大小 ,其最大值为255segments(每片255个字节),即页头部第26个字节的取值范围为:0x00-0xff (0-255)。页最大物理尺寸为65307bytes,小于64KB。
    ⑼ segment_table:逻辑流中的每个packet每个segment长度的取值(lacing values, 除了每个packet的最后一个segment小于255外,其它segment都为255 ),这些值以segment出现的先后顺序依次排列。此域的字节数为number_page_segments域所表示的数字(即在0-255之间)。
byte     value
 27       0xff (255)
      [.................  ]
      n-1      0xff (255)
n        0x00-0xfe (0-254, n=num_segments+26)
页头部长度的字节数:
  header_size = 27 + number_page_segments [Byte]  
  即页头部长度为上述9个域名所表述占据的字节数之和。
页的总长度:
  page_size = header_size + sum(lacing_values: 1...number_page_segments)   [Byte]
即页的总长度为页头部长度加上紧随其后的若干segments长度之和(净载荷长度)。

 3.3  Ogg封装处理过程

    (1)音视频编码在提供给Ogg封装之前是以具有包边界的“Packets”形式呈现的,包边界依赖于具体的编码格式。如图5所示。
    (2)将逻辑流的各个包进行分片segmentation,每片大小固定为255Byte,但包的最后一个segment通常小于255字节。因为packet的大小可以是任意长度,由具体的媒体编码器来决定。
    (3)进行页封装,每页都被加上页头,每页的长度可不等,由具体情况而确定。页头部segment_table域告知了 “lacing_value”值的大小,即页中最后一个segment的长度(可以为0,或小于255)。一次处理一个packet,此 packet被封装成一个或多个page页 (page的长度设定了上限,一般为4kB);下一个packet必须用新的page开始封装,由首部字段域header_type_flag的设置规定来表示。
    (4)多个已被页格式封装好的 逻辑流(如语音、文本、图片、音频、视频等) 按应用要求的时序关系合成物理流。

3.4  Ogg文件的映射与逆映射

    用Ogg文件格式封装好压缩编码媒体流可用于存储(磁盘文件)或直接传输(TCP或管道),这是因为Ogg比特流格式提供了封装/同步、差错同步捕获、寻找标记以及其它足够的信息使得这种分散开的数据能够完全地还原为封装之前的具有包边界“packet”形式的压缩编码媒体流,恢复到这种原来媒体流就具有的包边界形式不需要依赖于针对压缩编码的解码器。也就是说Ogg映射与逆映射和媒体流的压缩编码、解码具有相对独立性。

图5  Ogg封装流程示意图


  具有包边界的逻辑流
------------------------------------------------------------------------------------
> |packet1| | | | ||packet2| | ||packet3| | <
------------------------------------------------------------------------------------


分片segmentation
packet1(5 segments)                      packet2(3 segments)     packet3(2 segments)
------------------------------------------------------------------------------------
> |seg1   |seg2 |seg3 |seg4 |seg5 ||seg1| |seg2 |seg3   ||seg1 |seg2   | <
------------------------------------------------------------------------------------


页封装
page1(packet1+data)                      page2(packet2+data)      page3(packet3+data)
-----------------------------------------------------------------------------------------------------
> |H|                                                                             |H|                                               |H|
    |D|                                                                             |D|                                                |D|   
    |R|seg1   |seg2 |seg3 |seg4 |seg5 |R|seg1| |seg2 |seg3   |R|seg1 |seg2   | <
-----------------------------------------------------------------------------------------------------


MUX pages of other lgical bitstreams


多个逻辑流合成ogg物理流


page1 page2 page3 ......
---------------------------------------------------------------------------
| | | | | |......
---------------------------------------------------------------------------
OGG 物理流

 Ogg文件需要解封装的情况有两种:(1)播放器要对媒体流解码之前;(2)对媒体流进行RTP/UDP传输之前。解封装的过程就是ogg逆映射过程,即还原为具有包边界“packet”形式的媒体流,同时以预先填充好了的RTP首部字段与相应一段媒体数据捆绑,形成RTP封包。此过程便是媒体流从Ogg格式到RTP格式的转换过程。
    将以packet为单元的媒体流映射为以page为单元的Ogg格式比特流,其中间经过了segment的划分和重组环节,但方便了对媒体流的存储与传输(TCP)。对源缓冲区媒体数据(packet)的操作,需建立几个中间环节的数据结构,只需将切割的媒体数据在内存移动一次,操作指向媒体数据的指针便能达到媒体数据迁移到目的缓冲区(page)的意图,其过程可用两个函数转换来表述:
ogg_stream_packetin()àogg_stream_pageout()。 将Ogg格式比特流逆映射还原为packets媒体流,以备播放解码或以RTP封装进行UDP传输 。其中间环节是把page中的segment单元数据按顺序重组为packet,同样媒体数据在内存中的复制只有一次,其过程可用三个函数转换来表述:ogg_sync_pageout()à ogg_stream_pagein ()à ogg_stream_packetout(),媒体数据复制发生在第一个函数ogg_sync_pageout()。
Ogg映射与逆映射的功能都体现在ogg函数库中,当前最新版本为libogg-1.1.3。

4 结束语    

    Ogg格式是在吸收其它流媒体文件格式优点的基础上针对具有“packet”包边界形式的媒体流而制定的利于其存储和传输的开源流媒体文件格式,在icecast流服务器的传输中得到了很好的应用;根据icecast官方网站公布其测试结果,在GB主干网的条件下对Oggvorbis音频传输的客户端并发流可达14000个。更为重要的是,作为流媒体技术的核心环节,大多数流媒体文件格式至今仍没有完全公开,且受专利保护。要在流媒体技术和应用飞速 发展的今天占得一席之地,遵从GNU/GPL协定,走开源之路,发展不受知识产权约束的流媒体文件格式是紧追先进流媒体技术的较佳选择。

 


你可能感兴趣的:(音视频,ffmpeg)