mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Add setForceAudioTrack method on EditedMediaItemSequence
PiperOrigin-RevId: 740808813
This commit is contained in:
parent
0d60c5bf25
commit
87e0d7b95a
@ -22,7 +22,6 @@ import static java.lang.annotation.RetentionPolicy.SOURCE;
|
|||||||
import androidx.annotation.IntDef;
|
import androidx.annotation.IntDef;
|
||||||
import androidx.media3.common.MediaItem;
|
import androidx.media3.common.MediaItem;
|
||||||
import androidx.media3.common.VideoCompositorSettings;
|
import androidx.media3.common.VideoCompositorSettings;
|
||||||
import androidx.media3.common.audio.AudioProcessor;
|
|
||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
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.
|
* @deprecated Use {@link EditedMediaItemSequence.Builder#setForceAudioTrack(boolean)} instead.
|
||||||
*
|
|
||||||
* <p>The default value is {@code false}.
|
|
||||||
*
|
|
||||||
* <ul>
|
|
||||||
* <li>If {@code false}:
|
|
||||||
* <ul>
|
|
||||||
* <li>If the {@link Composition} export doesn't produce any audio at timestamp 0, but
|
|
||||||
* produces audio later on, the export is {@linkplain
|
|
||||||
* Transformer.Listener#onError(Composition, ExportResult, ExportException)
|
|
||||||
* aborted}.
|
|
||||||
* <li>If the {@link Composition} doesn't produce any audio during the entire export,
|
|
||||||
* the output won't contain any audio.
|
|
||||||
* <li>If the {@link Composition} export produces audio at timestamp 0, the output will
|
|
||||||
* contain an audio track.
|
|
||||||
* </ul>
|
|
||||||
* <li>If {@code true}, the output will always contain an audio track.
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* <p>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}.
|
|
||||||
*
|
|
||||||
* <p>Forcing an audio track and {@linkplain #setTransmuxAudio(boolean) requesting audio
|
|
||||||
* transmuxing} are not allowed together because generating silence requires transcoding.
|
|
||||||
*
|
|
||||||
* <p>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
|
||||||
@CanIgnoreReturnValue
|
@CanIgnoreReturnValue
|
||||||
public Builder experimentalSetForceAudioTrack(boolean forceAudioTrack) {
|
public Builder experimentalSetForceAudioTrack(boolean forceAudioTrack) {
|
||||||
this.forceAudioTrack = forceAudioTrack;
|
this.forceAudioTrack = forceAudioTrack;
|
||||||
@ -260,8 +228,20 @@ public final class Composition {
|
|||||||
|
|
||||||
/** Builds a {@link Composition} instance. */
|
/** Builds a {@link Composition} instance. */
|
||||||
public Composition build() {
|
public Composition build() {
|
||||||
|
ImmutableList<EditedMediaItemSequence> updatedSequences;
|
||||||
|
if (forceAudioTrack) {
|
||||||
|
ImmutableList.Builder<EditedMediaItemSequence> 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(
|
return new Composition(
|
||||||
sequences,
|
updatedSequences,
|
||||||
videoCompositorSettings,
|
videoCompositorSettings,
|
||||||
effects,
|
effects,
|
||||||
forceAudioTrack,
|
forceAudioTrack,
|
||||||
@ -379,11 +359,10 @@ public final class Composition {
|
|||||||
public final Effects effects;
|
public final Effects effects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the output file should always contain an audio track.
|
* @deprecated Use {@link EditedMediaItemSequence.Builder#setForceAudioTrack(boolean)} to set the
|
||||||
*
|
* flag and {@link EditedMediaItemSequence#forceAudioTrack} to read the flag.
|
||||||
* <p>For more information, see {@link Builder#experimentalSetForceAudioTrack(boolean)}.
|
|
||||||
*/
|
*/
|
||||||
public final boolean forceAudioTrack;
|
@Deprecated public final boolean forceAudioTrack;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to transmux the {@linkplain MediaItem media items'} audio tracks.
|
* Whether to transmux the {@linkplain MediaItem media items'} audio tracks.
|
||||||
|
@ -18,6 +18,7 @@ package androidx.media3.transformer;
|
|||||||
import static androidx.media3.common.util.Assertions.checkArgument;
|
import static androidx.media3.common.util.Assertions.checkArgument;
|
||||||
|
|
||||||
import androidx.media3.common.MediaItem;
|
import androidx.media3.common.MediaItem;
|
||||||
|
import androidx.media3.common.audio.AudioProcessor;
|
||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
import com.google.errorprone.annotations.CanIgnoreReturnValue;
|
||||||
@ -35,6 +36,7 @@ public final class EditedMediaItemSequence {
|
|||||||
public static final class Builder {
|
public static final class Builder {
|
||||||
private final ImmutableList.Builder<EditedMediaItem> items;
|
private final ImmutableList.Builder<EditedMediaItem> items;
|
||||||
private boolean isLooping;
|
private boolean isLooping;
|
||||||
|
private boolean forceAudioTrack;
|
||||||
|
|
||||||
/** Creates an instance. */
|
/** Creates an instance. */
|
||||||
public Builder(EditedMediaItem... editedMediaItems) {
|
public Builder(EditedMediaItem... editedMediaItems) {
|
||||||
@ -46,6 +48,15 @@ public final class EditedMediaItemSequence {
|
|||||||
items = new ImmutableList.Builder<EditedMediaItem>().addAll(editedMediaItems);
|
items = new ImmutableList.Builder<EditedMediaItem>().addAll(editedMediaItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Creates a new instance to build upon the provided {@link EditedMediaItemSequence}. */
|
||||||
|
private Builder(EditedMediaItemSequence editedMediaItemSequence) {
|
||||||
|
items =
|
||||||
|
new ImmutableList.Builder<EditedMediaItem>()
|
||||||
|
.addAll(editedMediaItemSequence.editedMediaItems);
|
||||||
|
isLooping = editedMediaItemSequence.isLooping;
|
||||||
|
forceAudioTrack = editedMediaItemSequence.forceAudioTrack;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the {@linkplain EditedMediaItem item} to the sequence.
|
* Adds the {@linkplain EditedMediaItem item} to the sequence.
|
||||||
*
|
*
|
||||||
@ -116,6 +127,41 @@ public final class EditedMediaItemSequence {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forces silent audio in the {@linkplain EditedMediaItemSequence sequence}.
|
||||||
|
*
|
||||||
|
* <p>This flag is necessary when:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>The first {@link EditedMediaItem} in the sequence does not contain audio, but
|
||||||
|
* subsequent items do.
|
||||||
|
* <li>The first item in the sequence is a {@linkplain #addGap(long) gap} and the subsequent
|
||||||
|
* {@linkplain EditedMediaItem media items} contain audio.
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>If the flag is not set appropriately, then the export will {@linkplain
|
||||||
|
* Transformer.Listener#onError(Composition, ExportResult, ExportException) fail}.
|
||||||
|
*
|
||||||
|
* <p>If the first {@link EditedMediaItem} already contains audio, this flag has no effect.
|
||||||
|
*
|
||||||
|
* <p>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}.
|
||||||
|
*
|
||||||
|
* <p>Forcing an audio track and {@linkplain Composition.Builder#setTransmuxAudio(boolean)
|
||||||
|
* requesting audio transmuxing} are not allowed together because generating silence requires
|
||||||
|
* transcoding.
|
||||||
|
*
|
||||||
|
* <p>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}.
|
* Builds the {@link EditedMediaItemSequence}.
|
||||||
*
|
*
|
||||||
@ -147,6 +193,9 @@ public final class EditedMediaItemSequence {
|
|||||||
*/
|
*/
|
||||||
public final boolean isLooping;
|
public final boolean isLooping;
|
||||||
|
|
||||||
|
/** Forces silent audio in the {@linkplain EditedMediaItemSequence sequence}. */
|
||||||
|
public final boolean forceAudioTrack;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use {@link Builder}.
|
* @deprecated Use {@link Builder}.
|
||||||
*/
|
*/
|
||||||
@ -172,11 +221,17 @@ public final class EditedMediaItemSequence {
|
|||||||
this(new Builder().addItems(editedMediaItems).setIsLooping(isLooping));
|
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) {
|
private EditedMediaItemSequence(EditedMediaItemSequence.Builder builder) {
|
||||||
this.editedMediaItems = builder.items.build();
|
this.editedMediaItems = builder.items.build();
|
||||||
checkArgument(
|
checkArgument(
|
||||||
!editedMediaItems.isEmpty(), "The sequence must contain at least one EditedMediaItem.");
|
!editedMediaItems.isEmpty(), "The sequence must contain at least one EditedMediaItem.");
|
||||||
this.isLooping = builder.isLooping;
|
this.isLooping = builder.isLooping;
|
||||||
|
this.forceAudioTrack = builder.forceAudioTrack;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return whether any items are a {@linkplain Builder#addGap(long) gap}. */
|
/** Return whether any items are a {@linkplain Builder#addGap(long) gap}. */
|
||||||
|
@ -68,7 +68,7 @@ public final class Effects {
|
|||||||
* <p>The {@linkplain AudioProcessor audio processor} and {@linkplain Effect video effect} are
|
* <p>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
|
* 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
|
* 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
|
* effects to function correctly. Alternatively, you can use {@link SpeedChangeEffect} when input
|
||||||
* has no audio.
|
* has no audio.
|
||||||
*
|
*
|
||||||
|
@ -130,7 +130,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
|
|
||||||
public SequenceAssetLoader(
|
public SequenceAssetLoader(
|
||||||
EditedMediaItemSequence sequence,
|
EditedMediaItemSequence sequence,
|
||||||
boolean forceAudioTrack,
|
|
||||||
Factory assetLoaderFactory,
|
Factory assetLoaderFactory,
|
||||||
CompositionSettings compositionSettings,
|
CompositionSettings compositionSettings,
|
||||||
Listener listener,
|
Listener listener,
|
||||||
@ -138,7 +137,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
Looper looper) {
|
Looper looper) {
|
||||||
editedMediaItems = sequence.editedMediaItems;
|
editedMediaItems = sequence.editedMediaItems;
|
||||||
isLooping = sequence.isLooping;
|
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.assetLoaderFactory = new GapInterceptingAssetLoaderFactory(assetLoaderFactory);
|
||||||
this.compositionSettings = compositionSettings;
|
this.compositionSettings = compositionSettings;
|
||||||
sequenceAssetLoaderListener = listener;
|
sequenceAssetLoaderListener = listener;
|
||||||
|
@ -937,8 +937,8 @@ public final class Transformer {
|
|||||||
* <li>If an {@link EditedMediaItem} in a sequence contains data of a given {@linkplain
|
* <li>If an {@link EditedMediaItem} in a sequence contains data of a given {@linkplain
|
||||||
* C.TrackType track}, so must all items in that sequence.
|
* C.TrackType track}, so must all items in that sequence.
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>For audio, this condition can be removed by setting an experimental {@link
|
* <li>For audio, this condition can be removed by setting {@link
|
||||||
* Composition.Builder#experimentalSetForceAudioTrack(boolean) flag}.
|
* EditedMediaItemSequence.Builder#setForceAudioTrack(boolean)} flag.
|
||||||
* </ul>
|
* </ul>
|
||||||
* <li>If a sequence starts with an HDR {@link EditedMediaItem}, all the following items in the
|
* <li>If a sequence starts with an HDR {@link EditedMediaItem}, all the following items in the
|
||||||
* sequence must be HDR.
|
* sequence must be HDR.
|
||||||
|
@ -248,7 +248,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
sequenceAssetLoaders.add(
|
sequenceAssetLoaders.add(
|
||||||
new SequenceAssetLoader(
|
new SequenceAssetLoader(
|
||||||
sequence,
|
sequence,
|
||||||
composition.forceAudioTrack,
|
|
||||||
assetLoaderFactory,
|
assetLoaderFactory,
|
||||||
new CompositionSettings(
|
new CompositionSettings(
|
||||||
transformationRequest.hdrMode, composition.retainHdrFromUltraHdrImage),
|
transformationRequest.hdrMode, composition.retainHdrFromUltraHdrImage),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user