32blogby Studio Mitsu

FFmpegのlibavutilとは?機能・使い方・サンプルコードを徹底解説

FFmpegの基盤ライブラリlibavutilを解説。メモリ管理・時間計算・エラーハンドリングの実装例からインストール・よくあるエラーの対処法まで網羅。

by omitsu22 min read
FFmpeglibavutilClibraryerror-handlingmemory management
目次

libavutil は FFmpeg の基盤ライブラリで、メモリ管理・タイムスタンプ計算・エラーハンドリング・ロギング・ピクセルフォーマット変換など、FFmpeg の全ライブラリが依存するユーティリティ関数を提供している。C 言語で FFmpeg の API を使うなら、ほぼすべてのファイルで libavutil のヘッダをインクルードすることになる。

この記事では、FFmpeg の C API でメディア処理アプリを開発するときに頻出する関数を、コンパイル可能なサンプルコード付きで解説する。

この記事でわかること

  • libavutil の役割と FFmpeg エコシステムでの位置づけ
  • av_malloc / av_free によるメモリ管理
  • av_rescale_q によるタイムスタンプ変換
  • av_strerror によるエラーハンドリング
  • av_log によるログ制御
  • AVFrame と AVDictionary の使い方
  • ハッシュ計算によるファイル整合性チェック
  • インストールとビルド設定

libavutil とは?

概要

libavutil は FFmpeg のコアユーティリティライブラリだ。libavcodeclibavformatlibavfilter など、FFmpeg の全ライブラリがこの libavutil に依存している。

