Я думаю, что у меня здесь видение туннеля, поэтому мне нужна ваша помощь.
Я пытаюсь разобрать Файл транспортного потока MPEG и я застрял в Заголовке, в вики вы увидите, что для извлечения данных из 4-байтового заголовка предусмотрены некоторые 32-битные БЕЗ МАСКИ. Мой код учитывает порядок байтов (я думаю) и инвертирует байты, если обнаруживает, что вы работаете с прямым порядком байтов. Затем я привожу 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
Каким-то образом это снова меняется, и я не понимаю, почему …
Итак, проблема заключалась в том, что 13 бит PID расположены в str[1]
а также str[2]
что означает, что после кастинга *((int *)str)
и применяя маску, все еще есть 8 завершающих 0 битов из последнего байта str[3]
,
Решение:
this->_pid = bytes & PID_MASK;
this->_pid >>= 8;
Благодаря @ Wimmel.