0%

Experience on writing a on-the-fly mp4 muxer

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
2
/*0 - raw; 1 - ADTS*/
pConfiguration->outputFormat = 0;

看起來都沒問題的部分最後變成夢靨啊..

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
2
/*0 - raw; 1 - ADTS*/
pConfiguration->outputFormat = 1;

之在外面切割Frame,在一個一個填入MP4,這下Quicktime和iOS就正常了

Conclusion

走了這麼多冤枉路,終於完成一個能動的方案
用FFMpeg方案沒有不好,不過我方面的經驗不夠,之前也沒做太多涉獵
用第二個方案也是遇到了困難,有碰到問題才會知道痛