EBML的全称为Extensible Binary Meta Language,一种更加灵活的音视频框架,扩展性能更为强大,支持更多格式音视频扩展。EBML能够确保视频、音频容器格式支持将来新出现的压缩格式。这种架构允许增加对容器格式的新特性,同时不破坏原有软件和文件的向后兼容性。支持动态音频编码(VBR)、动态帧率视频编码(VFR)。此格式已经应用于多媒体容器格式MATROSKA(MKV)。
EBML使用不定长整数,这种方式相对于固定长度的32位/64位字长的整数值更节约空间,放置的位置也不受字节对齐约束。这种长度编码方式来自于UTF-8编码格式。
1、可变长无符号整数值(vint)
一个整数的长度可以通过下面的方式获得:
length = 1 + number_of_leading_zero_bits
所有的整数都使用大印第安序来存储。number_of_leading_zero_bits的值可以大于7,这种情况下第一个字节就是0x00,但是这种情况仅仅在整数的长度超过56个bit时才需要。
一个简单的例子:0X3A41FE
第一个字节0X3A的二进制码是0011 1010,包含两个前缀0比特,因此长度是三个字节。0011 1010中的第一个1仅仅是为了标识前缀0的结束,将该bit位去掉后0X3A41FE就转化为0X1A41FE,这个数值就是所需要的那三个字节。
当然,0X1A41FE也可以写成0X101A41FE或者0X08001A41FE,对于0X101A41FE,第一个字节0X10的二进制码是0001 0000,因此长度是四个字节;对于0X08001A41FE,第一个字节0X08的二进制码是0000 1000,因此长度是五个字节。不过在实际的编码过程中不会这样用,浪费空间。
2、可变长有符号整数值(svint)
对于有符号整数的处理过程是这样的,首先将该有符号整数看作无符号整数,然后减去vsint_subtr[length-1]。
vsint_subtr[length-1]的定义如下所示:
__int64 vsint_subtr [] = { 0x3F, 0x1FFF, 0x0FFFFF, 0x07FFFFFF,
0x03FFFFFFFF, 0x01FFFFFFFFFF,
0x00FFFFFFFFFFFFFF, 0x007FFFFFFFFFFFFF };
一个简单的例子:0x5ED3
首先将它看作无符号整数处理,分析得length为2,将前缀去掉,0x5ED3------>0x1ED3;
然后,0x1ED3 - vsint_subtr[length -1] = 0x1ED3 - 0x1FFF = -0x12C(-300)。
3、EBML元素
EBML是类似于XML那样的层次化结构,每一个元素都有它的ID(就是元素名)和值。另外由于是二进制存储,还含有一个长度值来记录它的值的长度,每个元素的排列是ID,长度,值。每个EBML元素可以用下列方式来存储:
typedef struct {
vint ID // EBML-ID
vint size // size of element
char[size] data // data
} EBML_ELEMENT;
包含其它元素的元素被称EBML Master Elements。子元素的排列顺序是任意的,当然在某些情况下推荐使用特定的顺序。
以MKV文件的一段码流为例,如下:
42 82 88 6D 61 74 72 6F 73 6B 61
首先分析ID,第一个字节为0X42,对应的二进制码为0100 0010。由于是01开头所以知道ID的长度是2个字节,于是0X4282就是它的ID。
然后分析长度和值,0X88对应的二进制码为1000 1000,以1开头,于是长度只有1字节,去掉前缀1后值为0001000,也就是8,即是说后8个字节都是它的值。查表可知ID 42 82也就是DocType,它的值是字符串,于是把后面8字节6D 61 74 72 6F 73 6B 61按UTF-8解码可得"matroska"。