Как извлечь Timstemp кластера из MKV чтения файла двоичного файла - PullRequest
3 голосов
/ 09 марта 2020

Когда я читаю двоичный файл mkv, идентификатор кластера составляет байт E7, а метка времени имеет значение unsigned int, но когда я читаю его, 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;
}

Is есть что-то, что я пропустил?

1 Ответ

1 голос
/ 14 марта 2020
Двоичные данные

MKV имеют формат EBML , а целое число без знака может иметь переменный размер. Размер переменной int может состоять из переменного числа октетов (может иметь разный размер в байтах).

Каждое целое число переменного размера начинается с VINT_WIDTH, за которым следует VINT_MARKER. VINT_WIDTH является последовательностью из нуля или более битов значения 0 и заканчивается VINT_MARKER, который является единственным битом значения 1. Общая длина в битах как VINT_WIDTH, так и VINT_MARKER является общей длиной в октетах целого числа переменного размера.

Одиночный бит 1 запускает целое число переменного размера с длиной в один октет. Последовательность битов 01 запускает целое число переменного размера длиной два октета. 001 запускает целочисленное значение переменного размера длиной в три октета и т. Д., При этом каждый дополнительный 0-разрядный бит добавляет один октет к длине целого числа переменного размера.

Положение первого ' 1 'бит в первом байте переменного размера целое число обозначает размер в байтах. Если он находится на первой позиции

1XXXXXXX (здесь я использую 'X' для других битов числа, кроме части длины)

, тогда переменная составляет один байт long и остальные биты после первого бита '1' (в данном случае 7 младших битов) являются двоичным представлением числа. Переменный размер int , начинающийся с

0000001X XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX

- это длина в семь байт для первого '1' бита здесь седьмая позиция.

Итак, сначала вам нужно прочитать первый байт числа и найти позицию N первого бита '1', а затем прочитать все число 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;
}
...