[FFmpeg] Video4Linux2 におけるピクセルフォーマットと iOS へのストリーミング

スポンサーリンク

環境

iOS 6.1 (10B143) の iPhone 5 と iPad(3rd)
FFmepg 0.11.2 (1.x 系も)

内容

下記のような FFmpeg の設定で,USB カメラの映像と音声を Video4Linux2 でリアルタイムにキャプチャしながら MPEG2-TS にエンコードし,HTTP Live Streaming の方式で iOS にストリーミングする場合,iOS でストリーミングの再生が行われません.
具体的には,「操作を完了できませんでした」というポップアップが表示されます.

/usr/local/ffmpeg-0.11.2/bin/ffmpeg -f video4linux2 -s 960x540 -r 30 -i /dev/video0 -f alsa -i hw:0,0 -acodec libfaac -ab 128k -ac 2 -s 960x540 -vcodec libx264 -preset ultrafast -b:v 3000k -threads 3 -t 3600 -f mpegts -y /tmp/hls/hls3000.ts

FFmpeg のログを見てみると,H.264 エンコード後のプロファイルが High で,ピクセルフォーマットが yuv422p となっています.

Technical Note TN2224 Best Practices for Creating and Deploying HTTP Live Streaming Media for the iPhone and iPad の Recommended Encoding Settings for HTTP Live Streaming Media を見ると,High プロファイルには対応しているようなので,yuv422p なのが原因?と推測してみます.

Input #0, video4linux2,v4l2, from '/dev/video0':
Duration: N/A, start: 35064.013258, bitrate: 167116 kb/s
Stream #0:0: Video: rawvideo (YUY2 / 0x32595559), yuyv422, 960x544, 167116 kb/s, 20 fps, 15.08 tbr, 1000k tbn, 1000k tbc

[scale @ 0xd036e0] w:960 h:544 fmt:yuyv422 sar:0/1 -> w:960 h:540 fmt:yuv422p sar:0/1 flags:0x4
[libx264 @ 0xd14ec0] using cpu capabilities: MMX2 SSE2Fast SSSE3 FastShuffle SSE4.2 AVX
[libx264 @ 0xd14ec0] profile High 4:2:2, level 3.1, 4:2:2 8-bit

Output #0, mpegts, to '/tmp/hls/hls3000.ts':
Metadata:
encoder         : Lavf54.61.104
Stream #0:0: Video: h264, yuv422p, 960x540, q=-1--1, 3000 kb/s, 90k tbn, 15.08 tbc
Stream #0:1: Audio: aac, 32000 Hz, stereo, s16, 128 kb/s
Stream mapping:
Stream #0:0 -> #0:0 (rawvideo -> libx264)
Stream #1:0 -> #0:1 (pcm_s16le -> libfaac)

上記の通り,Video4Linux2 での H.264 エンコード時にピクセルフォーマットを指定しないと,デフォルトでは yuv422p となるようなので,強制的に yuv420p とするように,オプション -pix_fmt yuv420p を付けてエンコードしてみます.

/usr/local/ffmpeg-0.11.2/bin/ffmpeg -f video4linux2 -s 960x540 -r 30 -i /dev/video0 -f alsa -i hw:0,0 -acodec libfaac -ab 128k -ac 2 -s 960x540 -vcodec libx264 -preset ultrafast -b:v 3000k -pix_fmt yuv420p -threads 3 -t 3600 -f mpegts -y /tmp/hls/hls3000.ts

FFmpeg のログは下記の通り.
今度は正常にストリームが再生されました.

Input #0, video4linux2,v4l2, from '/dev/video0':
Duration: N/A, start: 34967.677276, bitrate: 167116 kb/s
Stream #0:0: Video: rawvideo (YUY2 / 0x32595559), yuyv422, 960x544, 167116 kb/s, 20 fps, 15.08 tbr, 1000k tbn, 1000k tbc

[scale @ 0xd2c4c0] w:960 h:544 fmt:yuyv422 sar:0/1 -> w:960 h:540 fmt:yuv420p sar:0/1 flags:0x4
[libx264 @ 0xd4c140] using cpu capabilities: MMX2 SSE2Fast SSSE3 FastShuffle SSE4.2 AVX
[libx264 @ 0xd4c140] profile Constrained Baseline, level 3.1

Output #0, mpegts, to '/tmp/hls/hls3000.ts':
Metadata:
encoder         : Lavf54.61.104
Stream #0:0: Video: h264, yuv420p, 960x540, q=-1--1, 3000 kb/s, 90k tbn, 15.08 tbc
Stream #0:1: Audio: aac, 32000 Hz, stereo, s16, 128 kb/s
Stream mapping:
Stream #0:0 -> #0:0 (rawvideo -> libx264)
Stream #1:0 -> #0:1 (pcm_s16le -> libfaac)

Android ではどうか

Nexus 7 (Android 4.2.1) でも同様に試してみたところ,yuv422p の場合は,iOS のように再生自体が行われないことはありませんが,再生時,映像は真っ暗で音声のみが再生されます.
yuv420p の場合は,iOS 同様に正常に再生されました.