FFmpegによる動画ファイル分析入門

投稿者 : OSCA

[PR] "東野・岡村の旅猿"で登場したロケ地を紹介するファンサイト「あの場所へ行こう!」はこちら。

動画ファイルを入力にして処理をするプログラムを書く必要があり、その際の動画ファイルの分析にFFmpegを利用しました。 本稿では、FFmpegを利用して動画を分析した際のノウハウを整理して共有します。

FFmpegとは?

FFmpegは、動画や画像・音声を記録・変換・再生するためのソフトウェアパッケージです。 FFmpegには次のようなソフトウェアが含まれています。

ソフトウェア説明
ffmpeg動画や画像・音声などを記録・変換するソフトウェア
ffprobe動画や画像・音声の詳細な情報を取得するためのソフトウェア
ffplay動画や画像・音声を再生するためのソフトウェア

FFmpeg = ffmpeg と思われていることも多いですが、パッケージ名としては「FF」が大文字なのが正しい表記です。 FFmpeg に含まれるソフトウェアは小文字表記の ffmpeg です。

本稿は、動画ファイルの分析にフォーカスし、主に ffprobe コマンドを利用していきます。

基本操作

それではさっそく、動画ファイルの分析をについて解説していきましょう。 上記の通り、動画ファイルの情報を取得するために ffprobe を利用します。 ffprobe を実行するための構文は次の通りです。

$ ffprobe <オプション> ファイル名

まずは次のようにオプションを何も指定せず、動画ファイルを指定してみましょう。 次の例では input.mp4 を入力として指定しています。

$ ffprobe input.mp4
ffprobe version 4.3.1 Copyright (c) 2007-2020 the FFmpeg developers
  built with Apple clang version 11.0.0 (clang-1100.0.33.17)
  configuration: --prefix=/usr/local/Cellar/ffmpeg/4.3.1_7 --enable-shared --enable-pthreads --enable-version3 --enable-avresample --cc=clang --host-cflags= --host-ldflags= --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libbluray --enable-libdav1d --enable-libmp3lame --enable-libopus --enable-librav1e --enable-librubberband --enable-libsnappy --enable-libsrt --enable-libtesseract --enable-libtheora --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-librtmp --enable-libspeex --enable-libsoxr --enable-videotoolbox --enable-libzmq --enable-libzimg --disable-libjack --disable-indev=jack
  libavutil      56. 51.100 / 56. 51.100
  libavcodec     58. 91.100 / 58. 91.100
  libavformat    58. 45.100 / 58. 45.100
  libavdevice    58. 10.100 / 58. 10.100
  libavfilter     7. 85.100 /  7. 85.100
  libavresample   4.  0.  0 /  4.  0.  0
  libswscale      5.  7.100 /  5.  7.100
  libswresample   3.  7.100 /  3.  7.100
  libpostproc    55.  7.100 / 55.  7.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'input.mp4':
  Metadata:
    major_brand     : mp42
    minor_version   : 1
    compatible_brands: mp42avc1
    creation_time   : 2018-12-27T07:32:35.000000Z
  Duration: 00:00:30.00, start: 0.000000, bitrate: 11719 kb/s
    Stream #0:0(eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 159 kb/s (default)
    Metadata:
      creation_time   : 2018-12-27T07:32:35.000000Z
      handler_name    : Apple ?T?E???h?E???f?B?A?n???h??
    Stream #0:1(eng): Video: h264 (Main) (avc1 / 0x31637661), yuv420p(tv, bt709), 1920x1080, 11553 kb/s, 30 fps, 30 tbr, 30 tbn, 60 tbc (default)
    Metadata:
      creation_time   : 2018-12-27T07:32:35.000000Z
      handler_name    : Apple ?r?f?I?E???f?B?A?n???h??

コマンドを実行すると、上のように分析結果が表示されました。 最初に ffprobe のバージョン情報などが表示されています、この部分をFFmpegでは バナー と呼んでおり、ここは無視して良い部分で、動画の分析結果は Input #0, ... という行以降です。

次の例のように、コマンド実行時に -hide_banner オプションを指定するとバナーが表示されなくなりますので、鬱陶しい場合は -hide_banner オプションを指定しましょう。

$ ffprobe -hide_banner input.mp4
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'input.mp4':
  Metadata:
    major_brand     : mp42
    minor_version   : 1
    compatible_brands: mp42avc1
    creation_time   : 2018-12-27T07:32:35.000000Z
  Duration: 00:00:30.00, start: 0.000000, bitrate: 11719 kb/s
    Stream #0:0(eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 159 kb/s (default)
    Metadata:
      creation_time   : 2018-12-27T07:32:35.000000Z
      handler_name    : Apple ?T?E???h?E???f?B?A?n???h??
    Stream #0:1(eng): Video: h264 (Main) (avc1 / 0x31637661), yuv420p(tv, bt709), 1920x1080, 11553 kb/s, 30 fps, 30 tbr, 30 tbn, 60 tbc (default)
    Metadata:
      creation_time   : 2018-12-27T07:32:35.000000Z
      handler_name    : Apple ?r?f?I?E???f?B?A?n???h??

さて、表示された結果を見てみると、大きく2つのブロックが表示されています。

ブロック説明
Metadata指定したファイルの形式に関する情報
Duration動画の内容に関する詳細情報

