2017年1月27日 星期五

將 H.265 的資料封裝成 MP4 檔案

此篇紀錄將 H.265 資料儲存成 mp4 檔案的過程。
測試環境設定:
  • MAC OS X EI Capitan -- version 10.11.6
  • live555 -- version 2016/10/12
  • ffmpeg -- version 3.2

1. 下載並編譯 live555
$ git clone https://github.com/xanview/live555
$ cd live555
$ ./genMakefiles macosx
$ make

2. 下載 h.265 測試檔案,並使用 FFmpeg 將資料封裝成  MP4
a. download surfing.265 from http://www.live555.com/liveMedia/public/265/ 
b. copy surfing.265 to the testProgs directory, rename the file to test.265 
c. download the latest ffmpeg and ffplay from http://evermeet.cx/ffmpeg/ 
d. run ffmpeg, and make sure it was built with "--enable-libx265" flag 
LiaotekiMacBook-Pro:testProgs liaokuohsun$ ./ffmpeg
ffmpeg version 3.2-tessus Copyright (c) 2000-2016 the FFmpeg developers
  built with Apple LLVM version 8.0.0 (clang-800.0.38)
  configuration: --cc=/usr/bin/clang --prefix=/opt/ffmpeg --extra-version=tessus --enable-avisynth --enable-fontconfig --enable-gpl --enable-libass --enable-libbluray --enable-libfreetype --enable-libgsm --enable-libmodplug --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopus --enable-libschroedinger --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libtheora --enable-libvidstab --enable-libvo-amrwbenc --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libx264 --enable-libx265 --enable-libxavs --enable-libxvid --enable-libzmq --enable-version3 --disable-ffplay --disable-indev=qtkit --disable-indev=x11grab_xcb
  libavutil      55. 34.100 / 55. 34.100
  libavcodec     57. 64.100 / 57. 64.100
  libavformat    57. 56.100 / 57. 56.100
  libavdevice    57.  1.100 / 57.  1.100
  libavfilter     6. 65.100 /  6. 65.100
  libswscale      4.  2.100 /  4.  2.100
  libswresample   2.  3.100 /  2.  3.100
  libpostproc    54.  1.100 / 54.  1.100
e. check test.265 media information 
$ ./ffmpeg -i test.265
Input #0, hevc, from 'test.265':
  Duration: N/A, bitrate: N/A
    Stream #0:0: Video: hevc, yuv420p(tv), 1280x720, 25 fps, 25 tbr, 1200k tbn, 25 tbc 
f. play test.265 media information
$ ./ffplay test.265 
g. use ffmpeg to put hevc data into mp4 container
$ ./ffmpeg -i test.265 -acodec copy -vcodec copy test_h265.mp4 
h. use ffmpeg to put hevc data into mp4 container
$ ./ffmpeg -i test.265 -acodec copy -vcodec copy test_h265.mp4 
Note
  • The data in test.265 is NAL units (start code prefixes). We can search "00 00 00 01" to find the start code 
  • The data in test_h265.mp4 will replace the start code with 4-byt size fields. 
  • Both test.265 and test_h265.mp4 can play by ffplay

3. 觀察 mp4 封裝資訊
若要觀察網路封包格式,可以使用 live555 的測試程式,啟動 RTSP server,並透過 ffmpeg 將檔案儲存為 mp4 格式。 
$ ./testOnDemandRTSPServer

$ ./ffmpeg -i rtsp://172.19.19.50:8554/h265ESVideoTest  -vcodec copy h265_ex3.mp4 
此 mp4 檔可以使用 VLC 與 FFMPEG 進行播放,檔案封裝方式是沒問題的。
註1:testH265VideoStreamer 預設採用 multicast 進行播放,不適合進行此項測試。
註2:openRTSP 能夠將某些媒體封裝成 mp4 檔案,但並無法將 h.265 封裝成 mp4,因此若要自行實作 H265 to MP4,還是應該要參考 FFmpeg 。

我們可由 SDP 得知 h.265 的 SPS/PPS/VPS 如下:
sprop-vps=QAEMAf//AIAAAAMAAAMAAAMAAAMAALUCQA==;
sprop-sps=QgEBAIAAAAMAAAMAAAMAAAMAAKACgIAtH+W1kkbQzkkktySqSfKSyA==;
sprop-pps=RAHBpVgeSA==

gpac 取得最新版本 mp4box,設定 alias MP4Box="/Applications/Osmo4.app/Contents/MacOS/MP4Box" 以方便存取,接著執行 MP4Box  h265_ex3.mp4  -diso,將所有資訊都輸至 h265_ex3_info.xml。
此時可以看到 SPS/PPS/VPS 被封裝在 hvcC box 之內,並且其 NALU type 分別是 32,33,34。

比較 xml 與 SDP 內的 SPS/PPS/VPS 內容,可以發現內容一致。 
(可透過 http://tomeko.net/online_tools/base64.php?lang=en 進行 Base64轉換)

4. 自行撰寫程式,將 H.265 封裝成 mp4
此處作法與之前 H.264 封裝類似,差異處只在於 H.265 多了一個 VPS,ffmpeg 的封裝實作可以參考 hevc_mp4toannexb_bsf.c。作法原理是使用 FFmpeg API,將 SPS/PPS/VPS 都設定到 extradata 即可。以上述資料為例,封裝之後,extradata 內容應該如下:

VPS = 40010C01FFFF00800000030000030000030000030000B50240,SPS=42010100800000030000030000030000030000A00280802D1FE5B59246D0CE4924B724AA49F292C8,
PPS=4401C1A5581E48

實際程式範例可以參考 https://github.com/alb423/iFrameExtractor,此範例可在 iOS simulator 上正常運行。


參考資料: