參照tstools這個開源項目完成了CMMB的merge aac with 264 to TS.
在做的過程中,分成了幾個階段。先試著將H264打包成TS,這花了最大的精力和時間;接著將AAC打包成TS;最后將其合并起來。
一、處理H264
1、H264 -> pes
在查找了大量資料后,對H264有了初步的認識。H264的結構從大到小依次為視頻序列(sequence )、圖像(picture ,相當于幀)、片組、片(slice)、宏塊(MacroBlock)、子塊(SubBlock)。
其中,幀率是針對于圖像來說的,例如25Hz的幀率,就差不多是每個40ms顯示1個圖像。
圖像分為 I圖像、P圖像、B圖像。
每個圖像又由多個片組組成,片組由多個片組成。
每個片又由多個宏塊組成。片分為I_slice、P_slice、B_slice。宏塊有I、P、B三種宏塊。
I_slice里只有I_MB, p_slice里可有P_MB和I_MB, B_slice里可有B_MB和I_MB。
通常的一個圖像里就含一種片,這次的CMMB里的H264比較簡單,是Baseline的profile,只含有I、P幀,而且每個圖像就1個slice。
對于H264按功能層次劃分,又分為視頻編碼層VCL(video coding layer)和網絡抽象層 NAL(Network abstraction layer).
每個NAL單元包含:NAl頭+負荷
NAl的頭一般為00 00 01 或者00 00 00 01,然后到下一個頭之間都為這一個nalu的數據。
所以,對于封裝成ts流,只需要去讀取H264的原始文件,然后找到這個nal頭,再將這個nalu(包含頭和負荷)當成數據打包成pes再打成ts即可。
在打包成pes的時候,需要注意的一個問題就是pts/dts,其單位應該是系統(tǒng)時鐘。需要在找到每個圖像的起始slice的時候,在打包成pes的時候加上pts/dts。這次的CMMB中,其視頻幀只含I/P圖像(幀),且每個圖像只有1個片,所以就在讀取264原始數據時讀到I_slice或P_slice的時候,一并打入pts。CMMB流正好又有現成的pts,只需讀出來,按照CMMB中的換算方法,每22500就是1秒,就能得出pts的值,而不需要我自己手動的去計算添加。
例如,視頻幀率為25HZ的時候,即1秒25幀,每幀的間隔40ms。按90Khz的視頻頻率來算的話,其對應的系統(tǒng)時鐘數應該是
1/25*90000 = 3600 個clk。
所以當分析pes時,其pts字段的33個bit算出來的話,就是按這個clk為單位的。相鄰的視頻幀的pts之差值為3600.
2、pes -> ts
h264打包成ts的時候,還需要打入pat和pmt。pmt里指定了視頻的類型和pid。
pes打包的時候,按ts協(xié)議格式封裝即可。
PCR使用和視頻一樣的pid,這里把pts當成pcr打進ts包。
二、處理AAC
AAC的ts封裝相對于H264來說就簡單多了。這次的CMMB采用的是aac的adts格式封裝,同h264類似,也有其自己的分界符,然后兩分界符之間就是數據,分界符為1111 1111 1111,即FFF。依次讀取AAC的原始文件,遇到一個FFF時,將其后的數據連同這個FFF的頭看成整體,作為負載封入PES。同樣的,每幀都需要打入pts。CMMB流中也附有AAC的pts,讀取后計算寫入PES即可。也省了我去根據采樣率,每幀的樣本率去計算pts。
三、合并H264和AAC的ts流
做完了上兩步工作,最后一步就更簡單了。
先是打入PAT、PMT。PMT需要稍微修改,因為加入了音頻,所以要在其中指明音頻的類型和pid。
接著就是視頻、音頻的ts包依次打。打的時候稍微注意要判斷下視頻和音頻的pts值,保持同步。
對于H264更底層的東西,就沒研究下去了。對于H264的SPS獲取PTS,也沒整太明白。還有PCR這方面,都還不太清楚。后面再找時間慢慢研究吧~