C++ - MPEG TS - Заголовок синтаксического анализа - PID перепутан - Маска 32 бита с обратным порядком байтов

Я думаю, у меня тут туннельное зрение, поэтому мне нужна твоя помощь.

Я пытаюсь проанализировать файл MPEG Transport-stream и застрял на заголовке, на В вики вы увидите, что некоторые 32-битные BE MASK предоставляются для извлечения данных из 4-байтового заголовка. Мой код учитывает порядок следования байтов (я думаю) и переворачивает байты, если обнаруживает, что вы работаете с прямым порядком байтов. Затем я привожу char* к int и применяю маску, все значения выглядят нормально, но PID испорчен, и я не понимаю, почему...

определение заголовка

namespace ts {

#define SYNC_BYTE_MASK 0xff000000
#define TEI_MASK 0x800000
#define PAYLOAD_START_MASK 0x400000
#define PRIORITY_MASK 0x200000
#define PID_MASK 0x1fff00
#define SCRAMBLING_CTL_MASK 0xc0
#define ADAPTATION_FIELD_MASK 0x20
#define HAS_PAYLOAD_MASK 0x10
#define COUNTER_MASK 0xf

#define HEADER_BYTES 4
#define HEADER_BITS 8 * HEADER_BYTES

class Header {

public:
    std::bitset<HEADER_BITS> *full;

    unsigned char _syncByte;
    bool _tei;
    bool _payloadStart;
    bool _priority;
    int16_t _pid;
    std::bitset<2> *_scramblingCtl;
    bool _adaptationField;
    bool _hasPayload;
    int _counter;

    Header(const char *, size_t);
    ~Header();

    const std::string toString();
    bool isValid();

};

}

Назначение значений заголовка

ts::Header::Header(const char *header, size_t n) {
    uint32_t bytes = reverseLE(header, n);

    // just for display
    char t[4];
    memcpy(t, header, 4);
    std::cout << "Original: " << std::bitset<32>(*((uint32_t *)t)) << std::endl;
    this->full = new std::bitset<HEADER_BITS>(bytes);

    uint32_t tmp = bytes & SYNC_BYTE_MASK;
    this->_syncByte = ((char *)&tmp)[n - 1];

    this->_tei = bytes & TEI_MASK;
    this->_payloadStart = bytes & PAYLOAD_START_MASK;
    this->_priority = bytes & PRIORITY_MASK;
    this->_pid = bytes & PID_MASK; // THIS ONE IS MESSED UP !!
    this->_scramblingCtl = new std::bitset<2>(bytes & SCRAMBLING_CTL_MASK);
    this->_adaptationField = bytes & ADAPTATION_FIELD_MASK;
    this->_hasPayload = bytes & HAS_PAYLOAD_MASK;
    this->_counter = bytes & COUNTER_MASK;
}

Функции для реверса

   #include "utils.h"

int is_big_endian(void)
{
    union {
        uint32_t i;
        char c[4];
    } e = { 0x01000000 };

    return e.c[0];
}

void swap(char *s, int a, int b) {
    char tmp;

    tmp = s[a];
    s[a] = s[b];
    s[b] = tmp;
}

// Converts string to int taking endianess into account
uint32_t reverseLE(const char *bits, size_t n) {
    uint32_t ret = 0;
    char *cp = (char *)malloc(n * sizeof(char));

    memcpy(cp, bits, n);
    if ( ! is_big_endian() ) {
        for (int i = 0; i < n / 2; i++)
            swap(cp, i, n - 1 - i);
    }

    ret = *((uint32_t *)cp);
    free(cp);
    return ret;
}

Вот пример заголовка, который должен иметь PID 33.

Original: 00010010001000010000000001000111
Binary: 01000111000000000010000100010010
Sync byte: G
TEI: 0
Payload start: 0
Priority: 0
PID: 8448 0010000100000000
Scrambling Ctl: 00
Adaptation field: 0
Has Payload: 1
Counter: 2

Каким-то образом он снова переворачивается, и я не понимаю, почему...


person Maresh    schedule 04.06.2015    source источник
comment
Вам не нужно переворачивать байты, так как вы читаете не целое число, а 4 байта. Они всегда будут в правильном порядке. Но вывод их с использованием битового набора может быть проблемой.   -  person wimh    schedule 04.06.2015
comment
Я реверсирую, потому что мне нужно применить MASK (BE) к int, а моя машина LE, поэтому, если я не реверсирую перед приведением, это испортится, верно? Когда я оставляю все как есть, логические значения не устанавливаются должным образом, как и PID :(   -  person Maresh    schedule 04.06.2015
comment
Я вижу, вы используете целые числа. Но если вы И с 0x1fff00, вы должны сдвинуть результат на 8 бит (нули в конце). Итак, ваш пример имеет PID 33.   -  person wimh    schedule 04.06.2015
comment
Ах! хорошо, я должен учитывать 4-й байт ... Отправьте ответ, если вам небезразличны точки репутации :). Спасибо !   -  person Maresh    schedule 04.06.2015


Ответы (1)


Итак, проблема заключалась в том, что 13 бит PID расположены в str[1] и str[2], что означает, что после приведения *((int *)str) и применения маски остается 8 завершающих 0 бит от последнего байта str[3].

Решение:

this->_pid = bytes & PID_MASK; 
this->_pid >>= 8;

Благодаря @Wimmel.

person Maresh    schedule 04.06.2015