Raspberry PiでH.264エンコード

かつて Raspberry Piでh264動画をハードウェアエンコードする という記事の後に
(録画をWindowsのEPGDataCap_Bonでやって録画マシンと違い常時起きてるRaspberryPiにファイルを貯めていくという構成だったので)Raspberry PiでMPEG2-TSをH.264にしようとしてた事があった.その記事の主に,いくつかこちらでわかった事をブログにまとめるといいながら1年半ブログに書いていない事に今気がついてしまった.
忘れないうちに書きます.いまさらこの情報役に立つかなあ…….

2,3日試行錯誤してたと思うのだけどその結果がこちら.
#!/usr/bin/bash
#
# Usage: mpegts2h264.sh <src.ts> <dst.mp4>
#
program_no=$(ffmpeg -i $1 2>&1 | grep Program | head -n 1 | awk '{ print $2 }')
video_sid=$(ffmpeg -i $1 2>&1 | grep Stream | grep Video | sed -e "s/^.*Stream #0:0\[0x\([0-9a-f][0-9a-f][0-9a-f]\)\].*$/\1/g")
audio_sid=$(ffmpeg -i $1 2>&1 | grep Stream | grep Audio | sed -e "s/^.*Stream #0:1\[0x\([0-9a-f][0-9a-f][0-9a-f]\)\].*$/\1/g")
gst-launch-1.0 filesrc location=./$1 ! progressreport ! \
tsdemux program-number=$program_no name=demuxer \
demuxer.video_0$video_sid ! video/mpeg ! queue max-size-time=0 max-size-buffers=0 ! \
mpegvideoparse ! omxmpeg2videodec ! \
videoconvert ! omxh264enc target-bitrate=4500000 control-rate=variable periodicty-idr=240 ! \
video/x-h264,stream-format=byte-stream,profile=high ! h264parse ! mux. \
demuxer.audio_0$audio_sid ! audio/mpeg ! queue max-size-time=0 max-size-buffers=0 ! \
aacparse ! avdec_aac ! audioresample ! audioconvert dithering=0 ! faac bitrate=128000 ! \
mp4mux streamable=true name=mux ! filesink location=$2
view raw mpegts2h264.sh hosted with ❤ by GitHub
このスクリプトです.MPEG2のハードウェアデコードのライセンスを買う必要あり.
最初に紹介した記事最後で,エンコードした動画がカクつくという記述があったが,
あれは彼のパラメータ指定がわるくって,H.264のGOPがやたら小さいとどんなマシンでも
デコードの負荷が異常になって再生がおっつかなくなるという話だった.
RaspberryPiのハードウェアエンコーダ(OpenMax)向けのgstreamerプラグイン(gst-omx)では,
periodicty-idrでIDRフレームの間隔を指定できるので,元動画のフレーム数の10倍ぐらいに指定しておけばいいとおもう.アニメなら240ぐらい?
GOPが大きすぎるとシーク位置があまりにも飛び飛びになる上に,動き予測を失敗して本当にひどい動画が出来上がる.

それと,どうやらgst-omxはBフレームとか使えないっぽいので,quant-b-framesとかのパラメータは指定できないようだし,参照フレーム数は1で固定の模様で,さらにデインターレースやリサイズ,平滑化といった処理はどれもCPU処理になるのでこれらをやらせようと絶望的な速度になるようだ.加えて,interval-intraframesでI/IDRフレームの挿入頻度を決定してて,動きの多い部分で増やして,そうじゃない部分では減らすとかないので,ファイルサイズがそんなに小さくならない.
また,音声部分について,aacparse + avdec_aacはなぜか失敗するので,gstreamerのbadプラグインだったかuglyプラグインだったかを追加して,mpegaudioparse + madを用いて再エンコードしている.非効率だしよくないなあ.

追記:
RaspberryPi 3 をh264動画変換サーバにする(ハードウェアエンコーダをgstreamerで使う) - min117の日記
という記事をみつけたのだけどこの人がハマってるエラーはたぶん私が上述のスクリプト作るにあたってハマったエラーど同じ.
録画データがソースなMPEG2-TSはStream IDとか指定しないとエラーになる.
なぜなら,録画データは複数のストリームをもってるからである.
上のスクリプトに付いたコメント(Gistのコメント欄です)にはMenuIDあるならSID指定しなくていいって書かれたけどなんかそれはうまくいかなかった気がするけどいかんせん1年半前の事なのですっかり覚えていない.
だれかつっこみor検証たのみます