Jetpack Media3 の Transformer API は、メディア編集を高性能かつ高信頼性にするように設計されています。Transformer は、次のようなさまざまなオペレーションをサポートしています。
- トリミング、スケーリング、回転による動画の変更
- オーバーレイやフィルタなどのエフェクトの追加
- HDR やスローモーション動画などの特殊な形式の処理
- 編集を適用した後のメディア アイテムのエクスポート
このページでは、Transformer でカバーされる主なユースケースについて説明します。詳細については、 Media3 Transformer の完全なガイドをご覧ください。
始める
まず、Jetpack Media3 の Transformer、Effect、Common モジュールに依存関係を追加します。
implementation "androidx.media3:media3-transformer:1.10.0" implementation "androidx.media3:media3-effect:1.10.0" implementation "androidx.media3:media3-common:1.10.0"
1.10.0 は、ライブラリの優先バージョンに置き換えてください。最新バージョンについては、
リリースノート
をご覧ください。
重要なクラス
| クラス | 目的 |
|---|---|
Transformer |
変換の開始と停止、実行中の変換の進行状況の更新の確認を行います。 |
EditedMediaItem |
処理するメディア アイテムと、適用する編集を表します。 |
Effects |
音声エフェクトと動画エフェクトのコレクションです。 |
出力を構成する
Transformer.Builder を使用すると、TransformationRequest オブジェクトを作成しなくても、関数を設定して videoMimeType ディレクトリと audioMimetype ディレクトリを指定できるようになりました。
形式間でトランスコードする
次のコードは、H.265/AVC 動画と AAC 音声を出力するように Transformer オブジェクトを構成する方法を示しています。
Kotlin
val transformer = Transformer.Builder(context) .setVideoMimeType(MimeTypes.VIDEO_H265) .setAudioMimeType(MimeTypes.AUDIO_AAC) .build()
Java
Transformer transformer = new Transformer.Builder(context) .setVideoMimeType(MimeTypes.VIDEO_H265) .setAudioMimeType(MimeTypes.AUDIO_AAC) .build();
入力メディア形式が音声 または動画の変換リクエストとすでに一致している場合、Transformer は自動的に トランスマルチプレクスに切り替わります。つまり、圧縮されたサンプルを入力コンテナから出力コンテナにコピーします。これにより、同じ形式でデコードと再エンコードを行う際の計算コストと品質の低下を回避できます。
HDR モードを設定する
入力メディア ファイルが HDR 形式の場合、Transformer が HDR 情報を処理する方法について、いくつかの異なるモードから選択できます。おそらく、HDR_MODE_KEEP_HDR または HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL のいずれかを使用することをおすすめします。
HDR_MODE_KEEP_HDR |
HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL |
|
|---|---|---|
| 説明 | HDR データを保持します。つまり、HDR 出力形式は HDR 入力形式と同じになります。 | OpenGL トーンマッパーを使用して HDR 入力を SDR にトーンマッピングします。つまり、出力形式は SDR になります。 |
| サポート | `FEATURE_HdrEditing` 機能を備えたエンコーダを搭載したデバイスの API レベル 31 以降でサポートされています。 |
API レベル 29 以降でサポートされています。 |
| エラー | サポートされていない場合は、代わりに HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL を使用しようとします。 |
サポートされていない場合は、ExportException がスローされます。 |
必要なエンコード機能をサポートし、Android 13(API レベル 33)以降を実行しているデバイスでは、Transformer オブジェクトを使用して HDR 動画を編集できます。
次のコードに示すように、Composition オブジェクトをビルドする場合、デフォルト モードは HDR_MODE_KEEP_HDR です。
Kotlin
val composition = Composition.Builder( ImmutableList.of(videoSequence)) .setHdrMode(HDR_MODE_KEEP_HDR) .build()
Java
Composition composition = new Composition.Builder( ImmutableList.of(videoSequence)) .setHdrMode(Composition.HDR_MODE_KEEP_HDR) .build();
メディア アイテムを準備する
MediaItem は、アプリ内の音声
または動画アイテムを表します。EditedMediaItem は、MediaItem と、それに適用する変換を収集します。
動画をトリミングする
動画の不要な部分を削除するには、MediaItem に ClippingConfiguration を追加して、カスタムの開始位置と終了位置を設定します。
Kotlin
val clippingConfiguration = MediaItem.ClippingConfiguration.Builder() .setStartPositionMs(10_000) // start at 10 seconds .setEndPositionMs(20_000) // end at 20 seconds .build() val mediaItem = MediaItem.Builder() .setUri(videoUri) .setClippingConfiguration(clippingConfiguration) .build()
Java
ClippingConfiguration clippingConfiguration = new MediaItem.ClippingConfiguration.Builder() .setStartPositionMs(10_000) // start at 10 seconds .setEndPositionMs(20_000) // end at 20 seconds .build(); MediaItem mediaItem = new MediaItem.Builder() .setUri(videoUri) .setClippingConfiguration(clippingConfiguration) .build();
組み込みエフェクトを使用する
Media3 には、一般的な変換用の組み込み動画エフェクトが多数用意されています。たとえば、次のようなものがあります。
| クラス | 効果 |
|---|---|
Presentation |
解像度またはアスペクト比でメディア アイテムをスケーリングする |
ScaleAndRotateTransformation |
メディア アイテムを乗数でスケーリングする、メディア アイテムを回転させる |
Crop |
メディア アイテムを小さいフレームまたは大きいフレームに切り抜く |
OverlayEffect |
メディア アイテムの上にテキストまたは画像のオーバーレイを追加する |
音声エフェクトの場合は、生の(PCM)音声データを変換する
AudioProcessor
インスタンスのシーケンスを追加できます。たとえば、
a ChannelMixingAudioProcessor
を使用して音声チャンネルをミキシングしてスケーリングできます。
これらのエフェクトを使用するには、エフェクトまたはオーディオ プロセッサのインスタンスを作成し、メディア アイテムに適用する音声エフェクトと動画エフェクトを使用して Effects のインスタンスをビルドします。次に、Effects オブジェクトを EditedMediaItem に追加します。
Kotlin
val channelMixingProcessor = ChannelMixingAudioProcessor() val rotateEffect = ScaleAndRotateTransformation.Builder().setRotationDegrees(60f).build() val cropEffect = Crop(-0.5f, 0.5f, -0.5f, 0.5f) val effects = Effects(listOf(channelMixingProcessor), listOf(rotateEffect, cropEffect)) val editedMediaItem = EditedMediaItem.Builder(mediaItem) .setEffects(effects) .build()
Java
ChannelMixingAudioProcessor channelMixingProcessor = new ChannelMixingAudioProcessor(); ScaleAndRotateTransformation rotateEffect = new ScaleAndRotateTransformation.Builder() .setRotationDegrees(60f) .build(); Crop cropEffect = new Crop(-0.5f, 0.5f, -0.5f, 0.5f); Effects effects = new Effects( ImmutableList.of(channelMixingProcessor), ImmutableList.of(rotateEffect, cropEffect) ); EditedMediaItem editedMediaItem = new EditedMediaItem.Builder(mediaItem) .setEffects(effects) .build();
カスタム エフェクトを作成する
Media3 に含まれるエフェクトを拡張することで、ユースケースに固有のカスタム エフェクトを作成できます。次の例では、サブクラス MatrixTransformation を使用して、再生の最初の 1 秒間に動画をズームしてフレームを埋めます。
Kotlin
val zoomEffect = MatrixTransformation { presentationTimeUs -> val transformationMatrix = Matrix() // Set the scaling factor based on the playback position val scale = min(1f, presentationTimeUs / 1_000f) transformationMatrix.postScale(/* x */ scale, /* y */ scale) transformationMatrix } val editedMediaItem = EditedMediaItem.Builder(inputMediaItem) .setEffects(Effects(listOf(), listOf(zoomEffect)) .build()
Java
MatrixTransformation zoomEffect = presentationTimeUs -> { Matrix transformationMatrix = new Matrix(); // Set the scaling factor based on the playback position float scale = min(1f, presentationTimeUs / 1_000f); transformationMatrix.postScale(/* x */ scale, /* y */ scale); return transformationMatrix; }; EditedMediaItem editedMediaItem = new EditedMediaItem.Builder(inputMediaItem) .setEffects(new Effects(ImmutableList.of(), ImmutableList.of(zoomEffect))) .build();
エフェクトの動作をさらにカスタマイズするには、
GlShaderProgram を実装します。queueInputFrame() メソッドは、入力フレームの処理に使用されます。たとえば、
MediaPipe の
ML 機能を利用するには、
MediaPipe FrameProcessor
を使用して、各フレームを MediaPipe グラフに送信します。この例については、
Transformer デモアプリをご覧ください。
エフェクトをプレビューする
ExoPlayer を使用すると、エクスポート プロセスを開始する前に、メディア アイテムに追加されたエフェクト
をプレビューできます。EditedMediaItem と同じ
Effects オブジェクトを使用して、
ExoPlayer インスタンスで setVideoEffects() を呼び出します。
Kotlin
val player = ExoPlayer.builder(context) .build() .also { exoPlayer -> exoPlayer.setMediaItem(inputMediaItem) exoPlayer.setVideoEffects(effects) exoPlayer.prepare() }
Java
ExoPlayer player = new ExoPlayer.builder(context).build(); player.setMediaItem(inputMediaItem); player.setVideoEffects(effects); exoPlayer.prepare();
ExoPlayer で音声エフェクトをプレビューすることもできます。ExoPlayer インスタンスをビルドするときに、カスタムの RenderersFactory を渡します。これにより、プレーヤーのオーディオ レンダラが、AudioProcessor シーケンスを使用する AudioSink に音声を出力するように構成されます。次の例では、DefaultRenderersFactory の buildAudioSink() メソッドをオーバーライドしてこれを行います。
Kotlin
val player = ExoPlayer.Builder(context, object : DefaultRenderersFactory(context) { override fun buildAudioSink( context: Context, enableFloatOutput: Boolean, enableAudioTrackPlaybackParams: Boolean, enableOffload: Boolean ): AudioSink? { return DefaultAudioSink.Builder(context) .setEnableFloatOutput(enableFloatOutput) .setEnableAudioTrackPlaybackParams(enableAudioTrackPlaybackParams) .setOffloadMode(if (enableOffload) { DefaultAudioSink.OFFLOAD_MODE_ENABLED_GAPLESS_REQUIRED } else { DefaultAudioSink.OFFLOAD_MODE_DISABLED }) .setAudioProcessors(arrayOf(channelMixingProcessor)) .build() } }).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context, new DefaultRenderersFactory(context) { @Nullable @Override protected AudioSink buildAudioSink( Context context, boolean enableFloatOutput, boolean enableAudioTrackPlaybackParams, boolean enableOffload ) { return new DefaultAudioSink.Builder(context) .setEnableFloatOutput(enableFloatOutput) .setEnableAudioTrackPlaybackParams(enableAudioTrackPlaybackParams) .setOffloadMode( enableOffload ? DefaultAudioSink.OFFLOAD_MODE_ENABLED_GAPLESS_REQUIRED : DefaultAudioSink.OFFLOAD_MODE_DISABLED) .setAudioProcessors(new AudioProcessor[]{channelMixingProcessor}) .build(); } }).build();
変換を開始する
最後に、Transformer を作成して編集を適用し、結果のメディア アイテムのエクスポートを開始します。
Kotlin
val transformer = Transformer.Builder(context) .addListener(listener) .build() transformer.start(editedMediaItem, outputPath)
Java
Transformer transformer = new Transformer.Builder(context) .addListener(listener) .build(); transformer.start(editedMediaItem, outputPath);
同様に、必要に応じてエクスポート プロセスをキャンセルできます。
Transformer.cancel()
進行状況の更新を確認する
Transformer.start はすぐに返され、非同期的に実行されます。変換の
現在の進行状況をクエリするには、
Transformer.getProgress()を呼び出します。このメソッドは ProgressHolder を受け取ります。進行状況の状態が使用可能な場合(つまり、メソッドが PROGRESS_STATE_AVAILABLE を返す場合)、指定された ProgressHolder は現在の進行状況のパーセンテージで更新されます。
リスナーを Transformer にアタッチして、完了イベントまたはエラーイベントに関する通知を受け取ることもできます。