3

当我读取二进制 mkv 时,集群的 id 是 E7 字节并且时间戳具有无符号整数值,但是当我读取它时,id 并没有给我正确的时间戳。

double mkVSParser::get_clusters_timestamps(char *&package,unsigned long &size)
{
      uint8_t *data_to_find = new uint8_t;
      *data_to_find=0xE7;//the id
      char * buffer = new char[sizeof (uint8_t)];
      uint8_t current_data[sizeof (uint8_t)];

      for(int i=0;i<size;i++)//finde the first 0xE7 in an cluster
      {
          memcpy(&buffer[0],&package[i],sizeof (uint8_t));

          memcpy(&current_data[0],buffer,sizeof (uint8_t));

          if (memcmp(data_to_find, current_data, sizeof (uint8_t)) == 0)
          {
              unsigned int timestemp;
              std::cout<<"position of byte =="<<i<<"and id =="<<(unsigned int)package[i]<<std::endl;

              memcpy(&timestemp,&package[i+1],sizeof(unsigned int));

              std::cout<<"cluster timestemp ="<<timestemp<<std::endl;
              return 0;
          }

            }

      return 0;
}

有什么我错过的吗?

4

1 回答 1

1

MKV 二进制数据采用EBML格式,无符号整数的大小可能是可变的。可变大小的 int可能由可变数量的八位字节组成(可能具有不同的字节大小)。

每个可变大小整数都以 VINT_WIDTH 开头,后跟 VINT_MARKER。VINT_WIDTH 是零位或多位 value 的序列,0并由 VINT_MARKER 终止,VINT_MARKER 是一位 value 1。VINT_WIDTH 和 VINT_MARKER 的总长度(以位为单位)是可变大小整数的总长度(以八位字节为单位)。

单个位1开始一个长度为一个八位字节的可变大小整数。位序列01以长度为两个八位字节的可变大小整数开始。001开始一个长度为三个八位字节的可变大小整数,依此类推,每增加一个 0 位,可变大小整数的长度就会增加一个八位字节。

可变大小整数的第一个字节中第一个“1”位的位置表示大小(以字节为单位)。如果它在第一个位置

1XXXXXXX(除了长度部分,我在这里用'X'表示数字的其他位)

那么变量是一个字节长,第一个“1”位之后的其余位(在这种情况下为 7 个低位)是数字的二进制表示。可变大小 int

0000001X XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX

是七个字节长,因为这里的第一个“1”位在第七位。

因此,首先您需要读取数字的第一个字节并找到第一个“1”位的位置N,然后读取整数N个字节长,忽略第一个“1”位(就像它是一个零位)。

constexpr uint8_t VarSizeIntLenMark(int length)
{
    return 1 << (8 - length); // set single bit at length's position
}

int VarSizeIntLen(const uint8_t* data)
{
    for (int i = 1; i <= 8; i++)
        if (VarSizeIntLenMark(i) & data[0]) return i;
    return 0;
}

uint64_t ReadVariableSizeInt(const uint8_t* data)
{
    int length = VarSizeIntLen(data[0]);
    uint64_t parsedValue = data[0] & (~VarSizeIntLenMark(length)); // invert VINT_MARKER bit
    for (int i = 1; i < length; i++) // read other bytes
        parsedValue = (parsedValue << 8) + data[i];
    return parsedValue;
}
于 2020-03-13T23:13:25.540 回答