はじめに

Transformer の使用を開始する手順は次のとおりです。

  1. Media3 Transformer をプロジェクトの依存関係として追加します。
  2. 処理するメディアとそれに適用する編集を表す EditedMediaItem を作成します。
  3. 必要な出力と、完了イベントとエラーイベントのリスナーを記述する Transformer をビルドします。
  4. エクスポート オペレーションを開始し、編集する EditedMediaItem と出力パスを渡します。エクスポート中は、現在の進行状況をクエリしたり、オペレーションをキャンセルしたりできます。
  5. エクスポートが完了したら、必要に応じて出力を処理します。たとえば、出力を別のアプリと共有したり、サーバーにアップロードしたりできます。

これらの手順の詳細については、以下をご覧ください。また、Transformer デモアプリTransformerActivity で完全な例をご覧ください。

Media3 Transformer を依存関係として追加する

Transformer の使用を開始する最も簡単な方法は、アプリ モジュールの build.gradle ファイルにライブラリの Gradle 依存関係を追加することです。

Kotlin

implementation("androidx.media3:media3-transformer:1.5.0")
implementation("androidx.media3:media3-effect:1.5.0")
implementation("androidx.media3:media3-common:1.5.0")

Groovy

implementation "androidx.media3:media3-transformer:1.5.0"
implementation "androidx.media3:media3-effect:1.5.0"
implementation "androidx.media3:media3-common:1.5.0"

ここで、1.5.0 は目的のバージョンです。最新バージョンについては、リリースノートをご覧ください。

利用可能なライブラリ モジュールの詳細については、Google Maven AndroidX Media3 のページをご覧ください。

Java 8 のサポートを有効にする

まだ有効になっていない場合は、Transformer に依存するすべての build.gradle ファイルで Java 8 サポートを有効にする必要があります。そのためには、android セクションに次の行を追加します。

compileOptions {
  targetCompatibility JavaVersion.VERSION_1_8
}

変換を開始する

次の例では、EditedMediaItem を作成して入力ファイルの音声を削除し、Transformer インスタンスを作成して構成し、H.265/HEVC 動画をエクスポートして、結果を outputPath に出力します。

Kotlin

val inputMediaItem = MediaItem.fromUri("path_to_input_file")
val editedMediaItem =
    EditedMediaItem.Builder(inputMediaItem).setRemoveAudio(true).build()
val transformer = Transformer.Builder(context)
    .setVideoMimeType(MimeTypes.VIDEO_H265)
    .addListener(transformerListener)
    .build()
transformer.start(editedMediaItem, outputPath)

Java

MediaItem inputMediaItem = MediaItem.fromUri("path_to_input_file");
EditedMediaItem editedMediaItem =
    new EditedMediaItem.Builder(inputMediaItem).setRemoveAudio(true).build();
Transformer transformer =
    new Transformer.Builder(context)
        .setVideoMimeType(MimeTypes.VIDEO_H265)
        .addListener(transformerListener)
        .build();
transformer.start(editedMediaItem, outputPath);

メディア アイテムの詳細については、ExoPlayer メディア アイテムのページをご覧ください。入力はプログレッシブ ストリームまたはアダプティブ ストリームにできますが、出力は常にプログレッシブ ストリームです。アダプティブ入力の場合、変換には常に最高解像度のトラックが選択されます。入力は、ExoPlayer でサポートされている任意のコンテナ形式にできますが、出力は常に MP4 ファイルです。

同じ Transformer インスタンスで複数のエクスポート オペレーションを順番に実行できますが、同じインスタンスでの同時エクスポートはサポートされていません。

スレッド化に関する注意事項

トランスフォーマー インスタンスには単一のアプリケーション スレッドからアクセスする必要があり、リスナー メソッドは同じスレッドで呼び出されます。ほとんどの場合、アプリケーション スレッドはアプリのメインスレッドにできます。内部的には、Transformer はバックグラウンドで処理を行い、アプリケーション スレッドでリスナー メソッドへの呼び出しをポストします。

イベントをリッスンする

start メソッドは非同期です。すぐに返され、Transformer ビルダーに渡されたリスナーを通じてアプリにイベントが通知されます。

Kotlin

val transformerListener: Transformer.Listener =
    object : Transformer.Listener {
  override fun onCompleted(composition: Composition, result: ExportResult) {
    playOutput()
  }

  override fun onError(composition: Composition, result: ExportResult,
                       exception: ExportException) {
    displayError(exception)
  }
}

Java

Transformer.Listener transformerListener =
    new Transformer.Listener() {
      @Override
      public void onCompleted(Composition composition, ExportResult result) {
        playOutput();
      }

      @Override
      public void onError(Composition composition, ExportResult result,
          ExportException exception) {
        displayError(exception);
      }
    };

ExportResult には、出力ファイルに関する情報(ファイルサイズ、音声と動画の平均ビットレートなど)が含まれます。

進行状況の最新情報を受け取る

Transformer.getProgress を呼び出して、変換の現在の進行状況をクエリします。返される値は進行状況を示します。進行状況のステータスが PROGRESS_STATE_AVAILABLE の場合、指定された ProgressHolder が現在の進行状況のパーセンテージで更新されます。次の例は、変換の進行状況を定期的にクエリする方法を示しています。ここでは、updateProgressInUi メソッドを実装して進行状況バーを更新できます。

Kotlin

transformer.start(inputMediaItem, outputPath)
val progressHolder = ProgressHolder()
mainHandler.post(
    object : Runnable {
      override fun run() {
        val progressState: @ProgressState Int = transformer.getProgress(progressHolder)
        updateProgressInUi(progressState, progressHolder)
        if (progressState != Transformer.PROGRESS_STATE_NOT_STARTED) {
          mainHandler.postDelayed(/* r= */this,  /* delayMillis= */500)
        }
      }
    }
)

Java

transformer.start(inputMediaItem, outputPath);
ProgressHolder progressHolder = new ProgressHolder();
mainHandler.post(
    new Runnable() {
      @Override
      public void run() {
        @Transformer.ProgressState int progressState = transformer.getProgress(progressHolder);
        updateProgressInUi(progressState, progressHolder);
        if (progressState != PROGRESS_STATE_NOT_STARTED) {
          mainHandler.postDelayed(/* r= */ this, /* delayMillis= */ 500);
        }
      }
    });

変換をキャンセルする

ユーザーがエクスポート フローをキャンセルする場合は、Transformer.cancel を使用してエクスポート オペレーションをキャンセルします。ハードウェア動画コーデックなどのリソースは、特にローエンド デバイスでは限られているため、出力が不要な場合はリソースを解放することが重要です。