1. 程式人生 > 其它 >Android 12(S) MultiMedia(十一)從MPEG2TSExtractor瞭解MPEG2-TS

Android 12(S) MultiMedia(十一)從MPEG2TSExtractor瞭解MPEG2-TS

本節主要學習內容是看看MPEG2TSExtractor是如何處理TS流的。

相關程式碼位置:

frameworks/av/media/extractors/mpeg2/MPEG2TSExtractor.cpp

frameworks/av/media/libstagefright/mpeg2ts/ATSParser.cpp

 

MPEG2TSExtractor的建構函式中有個init方法用於載入ts流所包含的資訊,而關鍵方法是feedMore,讀完這個方法大致就可以直到ts包的結構以及ts流的組成,再回過頭來看MPEG2TSExtractor中的方法就會很簡單了。

status_t MPEG2TSExtractor::feedMore(bool
isInit) { Mutex::Autolock autoLock(mLock); uint8_t packet[kTSPacketSize]; // 1、通過DataSource讀取一個ts packet ssize_t n = mDataSource->readAt(mOffset + mHeaderSkip, packet, kTSPacketSize); // 如果讀取到的位元組數小於188 if (n < (ssize_t)kTSPacketSize) { // 通知ATSParser讀取結束 if
(n >= 0) { mParser->signalEOS(ERROR_END_OF_STREAM); } // 如果讀取錯誤,返回-1,否則返回EOS return (n < 0) ? (status_t)n : ERROR_END_OF_STREAM; } // 利用當前的offset,建立一個同步點 ATSParser::SyncEvent event(mOffset); // 2、更新下次讀取的offset mOffset += mHeaderSkip + n;
// 3、呼叫ATSParser的方法進行demux status_t err = mParser->feedTSPacket(packet, kTSPacketSize, &event); if (event.hasReturnedData()) { if (isInit) { mLastSyncEvent = event; } else { addSyncPoint_l(event); } } return err; }

看起來feedMore這個方法並不複雜,但是feedTSPacket這個方法實現還是挺複雜的,接下來就來看看。

status_t ATSParser::feedTSPacket(const void *data, size_t size,
        SyncEvent *event) {
    if (size != kTSPacketSize) {
        ALOGE("Wrong TS packet size");
        return BAD_VALUE;
    }
    // 利用讀取的資料建立一個ABitReader
    ABitReader br((const uint8_t *)data, kTSPacketSize);
    // 真正開始demux
    return parseTS(&br, event);
}

feedTSPacket中建立了個ABitReader,用它可以實現按位讀取,最後就呼叫parseTS做真正的demux操作。下面先貼一個TS包包頭格式圖:

status_t ATSParser::parseTS(ABitReader *br, SyncEvent *event) {
    // 1、讀取同步位元組 8 bit,不是0x47則丟棄
   unsigned sync_byte = br->getBits(8);
    if (sync_byte != 0x47u) {
        ALOGE("[error] parseTS: return error as sync_byte=0x%x", sync_byte);
        return BAD_VALUE;
    }
    // 2、讀取傳輸誤差指示符 1bit
    if (br->getBits(1)) {  // transport_error_indicator
        // silently ignore.
        return OK;
    }
   // 3、讀取有效載荷單元起始指示符 1 bit
    unsigned payload_unit_start_indicator = br->getBits(1);
   // 4、讀取傳輸優先順序 1 bit
    MY_LOGV("transport_priority = %u", br->getBits(1));
   // 5、PID 13 bit
    unsigned PID = br->getBits(13);
   // 6、傳輸加擾控制 2 bit
    unsigned transport_scrambling_control = br->getBits(2);
   // 7、自適應欄位控制 2 bit
    unsigned adaptation_field_control = br->getBits(2);
   // 8、連續計數器 4 bit
    unsigned continuity_counter = br->getBits(4);

    status_t err = OK;

    // 9、判斷自適應欄位控制,如果是2或者3就呼叫parseAdaptationField
    unsigned random_access_indicator = 0;
    if (adaptation_field_control == 2 || adaptation_field_control == 3) {
        err = parseAdaptationField(br, PID, &random_access_indicator);
    }
    if (err == OK) {
        // 10、如果自適應欄位控制為1或者3,則呼叫parsePID
        if (adaptation_field_control == 1 || adaptation_field_control == 3) {
            err = parsePID(br, PID, continuity_counter,
                    payload_unit_start_indicator,
                    transport_scrambling_control,
                    random_access_indicator,
                    event);
        }
    }
    ++mNumTSPacketsParsed;
    return err;
}

上面的1 - 8步可以對應上ts包頭的結構。第9步會根據自適應欄位控制的值去做下一步操作,所謂自適應欄位控制,意思也就是它的值控制著自適應欄位的內容,下面看下值與內容的對照表

自適應欄位控制值 對應內容
00 保留
01 沒有調整欄位,只含有184bytes的有效載荷
10 沒有有效載荷,只含有183bytes的調整欄位
11 0~182bytes的調整欄位後為有效載荷

愛丁堡