diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/Composition.java b/libraries/transformer/src/main/java/androidx/media3/transformer/Composition.java index a8a9bbd240..ac1c60b97e 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/Composition.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/Composition.java @@ -22,7 +22,6 @@ import static java.lang.annotation.RetentionPolicy.SOURCE; import androidx.annotation.IntDef; import androidx.media3.common.MediaItem; import androidx.media3.common.VideoCompositorSettings; -import androidx.media3.common.audio.AudioProcessor; import androidx.media3.common.util.UnstableApi; import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.CanIgnoreReturnValue; @@ -121,40 +120,9 @@ public final class Composition { } /** - * Sets whether the output file should always contain an audio track. - * - *

The default value is {@code false}. - * - *

- * - * If the output contains an audio track, silent audio will be generated for the segments where - * the {@link Composition} export doesn't produce any audio. - * - *

The MIME type of the output's audio track can be set using {@link - * Transformer.Builder#setAudioMimeType(String)}. The sample rate and channel count can be set - * by passing relevant {@link AudioProcessor} instances to the {@link Composition}. - * - *

Forcing an audio track and {@linkplain #setTransmuxAudio(boolean) requesting audio - * transmuxing} are not allowed together because generating silence requires transcoding. - * - *

This method is experimental and may be removed or changed without warning. - * - * @param forceAudioTrack Whether to force an audio track in the output. - * @return This builder. + * @deprecated Use {@link EditedMediaItemSequence.Builder#setForceAudioTrack(boolean)} instead. */ + @Deprecated @CanIgnoreReturnValue public Builder experimentalSetForceAudioTrack(boolean forceAudioTrack) { this.forceAudioTrack = forceAudioTrack; @@ -260,8 +228,20 @@ public final class Composition { /** Builds a {@link Composition} instance. */ public Composition build() { + ImmutableList updatedSequences; + if (forceAudioTrack) { + ImmutableList.Builder updatedSequencesBuilder = + new ImmutableList.Builder<>(); + for (int i = 0; i < sequences.size(); i++) { + updatedSequencesBuilder.add( + sequences.get(i).buildUpon().setForceAudioTrack(forceAudioTrack).build()); + } + updatedSequences = updatedSequencesBuilder.build(); + } else { + updatedSequences = sequences; + } return new Composition( - sequences, + updatedSequences, videoCompositorSettings, effects, forceAudioTrack, @@ -379,11 +359,10 @@ public final class Composition { public final Effects effects; /** - * Whether the output file should always contain an audio track. - * - *

For more information, see {@link Builder#experimentalSetForceAudioTrack(boolean)}. + * @deprecated Use {@link EditedMediaItemSequence.Builder#setForceAudioTrack(boolean)} to set the + * flag and {@link EditedMediaItemSequence#forceAudioTrack} to read the flag. */ - public final boolean forceAudioTrack; + @Deprecated public final boolean forceAudioTrack; /** * Whether to transmux the {@linkplain MediaItem media items'} audio tracks. diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/EditedMediaItemSequence.java b/libraries/transformer/src/main/java/androidx/media3/transformer/EditedMediaItemSequence.java index 5f7cdf825a..ffa9d7819d 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/EditedMediaItemSequence.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/EditedMediaItemSequence.java @@ -18,6 +18,7 @@ package androidx.media3.transformer; import static androidx.media3.common.util.Assertions.checkArgument; import androidx.media3.common.MediaItem; +import androidx.media3.common.audio.AudioProcessor; import androidx.media3.common.util.UnstableApi; import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.CanIgnoreReturnValue; @@ -35,6 +36,7 @@ public final class EditedMediaItemSequence { public static final class Builder { private final ImmutableList.Builder items; private boolean isLooping; + private boolean forceAudioTrack; /** Creates an instance. */ public Builder(EditedMediaItem... editedMediaItems) { @@ -46,6 +48,15 @@ public final class EditedMediaItemSequence { items = new ImmutableList.Builder().addAll(editedMediaItems); } + /** Creates a new instance to build upon the provided {@link EditedMediaItemSequence}. */ + private Builder(EditedMediaItemSequence editedMediaItemSequence) { + items = + new ImmutableList.Builder() + .addAll(editedMediaItemSequence.editedMediaItems); + isLooping = editedMediaItemSequence.isLooping; + forceAudioTrack = editedMediaItemSequence.forceAudioTrack; + } + /** * Adds the {@linkplain EditedMediaItem item} to the sequence. * @@ -116,6 +127,41 @@ public final class EditedMediaItemSequence { return this; } + /** + * Forces silent audio in the {@linkplain EditedMediaItemSequence sequence}. + * + *

This flag is necessary when: + * + *

+ * + *

If the flag is not set appropriately, then the export will {@linkplain + * Transformer.Listener#onError(Composition, ExportResult, ExportException) fail}. + * + *

If the first {@link EditedMediaItem} already contains audio, this flag has no effect. + * + *

The MIME type of the output's audio track can be set using {@link + * Transformer.Builder#setAudioMimeType(String)}. The sample rate and channel count can be set + * by passing relevant {@link AudioProcessor} instances to the {@link Composition}. + * + *

Forcing an audio track and {@linkplain Composition.Builder#setTransmuxAudio(boolean) + * requesting audio transmuxing} are not allowed together because generating silence requires + * transcoding. + * + *

The default value is {@code false}. + * + * @param forceAudioTrack Whether to force audio track. + */ + @CanIgnoreReturnValue + public Builder setForceAudioTrack(boolean forceAudioTrack) { + this.forceAudioTrack = forceAudioTrack; + return this; + } + /** * Builds the {@link EditedMediaItemSequence}. * @@ -147,6 +193,9 @@ public final class EditedMediaItemSequence { */ public final boolean isLooping; + /** Forces silent audio in the {@linkplain EditedMediaItemSequence sequence}. */ + public final boolean forceAudioTrack; + /** * @deprecated Use {@link Builder}. */ @@ -172,11 +221,17 @@ public final class EditedMediaItemSequence { this(new Builder().addItems(editedMediaItems).setIsLooping(isLooping)); } + /** Returns a {@link Builder} initialized with the values of this instance. */ + public Builder buildUpon() { + return new Builder(this); + } + private EditedMediaItemSequence(EditedMediaItemSequence.Builder builder) { this.editedMediaItems = builder.items.build(); checkArgument( !editedMediaItems.isEmpty(), "The sequence must contain at least one EditedMediaItem."); this.isLooping = builder.isLooping; + this.forceAudioTrack = builder.forceAudioTrack; } /** Return whether any items are a {@linkplain Builder#addGap(long) gap}. */ diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/Effects.java b/libraries/transformer/src/main/java/androidx/media3/transformer/Effects.java index 2920d006ba..8daf2b37aa 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/Effects.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/Effects.java @@ -68,7 +68,7 @@ public final class Effects { *

The {@linkplain AudioProcessor audio processor} and {@linkplain Effect video effect} are * interlinked to help maintain A/V sync. When using Transformer, if the input file doesn't have * audio, or audio is being removed, you may have to {@linkplain - * Composition.Builder#experimentalSetForceAudioTrack force an audio track} for the interlinked + * EditedMediaItemSequence.Builder#setForceAudioTrack force an audio track} for the interlinked * effects to function correctly. Alternatively, you can use {@link SpeedChangeEffect} when input * has no audio. * diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/SequenceAssetLoader.java b/libraries/transformer/src/main/java/androidx/media3/transformer/SequenceAssetLoader.java index b1ee871010..56067d209c 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/SequenceAssetLoader.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/SequenceAssetLoader.java @@ -130,7 +130,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; public SequenceAssetLoader( EditedMediaItemSequence sequence, - boolean forceAudioTrack, Factory assetLoaderFactory, CompositionSettings compositionSettings, Listener listener, @@ -138,7 +137,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; Looper looper) { editedMediaItems = sequence.editedMediaItems; isLooping = sequence.isLooping; - this.forceAudioTrack = forceAudioTrack || sequence.editedMediaItems.get(0).isGap(); + this.forceAudioTrack = sequence.forceAudioTrack || sequence.editedMediaItems.get(0).isGap(); this.assetLoaderFactory = new GapInterceptingAssetLoaderFactory(assetLoaderFactory); this.compositionSettings = compositionSettings; sequenceAssetLoaderListener = listener; diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java b/libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java index 26a83ee331..b72167df1a 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/Transformer.java @@ -937,8 +937,8 @@ public final class Transformer { *

  • If an {@link EditedMediaItem} in a sequence contains data of a given {@linkplain * C.TrackType track}, so must all items in that sequence. * *
  • If a sequence starts with an HDR {@link EditedMediaItem}, all the following items in the * sequence must be HDR. diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java b/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java index fca022c6fb..b0c1123e3e 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java @@ -248,7 +248,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; sequenceAssetLoaders.add( new SequenceAssetLoader( sequence, - composition.forceAudioTrack, assetLoaderFactory, new CompositionSettings( transformationRequest.hdrMode, composition.retainHdrFromUltraHdrImage),