MP4 Muxer的作法,網路上可以找到上百篇,不過On the fly的不多,只好自己動手做了
在這邊走了不少冤枉路,寫起來免得忘記
目標寫一個Library,從Raw H264 Stream和Raw G711 Stream中,打包變成MP4的故事
Libavformat / Libavcodec
大部分多媒體的問題,絕對少不了跟ffmpeg打交道的經驗,所以也在社面花了一點時間
Raw H264 to MP4
由於我們不是走正規路線使用,Google了一下找到Stackoverflow的這篇,沒有什麼問題,不過AV Sync又是另外一個問題,之後再談
G711 to AAC
這點實在搞得我很頭大啊
G711 to PCM這段其實還好,相關的程式碼 這裡有
問題在於PCM轉AAC,其中有兩個困難處
– G711的Sample Format是AV_SAMPLE_FMT_S16,不考慮外接AAC Enocder的話,FFmpeg AAC Encoder的Sample Format是AV_SAMPLE_FMT_FLTP,所以需要透過Resampling轉換
– 轉換過的Sample樹不一定跟原先取樣數相同,所以還需要放到Audio Fifo Buffer,等到數目夠的才處理
大致流程可以參考FFMmpeg的範例,一整個麻煩
AV Sync
好不容易通過前兩關,卻死在第三關,也是照FFMpeg的範例來處理PTS的問題,結果怎麼調都失敗,果斷放棄這絲路了,另謀其他做法
libmp4v2 / EasyAACEncoder
不得不大力稱讚EasyAACEncoder這個Project,把G711 to AAC這段難點彌平了不少,不過還是採到坑了
libmp4v2網路上教學不少,就不特別獎了,來說一下遇到那些問題
MP4裡面要放Raw Stream
所以在 PcmToAac.cpp
裡面要做如下修改
1 | /*0 - raw; 1 - ADTS*/ |
看起來都沒問題的部分最後變成夢靨啊..
AV Sync
在上面遇到的問題在這邊也遇到,不過這次找到可行解了,可喜可賀
解法在此
Quicktime issue
路出來的檔案在大部分撥放軟體都沒問題,結果在Quicktime和iOS出問題,Quicktime波一波聲音就消失了,也沒有Open Source可以參考,於是就進入鬼打牆,瞎子摸象的階段
經過多方查證之下,MP4 Info沒什麼問題,不是libmp4v2的問題
試著用ffmpeg轉檔,啜了以下實驗
– 用FFmpeg轉檔,Video / Audio 照舊,QuickTime還是不能播
– 用FFmpeg轉檔,Video照舊,Auido 用FFmpeg AAC Encoder,結果他能撥了
不過我不想走回第一條的路,那太可怕了
不過在ffmpeg轉檔時看到一行
1 | Multiple frames in a packet. |
這行一直被我忽略掉,因為ffplay沒抱怨,不過走投無路了只好猜是AAC的問題
Revisist EasyAACEncoder
既然懷疑一個Packet裡面有多個Fframe
那可能是
1 | Easy_AACEncoder_Encode(handle, pbG726Buffer, gBytesRead, pbAACBuffer, &out_len) |
有多個frame吐出來,不過沒有ADTS Header我們無法分辨出FFrame Boundary,於是我們又把ADTS家回去了
1 | /*0 - raw; 1 - ADTS*/ |
之在外面切割Frame,在一個一個填入MP4,這下Quicktime和iOS就正常了
Conclusion
走了這麼多冤枉路,終於完成一個能動的方案
用FFMpeg方案沒有不好,不過我方面的經驗不夠,之前也沒做太多涉獵
用第二個方案也是遇到了困難,有碰到問題才會知道痛