変換

Jetpack Media3 Transformer を使用すると、Android でメディア アセットの編集、変換、エクスポートを行うことができます。このページでは、コア変換を構成する方法について説明します。

  • コード変換とトランスマルチプレクス: 音声形式と動画形式を変換します。または、コンテナ サンプルのコピー(トランスマルチプレクス)によって 再エンコードをバイパスします。
  • トラックの削除: メディアから音声トラックまたは動画トラックを削除します。
  • トリミングと最適化: タイムスタンプでメディアをクリップします。 MP4 編集リストとトリミングの最適化を使用して、エクスポートを高速化するオプションがあります。
  • 動画エフェクト: スケーリング、回転、カスタム OpenGL シェーダー エフェクトの適用を行います。 ExoPlayer でプレビューすることもできます。
  • 画像入力: 静止画像を、カスタムの再生時間 とフレームレートの動画クリップに変換します。
  • 音声処理: AudioProcessor インスタンスを連結して、未加工の音声を変更します。

形式間のコード変換

Transformer のビルド時に生成する出力音声形式と動画形式を指定できます。たとえば、次のコードは、H.264/AVC 動画と AAC 音声を出力するように Transformer を構成する方法を示しています。

Kotlin

Transformer.Builder(context)
  .setVideoMimeType(MimeTypes.VIDEO_H264)
  .setAudioMimeType(MimeTypes.AUDIO_AAC)
  .build()

Java

new Transformer.Builder(context)
    .setVideoMimeType(MimeTypes.VIDEO_H264)
    .setAudioMimeType(MimeTypes.AUDIO_AAC)
    .build();

入力メディア形式が音声 または動画の設定と一致する場合、Transformer は自動的にトランスマルチプレクスに切り替わります。つまり、圧縮されたサンプルを入力コンテナから出力コンテナにそのままコピーします。これにより、同じ形式でデコードと再エンコードを行う場合の計算コストと品質の低下を回避できます。

音声または動画を削除する

EditedMediaItem.Builder を使用して音声または動画を削除します。例を次に示します。

Kotlin

EditedMediaItem.Builder(inputMediaItem).setRemoveAudio(true).build()

Java

new EditedMediaItem.Builder(inputMediaItem).setRemoveAudio(true).build();

クリップをトリミングする

入力メディア アイテムにクリッピング構成を設定すると、指定した開始タイムスタンプと終了タイムスタンプの外側のメディアを削除できます。たとえば、10 秒から 20 秒の間のメディアのみを含むクリップを生成するには、次のようにします。

Kotlin

val inputMediaItem =
  MediaItem.Builder()
    .setUri(uri)
    .setClippingConfiguration(
      MediaItem.ClippingConfiguration.Builder()
        .setStartPositionMs(10_000)
        .setEndPositionMs(20_000)
        .build()
    )
    .build()

Java

MediaItem inputMediaItem =
    new MediaItem.Builder()
        .setUri(uri)
        .setClippingConfiguration(
            new MediaItem.ClippingConfiguration.Builder()
                .setStartPositionMs(10_000)
                .setEndPositionMs(20_000)
                .build())
        .build();

MP4 編集リスト

トリミングを高速化するため、Transformer は MP4 編集リストをサポートしています。これにより、動画を完全に再コード変換することなく、より効率的な「トリミングのみ」の編集が可能になります。この方法では、既存のエンコードされたサンプルと編集リスト内の「プリロール」を使用します。これにより、プレーヤーは特定のポイントから再生を開始し、不要な最初のセグメントを効果的にスキップできます。

トリミングのみの編集を大幅に高速化するには、experimentalSetMp4EditListTrimEnabled(true) を呼び出します。

Kotlin

Transformer.Builder(context).experimentalSetMp4EditListTrimEnabled(true).build()

Java

new Transformer.Builder(context).experimentalSetMp4EditListTrimEnabled(true).build();
ただし、すべてのメディア プレーヤーが「プリロール」位置をサポートしているわけではないことに注意してください。つまり、このようなプレーヤーを使用する場合、開始点を指定する編集リストの情報に関係なく、エンコードされたサンプルの絶対的な先頭からファイルの再生が開始されます。

トリミングの最適化

動画の先頭をトリミングする際のレイテンシを短縮するには、トリミングの最適化を有効にします。

Kotlin

Transformer.Builder(context).experimentalSetTrimOptimizationEnabled(true).build()

Java

new Transformer.Builder(context).experimentalSetTrimOptimizationEnabled(true).build();

これにより、動画のデコードと再エンコードを可能な限り少なくして、再エンコードされたデータを元の動画の残りの部分とつなぎ合わせることで、エクスポートが高速化されます。最適化は、入力ファイルの一部を新しくエンコードされた出力とつなぎ合わせることができることを前提としています。つまり、エンコーダの出力形式と入力形式に互換性がある必要があります。そのため、たとえば、ファイルが元々別のエンコーダ実装のデバイスで作成された場合、最適化を適用できない可能性があります。 最適化を成功させるには、EncoderFactory を介して Transformer に提供されるエンコーダのレベルとプロファイルが入力形式と互換性がある必要があります。

