Android 12(S) MultiMedia(十一)從MPEG2TSExtractor瞭解MPEG2-TS
阿新 • • 發佈:2022-04-13
本節主要學習內容是看看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(boolisInit) { 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的調整欄位後為有效載荷 |
愛丁堡