Metadata は、そのファイルの形式に関する情報が含まれています。 上の例だと major_brand が mp42 と出力されているのでファイル形式は Microsoft MPEG-4 v2 で、ファイル作成日時が 2018-12-27 07:32:35であることがわかります。 開発するアプリケーションなどからFFmpegを呼び出して入力ファイルの形式のバリデーションをしっかりしたい場合などは、ファイルの拡張子ではなく、この情報を利用すると精度を高めることができます。

Duration の方には、動画の内容に関する情報が表示されています。 Duration は動画の長さ、 bitrate はエンコード時のビットレートです。 さて、このブロックで注目したいのは Stream が複数含まれている点です。 上の例ですと Stream #0:0Stream #0:1 と2つの Stream が含まれていることがわかります。 それぞれ AudioVideo という単語が含まれており、音声と映像のそれぞれの情報であることがわかります。

映像のストリーム情報からは、次のような情報を取得することができます。

項目上の例の場合の値
形式h264
解像度1920×1080
ビットレート11553 kb/s
フレームレート30 fps

音声のストリーム情報からは、次のような情報を取得することができます。

項目上の例の場合の値
形式aac
サンプリングレート48000Hz
チャンネルステレオ

Streamの情報をJSONで出力する

ここまでの説明では、コマンドの実行結果はが人が目で見るような形式で表示されていました。 次の例のように -loglevel quiet-show_streams-print_format json の3つのオプションを組み合わせることで、このストリーム情報をJSON形式で取得することができます。 プログラムからFFmpegを呼び出すような場合は、こちらが便利です。

$ ffprobe -loglevel quiet -show_streams -print_format json input.mp4
{
    "streams": [
        {
            "index": 0,
            "codec_name": "h264",
            "codec_long_name": "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10",
            "profile": "Constrained Baseline",
            "codec_type": "video",
            "codec_tag_string": "avc1",
            "codec_tag": "0x31637661",
            "width": 640,
            "height": 356,
            (中略)
        },
        {
            "index": 1,
            "codec_name": "aac",
            "codec_long_name": "AAC (Advanced Audio Coding)",
            "profile": "LC",
            "codec_type": "audio",
            "codec_tag_string": "mp4a",
            "codec_tag": "0x6134706d",
            "sample_fmt": "fltp",
            "sample_rate": "44100",
            (中略)
        }
    ]
}

動画内の音量の統計を調べる

さて、動画ファイル内の音声のボリュームの統計値を調べたい時があります。 これをFFmpegで実現する場合、オーディオフィルター(audio filter)機能の volumedetect というフィルタを利用すると調べることができます。 しかしオーディオフィルタのオプション指定は ffmpeg コマンドでしかできないため ffmpeg コマンドにオーディオフィルタを指定します。 コマンドの例は次の通りです。

$ ffmpeg -i input.mp4 -hide_banner -af volumedetect -vn -f null -
(中略)
[Parsed_volumedetect_0 @ 0x7fb195809dc0] n_samples: 243980288
[Parsed_volumedetect_0 @ 0x7fb195809dc0] mean_volume: -28.0 dB
[Parsed_volumedetect_0 @ 0x7fb195809dc0] max_volume: -5.2 dB
[Parsed_volumedetect_0 @ 0x7fb195809dc0] histogram_5db: 3
[Parsed_volumedetect_0 @ 0x7fb195809dc0] histogram_6db: 16
[Parsed_volumedetect_0 @ 0x7fb195809dc0] histogram_7db: 30
[Parsed_volumedetect_0 @ 0x7fb195809dc0] histogram_8db: 176
[Parsed_volumedetect_0 @ 0x7fb195809dc0] histogram_9db: 898
[Parsed_volumedetect_0 @ 0x7fb195809dc0] histogram_10db: 4301
[Parsed_volumedetect_0 @ 0x7fb195809dc0] histogram_11db: 13797
[Parsed_volumedetect_0 @ 0x7fb195809dc0] histogram_12db: 39935
[Parsed_volumedetect_0 @ 0x7fb195809dc0] histogram_13db: 99707
[Parsed_volumedetect_0 @ 0x7fb195809dc0] histogram_14db: 223105

分析する対象は音声ストリームだけで良いので-vn オプションを指定して動画ストリームの分析をしないようにし、また分析だけして何かファイルを出力する必要が無いので -f オプションで出力フォーマットとして null を指定し、また出力先として - (標準出力) を指定します。

オプション説明
-i入力ファイルを指定する
-vn動画ストリームの分析をしない
-f出力ファイルのフォーマットを指定する

すると上のような音量の統計情報が出力されました。 mean_volume は平均音量, max_volume は最大音量となります。

おわりに

本稿では、動画や画像・音声を記録・変換・再生するためのソフトウェアパッケージ「FFmpeg」を利用して、動画ファイルの分析をする簡単な方法について解説しました。 皆様のお仕事のお役に立てれば幸いです。

著者 : OSCA

OSCA

Java, PHP 系のWEBエンジニア。 WEBエンジニア向けコミュニティ「WEBエンジニア勉強会」を主催。
個人として何か一つでも世の中の多くの人に使ってもらえるものを作ろうと日々奮闘中。
@engineer_osca