Add an option to include background audio sequence in Composition.

PiperOrigin-RevId: 645100835
This commit is contained in:
simakova 2024-06-20 11:26:23 -07:00 committed by Copybara-Service
parent 99803066ea
commit 52bd9a2815
3 changed files with 47 additions and 5 deletions

View File

@ -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<String> 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<Effect> 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<EditedMediaItemSequence> 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();

View File

@ -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"/>
<androidx.appcompat.widget.AppCompatCheckBox
android:id="@+id/background_audio_checkbox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/add_background_audio"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="@id/preview_button" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/composition_export_button"
@ -100,9 +109,9 @@
android:layout_marginTop="16dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintStart_toEndOf="@id/preview_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="@id/preview_button"/>
app:layout_constraintBottom_toBottomOf="parent"/>
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/preview_button"
@ -111,7 +120,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintEnd_toStartOf="@id/composition_export_button"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -24,4 +24,5 @@
<string name="export_completed" translatable="false">Export completed in %.3f seconds.\nOutput: %s</string>
<string name="export_error" translatable="false">Export error</string>
<string name="export_started" translatable="false">Export started</string>
<string name="add_background_audio" translatable="false">Add background audio</string>
</resources>