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 のコアユーティリティライブラリだ。libavcodec、libavformat、libavfilter など、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 を使う開発では常に存在する。
メモリ管理
FFmpeg はメディア処理で大量のデータを扱うため、メモリ管理が極めて重要になる。av_malloc と free を混在させてセグフォに悩まされるケースは、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 にセット(安全版)
基本的な使い方
#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-512 | 64 バイト |
| AVX / AVX2 | 32 バイト |
| SSE / NEON | 16 バイト |
一般的な x86_64 ビルド(AVX2 対応)では、av_malloc は 32 バイトアライメントのメモリを返す。FFmpeg の DSP ルーチンは SIMD 命令を使うため、アライメントされていないデータでクラッシュする。標準の malloc はほとんどのプラットフォームで 16 バイトアライメントしか保証しない。
フレームバッファに普通の malloc を使うと、特定の解像度でランダムにセグフォが発生することがある。av_malloc に切り替えると解消するケースがほとんどで、原因は AVX2 のコードパスが 32 バイトアライメントを要求していることだ。
av_freep: より安全な解放
av_freep はメモリを解放すると同時にポインタを NULL にセットしてくれる。解放済みメモリへのアクセス(use-after-free)を防ぐのに有効だ:
#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 を計算
タイムスタンプ変換の例
#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 ビット中間演算を使ってこれを防ぐ。たとえば数時間のライブ配信録画を処理する場合、タイムスタンプがオーバーフローして出力のシーク位置が完全に狂うことがある。
シンプルなスケーリング例
#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 システムによる参照カウント方式で管理されるため、フレームのコピーは低コスト(ピクセルデータの複製ではなく、参照カウントのインクリメントだけ)。
#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 の汎用キー・バリューストアだ。コンテナのメタデータ、コーデックオプション、フォーマットオプションなどに使われる。
#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)、フォーマットコンテキストの設定などで頻繁に使う。
画像・音声処理ユーティリティ
ピクセルフォーマットのヘルパー
#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 エンコードでのフォーマット変換を扱うときに必要になる。
音声バッファサイズの計算
#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 がこれを人間が読めるメッセージに変換してくれる。
#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;
}
構造化ログ
#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_PANICAV_LOG_FATALAV_LOG_ERRORAV_LOG_WARNINGAV_LOG_INFOAV_LOG_VERBOSEAV_LOG_DEBUG
開発中は AV_LOG_DEBUG にすると FFmpeg 内部の詳細ログが見える。本番では AV_LOG_WARNING か AV_LOG_ERROR で出力を管理しよう。
カスタムログコールバック
FFmpeg のログ出力を自前のロギングシステムにリダイレクトできる:
#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
sudo apt update
sudo apt install ffmpeg libavutil-dev
最新版(2026年3月時点で FFmpeg 8.1)をソースからビルドする場合:
git clone https://git.ffmpeg.org/ffmpeg.git
cd ffmpeg
git checkout release/8.1
./configure
make -j$(nproc)
sudo make install
macOS
brew install ffmpeg
開発用の pkg-config パス設定:
export PKG_CONFIG_PATH="$(brew --prefix)/lib/pkgconfig"
Windows
ffmpeg.org/download.html から開発ライブラリ(ヘッダと .lib ファイル込み)をダウンロードして IDE に設定する。本格的なビルド環境には MSYS2 + MinGW を推奨。
libavutil を使ったプログラムのコンパイル
gcc -o my_program my_program.c $(pkg-config --cflags --libs libavutil)
フォーマットやコーデックのサポートも必要な場合(実際のプロジェクトではほぼ必須):
gcc -o my_program my_program.c \
$(pkg-config --cflags --libs libavutil libavformat libavcodec)
よくあるエラーと解決方法
undefined reference to 'av_malloc'
原因: libavutil がリンクされていない。
解決策: コンパイル時にライブラリフラグを追加する:
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 に設定されていない。
解決策:
# ライブラリパスを確認
ldd $(which ffmpeg) | grep libavutil
# パスを追加
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
# システムにライブラリを登録
sudo ldconfig
Segmentation fault(セグメンテーションフォルト)
原因: メモリの不正アクセス — 解放済みメモリへのアクセス、未初期化ポインタの使用、av_malloc / free の混在が主な原因。
解決策:
av_mallocは必ずav_freeとペアにするav_mallocで取得していないポインタにav_freeを呼ばないav_freepを使ってポインタを自動的に NULL にする- AddressSanitizer で素早く検出:
gcc -fsanitize=address -g -o my_program my_program.c \
$(pkg-config --cflags --libs libavutil)
./my_program
または GDB でクラッシュ箇所を特定:
gdb --args ./my_program
run
bt
実践例: MD5 ハッシュによるファイル整合性チェック
libavutil には暗号ハッシュ関数が含まれている。MD5 ハッシュを計算する完全な例:
#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 アプリケーションで堅牢なエラーハンドリングを実現するパターン:
#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]);
}
このパターンを使えば、どのステップで何のエラーが起きたかを明確にトレースできる。コンパイル方法:
gcc -o inspect inspect.c $(pkg-config --cflags --libs libavutil libavformat)
関連記事
- FFmpeg インストール完全ガイド — 各プラットフォームへの FFmpeg インストール手順
- FFmpegの使い方 完全ガイド — C API ではなくコマンドラインから FFmpeg を使う方法
- FFmpeg GPU エンコード(NVENC / QSV) — libavutil の
hwcontextAPI を活用したハードウェアアクセラレーション - FFmpeg 動画圧縮ガイド — libavutil がサポートするコーデックを使った実践的な圧縮テクニック
- FFmpeg × Python バッチ処理自動化 — C API を使わずに Python の
subprocessで FFmpeg を制御する方法 - ffmpeg.wasm: ブラウザで動画処理 — libavutil を WebAssembly にコンパイルしてクライアントサイドで処理
- FFmpeg 商用ライセンスガイド — 商用プロダクトで libavutil をリンクする際の LGPL / GPL の注意点
FAQ
libavutil と libavcodec の違いは?
libavutil はメモリ管理・数学演算・ログ・エラーハンドリングなど、全 FFmpeg ライブラリが依存する低レベルのユーティリティ関数を提供する。libavcodec は音声・動画のエンコード/デコードに特化したライブラリだ。libavcodec は libavutil なしでは動作しないが、libavutil は単独で使える。
libavutil だけを FFmpeg の他のライブラリなしで使える?
使える。libavutil は他の FFmpeg ライブラリに依存していない。-lavutil だけをリンクすれば、メモリ管理関数・数学ユーティリティ・ハッシュ関数・ロギングが使える。完全なメディア処理は不要だが、アライメント付きメモリ確保やタイムスタンプ演算が必要な小さなツールに便利だ。
libavutil はスレッドセーフ?
ほとんどの libavutil 関数はスレッドセーフだ。メモリ確保(av_malloc、av_free)、数学関数(av_rescale_q)、エラーハンドリング(av_strerror)は同期なしに複数スレッドから呼べる。ただし av_log_set_level と av_log_set_callback はグローバル状態を変更するため、初期化時にだけ呼ぶべきだ。
av_malloc のアライメントは何バイト?
ビルドの SIMD サポートに依存する: AVX-512 なら 64 バイト、AVX/AVX2 なら 32 バイト、SSE/NEON なら 16 バイト。一般的な x86_64 Linux ビルドでは通常 32 バイトだ。このアライメントにより、FFmpeg の SIMD 最適化ルーチンがアライメント不一致でクラッシュしないことが保証される。
インストールされている libavutil のバージョンを確認する方法は?
pkg-config を使うか、プログラムから確認できる:
pkg-config --modversion libavutil
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_base と av_rescale_q を使う。
非推奨になった libavutil 関数への対処法は?
FFmpeg は非推奨関数に attribute_deprecated を付け、次のメジャーバージョンで削除する。移行方法は API 変更ドキュメントを確認してほしい。-Wdeprecated-declarations でコンパイルすれば、非推奨 API の使用を早期に検出できる。
まとめ
libavutil は FFmpeg 開発を支える低レベルの基盤だ:
- メモリ管理:
av_malloc/av_freeで FFmpeg 関連の全メモリ確保を行う — SIMD のためにアライメントが重要 - 時間計算:
av_rescale_qで timebase 間のタイムスタンプ変換 — 手動の乗除算は使わない - フレーム:
AVFrameとav_frame_alloc/av_frame_freeでデコード済みメディアデータを管理 - メタデータ:
AVDictionaryでキー・バリューペア(オプション、メタデータ、コーデック設定)を扱う - エラーハンドリング:
av_strerrorでエラーコードを人間が読めるメッセージに変換 - ロギング:
av_logでデバッグ・本番それぞれに適切なログレベルを設定 - ハッシュ計算:
av_md5_*でファイルの整合性チェック
libavutil を理解することが、FFmpeg の C API を効果的に使うための土台になる。フレームのデコード、フィルターの適用、出力の書き込み — すべての高レベル操作が、このライブラリのユーティリティに依存している。