2019年1月17日木曜日

MP4(AVC)からIフレームだけ取得する

Iフレームが欲しい!

詳細は割愛しますが、MPEG4 AVCはフレーム間予測に基づき、I、P、Bフレームが生成されます。Iフレームは単体で成立するフレーム、Pフレームは差分フレーム、Bフレームは自由度の高い差分フレーム、みたいな感じです。Iフレームの入る間隔や閾値はエンコーダで設定できますが、主に大きくシーンが変わった場面ではIフレームが入ると考えていいでしょう。
今回は、超ニッチですが、Iフレームだけ取得したくなったのでその方法を考えました。

方法

ffmpegでできます。ffmpegは何でもできますね。
ffmpegの公式から飛ばされるWindowsビルドはこちら
公式ドキュメントは、ものすごく詳しく使い方が書いています。
一般的なことはここ、ビデオフィルタ(-vfオプション)はここです。

ffmpeg.exe -i "input.mp4" -an -qmin 1 -q 1 -vf select="eq(pict_type\,I)",scale=1280:720 -vsync 0 "out_frame%04d.jpg"

にて取得できます。
オプションの説明を軽くすると、

-an
オーディオ無効。必要ないと思うが念の為

-qmin  -q
jpegエンコードの品質で、小さいほど良い。-qminは-qの下限を定めてある。デフォだと下限2なので、-qだけ下げでも無意味になる。2は明らかに汚いので使いにくい。1は綺麗。小数は切り落としされるらしく、生成物がハッシュレベルで同じだった。

-vf
以降にビデオフィルタを列挙する。カンマで複数フィルタ指定。
select="eq(pict_type\,I)"
>フレームタイプがIフレームなものをピックアップする。ドキュメントによるとIの代わりにB、Pとかも指定できるらしい。
scale=1280:720
>出力画像サイズ。dar(=w/h)という変数が使えるので、1280:1280/darや、720*dar:720などとも書ける。ビデオフィルタでリサイズしなくても、-sオプションでも同じことができる。

-vsync 0
0の意味はドキュメントに書いてあるが、とにかくIフレーム取得のときは0以外だと重複フレームが出まくってダメだった。未指定もダメ。 必須。

出力
%数字dで連番&桁数指定できる。0詰め4桁で普通は十分かと。拡張子はffmpegが出力形式を類推するのに使うので必須。ちなみに、バッチファイルだと%は%%でエスケープが必要。


という感じです。
てっきりデコーダのライブラリを使ってシコシコ書かないといけないかと思ったら、ffmpegで簡単に実現できて助かりました。

0 件のコメント:

コメントを投稿