diff --git a/demos/composition/src/main/java/androidx/media3/demo/composition/CompositionPreviewActivity.java b/demos/composition/src/main/java/androidx/media3/demo/composition/CompositionPreviewActivity.java index 36a4ade823..edf1f4a1ea 100644 --- a/demos/composition/src/main/java/androidx/media3/demo/composition/CompositionPreviewActivity.java +++ b/demos/composition/src/main/java/androidx/media3/demo/composition/CompositionPreviewActivity.java @@ -23,6 +23,7 @@ import androidx.annotation.Nullable; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.AppCompatButton; +import androidx.appcompat.widget.AppCompatCheckBox; import androidx.appcompat.widget.AppCompatTextView; import androidx.media3.common.Effect; import androidx.media3.common.MediaItem; @@ -63,6 +64,8 @@ import org.json.JSONObject; */ public final class CompositionPreviewActivity extends AppCompatActivity { private static final String TAG = "CompPreviewActivity"; + private static final String AUDIO_URI = + "https://storage.googleapis.com/exoplayer-test-media-0/play.mp3"; private ArrayList sequenceAssetTitles; private boolean[] selectedMediaItems; @@ -75,6 +78,7 @@ public final class CompositionPreviewActivity extends AppCompatActivity { private AppCompatButton exportButton; private AppCompatTextView exportInformationTextView; private Stopwatch exportStopwatch; + private boolean includeBackgroundAudioTrack; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { @@ -94,6 +98,10 @@ public final class CompositionPreviewActivity extends AppCompatActivity { exportButton = findViewById(R.id.composition_export_button); exportButton.setOnClickListener(view -> exportComposition()); + AppCompatCheckBox backgroundAudioCheckBox = findViewById(R.id.background_audio_checkbox); + backgroundAudioCheckBox.setOnCheckedChangeListener( + (compoundButton, checked) -> includeBackgroundAudioTrack = checked); + presetDescriptions = getResources().getStringArray(R.array.preset_descriptions); // Select two media items by default. selectedMediaItems = new boolean[presetDescriptions.length]; @@ -140,6 +148,9 @@ public final class CompositionPreviewActivity extends AppCompatActivity { ImmutableList effects = ImmutableList.of( MatrixTransformationFactory.createDizzyCropEffect(), RgbFilter.createGrayscaleFilter()); + // Preview requires all sequences to be the same duration, so calculate main sequence duration + // and limit background sequence duration to match. + long videoSequenceDurationUs = 0; for (int i = 0; i < selectedMediaItems.length; i++) { if (selectedMediaItems[i]) { SonicAudioProcessor pitchChanger = new SonicAudioProcessor(); @@ -156,13 +167,19 @@ public final class CompositionPreviewActivity extends AppCompatActivity { /* audioProcessors= */ ImmutableList.of(pitchChanger), /* videoEffects= */ effects)) .setDurationUs(presetDurationsUs[i]); + videoSequenceDurationUs += presetDurationsUs[i]; mediaItems.add(itemBuilder.build()); } } EditedMediaItemSequence videoSequence = new EditedMediaItemSequence(mediaItems); + List compositionSequences = new ArrayList<>(); + compositionSequences.add(videoSequence); + if (includeBackgroundAudioTrack) { + compositionSequences.add(getAudioBackgroundSequence(Util.usToMs(videoSequenceDurationUs))); + } SonicAudioProcessor sampleRateChanger = new SonicAudioProcessor(); sampleRateChanger.setOutputSampleRateHz(8_000); - return new Composition.Builder(/* sequences= */ ImmutableList.of(videoSequence)) + return new Composition.Builder(/* sequences= */ compositionSequences) .setEffects( new Effects( /* audioProcessors= */ ImmutableList.of(sampleRateChanger), @@ -170,6 +187,21 @@ public final class CompositionPreviewActivity extends AppCompatActivity { .build(); } + private EditedMediaItemSequence getAudioBackgroundSequence(long durationMs) { + MediaItem audioMediaItem = + new MediaItem.Builder() + .setUri(AUDIO_URI) + .setClippingConfiguration( + new MediaItem.ClippingConfiguration.Builder() + .setStartPositionMs(0) + .setEndPositionMs(durationMs) + .build()) + .build(); + EditedMediaItem audioItem = + new EditedMediaItem.Builder(audioMediaItem).setDurationUs(59_000_000).build(); + return new EditedMediaItemSequence(audioItem); + } + private void previewComposition() { releasePlayer(); Composition composition = prepareComposition(); diff --git a/demos/composition/src/main/res/layout/composition_preview_activity.xml b/demos/composition/src/main/res/layout/composition_preview_activity.xml index 83819ec920..185565b2d9 100644 --- a/demos/composition/src/main/res/layout/composition_preview_activity.xml +++ b/demos/composition/src/main/res/layout/composition_preview_activity.xml @@ -92,7 +92,16 @@ android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintBottom_toTopOf="@id/composition_export_button"/> + app:layout_constraintBottom_toTopOf="@id/background_audio_checkbox"/> + + + app:layout_constraintBottom_toBottomOf="parent"/> diff --git a/demos/composition/src/main/res/values/strings.xml b/demos/composition/src/main/res/values/strings.xml index b31465ffc0..bff981a978 100644 --- a/demos/composition/src/main/res/values/strings.xml +++ b/demos/composition/src/main/res/values/strings.xml @@ -24,4 +24,5 @@ Export completed in %.3f seconds.\nOutput: %s Export error Export started + Add background audio