2015-06-04 32 views
0

我想我在這裏有一個隧道視覺,所以我需要你的幫助。C++ - MPEG TS - 解析頭 - PID搞砸了 - 大端32位掩碼

我想解析一個MPEG Transport-stream file,我被困在Header上,在wiki上你會看到爲了從4字節頭中提取數據而提供了一些32位的BE MASK。我的代碼考慮了endianess(我認爲),並在檢測到您運行的是小端時反轉了字節。然後,我投了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; 
} 

下面是應該有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 

不知怎的,它被再次逆轉,我不知道爲什麼一個PID的頭示例...

+0

您不需要反轉字節,因爲您沒有讀取整數,但是您正在讀取4個字節。他們將始終以正確的順序。但是使用bitset輸出它們可能是個問題。 – wimh

+0

因爲我需要在一個int上應用MASK(BE),並且我的機器是LE,所以如果我在轉換之前沒有反轉,它會搞砸了,對吧?當我離開它時,bools設置不正確,我也沒有看到PID :( – Maresh

+1

我看到,你確實使用了整數,但是如果你使用'0x1fff00',你應該將結果移位8位(在所以你的例子有PID 33. – wimh

回答

0

好,所以問題是PID的13位位於str[1]str[2]這意味着在鑄造*((int *)str)並應用掩碼後,仍然會有8位從最後一個字節str[3]開始的0位。

解決方案:

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

感謝@Wimmel。