FFmpegテストアプリの画面とビルドログ

s – 「ffmpegらしい」NDK / JNI 実験アプリ

Android NDK 上で FFmpeg をどう扱うかを探るための、 小さなテストアプリです。 事前にビルドした libav* 系 .so や FFmpeg バイナリを JNI から呼び出し、 動画のトリミング・リサイズ・フィルタ適用などを、 実際の端末上で検証することを目的としています。

作品の説明

スマホの中にある動画を選び、 「この区間だけ切り抜きたい」「この解像度にリサイズしたい」 といった処理を FFmpeg で行うための基礎実験アプリです。

Kotlin 側から JNI を通じて C/C++ のラッパーを呼び出し、 そこから FFmpeg のフィルタグラフや avcodec / avformat を使って、 エンコード/デコードの一連の処理を走らせます。 失敗したらログをそのまま画面に出し、「どのビルド・どの引数で動いたか」を 一つずつメモしていくための“実験ノート”のようなアプリです。

  • ① PC で FFmpeg の .so / バイナリをクロスビルド
  • ② Android Studio プロジェクトに組み込み、CMake / NDK 設定
  • ③ JNI ブリッジコードから FFmpeg 関数を呼び出す
  • ④ Kotlin 側(UI)から入力動画・出力パス・コマンドを指定
  • ⑤ 実行ログ・エラーを画面で確認
  • ⑥ 成功したパターンを ebutuoY など本命プロジェクトへ還元

システム概要

Kotlin・JNI・FFmpegライブラリの構成図

Kotlin UI → JNI ブリッジ → FFmpeg ライブラリ群(libavformat, libavcodec, libavfilter, libswscale, libavutil …)という流れで処理を行います。 一部の検証では、既成の FFmpeg バイナリを exec で呼ぶパターンも試しています。

技術スタック

  • Android: Kotlin, NDK, CMake, JNI
  • FFmpeg: libavformat, libavcodec, libavfilter, libswscale, libavutil(クロスビルド)
  • Build: clang, configure スクリプト, shell スクリプトでのビルド自動化

主要コンポーネント

  • Native ライブラリ(C/C++): FFmpeg API を薄くラップした関数群。
    例:trimVideo(input, output, start, end)applyFilterGraph(...) など。
  • JNI ブリッジ: Kotlin ⇔ C 間の型変換とスレッド管理を担当。
  • FFmpeg ビルドスクリプト: Android 向けに必要なライブラリだけをビルドし、 不要な codec / filter を削ってサイズ・ビルド時間を抑制。
  • テスト UI: 入力ファイル選択、開始/終了時間、フィルタ文字列、ログ表示領域など。

技術解説

NDK / JNI

JNI で FFmpeg API を呼び出すための最小ラッパー

まずは「巨大な FFmpeg API の中から、どの関数を最小セットとして使うか」を整理しました。 デコード → フィルタ → エンコードの流れに必要な部分だけを抜き出し、 Kotlin からは “関数1つ” のように呼べるよう薄くラップしています。

JNI 側イメージ:
JNIEXPORT jint JNICALL
Java_com_example_s_FFmpegNative_trim(
  JNIEnv* env, jobject thiz,
  jstring inPath, jstring outPath,
  jdouble startSec, jdouble endSec) {
  // jstring → const char* 変換など
  // FFmpeg の avformat_open_input, av_seek_frame ... を呼び出す
}
LIBAVFILTER

filtergraph を使ったトリミング・リサイズ・回転テスト

C レベルで libavfilter を直接触り、 scalecroptranspose など よく使うフィルタを filtergraph としてつなげる実験を行いました。 これにより、後の ebutuoY のような動画編集アプリで どの程度まで FFmpeg の機能を使い込めるかを見ています。

例:"trim=start=5:end=10,scale=720:-1" のような文字列を Kotlin 側で組み立てて C 側へ渡し、avfilter_graph_parse_ptr で解釈。
BUILD / .SO

libavfilter.so をはじめとする .so のビルドと構成

