Asial Blog

Recruit! Asialで一緒に働きませんか?

FFmpegによる動画エンコードの基本

カテゴリ :
バックエンド(プログラミング)
タグ :
FFmpeg
PHP
こんにちは。宇都宮です。

今回は、FFmpegを使用した動画エンコードの基本について紹介します。

FFmpegとは



FFmpegは、LGPL version 2.1ライセンスのオープンソース・ソフトウェアです。動画・音声といったマルチメディアのエンコード・デコード等を行うことができます。特長は、豊富なメディアフォーマットのサポートと、Linux/Windows/Macといった様々な環境で動作する点です。

FFmpegのコンポーネント



FFmpegの主要なコンポーネントは、以下の4つです。


ffmpeg

マルチメディアのフォーマットを変換するためのコマンドラインツール

ffserver

マルチメディアストリーミングサーバ

ffplay

メディアプレイヤー

ffprobe

マルチメディアのストリーム情報を分析するツール



本記事ではffmpegをメインに、ffprobeについても軽く紹介します。

実行環境について



本記事では、セットアップの簡単さを重視してMac上に環境を作ります。

Macでの環境構築は簡単で、homebrewでは「brew install ffmpeg」、MacPortsなら「port install ffmpeg」です。本記事ではhomebrewでインストールしたバージョンのffmpegを使用します。

インストールが完了したら「ffmpeg -version」「ffprobe -version」を実行して、ffmpeg及びffprobeがインストールされたことと、それぞれのバージョンを確認しておきましょう。ちなみに、ffserverもインストールされますが、本記事では使用しません。

手元の環境では以下のような出力になりました(ffprobe/ffserverはffmpegとほとんど同じなので省略)。

  1. $ ffmpeg -version
  2. ffmpeg version 2.3.3 Copyright (c) 2000-2014 the FFmpeg developers
  3. built on Aug 25 2014 19:47:15 with Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
  4. configuration: --prefix=/usr/local/Cellar/ffmpeg/2.3.3 --enable-shared --enable-pthreads --enable-gpl --enable-version3 --enable-nonfree --enable-hardcoded-tables --enable-avresample --enable-vda --cc=clang --host-cflags= --host-ldflags= --enable-libx264 --enable-libfaac --enable-libmp3lame --enable-libxvid
  5. libavutil      52. 92.100 / 52. 92.100
  6. libavcodec     55. 69.100 / 55. 69.100
  7. libavformat    55. 48.100 / 55. 48.100
  8. libavdevice    55. 13.102 / 55. 13.102
  9. libavfilter     4. 11.100 /  4. 11.100
  10. libavresample   1.  3.  0 /  1.  3.  0
  11. libswscale      2.  6.100 /  2.  6.100
  12. libswresample   0. 19.100 /  0. 19.100
  13. libpostproc    52.  3.100 / 52.  3.100

Windowsの方は公式情報を参照してセットアップを行って下さい。

Linuxについては、aptやyumで一発インストール、といきたいところですが、色々と経緯があって外部リポジトリの登録が必要だったりします。また、パッケージマネージャ経由で入れると0.x系といった古いブランチのものが入ったりするので、基本的にはソースからのビルドをおすすめします。CentOSUbuntuに関しては、公式のコンパイルガイドがあるのでこちらを参照して下さい。

FFmpegのバージョンについて



FFmpegには、現在、「0.x系」「1.x系」「2.x系」の3つのブランチがあります。いずれのブランチもメンテナンスが続いています。

サンプル動画ファイルについて



本記事ではBig BuckBunnyというショートアニメの動画ファイルを使用します。このアニメは、サンプルの動画ファイルがCC-byライセンスで公開されています(ライセンスの詳細)。http://www.bigbuckbunny.org/index.php/download/から様々なサイズとフォーマットの動画をダウンロードできます。本記事では480pのMP4(big_buck_bunny_480p_surround-fix.avi)を使用します。

ffprobeを使った動画情報の確認



動画の情報を確認するには、ffprobeを使用します。