この最適化は、no op 動画エフェクトと 90 度で割り切れる回転以外のエフェクトがない単一アセットの MP4 入力でのみ機能します。最適化に失敗した場合、Transformer は自動的に通常のエクスポートにフォールバックし、ExportResult.OptimizationResult で最適化の結果を報告します。

この機能は検証中であり、今後のリリースで試験運用版ではなくなる予定です。

動画の編集

EditedMediaItems には、順番に適用する音声プロセッサと動画エフェクトのリストがあります。ライブラリには、一般的なユースケース向けの動画エフェクトの実装が含まれています。また、カスタム エフェクトを作成して、編集済みメディア アイテムのビルド時に渡すこともできます。

メディアを再スケーリングできます。これは、4K や 8K 動画など、非常に高解像度の入力を使用する場合に、処理リソースや帯域幅を節約するのに役立ちます。 たとえば、高さ 480 ピクセルに比例してスケーリングするには、次のようにします。

Kotlin

EditedMediaItem.Builder(MediaItem.fromUri(uri))
  .setEffects(
    Effects(
      /* audioProcessors= */ listOf(),
      /* videoEffects= */ listOf(Presentation.createForHeight(480)),
    )
  )
  .build()

Java

new EditedMediaItem.Builder(MediaItem.fromUri(uri))
    .setEffects(
        new Effects(
            /* audioProcessors= */ ImmutableList.of(),
            /* videoEffects= */ ImmutableList.of(Presentation.createForHeight(480))))
    .build();

または、指定した係数でスケーリングすることもできます。たとえば、サイズを半分にするには、次のようにします。

Kotlin

val editedMediaItem =
  EditedMediaItem.Builder(MediaItem.fromUri(uri))
    .setEffects(
      Effects(
        /* audioProcessors= */ listOf(),
        /* videoEffects= */ listOf(
          ScaleAndRotateTransformation.Builder().setScale(.5f, .5f).build()
        ),
      )
    )
    .build()

Java

new EditedMediaItem.Builder(MediaItem.fromUri(uri))
    .setEffects(
        new Effects(
            /* audioProcessors= */ ImmutableList.of(),
            /* videoEffects= */ ImmutableList.of(
                new ScaleAndRotateTransformation.Builder().setScale(.5f, .5f).build())))
    .build();

回転も同様に構成できます。

Kotlin

EditedMediaItem.Builder(MediaItem.fromUri(uri))
  .setEffects(
    Effects(
      /* audioProcessors= */ listOf(),
      /* videoEffects= */ listOf(
        ScaleAndRotateTransformation.Builder().setRotationDegrees(90f).build()
      ),
    )
  )
  .build()

Java

new EditedMediaItem.Builder(MediaItem.fromUri(uri))
    .setEffects(
        new Effects(
            /* audioProcessors= */ ImmutableList.of(),
            /* videoEffects= */ ImmutableList.of(
                new ScaleAndRotateTransformation.Builder().setRotationDegrees(90f).build())))
    .build();

カスタム動画エフェクト

Effects コンストラクタは、適用する音声エフェクトと動画エフェクトのリストを受け取ります。内部的には、Transformer のエフェクト フレームワークは、動画エフェクトのリストを順番に適用される GL シェーダー プログラムのシーケンスに変換します。場合によっては、エフェクト フレームワークで 1 つのシェーダー プログラムで複数のエフェクトを適用できます。 たとえば、1 つのシェーダー プログラムで複数の連続する行列変換を適用できるため、効率と品質が向上します。

動画エフェクトは、ExoPlayer.setVideoEffects を使用して、ExoPlayer でのプレビューでもサポートされています。この API の使用方法の例については、 エフェクト デモアプリをご覧ください。

デモアプリには、カスタム動画エフェクトの例が含まれています。

画像入力

Transformer は、静止画像を入力として扱い、静止動画クリップとして処理することで、画像入力をサポートします。画像を入力ソースとして構成する手順は次のとおりです。

  • MediaItem.Builder を使用して MediaItem を作成します。setImageDurationMs を呼び出して、出力動画での画像の表示時間を指定します。

  • MediaItem をラップする EditedMediaItem を作成します。EditedMediaItem.Builder#setFrameRate を使用して、生成された動画ストリームのターゲット フレームレートを指定します。

次の例は、画像入力を構成して、1 秒あたり 30 フレームの 5 秒間の動画を生成する方法を示しています。

Kotlin

val imageMediaItem =
  MediaItem.Builder()
    .setUri(imageUri)
    .setImageDurationMs(5000) // 5 seconds
    .build()

val editedImageItem =
  EditedMediaItem.Builder(imageMediaItem)
    .setFrameRate(30) // 30 frames per second
    .build()

Java

MediaItem imageMediaItem =
    new MediaItem.Builder()
        .setUri(imageUri)
        .setImageDurationMs(5000) // 5 seconds
        .build();
new EditedMediaItem.Builder(imageMediaItem)
    .setFrameRate(30) // 30 frames per second
    .build();

音声の編集

音声エフェクトは、AudioProcessor インスタンスのシーケンスを未加工の(PCM)音声に適用することで実装されます。ExoPlayer では、音声プロセッサを DefaultAudioSink.Builder に渡すことができるため、音声編集をプレビューできます。