2012年10月31日 星期三

[多媒體] FLV文件格式解析 Part 3 - 實作

隨著年紀越來越大,人也越來越懶,能夠用現成的就不會想自己動手作。可惜現實就是這樣,越不想動手做,老天就越喜歡挖這樣的洞讓你跳...

根據 H.264 to FLV 的條件去拜完 Google 大神之後,祂老人家給我一個答案:有一份叫做 h264toFlv 的原始碼 (from pudn, in C)。實際編譯能過,也能成功的執行,能夠把 input.264 轉成 out.flv。雖然隨該套件附 H.264 raw 檔產生出來的 out.flv 有問題,不過隨手用 ffmpeg 產生一個 H.264 raw file 丟給 h264toFlv 之後,的確能夠產生一個可使用VLC player播放的 .flv 檔。

然而,事實往往比較坎柯。不知道為什麼,自從 demo 完之後,無論我用 ffmpeg 如何產生 H.264 檔,雖然 VLC player 依然可以播放產生出來的 .flv,但是卻發生 flash player 無法接受的鬼打牆現象。因此,小弟的漫漫 FLV 文件格式攻關之旅,從此揭開序幕...

參閱網路上能夠找到關於 FLV 相關資訊,各文件都告訴我,h264toFlv 生出來的 FLV 文件格式是正確的。使用 FlvParser 來解析,也能夠順利解開整個 FLV 文件包,如下圖所示:


對照使用 ffmpeg 產生出來的 .flv 檔 (指令如下),兩相比較會發現其實 h264toFlv 跟 ffmpeg 產生出來的 .flv 是有些微差異的 (廢話!)
# ffmpeg -i imput.mp4 -vcodec copy -an out.flv
使用 ffmpeg 產生出來的 .flv 檔

 使用 h264toFlv 產生出來的 .flv 檔

經過廣泛 (漫無目的) 的搜尋相關資料之後,看到有人對於 H.264 資料流的解釋,每個 Nal 都是以 0x00 0x00 0x00 0x01 作為開頭。於是用Hex編輯軟體打開 H.264 進行人工比對,發現原來有部份切割段落是以 0x00 0x00 0x01 作為分割記號,因此造成部份 H.264 Nal 包解析錯誤
ffmpeg 產生出來的 H.264 檔
 mp4box 產生出來的 H.264 檔

然而故事繼續發展下去,當有部份 H.264 檔的 Nal 包解析開始變得很奇怪,具體來說就是 Nal包的順序會有錯置的狀況。可以發現 H.264中第一個 Nal 包卻被放在 .flv 的第二個 tag 中。繼續無止盡的爬文...
ffmpeg 產生的 .flv 檔案 (另外一個mp4檔)
 ffmpeg 產生的 H.264 檔案 (另外一個mp4檔)

終於找到關於 Video tag 中對於 H.264 資訊的解析文章 [#1]。對照之下才發現 .flv 的第一個 tag 也具有 header 的資訊效果 (SPS + PPS),以及第一個資料 tag (第二個 Video tag) 的格式是如何形成的。
重新檢視 h264toFlv,發現存在了不少問題:
1. 對於 Nal 開頭的判定 (0x00 0x00 0x00 0x00 與 0x00 0x00 0x01)
2. SEI 資訊的處理。必須將 SEI資訊、分隔符號 移至第一個資料 tag
3. 資料 tag 格式解讀錯誤。tag header 應該為 09 xx xx xx oo oo oo oo x7 01 00 00 00 ss ss ss ss dd ... ss ss ss ss dd ... ss ss ss ss dd ... ... ... ... XX XX XX XX 09 .................................
其中,XX XX XX XX 為 xx xx xx +12。00 00 00 並非為 offset。ss ss ss ss dd ... 是 Nal 資料包。

終於... 修改之後的 h264toFlv,產生出來的 .flv 能夠正常的被 flash player 解讀



[ 補充 ]
1. 若是影片播放有不順暢的現象,可能是 video frame (key frame/slice) 不到位 (隨著 timestamp) 所導致。解決辦法為使用 flvParser 觀察做出來的資料包,觀察每個 video tag 是否都有 video frame



[ 結論 ]
1. Nal 的開頭並非只有 0x00 0x00 0x00 0x01 還可以是 0x00 0x00 0x01

2. 每個 timestamp 的 video tag 都必須包含一個 slice(0x01) or key frame(0x05),否則影片會有卡卡的現象

3. 同樣的 .mp4 檔案,ffmpeg 與 mp4Box 所產生的 H.264 會有些微不同
# ffmpeg -i input.mp4 -vcodec copy -bsf h264_mp4toannexb -an -f h264 out.h264
# mp4box -raw 1 input.mp4   (產生 out.h264)

4. VLC player 是很強大的,容錯程度頗高,很適合用來安慰自己做出來的作品是可用的

5. 對於 Programmer 瞭解問題點之後要解決問題是很容易的(?),但是如何找出問題點則是個大學問。花了一個禮拜的時間去找問題點,但是解決只需要半天的時間



[ Reference ]
#1> h264toFlv package

1 則留言:

Unknown 提到...

hi~根據您的分析,所以pudn上所提供的h264toFlv是無法被adobe flash player 所播放,不知道大大是否可提供您修改後的h264toflv 的 source code??給我參考??
謝謝