既成の ffmpeg-kit のようなプロジェクトを見るだけでなく、 自分でも libavfilter.so などをビルドして構成を理解しました。 どの依存ライブラリが必要か、どの codec / filter を切り落としても大丈夫かを、 実際にビルドを通して体感しています。

・configure オプションで不要な codec を disable
・ABI(arm64-v8a / armeabi-v7a)ごとに .so を生成
・CMakeLists.txt に target_link_libraries で追加
PERFORMANCE

本命アプリ(切り抜き・スペクトログラム)への橋渡し

s アプリ自体は地味ですが、 ここで得た知見は「スペクトログラム生成」「ショート切り抜き」など 他のアプリの裏側にそのまま乗る予定です。 どの設定が端末で実用速度か、どの解像度から厳しくなるかなどを この段階で実測しておきます。

実験・結果・課題

簡単なトリミングから始めた検証

まずは 10 秒の動画から 3–7 秒だけを抜き出す、 といった単純なタスクから検証を始めました。 最初はクラッシュやノイズ混じりの動画も多かったですが、 パラメータの組み合わせを変えながら一つずつ潰していきました。

オリジナル動画のプレビュー
(a) オリジナル動画
FFmpegでトリミングした動画のプレビュー
(b) トリミング後(3–7秒)動画

現在の課題

今の s アプリは「実験用ツール」に留まっており、 一般ユーザが触る前提の UI やエラー表示にはなっていません。 また、端末ごとのハードウェアエンコーダとの兼ね合い、 ファイルサイズ・ビットレート最適化なども今後の課題です。

ハードウェアエンコードとの住み分けは未設計 ebutuoY への組み込み前に検証項目を整理

動画リンク

動画を選択 → 「trim」ボタンを押す → JNI 経由で FFmpeg が動き、 出力フォルダにトリミング済み動画が生成されるまでの様子を撮影したデモです。

s アプリで FFmpeg トリミングを実行するデモ

まだできていない部分と今後

「動画処理ミドルウェア」としての FFmpeg ラッパーへ

s アプリで確立した JNI ラッパーやビルドスクリプトは、 将来的に「動画処理ミドルウェア」として他のアプリから再利用していきます。 たとえば ebutuoY のショート切り抜き、 スペクトログラム生成前の前処理などです。

  • 短期: 基本的な trim / scale / crop / transpose の安定化。
  • 中期: filtergraph をプリセット化して、 Kotlin 側から簡単に選べるようにする。
  • 長期: FFmpeg ラッパーを別モジュール化し、 複数プロジェクトで共有する。

これからの改善点と開発計画

ビルド環境の安定化・ラッパーの整理・本命アプリへの組み込みの3ステップで考えています。

  • Build: FFmpeg ビルドスクリプトのテンプレート化。
  • API: JNI ラッパーのインターフェース整理(引数と戻り値)。
  • Integration: ebutuoY / Loopit / スペクトログラム系アプリへ連結。
17
18
19
20
21
22
23
24
25
26
27
28
29
30
FFmpeg ビルドスクリプトの整理
JNI ラッパー API の統一
ebutuoY などへの組み込み

このプロジェクトを通して

感じていること

FFmpeg を「ライブラリとして Android で動かす」ことは、 想像以上にビルドと依存関係のパズルでした。 ただ、その過程で CMake・NDK・クロスコンパイルにかなり慣れ、 他のネイティブライブラリも怖くなくなってきました。

s は UI 的には地味ですが、 ebutuoY やスペクトログラムアプリの“裏方”として 技術の底力を支えてくれる存在になると思います。 こういう「ちょっと地味な実験アプリ」をちゃんと残しておくことが、 将来の開発速度を何倍にもしてくれるはずだと感じました。

今の自分へのメモ

  • ・ビルドが通った設定は必ずメモして、二度とゼロから迷子にならないようにする。
  • ・「なぜこのオプションが必要だったか」を言葉で書き残しておく。

リファレンス & リンク

リファレンス

  • FFmpeg Documentation(libavformat, libavcodec, libavfilter, libswscale, libavutil)
  • Android NDK / CMake ドキュメント
  • tanersener/ffmpeg-kit など既存プロジェクトのビルドスクリプト

リンク