主な機能:

  • メモリ確保・バッファ管理
  • 数学演算・スケーリング
  • ピクセルフォーマット・サンプルフォーマットのユーティリティ
  • エラーコードから文字列への変換
  • レベル制御付きの構造化ログ
  • 暗号ハッシュ関数(MD5, SHA1, HMAC)
  • 有理数(分数)演算
  • 参照カウント付きフレーム(AVFrame
  • キー・バリュー型メタデータ辞書(AVDictionary

FFmpeg 8.1(2026年3月リリース)時点でも、libavutil のコア API は安定している。公式 Doxygen ドキュメント には 10 カテゴリ・148 ヘッダファイルが掲載されている。

FFmpeg ライブラリスタックでの位置づけ

ライブラリ名主な役割
libavcodec音声・動画のエンコード / デコード処理
libavformatメディアフォーマットの解析と処理
libavfilter映像・音声のフィルタリング処理
libavutilユーティリティ関数(メモリ管理、数学演算、ログ、エラーハンドリング)
libswscale映像のリサイズや色空間変換
libswresample音声のリサンプリングやフォーマット変換

libavutil は基盤レイヤーだ。単独で使う場面は少ないが、FFmpeg の C API を使う開発では常に存在する。

libavutilメモリ / 数学 / エラー基盤libavcodecエンコード / デコード依存libavformatコンテナ入出力呼出アプリケーションあなたのコード

メモリ管理

FFmpeg はメディア処理で大量のデータを扱うため、メモリ管理が極めて重要になる。av_mallocfree を混在させてセグフォに悩まされるケースは、FFmpeg 開発者の間で定番のトラブルだ。

主要関数

  • av_malloc(size_t size) — メモリ確保
  • av_free(void *ptr) — メモリ解放
  • av_mallocz(size_t size) — ゼロ初期化付きメモリ確保
  • av_realloc(void *ptr, size_t size) — メモリリサイズ
  • av_freep(void **ptr) — 解放後にポインタを NULL にセット(安全版)

基本的な使い方

c
#include <libavutil/mem.h>
#include <stdio.h>

int main() {
    // 10個分のint配列を確保
    int *data = (int *) av_malloc(sizeof(int) * 10);
    if (!data) {
        fprintf(stderr, "メモリ確保に失敗しました\n");
        return 1;
    }

    for (int i = 0; i < 10; i++) {
        data[i] = i * i;
    }

    printf("data[5] = %d\n", data[5]); // 25

    av_free(data);
    return 0;
}

なぜ malloc ではなく av_malloc を使うのか?

FFmpeg の内部では SIMD 最適化のためにアライメント付きメモリ確保を行っている。アライメントサイズは CPU の機能に依存する:

CPU機能アライメント
AVX-51264 バイト
AVX / AVX232 バイト
SSE / NEON16 バイト

一般的な x86_64 ビルド(AVX2 対応)では、av_malloc は 32 バイトアライメントのメモリを返す。FFmpeg の DSP ルーチンは SIMD 命令を使うため、アライメントされていないデータでクラッシュする。標準の malloc はほとんどのプラットフォームで 16 バイトアライメントしか保証しない。

フレームバッファに普通の malloc を使うと、特定の解像度でランダムにセグフォが発生することがある。av_malloc に切り替えると解消するケースがほとんどで、原因は AVX2 のコードパスが 32 バイトアライメントを要求していることだ。

av_freep: より安全な解放

av_freep はメモリを解放すると同時にポインタを NULL にセットしてくれる。解放済みメモリへのアクセス(use-after-free)を防ぐのに有効だ:

c
#include <libavutil/mem.h>
#include <stdio.h>

int main() {
    uint8_t *buffer = (uint8_t *) av_malloc(1024);
    if (!buffer) return 1;

    // ... buffer を使う ...

    av_freep(&buffer);
    // buffer は NULL になっている — 使用前にチェックできる
    printf("buffer after freep: %p\n", (void *)buffer); // (nil)

    return 0;
}

数学演算と時間計算

FFmpeg の時間処理は timebase(時間基準)に基づいている。timebase は有理数で、1 "tick" が何を表すかを定義する。例えば timebase が 1/90000 なら、PTS(Presentation Timestamp)の 1 単位は 1/90000 秒だ。

ストリームごとに timebase が異なるため、変換は日常的な操作になる。HLS ストリーミングや複数ストリームの muxing をやるなら、av_rescale_q は手放せない。

主要関数

  • av_rescale(int64_t a, int64_t b, int64_t c)a * b / c をオーバーフロー保護付きで計算
  • av_rescale_q(int64_t a, AVRational bq, AVRational cq) — 2つの timebase 間でタイムスタンプを変換
  • av_log2(unsigned v) — log2 を計算

タイムスタンプ変換の例

c
#include <libavutil/mathematics.h>
#include <libavutil/rational.h>
#include <inttypes.h>
#include <stdio.h>

int main() {
    // 30fpsのtimebaseからミリ秒に変換
    AVRational src_timebase = {1, 30};    // 30 fps(1単位 = 1/30秒)
    AVRational dst_timebase = {1, 1000};  // ミリ秒(1単位 = 1ms)

    int64_t frame_number = 300; // 30fpsで300フレーム目 = 10秒

    int64_t milliseconds = av_rescale_q(frame_number, src_timebase, dst_timebase);
    printf("30fpsの300フレーム目 = %" PRId64 " ms\n", milliseconds); // 10000 ms

    return 0;
}

異なる timebase を持つストリームを組み合わせるとき(例えばビデオの {1, 90000} とオーディオの {1, 48000})、この変換は必須だ。

なぜ av_rescale を使うのか?

素朴な a * b / c は大きなタイムスタンプで int64_t をオーバーフローする可能性がある。av_rescale は 128 ビット中間演算を使ってこれを防ぐ。たとえば数時間のライブ配信録画を処理する場合、タイムスタンプがオーバーフローして出力のシーク位置が完全に狂うことがある。

シンプルなスケーリング例

c
#include <libavutil/mathematics.h>
#include <inttypes.h>
#include <stdio.h>

int main() {
    // av_rescale: a * b / c を正しい丸めで計算
    int64_t result = av_rescale(1000, 3, 2);
    printf("1000 * 3 / 2 = %" PRId64 "\n", result); // 1500

    return 0;
}

AVFrame と AVDictionary

この 2 つの構造体は FFmpeg のコードのあちこちに登場する。どちらも libavutil に属している。

AVFrame — デコード済みメディアデータ

AVFrame は生の映像・音声データを保持する構造体だ。libavutil の AVBuffer システムによる参照カウント方式で管理されるため、フレームのコピーは低コスト(ピクセルデータの複製ではなく、参照カウントのインクリメントだけ)。

c
#include <libavutil/frame.h>
#include <libavutil/imgutils.h>
#include <stdio.h>

int main() {
    AVFrame *frame = av_frame_alloc();
    if (!frame) {
        fprintf(stderr, "フレームの確保に失敗しました\n");
        return 1;
    }

    frame->format = AV_PIX_FMT_YUV420P;
    frame->width  = 1920;
    frame->height = 1080;

    // 実際のピクセルバッファを確保
    int ret = av_frame_get_buffer(frame, 0); // 0 = デフォルトアライメント
    if (ret < 0) {
        fprintf(stderr, "フレームバッファの確保に失敗しました\n");
        av_frame_free(&frame);
        return 1;
    }

    printf("Frame: %dx%d, format=%d, linesize[0]=%d\n",
           frame->width, frame->height, frame->format, frame->linesize[0]);

    av_frame_free(&frame);
    return 0;
}

ポイント:

  • 必ず av_frame_alloc() / av_frame_free() を使う — スタックに AVFrame を置いてはいけない
  • av_frame_get_buffer() が適切なアライメントでピクセル/サンプルデータを確保する
  • av_frame_ref() は同じデータへの新しい参照を作る(低コストコピー)
  • av_frame_unref() は参照を解放する

AVDictionary — キー・バリューのメタデータ

AVDictionary は FFmpeg の汎用キー・バリューストアだ。コンテナのメタデータ、コーデックオプション、フォーマットオプションなどに使われる。

c
#include <libavutil/dict.h>
#include <stdio.h>

int main() {
    AVDictionary *dict = NULL;

    // エントリを追加
    av_dict_set(&dict, "title", "My Video", 0);
    av_dict_set(&dict, "artist", "32blog", 0);
    av_dict_set_int(&dict, "track", 1, 0);

    // エントリを検索
    const AVDictionaryEntry *entry = av_dict_get(dict, "title", NULL, 0);
    if (entry) {
        printf("Title: %s\n", entry->value); // "My Video"
    }

    // 全エントリをイテレート
    const AVDictionaryEntry *e = NULL;
    while ((e = av_dict_iterate(dict, e))) {
        printf("%s = %s\n", e->key, e->value);
    }

    av_dict_free(&dict);
    return 0;
}

AVDictionary はファイルのメタデータ読み取り、コーデックへのオプション渡し(avcodec_open2)、フォーマットコンテキストの設定などで頻繁に使う。


画像・音声処理ユーティリティ

ピクセルフォーマットのヘルパー

c
#include <libavutil/pixdesc.h>
#include <stdio.h>

int main() {
    // ピクセルフォーマット名を取得
    enum AVPixelFormat pix_fmt = AV_PIX_FMT_YUV420P;
    const char *name = av_get_pix_fmt_name(pix_fmt);
    printf("ピクセルフォーマット: %s\n", name); // yuv420p

    // 名前からピクセルフォーマットを検索
    enum AVPixelFormat found = av_get_pix_fmt("yuv420p");
    printf("フォーマット enum: %d\n", found);

    // 詳細なフォーマット情報を取得
    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
    printf("コンポーネント数: %d, ピクセルあたりのビット数: %d\n",
           desc->nb_components,
           av_get_bits_per_pixel(desc));

    return 0;
}

ピクセルフォーマットのリファレンスに利用可能な全フォーマットが記載されている。エンコード設定や GPU エンコードでのフォーマット変換を扱うときに必要になる。

音声バッファサイズの計算

c
#include <libavutil/channel_layout.h>
#include <libavutil/samplefmt.h>
#include <stdio.h>

int main() {
    // 1024サンプル、2チャンネル(ステレオ)、16bit符号付き整数
    // に必要なバッファサイズを計算
    int buffer_size = av_samples_get_buffer_size(
        NULL,               // linesize出力(NULL = 不要)
        2,                  // チャンネル数
        1024,               // チャンネルあたりのサンプル数
        AV_SAMPLE_FMT_S16,  // サンプルフォーマット(16bit符号付き整数)
        0                   // アライメント(0 = デフォルト)
    );
    printf("音声バッファサイズ: %d バイト\n", buffer_size); // 4096 バイト
    return 0;
}

エラーハンドリングとロギング

エラーコードから文字列への変換

FFmpeg の関数はエラー時に負の整数を返す。av_strerror がこれを人間が読めるメッセージに変換してくれる。

c
#include <libavutil/error.h>
#include <stdio.h>

int main() {
    char errbuf[AV_ERROR_MAX_STRING_SIZE];

    // AVERROR(EINVAL) = -22 (Invalid argument)
    int errnum = AVERROR(EINVAL);
    av_strerror(errnum, errbuf, sizeof(errbuf));
    printf("エラー: %s\n", errbuf); // "Invalid argument"

    // AVERROR_EOF = end of file
    av_strerror(AVERROR_EOF, errbuf, sizeof(errbuf));
    printf("エラー: %s\n", errbuf); // "End of file"

    return 0;
}

構造化ログ

c
#include <libavutil/log.h>

int main() {
    // 最低ログレベルを設定(これ以下のレベルは抑制される)
    av_log_set_level(AV_LOG_DEBUG);

    // 異なる重要度でログを出力
    av_log(NULL, AV_LOG_ERROR,   "エラーです\n");
    av_log(NULL, AV_LOG_WARNING, "警告です\n");
    av_log(NULL, AV_LOG_INFO,    "情報です\n");
    av_log(NULL, AV_LOG_DEBUG,   "デバッグ出力です\n");

    return 0;
}

ログレベル(重要度が高い順):

  • AV_LOG_QUIET(全出力を抑制)
  • AV_LOG_PANIC
  • AV_LOG_FATAL
  • AV_LOG_ERROR
  • AV_LOG_WARNING
  • AV_LOG_INFO
  • AV_LOG_VERBOSE
  • AV_LOG_DEBUG

開発中は AV_LOG_DEBUG にすると FFmpeg 内部の詳細ログが見える。本番では AV_LOG_WARNINGAV_LOG_ERROR で出力を管理しよう。

カスタムログコールバック

FFmpeg のログ出力を自前のロギングシステムにリダイレクトできる:

c
#include <libavutil/log.h>
#include <stdio.h>
#include <stdarg.h>

static void custom_log_callback(void *ptr, int level, const char *fmt, va_list vl) {
    if (level > av_log_get_level()) return;

    char line[1024];
    vsnprintf(line, sizeof(line), fmt, vl);

    // 自前のロギングシステムにルーティング
    fprintf(stderr, "[FFmpeg][%d] %s", level, line);
}

int main() {
    av_log_set_callback(custom_log_callback);
    av_log_set_level(AV_LOG_INFO);

    av_log(NULL, AV_LOG_INFO, "カスタムコールバック経由のログ\n");
    return 0;
}

インストールとセットアップ

まだ FFmpeg をインストールしていない場合は、FFmpeg インストール完全ガイドを参照してほしい。ここでは C API 開発向けの要点だけ記載する。

Ubuntu / Debian

bash
sudo apt update
sudo apt install ffmpeg libavutil-dev

最新版(2026年3月時点で FFmpeg 8.1)をソースからビルドする場合:

bash
git clone https://git.ffmpeg.org/ffmpeg.git
cd ffmpeg
git checkout release/8.1
./configure
make -j$(nproc)
sudo make install

macOS

bash
brew install ffmpeg

開発用の pkg-config パス設定:

bash
export PKG_CONFIG_PATH="$(brew --prefix)/lib/pkgconfig"

Windows

ffmpeg.org/download.html から開発ライブラリ(ヘッダと .lib ファイル込み)をダウンロードして IDE に設定する。本格的なビルド環境には MSYS2 + MinGW を推奨。

libavutil を使ったプログラムのコンパイル

bash
gcc -o my_program my_program.c $(pkg-config --cflags --libs libavutil)

フォーマットやコーデックのサポートも必要な場合(実際のプロジェクトではほぼ必須):

bash
gcc -o my_program my_program.c \
    $(pkg-config --cflags --libs libavutil libavformat libavcodec)

よくあるエラーと解決方法

undefined reference to 'av_malloc'

原因: libavutil がリンクされていない。

解決策: コンパイル時にライブラリフラグを追加する:

bash
gcc -o my_program my_program.c $(pkg-config --cflags --libs libavutil)
# または手動でリンク:
gcc -o my_program my_program.c -lavutil

libavutil.so.XX: cannot open shared object file

原因: 共有ライブラリのパスが LD_LIBRARY_PATH に設定されていない。

解決策:

bash
# ライブラリパスを確認
ldd $(which ffmpeg) | grep libavutil

# パスを追加
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH

# システムにライブラリを登録
sudo ldconfig

Segmentation fault(セグメンテーションフォルト)

原因: メモリの不正アクセス — 解放済みメモリへのアクセス、未初期化ポインタの使用、av_malloc / free の混在が主な原因。

解決策:

  1. av_malloc は必ず av_free とペアにする
  2. av_malloc で取得していないポインタに av_free を呼ばない
  3. av_freep を使ってポインタを自動的に NULL にする
  4. AddressSanitizer で素早く検出:
bash
gcc -fsanitize=address -g -o my_program my_program.c \
    $(pkg-config --cflags --libs libavutil)
./my_program

または GDB でクラッシュ箇所を特定:

bash
gdb --args ./my_program
run
bt

実践例: MD5 ハッシュによるファイル整合性チェック

libavutil には暗号ハッシュ関数が含まれている。MD5 ハッシュを計算する完全な例:

c
#include <libavutil/md5.h>
#include <stdio.h>
#include <string.h>

int main() {
    AVMD5 *md5 = av_md5_alloc();
    if (!md5) {
        fprintf(stderr, "MD5コンテキストの確保に失敗しました\n");
        return 1;
    }

    const char *data = "Hello, FFmpeg!";
    unsigned char digest[16];

    av_md5_init(md5);
    av_md5_update(md5, (const uint8_t*)data, strlen(data));
    av_md5_final(md5, digest);

    printf("MD5 of \"%s\": ", data);
    for (int i = 0; i < 16; i++) {
        printf("%02x", digest[i]);
    }
    printf("\n");

    av_free(md5);
    return 0;
}

実践例: 安全なエラーハンドリングパターン

FFmpeg アプリケーションで堅牢なエラーハンドリングを実現するパターン:

c
#include <libavutil/error.h>
#include <libavformat/avformat.h>
#include <stdio.h>

// エラーチェックマクロ
#define CHECK(ret, msg) \
    do { \
        if ((ret) < 0) { \
            char errbuf[AV_ERROR_MAX_STRING_SIZE]; \
            av_strerror(ret, errbuf, sizeof(errbuf)); \
            fprintf(stderr, "%s: %s\n", msg, errbuf); \
            return (ret); \
        } \
    } while (0)

int inspect_media_file(const char *filename) {
    AVFormatContext *fmt_ctx = NULL;
    int ret;

    ret = avformat_open_input(&fmt_ctx, filename, NULL, NULL);
    CHECK(ret, "ファイルを開けませんでした");

    ret = avformat_find_stream_info(fmt_ctx, NULL);
    CHECK(ret, "ストリーム情報の取得に失敗しました");

    printf("フォーマット: %s\n", fmt_ctx->iformat->name);
    printf("再生時間: %ld 秒\n", fmt_ctx->duration / AV_TIME_BASE);
    printf("ストリーム数: %u\n", fmt_ctx->nb_streams);

    // AVDictionaryのイテレーションでメタデータを表示
    const AVDictionaryEntry *tag = NULL;
    while ((tag = av_dict_iterate(fmt_ctx->metadata, tag))) {
        printf("  %s: %s\n", tag->key, tag->value);
    }

    avformat_close_input(&fmt_ctx);
    return 0;
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
        printf("Usage: %s <input_file>\n", argv[0]);
        return 1;
    }
    return inspect_media_file(argv[1]);
}

このパターンを使えば、どのステップで何のエラーが起きたかを明確にトレースできる。コンパイル方法:

bash
gcc -o inspect inspect.c $(pkg-config --cflags --libs libavutil libavformat)

関連記事


FAQ

libavutil と libavcodec の違いは?

libavutil はメモリ管理・数学演算・ログ・エラーハンドリングなど、全 FFmpeg ライブラリが依存する低レベルのユーティリティ関数を提供する。libavcodec は音声・動画のエンコード/デコードに特化したライブラリだ。libavcodec は libavutil なしでは動作しないが、libavutil は単独で使える。

libavutil だけを FFmpeg の他のライブラリなしで使える?

使える。libavutil は他の FFmpeg ライブラリに依存していない。-lavutil だけをリンクすれば、メモリ管理関数・数学ユーティリティ・ハッシュ関数・ロギングが使える。完全なメディア処理は不要だが、アライメント付きメモリ確保やタイムスタンプ演算が必要な小さなツールに便利だ。

libavutil はスレッドセーフ?

ほとんどの libavutil 関数はスレッドセーフだ。メモリ確保(av_mallocav_free)、数学関数(av_rescale_q)、エラーハンドリング(av_strerror)は同期なしに複数スレッドから呼べる。ただし av_log_set_levelav_log_set_callback はグローバル状態を変更するため、初期化時にだけ呼ぶべきだ。

av_malloc のアライメントは何バイト?

ビルドの SIMD サポートに依存する: AVX-512 なら 64 バイト、AVX/AVX2 なら 32 バイト、SSE/NEON なら 16 バイト。一般的な x86_64 Linux ビルドでは通常 32 バイトだ。このアライメントにより、FFmpeg の SIMD 最適化ルーチンがアライメント不一致でクラッシュしないことが保証される。

インストールされている libavutil のバージョンを確認する方法は?

pkg-config を使うか、プログラムから確認できる:

bash
pkg-config --modversion libavutil

C コードからの確認:

c
#include <libavutil/version.h>
printf("libavutil %d.%d.%d\n",
       LIBAVUTIL_VERSION_MAJOR,
       LIBAVUTIL_VERSION_MINOR,
       LIBAVUTIL_VERSION_MICRO);

av_frame_clone と av_frame_ref のどちらを使うべき?

av_frame_ref() は同じデータへの新しい参照を作る(低コスト、参照カウントのインクリメントだけ)。av_frame_clone() は完全に独立したコピーを作る。ほとんどの場合は av_frame_ref を使えばいい — 不要なデータコピーを避けられる。

AV_TIME_BASE とは何か?いつ使う?

AV_TIME_BASE は FFmpeg の内部時間単位で、1,000,000(マイクロ秒)として定義されている。AVFormatContext.duration のようなコンテナレベルのタイムスタンプはこの base を使う。秒に変換するには AV_TIME_BASE で割る。ストリームレベルのタイムスタンプには、そのストリーム固有の time_baseav_rescale_q を使う。

非推奨になった libavutil 関数への対処法は?

FFmpeg は非推奨関数に attribute_deprecated を付け、次のメジャーバージョンで削除する。移行方法は API 変更ドキュメントを確認してほしい。-Wdeprecated-declarations でコンパイルすれば、非推奨 API の使用を早期に検出できる。


まとめ

libavutil は FFmpeg 開発を支える低レベルの基盤だ:

  • メモリ管理: av_malloc / av_free で FFmpeg 関連の全メモリ確保を行う — SIMD のためにアライメントが重要
  • 時間計算: av_rescale_q で timebase 間のタイムスタンプ変換 — 手動の乗除算は使わない
  • フレーム: AVFrameav_frame_alloc / av_frame_free でデコード済みメディアデータを管理
  • メタデータ: AVDictionary でキー・バリューペア(オプション、メタデータ、コーデック設定)を扱う
  • エラーハンドリング: av_strerror でエラーコードを人間が読めるメッセージに変換
  • ロギング: av_log でデバッグ・本番それぞれに適切なログレベルを設定
  • ハッシュ計算: av_md5_* でファイルの整合性チェック

libavutil を理解することが、FFmpeg の C API を効果的に使うための土台になる。フレームのデコード、フィルターの適用、出力の書き込み — すべての高レベル操作が、このライブラリのユーティリティに依存している。