ダウンロードしてきたbig_buck_bunny_480p_surround-fix.aviにffprobeを使用すると、以下のようになりました(出力の冒頭のfforobeのバージョン情報等は省略しています)。

  1. $ ffprobe big_buck_bunny_480p_surround-fix.avi
  2. (中略)
  3. Input #0, avi, from 'big_buck_bunny_480p_surround-fix.avi':
  4.   Duration: 00:09:56.46, start: 0.000000, bitrate: 2957 kb/s
  5.     Stream #0:0: Video: mpeg4 (Simple Profile) (FMP4 / 0x34504D46), yuv420p, 854x480 [SAR 1:1 DAR 427:240], 2500 kb/s, 24 fps, 24 tbr, 24 tbn, 24 tbc
  6.     Stream #0:1: Audio: ac3 ([0] [0][0] / 0x2000), 48000 Hz, 5.1(side), fltp, 448 kb/s

ややこしい出力ですが、この動画ファイルにはVideoとAudioの2つのストリームがあり、Videoの方はmpeg4 (Simple Profile)で解像度は854x480、ビットレートは2500 kb/sで24 fpsなんだな、といった情報が読み取れます。

これだけだとありがたみが分かりづらいですが、-show_streamsオプションをつけると動画の詳細な情報を出力し、-print_format jsonオプションをつけるとjson形式に出力を整形してくれます。なお、ffprobeのバージョン情報等は標準エラーとして出力されているので、2>/dev/nullで表示しないようにできます。

  1. $ ffprobe -show_streams -print_format json big_buck_bunny_480p_surround-fix.avi 2>/dev/null
  2. {
  3.     "streams": [
  4.         {
  5.             "index": 0,
  6.             "codec_name": "mpeg4",
  7.             "codec_long_name": "MPEG-4 part 2",
  8.             "profile": "Simple Profile",
  9.             "codec_type": "video",
  10. (以下省略)

このように、ffprobeはプログラムに組み込みやすく加工された出力を行うことができるのが特長です。プログラムから動画の情報を取得する必要がある場合、ffprobeの出力を利用するのが最も簡単な方法です。

ffmpegコマンドの基本構造



ffmpegコマンドの基本的な構造は以下のとおりです(入力・出力は好きなだけ増やせます)。

  1. ffmpeg (グローバルオプション) (入力1オプション) (入力1) (出力1のオプション) (出力1)

例として、以下のコマンドを実行してみましょう。

  1. ffmpeg -y -i big_buck_bunny_480p_surround-fix.avi -ss 0 -t 10 10sec.mp4

「-y」はコマンド全体に適用されるグローバルオプションです。確認を求められる場合は自動的にyを選択する、というもので、ファイルの上書きなどを確認なしに行います。

「big_buck_bunny_480p_surround-fix」が「入力1」です。

「-ss 0」と「-t 10」が「出力1のオプション」。「-ss」は出力される動画の開始地点を指定するオプションで、0を指定しているので入力動画の0秒地点から開始します。「-t」は動画の長さを秒単位で指定するオプションで、10を指定しています。

「10sec.mp4」が「出力1」です。

このコマンドでは、結果として、入力された動画の0秒地点から10秒地点までを切り取った動画ファイルが作成されます。

big_buck_bunny_480p_surround-fix.aviはそのままだとエンコードに時間がかかるので、コマンドを試してみる際には10sec.mp4のような短くカットされた動画の使用をおすすめします。

各オプションの位置づけは初めに覚えておいたほうがいいでしょう。また、この知識を応用すると、以下のように1コマンドで内容の異なる2つの動画ファイルを作成したりできます。

  1. ffmpeg -i video.mov -ss 0 -t 10 video_0to10.mp4 -ss 10 -t 20 video_10to20.mp4

ffmpegのフィルタ



フィルタは、ffmpegにおける最も強力な機能の1つです。しかし、その指定方法は複雑で馴染みにくいものです。まず、フィルタの簡単な使用例をみてみます。

  1. ffmpeg -i video.avi -i another.avi -filter_complex overlay=w out.mp4

ここでは、2つの入力ファイルを使用し、overlayフィルタを適用して、1つの動画ファイルに出力しています。出力された動画ファイルでは、video.aviの上にanother.aviの内容が重なっているように見えます。

やや複雑な例で、フィルタの指定方法を詳しくみていきましょう。

  1. ffmpeg -i 10sec.mp4 -vf "hqdn3d,pad=2*iw" output.mp4
  2. ffmpeg -i output.mp4 -i 10sec.mp4 -filter_complex overlay=w compare.mp4

1行目では、「-vf」(video filter)オプションに「hqdn3d」と「pad=2*iw」という2つのフィルタを設定しています。このように、複数のフィルタをカンマ区切りで指定することを「フィルタチェイン(filterchain)」と呼びます。

hqdn3dというのは、動画のクオリティを上昇させるフィルタで、pad=2*iwでは、動画と同じ幅を黒枠で埋めています。なお、フィルタを指定する文字列の中にシェルで特殊な意味を持つ記号(半角スペース等)が入る場合は、""でくくってやる必要があります。

1行目の結果として、以下のような動画が作成されます。



2行目では、最初の入力ファイル(output.mp4)の上に、2つ目の入力ファイル(10sec.mp4)を重ねる(overlay)というフィルタを指定しています。結果として、以下のような動画が作成されます。



では、次に同じことを1行で使ってやってみます。

  1. ffmpeg -i 10sec.mp4 -vf "split[a][b];[a]pad=2*iw[A];[b]hqdn3d[B];[A][B]overlay=w" compare2.mp4

ここで使われているのは、フィルタグラフ(filtergraph)と、リンクラベル(link label)という指定方法です。

フィルタグラフとは、フィルタをセミコロン区切りで指定することです。フィルタチェインとフィルタグラフの違いですが、フィルタグラフはフィルタチェインを内包することができます。

リンクラベルは、[a]といった記法で、出力に名前を付けることです。

コマンド例は複雑ですが、順を追ってみていきましょう。まず、「split[a][b]」で、入力された動画を[a][b]という2つの出力に分割しています。次に、[a]に対して右側を黒枠で埋めるフィルタを当て、その出力に[A]という新しいラベルをつけています。[b]の方は、hqdn3dフィルタを適用して[B]ラベルをつけています。最後に、[A]と[B]をoverlayフィルタで一つにまとめ、compare2.mp4として書き出しています。

フィルタを1つずつ当てるのに比べて、複数のフィルタを同時に当てたほうが、処理に要する時間が少なくて済む、という大きな利点があります。

まとめ



以上、FFmpegの基本情報から、ffmpeg及びffprobeコマンドの基本的な使い方までを紹介しました。ffmpegを使う場合、学習時間の多くはオプションやフィルタを調べることに費やされます。その前提として、オプション・フィルタの構文を正確に理解している必要があります。構文が曖昧なままオプションを使っていると、応用が効きません。

付録(1) PHPとffmpegの連携について



PHPでffmpegを利用するには、PHP-FFMpegがおすすめです。Composer対応のモダンなPHP実装なので、PHP5.3以上のコードベースではとても扱いやすいです。

ffmpeg-phpというPHP拡張もありますが、2012年で開発が止まっているのであまりおすすめしません。

付録(2) 情報源について



https://www.ffmpeg.org/documentation.htmlが、FFmpegのドキュメントの一覧です。https://www.ffmpeg.org/ffmpeg-all.htmlは、ffmpegのオプションやフィルタまで含めた包括的なドキュメントです。

また、上記ドキュメントの日本語訳もあります。

http://www.fixedpoint.jp/ffmpeg/

2012年で更新が停止していますが、日本語で閲覧できるドキュメントとしては最も価値の高いものの1つです。

FFmpegの入門者向け情報としては、FFmpeg Basicsという電子書籍(英語)がおすすめです。本記事は、FFmpeg Basicsの第1章を参考にしています。