Add an option to include background audio sequence in Composition.
PiperOrigin-RevId: 645100835
This commit is contained in:
parent
99803066ea
commit
52bd9a2815
@ -23,6 +23,7 @@ import androidx.annotation.Nullable;
|
|||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.appcompat.widget.AppCompatButton;
|
import androidx.appcompat.widget.AppCompatButton;
|
||||||
|
import androidx.appcompat.widget.AppCompatCheckBox;
|
||||||
import androidx.appcompat.widget.AppCompatTextView;
|
import androidx.appcompat.widget.AppCompatTextView;
|
||||||
import androidx.media3.common.Effect;
|
import androidx.media3.common.Effect;
|
||||||
import androidx.media3.common.MediaItem;
|
import androidx.media3.common.MediaItem;
|
||||||
@ -63,6 +64,8 @@ import org.json.JSONObject;
|
|||||||
*/
|
*/
|
||||||
public final class CompositionPreviewActivity extends AppCompatActivity {
|
public final class CompositionPreviewActivity extends AppCompatActivity {
|
||||||
private static final String TAG = "CompPreviewActivity";
|
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 ArrayList<String> sequenceAssetTitles;
|
||||||
private boolean[] selectedMediaItems;
|
private boolean[] selectedMediaItems;
|
||||||
@ -75,6 +78,7 @@ public final class CompositionPreviewActivity extends AppCompatActivity {
|
|||||||
private AppCompatButton exportButton;
|
private AppCompatButton exportButton;
|
||||||
private AppCompatTextView exportInformationTextView;
|
private AppCompatTextView exportInformationTextView;
|
||||||
private Stopwatch exportStopwatch;
|
private Stopwatch exportStopwatch;
|
||||||
|
private boolean includeBackgroundAudioTrack;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
@ -94,6 +98,10 @@ public final class CompositionPreviewActivity extends AppCompatActivity {
|
|||||||
exportButton = findViewById(R.id.composition_export_button);
|
exportButton = findViewById(R.id.composition_export_button);
|
||||||
exportButton.setOnClickListener(view -> exportComposition());
|
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);
|
presetDescriptions = getResources().getStringArray(R.array.preset_descriptions);
|
||||||
// Select two media items by default.
|
// Select two media items by default.
|
||||||
selectedMediaItems = new boolean[presetDescriptions.length];
|
selectedMediaItems = new boolean[presetDescriptions.length];
|
||||||
@ -140,6 +148,9 @@ public final class CompositionPreviewActivity extends AppCompatActivity {
|
|||||||
ImmutableList<Effect> effects =
|
ImmutableList<Effect> effects =
|
||||||
ImmutableList.of(
|
ImmutableList.of(
|
||||||
MatrixTransformationFactory.createDizzyCropEffect(), RgbFilter.createGrayscaleFilter());
|
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++) {
|
for (int i = 0; i < selectedMediaItems.length; i++) {
|
||||||
if (selectedMediaItems[i]) {
|
if (selectedMediaItems[i]) {
|
||||||
SonicAudioProcessor pitchChanger = new SonicAudioProcessor();
|
SonicAudioProcessor pitchChanger = new SonicAudioProcessor();
|
||||||
@ -156,13 +167,19 @@ public final class CompositionPreviewActivity extends AppCompatActivity {
|
|||||||
/* audioProcessors= */ ImmutableList.of(pitchChanger),
|
/* audioProcessors= */ ImmutableList.of(pitchChanger),
|
||||||
/* videoEffects= */ effects))
|
/* videoEffects= */ effects))
|
||||||
.setDurationUs(presetDurationsUs[i]);
|
.setDurationUs(presetDurationsUs[i]);
|
||||||
|
videoSequenceDurationUs += presetDurationsUs[i];
|
||||||
mediaItems.add(itemBuilder.build());
|
mediaItems.add(itemBuilder.build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EditedMediaItemSequence videoSequence = new EditedMediaItemSequence(mediaItems);
|
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();
|
SonicAudioProcessor sampleRateChanger = new SonicAudioProcessor();
|
||||||
sampleRateChanger.setOutputSampleRateHz(8_000);
|
sampleRateChanger.setOutputSampleRateHz(8_000);
|
||||||
return new Composition.Builder(/* sequences= */ ImmutableList.of(videoSequence))
|
return new Composition.Builder(/* sequences= */ compositionSequences)
|
||||||
.setEffects(
|
.setEffects(
|
||||||
new Effects(
|
new Effects(
|
||||||
/* audioProcessors= */ ImmutableList.of(sampleRateChanger),
|
/* audioProcessors= */ ImmutableList.of(sampleRateChanger),
|
||||||
@ -170,6 +187,21 @@ public final class CompositionPreviewActivity extends AppCompatActivity {
|
|||||||
.build();
|
.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() {
|
private void previewComposition() {
|
||||||
releasePlayer();
|
releasePlayer();
|
||||||
Composition composition = prepareComposition();
|
Composition composition = prepareComposition();
|
||||||
|
@ -92,7 +92,16 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
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
|
<androidx.appcompat.widget.AppCompatButton
|
||||||
android:id="@+id/composition_export_button"
|
android:id="@+id/composition_export_button"
|
||||||
@ -100,9 +109,9 @@
|
|||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="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_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintBottom_toTopOf="@id/preview_button"/>
|
app:layout_constraintBottom_toBottomOf="parent"/>
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatButton
|
<androidx.appcompat.widget.AppCompatButton
|
||||||
android:id="@+id/preview_button"
|
android:id="@+id/preview_button"
|
||||||
@ -111,7 +120,7 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toStartOf="@id/composition_export_button"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"/>
|
app:layout_constraintBottom_toBottomOf="parent"/>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
@ -24,4 +24,5 @@
|
|||||||
<string name="export_completed" translatable="false">Export completed in %.3f seconds.\nOutput: %s</string>
|
<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_error" translatable="false">Export error</string>
|
||||||
<string name="export_started" translatable="false">Export started</string>
|
<string name="export_started" translatable="false">Export started</string>
|
||||||
|
<string name="add_background_audio" translatable="false">Add background audio</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user