Move generateSilentAudio to Composition

Also rename to forceAudioTrack

PiperOrigin-RevId: 510394620
This commit is contained in:
kimvde 2023-02-17 12:06:47 +00:00 committed by tonihei
parent 0c17605ff0
commit 5806414fba
9 changed files with 135 additions and 118 deletions

View File

@ -62,7 +62,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
public static final String SHOULD_REMOVE_AUDIO = "should_remove_audio";
public static final String SHOULD_REMOVE_VIDEO = "should_remove_video";
public static final String SHOULD_FLATTEN_FOR_SLOW_MOTION = "should_flatten_for_slow_motion";
public static final String GENERATE_SILENT_AUDIO = "generate_silent_audio";
public static final String FORCE_AUDIO_TRACK = "force_audio_track";
public static final String AUDIO_MIME_TYPE = "audio_mime_type";
public static final String VIDEO_MIME_TYPE = "video_mime_type";
public static final String RESOLUTION_HEIGHT = "resolution_height";
@ -213,7 +213,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
private @MonotonicNonNull CheckBox removeAudioCheckbox;
private @MonotonicNonNull CheckBox removeVideoCheckbox;
private @MonotonicNonNull CheckBox flattenForSlowMotionCheckbox;
private @MonotonicNonNull CheckBox generateSilentAudioCheckbox;
private @MonotonicNonNull CheckBox forceAudioTrackCheckbox;
private @MonotonicNonNull Spinner audioMimeSpinner;
private @MonotonicNonNull Spinner videoMimeSpinner;
private @MonotonicNonNull Spinner resolutionHeightSpinner;
@ -274,7 +274,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
flattenForSlowMotionCheckbox = findViewById(R.id.flatten_for_slow_motion_checkbox);
generateSilentAudioCheckbox = findViewById(R.id.generate_silent_audio_checkbox);
forceAudioTrackCheckbox = findViewById(R.id.force_audio_track_checkbox);
ArrayAdapter<String> audioMimeAdapter =
new ArrayAdapter<>(/* context= */ this, R.layout.spinner_item);
@ -385,7 +385,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
"removeAudioCheckbox",
"removeVideoCheckbox",
"flattenForSlowMotionCheckbox",
"generateSilentAudioCheckbox",
"forceAudioTrackCheckbox",
"audioMimeSpinner",
"videoMimeSpinner",
"resolutionHeightSpinner",
@ -405,7 +405,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
bundle.putBoolean(SHOULD_REMOVE_AUDIO, removeAudioCheckbox.isChecked());
bundle.putBoolean(SHOULD_REMOVE_VIDEO, removeVideoCheckbox.isChecked());
bundle.putBoolean(SHOULD_FLATTEN_FOR_SLOW_MOTION, flattenForSlowMotionCheckbox.isChecked());
bundle.putBoolean(GENERATE_SILENT_AUDIO, generateSilentAudioCheckbox.isChecked());
bundle.putBoolean(FORCE_AUDIO_TRACK, forceAudioTrackCheckbox.isChecked());
String selectedAudioMimeType = String.valueOf(audioMimeSpinner.getSelectedItem());
if (!SAME_AS_INPUT_OPTION.equals(selectedAudioMimeType)) {
bundle.putString(AUDIO_MIME_TYPE, selectedAudioMimeType);
@ -739,7 +739,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
@RequiresNonNull({
"removeVideoCheckbox",
"generateSilentAudioCheckbox",
"forceAudioTrackCheckbox",
"audioMimeSpinner",
"videoMimeSpinner",
"resolutionHeightSpinner",
@ -761,7 +761,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
@RequiresNonNull({
"removeAudioCheckbox",
"generateSilentAudioCheckbox",
"forceAudioTrackCheckbox",
"audioMimeSpinner",
"videoMimeSpinner",
"resolutionHeightSpinner",
@ -782,7 +782,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
}
@RequiresNonNull({
"generateSilentAudioCheckbox",
"forceAudioTrackCheckbox",
"audioMimeSpinner",
"videoMimeSpinner",
"resolutionHeightSpinner",
@ -794,7 +794,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
"selectVideoEffectsButton"
})
private void enableTrackSpecificOptions(boolean isAudioEnabled, boolean isVideoEnabled) {
generateSilentAudioCheckbox.setEnabled(isVideoEnabled);
forceAudioTrackCheckbox.setEnabled(isVideoEnabled);
audioMimeSpinner.setEnabled(isAudioEnabled);
videoMimeSpinner.setEnabled(isVideoEnabled);
resolutionHeightSpinner.setEnabled(isVideoEnabled);

View File

@ -82,6 +82,7 @@ import androidx.media3.transformer.Composition;
import androidx.media3.transformer.DefaultEncoderFactory;
import androidx.media3.transformer.DefaultMuxer;
import androidx.media3.transformer.EditedMediaItem;
import androidx.media3.transformer.EditedMediaItemSequence;
import androidx.media3.transformer.Effects;
import androidx.media3.transformer.ExportException;
import androidx.media3.transformer.ExportResult;
@ -99,6 +100,8 @@ import com.google.common.util.concurrent.ListenableFuture;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
@ -226,9 +229,9 @@ public final class TransformerActivity extends AppCompatActivity {
MediaItem mediaItem = createMediaItem(bundle, uri);
try {
Transformer transformer = createTransformer(bundle, filePath);
EditedMediaItem editedMediaItem = createEditedMediaItem(mediaItem, bundle);
Composition composition = createComposition(mediaItem, bundle);
exportStopwatch.start();
transformer.start(editedMediaItem, filePath);
transformer.start(composition, filePath);
this.transformer = transformer;
} catch (PackageManager.NameNotFoundException e) {
throw new IllegalStateException(e);
@ -300,10 +303,7 @@ public final class TransformerActivity extends AppCompatActivity {
requestBuilder.setHdrMode(bundle.getInt(ConfigurationActivity.HDR_MODE));
transformerBuilder.setTransformationRequest(requestBuilder.build());
transformerBuilder
.experimentalSetGenerateSilentAudio(
bundle.getBoolean(ConfigurationActivity.GENERATE_SILENT_AUDIO))
.setEncoderFactory(
transformerBuilder.setEncoderFactory(
new DefaultEncoderFactory.Builder(this.getApplicationContext())
.setEnableFallback(bundle.getBoolean(ConfigurationActivity.ENABLE_FALLBACK))
.build());
@ -357,23 +357,28 @@ public final class TransformerActivity extends AppCompatActivity {
"exportStopwatch",
"progressViewGroup",
})
private EditedMediaItem createEditedMediaItem(MediaItem mediaItem, @Nullable Bundle bundle)
private Composition createComposition(MediaItem mediaItem, @Nullable Bundle bundle)
throws PackageManager.NameNotFoundException {
EditedMediaItem.Builder editedMediaItemBuilder = new EditedMediaItem.Builder(mediaItem);
if (bundle == null) {
return editedMediaItemBuilder.build();
}
// For image inputs. Automatically ignored if input is audio/video.
editedMediaItemBuilder.setDurationUs(5_000_000).setFrameRate(30);
boolean forceAudioTrack = false;
if (bundle != null) {
ImmutableList<AudioProcessor> audioProcessors = createAudioProcessorsFromBundle(bundle);
ImmutableList<Effect> videoEffects = createVideoEffectsFromBundle(bundle);
return editedMediaItemBuilder
editedMediaItemBuilder
.setRemoveAudio(bundle.getBoolean(ConfigurationActivity.SHOULD_REMOVE_AUDIO))
.setRemoveVideo(bundle.getBoolean(ConfigurationActivity.SHOULD_REMOVE_VIDEO))
.setFlattenForSlowMotion(
bundle.getBoolean(ConfigurationActivity.SHOULD_FLATTEN_FOR_SLOW_MOTION))
.setEffects(new Effects(audioProcessors, videoEffects))
.build();
.setEffects(new Effects(audioProcessors, videoEffects));
forceAudioTrack = bundle.getBoolean(ConfigurationActivity.FORCE_AUDIO_TRACK);
}
List<EditedMediaItem> editedMediaItems = new ArrayList<>();
editedMediaItems.add(editedMediaItemBuilder.build());
List<EditedMediaItemSequence> sequences = new ArrayList<>();
sequences.add(new EditedMediaItemSequence(editedMediaItems));
return new Composition(sequences, Effects.EMPTY, forceAudioTrack);
}
private ImmutableList<AudioProcessor> createAudioProcessorsFromBundle(Bundle bundle) {

View File

@ -116,9 +116,9 @@
android:layout_weight="1">
<TextView
android:layout_gravity="center_vertical"
android:text="@string/generate_silent_audio" />
android:text="@string/force_audio_track" />
<CheckBox
android:id="@+id/generate_silent_audio_checkbox"
android:id="@+id/force_audio_track_checkbox"
android:layout_gravity="end" />
</TableRow>
<TableRow

View File

@ -67,7 +67,7 @@
<string name="permission_denied">Permission Denied</string>
<string name="hide_input_video">Hide input video</string>
<string name="show_input_video">Show input video</string>
<string name="generate_silent_audio">Generate silent audio</string>
<string name="force_audio_track">Force audio track</string>
<string name="overlay_alpha">Alpha</string>
<string name="overlay_uri">Uri</string>
<string name="bitmap_overlay_settings">Specify bitmap overlay settings</string>

View File

@ -66,16 +66,15 @@ import org.checkerframework.dataflow.qual.Pure;
TransformationRequest transformationRequest,
boolean flattenForSlowMotion,
ImmutableList<AudioProcessor> audioProcessors,
long generateSilentAudioDurationUs,
long forceAudioTrackDurationUs,
Codec.EncoderFactory encoderFactory,
MuxerWrapper muxerWrapper,
FallbackListener fallbackListener)
throws ExportException {
super(firstInputFormat, streamStartPositionUs, muxerWrapper);
if (generateSilentAudioDurationUs != C.TIME_UNSET) {
silentAudioGenerator =
new SilentAudioGenerator(firstInputFormat, generateSilentAudioDurationUs);
if (forceAudioTrackDurationUs != C.TIME_UNSET) {
silentAudioGenerator = new SilentAudioGenerator(firstInputFormat, forceAudioTrackDurationUs);
} else {
silentAudioGenerator = null;
}

View File

@ -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 java.util.List;
@ -40,16 +41,57 @@ public final class Composition {
public final ImmutableList<EditedMediaItemSequence> sequences;
/** The {@link Effects} to apply to the composition. */
public final Effects effects;
/**
* Whether the output file should always contain an audio track.
*
* <ul>
* <li>If {@code false}:
* <ul>
* <li>If the {@link Composition} export doesn't produce any audio at timestamp 0, the
* output won't contain any audio, and audio tracks from the {@link MediaItem}
* instances in the {@link Composition} will be ignored.
* <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
* TransformationRequest.Builder#setAudioMimeType(String)}. The sample rate and channel count can
* be set by passing relevant {@link AudioProcessor} instances to the {@link Composition}.
*
* <p>This parameter is experimental and may be removed or changed without warning.
*/
public final boolean experimentalForceAudioTrack;
/**
* Creates an instance.
*
* <p>This is equivalent to calling {@link Composition#Composition(List, Effects, boolean)} with
* {@link #experimentalForceAudioTrack} set to {@code false}.
*/
public Composition(List<EditedMediaItemSequence> sequences, Effects effects) {
this(sequences, effects, /* experimentalForceAudioTrack= */ false);
}
/**
* Creates an instance.
*
* @param sequences The {@link #sequences}.
* @param effects The {@link #effects}.
* @param experimentalForceAudioTrack Whether to {@linkplain #experimentalForceAudioTrack always
* add an audio track in the output}.
*/
public Composition(List<EditedMediaItemSequence> sequences, Effects effects) {
public Composition(
List<EditedMediaItemSequence> sequences,
Effects effects,
boolean experimentalForceAudioTrack) {
checkArgument(!sequences.isEmpty());
this.sequences = ImmutableList.copyOf(sequences);
this.effects = effects;
this.experimentalForceAudioTrack = experimentalForceAudioTrack;
}
}

View File

@ -33,7 +33,6 @@ import androidx.media3.common.MediaLibraryInfo;
import androidx.media3.common.MimeTypes;
import androidx.media3.common.VideoFrameProcessor;
import androidx.media3.common.audio.AudioProcessor;
import androidx.media3.common.audio.SonicAudioProcessor;
import androidx.media3.common.util.Clock;
import androidx.media3.common.util.HandlerWrapper;
import androidx.media3.common.util.ListenerSet;
@ -86,7 +85,6 @@ public final class Transformer {
private boolean removeVideo;
private boolean flattenForSlowMotion;
private boolean transmux;
private boolean generateSilentAudio;
private ListenerSet<Transformer.Listener> listeners;
private AssetLoader.@MonotonicNonNull Factory assetLoaderFactory;
private VideoFrameProcessor.Factory videoFrameProcessorFactory;
@ -123,7 +121,6 @@ public final class Transformer {
this.videoEffects = transformer.videoEffects;
this.removeAudio = transformer.removeAudio;
this.removeVideo = transformer.removeVideo;
this.generateSilentAudio = transformer.generateSilentAudio;
this.listeners = transformer.listeners;
this.assetLoaderFactory = transformer.assetLoaderFactory;
this.videoFrameProcessorFactory = transformer.videoFrameProcessorFactory;
@ -395,39 +392,6 @@ public final class Transformer {
return this;
}
/**
* Sets whether to generate silent audio for the output file, if there is no audio available.
*
* <p>This method is experimental and may be removed or changed without warning.
*
* <p>To replace existing audio with silence, {@linkplain
* EditedMediaItem.Builder#setRemoveAudio(boolean) remove the audio} from the {@link
* EditedMediaItem} to export.
*
* <p>Audio properties/format:
*
* <ul>
* <li>Duration will match duration of the input media.
* <li>Sample mime type will match {@link TransformationRequest#audioMimeType}, or {@link
* MimeTypes#AUDIO_AAC} if {@code null}.
* <li>Sample rate will be {@code 44100} Hz. This can be modified by creating a {@link
* SonicAudioProcessor}, setting its {@linkplain
* SonicAudioProcessor#setOutputSampleRateHz(int) sample rate}, and passing it to the
* {@link EditedMediaItem} used to start the export.
* <li>Channel count will be {@code 2}. This can be modified by implementing a custom {@link
* AudioProcessor} and passing it to the {@link EditedMediaItem} used to start the export.
* </ul>
*
* @param generateSilentAudio Whether to generate silent audio for the output file if there is
* no audio track.
* @return This builder.
*/
@CanIgnoreReturnValue
public Builder experimentalSetGenerateSilentAudio(boolean generateSilentAudio) {
this.generateSilentAudio = generateSilentAudio;
return this;
}
/**
* Builds a {@link Transformer} instance.
*
@ -461,7 +425,6 @@ public final class Transformer {
removeVideo,
flattenForSlowMotion,
transmux,
generateSilentAudio,
listeners,
assetLoaderFactory,
videoFrameProcessorFactory,
@ -620,7 +583,6 @@ public final class Transformer {
private final boolean removeVideo;
private final boolean flattenForSlowMotion;
private final boolean transmux;
private final boolean generateSilentAudio;
private final ListenerSet<Transformer.Listener> listeners;
private final AssetLoader.Factory assetLoaderFactory;
private final VideoFrameProcessor.Factory videoFrameProcessorFactory;
@ -641,7 +603,6 @@ public final class Transformer {
boolean removeVideo,
boolean flattenForSlowMotion,
boolean transmux,
boolean generateSilentAudio,
ListenerSet<Listener> listeners,
AssetLoader.Factory assetLoaderFactory,
VideoFrameProcessor.Factory videoFrameProcessorFactory,
@ -659,7 +620,6 @@ public final class Transformer {
this.removeVideo = removeVideo;
this.flattenForSlowMotion = flattenForSlowMotion;
this.transmux = transmux;
this.generateSilentAudio = generateSilentAudio;
this.listeners = listeners;
this.assetLoaderFactory = assetLoaderFactory;
this.videoFrameProcessorFactory = videoFrameProcessorFactory;
@ -779,7 +739,6 @@ public final class Transformer {
path,
transformationRequest,
transmux,
generateSilentAudio,
assetLoaderFactory,
encoderFactory,
muxerFactory,

View File

@ -100,7 +100,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private final ConditionVariable transformerConditionVariable;
private final ExportResult.Builder exportResultBuilder;
private boolean generateSilentAudio;
private boolean forceAudioTrack;
private boolean isDrainingPipelines;
private @Transformer.ProgressState int progressState;
private @MonotonicNonNull RuntimeException cancelException;
@ -113,7 +113,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
String outputPath,
TransformationRequest transformationRequest,
boolean transmux,
boolean generateSilentAudio,
AssetLoader.Factory assetLoaderFactory,
Codec.EncoderFactory encoderFactory,
Muxer.Factory muxerFactory,
@ -124,7 +123,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
Clock clock) {
this.context = context;
this.transformationRequest = transformationRequest;
this.generateSilentAudio = generateSilentAudio;
this.forceAudioTrack = composition.experimentalForceAudioTrack;
this.encoderFactory = new CapturingEncoderFactory(encoderFactory);
this.listener = listener;
this.applicationHandler = applicationHandler;
@ -366,11 +365,11 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
throws ExportException {
int trackType = MimeTypes.getTrackType(firstInputFormat.sampleMimeType);
if (!trackAdded) {
if (generateSilentAudio) {
if (forceAudioTrack) {
if (trackCount.get() == 1 && trackType == C.TRACK_TYPE_VIDEO) {
trackCount.incrementAndGet();
} else {
generateSilentAudio = false;
forceAudioTrack = false;
}
}
@ -387,7 +386,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
compositeAssetLoader.addOnMediaItemChangedListener(samplePipeline, trackType);
internalHandler.obtainMessage(MSG_REGISTER_SAMPLE_PIPELINE, samplePipeline).sendToTarget();
if (generateSilentAudio) {
if (forceAudioTrack) {
Format silentAudioFormat =
new Format.Builder()
.setSampleMimeType(MimeTypes.AUDIO_AAC)
@ -479,7 +478,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
transformationRequest,
firstEditedMediaItem.flattenForSlowMotion,
firstEditedMediaItem.effects.audioProcessors,
generateSilentAudio ? durationUs : C.TIME_UNSET,
forceAudioTrack ? durationUs : C.TIME_UNSET,
encoderFactory,
muxerWrapper,
fallbackListener);
@ -525,7 +524,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
if (!firstEditedMediaItem.effects.audioProcessors.isEmpty()) {
return true;
}
if (generateSilentAudio) {
if (forceAudioTrack) {
return true;
}

View File

@ -279,14 +279,17 @@ public final class TransformerEndToEndTest {
}
@Test
public void start_silentAudioOnAudioOnly_isIgnored() throws Exception {
Transformer transformer =
createTransformerBuilder(/* enableFallback= */ false)
.experimentalSetGenerateSilentAudio(true)
.build();
public void start_forceAudioTrackOnAudioOnly_isIgnored() throws Exception {
Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build();
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_UNSUPPORTED_BY_ENCODER);
EditedMediaItem editedMediaItem = new EditedMediaItem.Builder(mediaItem).build();
EditedMediaItemSequence sequence =
new EditedMediaItemSequence(ImmutableList.of(editedMediaItem));
Composition composition =
new Composition(
ImmutableList.of(sequence), Effects.EMPTY, /* experimentalForceAudioTrack= */ true);
transformer.start(mediaItem, outputPath);
transformer.start(composition, outputPath);
TransformerTestRunner.runLooper(transformer);
DumpFileAsserts.assertOutput(
@ -294,31 +297,36 @@ public final class TransformerEndToEndTest {
}
@Test
public void start_silentAudioOnAudioVideo_isIgnored() throws Exception {
Transformer transformer =
createTransformerBuilder(/* enableFallback= */ false)
.experimentalSetGenerateSilentAudio(true)
.build();
public void start_forceAudioTrackOnAudioVideo_isIgnored() throws Exception {
Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build();
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO);
EditedMediaItem editedMediaItem = new EditedMediaItem.Builder(mediaItem).build();
EditedMediaItemSequence sequence =
new EditedMediaItemSequence(ImmutableList.of(editedMediaItem));
Composition composition =
new Composition(
ImmutableList.of(sequence), Effects.EMPTY, /* experimentalForceAudioTrack= */ true);
transformer.start(mediaItem, outputPath);
transformer.start(composition, outputPath);
TransformerTestRunner.runLooper(transformer);
DumpFileAsserts.assertOutput(context, testMuxer, getDumpFileName(FILE_AUDIO_VIDEO));
}
@Test
public void start_silentAudioRemoveAudio_completesSuccessfully() throws Exception {
Transformer transformer =
createTransformerBuilder(/* enableFallback= */ false)
.experimentalSetGenerateSilentAudio(true)
.build();
public void start_forceAudioTrackAndRemoveAudio_generatesSilentAudio() throws Exception {
Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build();
EditedMediaItem editedMediaItem =
new EditedMediaItem.Builder(MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO))
.setRemoveAudio(true)
.build();
EditedMediaItemSequence sequence =
new EditedMediaItemSequence(ImmutableList.of(editedMediaItem));
Composition composition =
new Composition(
ImmutableList.of(sequence), Effects.EMPTY, /* experimentalForceAudioTrack= */ true);
transformer.start(editedMediaItem, outputPath);
transformer.start(composition, outputPath);
TransformerTestRunner.runLooper(transformer);
DumpFileAsserts.assertOutput(
@ -326,31 +334,36 @@ public final class TransformerEndToEndTest {
}
@Test
public void start_silentAudioRemoveVideo_isIgnored() throws Exception {
Transformer transformer =
createTransformerBuilder(/* enableFallback= */ false)
.experimentalSetGenerateSilentAudio(true)
.build();
public void start_forceAudioTrackAndRemoveVideo_isIgnored() throws Exception {
Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build();
EditedMediaItem editedMediaItem =
new EditedMediaItem.Builder(MediaItem.fromUri(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO))
.setRemoveVideo(true)
.build();
EditedMediaItemSequence sequence =
new EditedMediaItemSequence(ImmutableList.of(editedMediaItem));
Composition composition =
new Composition(
ImmutableList.of(sequence), Effects.EMPTY, /* experimentalForceAudioTrack= */ true);
transformer.start(editedMediaItem, outputPath);
transformer.start(composition, outputPath);
TransformerTestRunner.runLooper(transformer);
DumpFileAsserts.assertOutput(
context, testMuxer, getDumpFileName(FILE_AUDIO_VIDEO + ".novideo"));
}
@Test
public void start_silentAudioOnVideoOnly_completesSuccessfully() throws Exception {
Transformer transformer =
createTransformerBuilder(/* enableFallback= */ false)
.experimentalSetGenerateSilentAudio(true)
.build();
public void start_forceAudioTrackOnVideoOnly_generatesSilentAudio() throws Exception {
Transformer transformer = createTransformerBuilder(/* enableFallback= */ false).build();
MediaItem mediaItem = MediaItem.fromUri(ASSET_URI_PREFIX + FILE_VIDEO_ONLY);
EditedMediaItem editedMediaItem = new EditedMediaItem.Builder(mediaItem).build();
EditedMediaItemSequence sequence =
new EditedMediaItemSequence(ImmutableList.of(editedMediaItem));
Composition composition =
new Composition(
ImmutableList.of(sequence), Effects.EMPTY, /* experimentalForceAudioTrack= */ true);
transformer.start(mediaItem, outputPath);
transformer.start(composition, outputPath);
TransformerTestRunner.runLooper(transformer);
DumpFileAsserts.assertOutput(