無料のFFmpegで動画変換
いつのまにか動画撮影は生活の一部になりました。しかしそのような動画を共有したり配布したりしようとすると意外と難しかったりします。iPhoneでは.mov、アンドロイドでは.mp4とフォーマットが違うのが原因です。また少し前のAndroid機では.3gpという拡張子が主流だったこともあり、さらに複雑になっています。
また、パソコンで再生しようとして「コーデックがありません」と表示され再生できなかったことはありませんか。
ここではFFmpegという無料で広告も入らないアプリを利用して、動画を活用してく中で必要になることが多いフォーマット変換やコーデック変換、リサイズ等に対応してみたいと思います。また、とにかく再生だけできればいいという話ならffmpegに付属しているffplayは幅広い種類のフォーマット・コーデックを再生できます。
筆者の利用環境はWindows10(64bit)でそれを前提に話を進めますが、FFmpegはマルチプラットフォームアプリなので他の多くのOSでも利用できると思います。
コーデック・フォーマット
まず、関係するワードからおさえていきます。文字にしてしまうと当たり前なのですが、「動画」は「音声データ」と「映像データ」の組み合わせであるということを頭に入れておくと理解が容易になります。
そして「音声データ」や「映像データ」は、「コーデック」と呼ばれる規則のようなものによって電子データ化されています。
音声をデータ化するコーデックには、MP3、AAC、WAVといったものがあります。映像をデータ化するものには、H.264、MPEG-4、DivXといったものがあります。
例えば、MP3形式の音声とMPEG-4の映像がセットになった動画ファイルが「xxxx.mp4」として保存されたとします。この時のmp4のことを「フォーマット」などと呼びます。「フォーマット」は「コンテナ」と呼ばれることもあります。
フォーマットによって取り扱えるコーデックの種類が異なります。1対1で結びついていることもありますし、そうでない場合もあります。複数のフォーマットに利用されるコーデックもあります。mp3やwmaなどのようにフォーマットとコーデックに同じ名前がつけられていることもあります。
音声や映像をデータ化するのがコーデック、コーデックによって作られたデータをアプリが読めるようにファイル化するのがフォーマットと考えるとわかりやすいと思います。
ビットレート・フレームレート
映像の質を左右する値に「ビットレート」と「フレームレート」があります。
ビットレートは1秒当たりのデータ量を指します。フレームレートは1秒当たりの画像のコマ数を指します。主にビットレートは画像の質、フレームレートは滑らかさに関係してきます。同じビットレートだった場合、フレームレートが小さい方が画質はよくなります(その分動作はカクカクします)。
ビットレートにはbps、フレームレートにはfpsという単位が用いられます。近年の環境においては、ビットレートは10Mbpsが、フレームレートは60fpsが一般的(中級)になります。
他、詳しくはフォトスク:『「フレームレート」や「ビットレート」とは?』にわかりやすい説明がありますので参考にしてみてください。
これも当たり前の話かもしれませんが、画質は画面サイズにも関係してきます。当然ですが同じビットレート・フレームレートなら、画面サイズが小さい方が画質はよくなります。
少し話がそれますが、画面サイズには「アスペクト比」という縦横の比率があり、ワイドなら16:9、スタンダードなら4:3といった設定が一般的です。
FFmpegのインストール
ここではWindows10 64bit用のアプリをダウンロードします(以前は32bitアーキテクチャも存在したのですが、今は見当たりません。)。ちなみにDebianならaptでインストール可能です。
ffmpegの公式ページを開いて、DownLoadをとリンクをたどると、OS別にダウンロードリンクが表示されます。編集時点では、Windows用コンパイル済みのアプリはCODEX FFMPEGや、GitHubからダウンロードできるようです。
筆者はGitHubから「ffmpeg-N-101174-g14dc28e969-win64-lgpl.zip」をダウンロードしました。展開したフォルダは長い名前がついていますが、ここでは「ffmpeg」と名前を変えました。
アプリはコマンドラインかPowerShellから使いますのでフォルダごとわかりやすい場所に移動してください。ここではd:¥に移動しました。
d:¥ffmpegフォルダ内にフォーマット変換したいファイルsample.aviがあり、mp4にフォーマット変更したい場合は、コマンドプロンプトで次のように入力します。
> d:¥ffmpeg¥bin¥ffmpeg -i d:¥ffmpeg¥sample.avi d:¥ffmpeg¥sample.mp4
ケース別のFFmpegの使い方
ケース別に詳しい使い方を説明していきます。
- 事前準備
フォルダ構造は例ですのでわかる人はこの通りにする必要はありませんが、とりえずd:¥ffmpegに展開したフォルダがあるとします。
ここに変換前のファイルを置くためのsrcフォルダと、変換後のファイルを置くためのexpフォルダをつくります。
PowerShellかコマンドプロンプトを起動させます。PowerShellはスタートメニュー内の「Windows PowerShell」「Windows PowerShell」から起動できます。コマンドプロンプトなら、スタートメニュー内の「Windowsシステムツール」に「コマンドプロンプト」があります。
PowerShellならcd d:¥ffmpeg、コマンドプロンプトなら cd /d d:¥ffmpegと入力します。
- サポートするフォーマットのリスト
まず対象のファイルがFFmpegによって操作できるものか確認してみましょう。拡張子を頼りにファイルフォーマットを推定して、それがFFmpegがサポートするフォーマットリスト内に存在するか確認します。リストの出し方は次の通りです。
d:¥ffmpeg> bin¥ffmpeg -formats先に、バージョンや対応しているオプション、利用するライブラリのバージョン等が表示された後、「file formats」という項目で対象のフォーマットが羅列されます。
行の先頭には、DやEとフラグが付きます。DはDemux、EはMuxを意味します。
demuxとはひとつの信号を複数の信号に分岐されている状態を指します。少し荒っぽい説明をすると、音声と映像データが分かれている状態をDemux、ひとつにまとめられた状態をMuxといいます。詳しくはQiita:「ffmpegでmp4をdemuxしたりmuxしたり」に載っています。
ファイルの拡張子から推定したフォーマットが、ここで表示されるものだったらサポートしていると判断します。
- サポートするコーデックのリスト
フォーマットが確認できたら今度はコーデックを確認してみましょう。先のフォーマットの際と同じ要領です。
d:¥ffmpeg> bin¥ffmpeg -codecsここでも先頭にはフラグがつきます。その説明を簡単にします
- D
デコード(読出)をサポートします
- E
エンコード(書出)をサポートします
- V
映像用のコーデックを示します
- A
音声用のコーデックを示します
- S
字幕(subtitle)用のコーデックを示します
- I
イントラフレームのみ(Intra frame-only)のコーデックを示します。
動画のエンコードに際して圧縮率を上げるために、同じ動画の他の場所(時間帯)の変化から法則を導出し次のコマの予測をたて、予測と実際のコマの差異をデータ化するという方法があります。このような方法を使わないのが「イントラフレーム」と呼ばれます。詳しくはWikipedia:「フレーム間予測」を参照してください。
- L
ロスのある圧縮が使われます
- S
ロスのない圧縮が使われます。
これらのうちV:映像とA:音声とS:字幕は同じ位置(3文字目)で表示されます。つまり共存することがありません。
サポートされるコーデックの調べかたは分かりましたか、目的のファイルが使用しているコーデックはファイル名からではわかりません。また先の拡張子からのフォーマット推定では誤った拡張子がつけられている可能性があります。それらを調べるにはffmpeg.exeと同じフォルダにあるffprobe.exeを使います。
d:¥ffmpeg> bin¥ffprobe -i src¥ファイル名ここでは調べる対象のファイルがsrcフォルダにあると仮定しています。
- D
- フレームレートを落とす
フレームレートを落とすには次のようにします。ここでは(30fpsから)24fpsに落としてみました。フレームレートを落とすと、1秒当たりの情報量も減るのでビットレートも落ちます。
d:¥ffmpeg> bin¥ffmpeg -i src¥sample.mp4 -r 24 exp¥conv.mp4筆者が試してみたファイルでの結果はファイルサイズが28515KB→15818KB、ビットレートが1140kbps→616kbpsに落ちました。
- ビットレートを落とす
今度はビットレートを落としてみます。vbオプションで映像のビットレートを指定します。先と同じ1140kbpsのファイルを200kbpsにしてみます。
d:¥ffmpeg> bin¥ffmpeg -i src¥sample.mp4 -vb 200k exp¥conv.mp4結果はファイルサイズが28515KB→6521KBまで下がりました。
フレームレート、ビットレートの落とし方はChikuma Engineering Co., Ltd.のページを参考にさせていただきました。
- 画面のサイズを変える
画面のサイズを変えるには次のようにして、画面のサイズを指定します。元の比率(アスペクト比)と違うサイズを指定するとサイズが優先されて歪みます。
d:¥ffmpeg> bin¥ffmpeg -i src¥sample.mp4 -s 640x360 exp¥conv.mp4先と同じサンプルファイル(1280x720)を640x360に変換した結果はファイルサイズが28515KB→5106KB、ビットレートが1140kbps→134kbpsに落ちました。
こちらに関してはQiita:「【ffmpeg】動画の解像度を指定してリサイズ、アスペクト比を維持したまま解像度を変更する、回転する」に載っています。
- アスペクト比を変更する d:¥ffmpeg> bin¥ffmpeg -i src¥sample.mp4 -aspect 4:3 exp¥conv.mp4
この処理で指定した比率にあわせて映像はゆがみます。16:9の映像をサイズを変更せずアスペクト比だけを4:3に変更した際、このゆがみはSAR(Sample Aspect Rate)と呼ばれるピクセル単位のアスペクト比の変更によって実現されます。ピクセルの四角を3:4に歪ませるさせることで全体を4:3にすることができます。
例えば1辺1mmの正方形を横160個 x 縦90個で並べていた場合、全体は160mm x 90mmで16:9です。ひとつの正方形を面積が一定のまま横と縦の辺の比率が3:4になるように歪ませると0.8658mm x 1.1544mmとなります。すると全体は横0.8658x160≒139mm、縦1.1544x90≒104mmで、4:3の画面となります。
画面サイズ変更を同時に行いそれが4:3になるように指定されていればSARは1:1になります。
ゆがまないようにしたい場合はフィルターを使って加工します。フィルターは -vf フィルター名=パラメーターという形で指定します。
d:¥ffmpeg> bin¥ffmpeg -i src¥sample.mp4 -vf name=param exp¥conv.mp4まず余白を作ってサイズを合わせる方法です。padフィルターは画面のサイズを大きくして余白を塗りつぶすフィルターです。:(半角コロン)で5つのパートに区切ってパラメーターを渡します。パラメーターは「変更後の幅:変更後の高さ:x軸移動:y軸移動:画像がなくなった部分の色」となります。
- 上下埋めで16:9から4:3に
-vf pad=iw:iw*3/4:0:(oh-ih)/2:black
iwという変数名は入力画像の幅(Input width)、ohという変数名は出力画像の高さ(Output Height)として使えます。同様にow(Output Width)やih(Input Height)も使えます。
元の横幅(iw)を基準に4:3の比になるように高さを指定し、変更後の高さ(oh)と変更前の高さ(ih)の差の半分(上下に余白をつくるので)位置を下げています。
- 左右埋めで4:3から16:9に
-vf pad=ih*16/9:ih:(ow-iw)/2:0:ffcccc
今度は切り取って比率を調整してみます。切り取りにはcropフィルターを使います。このパラメーターは「切り取り幅:切り取り高さ:切り取り開始x軸:切り取り開始y軸」となっています。
- 左右を切り取って16:9から4:3に
-vf crop=ih*4/3:ih:(iw-ow)/2:0
- 上下を切り取って4:3から16:9に
-vf crop=iw:iw*9/16:0:(ih-oh)/2
これらの方法はニコラボを参考にさせていただきました。
- 上下埋めで16:9から4:3に
- ファイルフォーマットを変える
ファイルフォーマットを変えるには次のようにします。特にコーデックを指定しない場合はそのフォーマットで利用できるコーデックに変換してくれるようです。
この方法はQiita:「ffmpegを利用した動画ファイルフォーマット変換」を参考にさせていただきました。
d:¥ffmpeg> bin¥ffmpeg -i src¥sample.avi exp¥conv.mp4 - コーデックを変える
コーデックを指定して変換するには次のようにします。たとえば映像コーデックがh.264のmp4フォーマットファイルがあったとして、映像コーデックをMPEG-4にしたい場合は次のようにします。
d:¥ffmpeg> bin¥ffmpeg -i src¥sample.mp4 -c:v mpeg4 exp¥conv.mp4 - ライブストリーミングを保存する
HLS(HTTP Live Streaming)を保存する方法は次の通りです。
HLSとは動画ファイルを細かく分断して保存して、後からインデックスファイルを使って順に再生させる形式です。ファイルの実体は.ts、インデックスには.m3u8ファイルが用いられます。この際の映像と音声の組み合わせには、例えばH.264とAACがあります。
d:¥ffmpeg> bin¥ffmpeg -i https://sample.com/xxxx.m3u8 -movflags faststart -c copy -bsf:a aac_adtstoasc exp¥save.mp4オプション内にある:aは(Audio)、:vは(Video)に限定して適用させています。bsfではaudioに対しbitstreamフィルタを指定しています。
aac_adtstoascは公式の解説によると「MPEG-2/4 ADTSヘッダ」から「MPEG-4音声設定」を作成し「MPEG-2/4 ADTSヘッダ」を除去するものです。
「-movflags faststart」ではエンコード後にメタデータ(音声・映像以外のデータ)を先頭に移動させます。
-cオプションはコーデックを指定するオプションです。音声なら:a、映像なら:vの後にコーデックを指定します。これにcopyを指定するととすると入力がデコードエンコードを経由せずに出力されます。
ストリーミングの保存はQiita:「ffmpeg を使い、HTTP Live Streaming(HLS)をファイルに保存し、保存したファイルからストリーミングを行う方法について」を参考にさせていただきました。
ちなみにオーディオの録音をする際は「ffmpeg -i M3U8 -to 30 -write_xing 0 outputfilename.mp3」等とすることが多いと思いますが、この-toは録音のストップ時間の設定、-write_xing 0はXing/LAMEフレームのメタデータを除去する指定です。
- ファイルを連結する
複数のファイルを連結する方法はffmpeg wiki「Concatenate」にあります。mp3ファイルの連結で例示していきます。
ffmpeg -f concat -safe 0 -i list.txt -c copy output.mp3-iで指定するのは連結したいファイルのリストです。テキストファイルで次のように作成します。Windowsで処理する場合、フォルダのセパレータである¥はエスケープする必要があります。
file d:¥¥ffmpeg¥¥src¥¥no1.mp3 file d:¥¥ffmpeg¥¥src¥¥no2.mp3 file d:¥¥ffmpeg¥¥src¥¥no3.mp3
-c copyは無変換オプションで、連結するすべてのフォーマットが出力に指定したフォーマットでないと使えません。
その場合はオプションを外して実行してください。
Invalid audio stream. Exactly one MP3 audio stream is required.ちなみに-safe 0オプションを外して実行すると次のようなエラーとなります。
Unsafe file name 'D:\ffmpeg\src\no1.mp3' list.txt: Operation not permitted
ffplay.exe
ここまで圧縮ファイルから展開されたffmpeg.exeとffprobe.exeについて触れてきました。もうひとつffplay.exeというものがあると思います。これはシンプルな再生アプリです。「ffplay -i ファイル」で起動されます。また動画ファイルをドラッグアンドドロップしても再生できます。シークバーなどのツール類は一切ありませんが、多様な形式の動画が再生できる万能なプレーヤーとなっています。
スクリプト例
最後に、変換用のPowerShell用スクリプトを紹介します。
convert.ps1
# 1.FFmpegのルートディレクトリを指定してください
# $strRootDir¥bin¥ffmpeg.exeが存在するようにします。
$strRootDir="d:¥ffmpeg"
# 2.変換したいファイルが入るフォルダを指定してください。
$strSrc="d:¥ffmpeg¥src"
# 3.出力フォルダを指定してください。
$strExp="d:¥ffmpeg¥exp"
# 4.変換後のフォーマットを指定してください。Windows10なら.mp4にすればたいてい再生できると思います。
$strSuffix=".mp4"
$strExePath=${strRootDir}+"¥bin¥ffmpeg.exe"
# 移動
cd $strSrc
# ファイル毎に実行
# Get-ChildItemでディレクトリ内のファイルオブジェクトを取得し、
# Nameオプションで名前だけ取得します。
# 取得した一覧に対して、ffmpeg用の引数を作成し
# Start-Processでffmpegの画像変換コマンドを実行しています。
# ファイル名は正規表現を使って拡張子を取り除き最後に.mp4の文字を付与しています。
# もし拡張子のないファイルを取り扱う場合は"¥.[^.]*$"を"$"にしてください。
Get-ChildItem -Name | ForEach-Object{ $strSrcFile=$strSrc+"¥"+$_; $strExpFile=$strExp+"¥"+($_ -replace
"¥.[^.]*$",".mp4"); Start-Process -FilePath $strExePath -Wait -ArgumentList @("-i",$strSrcFile,
$strExpFile)}
参考にさせていただいたサイトの皆様、ありがとうございました。