mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Add export settings to demo-composition
Added UI and logic implementation for the following export settings: * Output audio MIME type * Output video MIME type * Enable debug tracing * Use Media3 Muxer * Produce fragmented MP4 The settings are shown in a dialog when `Export` button is clicked. PiperOrigin-RevId: 685648147
This commit is contained in:
parent
45d2bc39ae
commit
5acb483222
@ -54,6 +54,7 @@ dependencies {
|
||||
implementation project(modulePrefix + 'lib-effect')
|
||||
implementation project(modulePrefix + 'lib-exoplayer')
|
||||
implementation project(modulePrefix + 'lib-exoplayer-dash')
|
||||
implementation project(modulePrefix + 'lib-muxer')
|
||||
implementation project(modulePrefix + 'lib-transformer')
|
||||
implementation project(modulePrefix + 'lib-ui')
|
||||
implementation 'androidx.annotation:annotation:' + androidxAnnotationVersion
|
||||
|
@ -23,7 +23,10 @@ import static androidx.media3.transformer.Composition.HDR_MODE_TONE_MAP_HDR_TO_S
|
||||
import android.app.Activity;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.Toast;
|
||||
import androidx.annotation.Nullable;
|
||||
@ -34,12 +37,14 @@ import androidx.appcompat.widget.AppCompatCheckBox;
|
||||
import androidx.appcompat.widget.AppCompatTextView;
|
||||
import androidx.media3.common.Effect;
|
||||
import androidx.media3.common.MediaItem;
|
||||
import androidx.media3.common.MimeTypes;
|
||||
import androidx.media3.common.PlaybackException;
|
||||
import androidx.media3.common.Player;
|
||||
import androidx.media3.common.audio.SonicAudioProcessor;
|
||||
import androidx.media3.common.util.Clock;
|
||||
import androidx.media3.common.util.Log;
|
||||
import androidx.media3.common.util.Util;
|
||||
import androidx.media3.effect.DebugTraceUtil;
|
||||
import androidx.media3.effect.LanczosResample;
|
||||
import androidx.media3.effect.Presentation;
|
||||
import androidx.media3.effect.RgbFilter;
|
||||
@ -50,6 +55,7 @@ import androidx.media3.transformer.EditedMediaItemSequence;
|
||||
import androidx.media3.transformer.Effects;
|
||||
import androidx.media3.transformer.ExportException;
|
||||
import androidx.media3.transformer.ExportResult;
|
||||
import androidx.media3.transformer.InAppMuxer;
|
||||
import androidx.media3.transformer.JsonUtil;
|
||||
import androidx.media3.transformer.Transformer;
|
||||
import androidx.media3.ui.PlayerView;
|
||||
@ -118,7 +124,7 @@ public final class CompositionPreviewActivity extends AppCompatActivity {
|
||||
|
||||
exportInformationTextView = findViewById(R.id.export_information_text);
|
||||
exportButton = findViewById(R.id.composition_export_button);
|
||||
exportButton.setOnClickListener(view -> exportComposition());
|
||||
exportButton.setOnClickListener(view -> showExportSettings());
|
||||
|
||||
AppCompatCheckBox backgroundAudioCheckBox = findViewById(R.id.background_audio_checkbox);
|
||||
backgroundAudioCheckBox.setOnCheckedChangeListener(
|
||||
@ -231,7 +237,7 @@ public final class CompositionPreviewActivity extends AppCompatActivity {
|
||||
Spinner hdrModeSpinner = findViewById(R.id.hdr_mode_spinner);
|
||||
int selectedHdrMode =
|
||||
HDR_MODE_DESCRIPTIONS.get(String.valueOf(hdrModeSpinner.getSelectedItem()));
|
||||
return new Composition.Builder(/* sequences= */ compositionSequences)
|
||||
return new Composition.Builder(compositionSequences)
|
||||
.setEffects(
|
||||
new Effects(
|
||||
/* audioProcessors= */ ImmutableList.of(sampleRateChanger),
|
||||
@ -302,7 +308,67 @@ public final class CompositionPreviewActivity extends AppCompatActivity {
|
||||
}
|
||||
}
|
||||
|
||||
private void exportComposition() {
|
||||
private void showExportSettings() {
|
||||
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
|
||||
LayoutInflater inflater = this.getLayoutInflater();
|
||||
View exportSettingsDialogView = inflater.inflate(R.layout.export_settings, null);
|
||||
|
||||
alertDialogBuilder
|
||||
.setView(exportSettingsDialogView)
|
||||
.setTitle(R.string.export_settings)
|
||||
.setPositiveButton(
|
||||
R.string.export, (dialog, id) -> exportComposition(exportSettingsDialogView))
|
||||
.setNegativeButton(R.string.cancel, (dialog, id) -> dialog.dismiss());
|
||||
|
||||
ArrayAdapter<String> audioMimeAdapter =
|
||||
new ArrayAdapter<>(/* context= */ this, R.layout.spinner_item);
|
||||
audioMimeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
Spinner audioMimeSpinner = exportSettingsDialogView.findViewById(R.id.audio_mime_spinner);
|
||||
audioMimeSpinner.setAdapter(audioMimeAdapter);
|
||||
audioMimeAdapter.addAll(
|
||||
SAME_AS_INPUT_OPTION, MimeTypes.AUDIO_AAC, MimeTypes.AUDIO_AMR_NB, MimeTypes.AUDIO_AMR_WB);
|
||||
|
||||
ArrayAdapter<String> videoMimeAdapter =
|
||||
new ArrayAdapter<>(/* context= */ this, R.layout.spinner_item);
|
||||
videoMimeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
Spinner videoMimeSpinner = exportSettingsDialogView.findViewById(R.id.video_mime_spinner);
|
||||
videoMimeSpinner.setAdapter(videoMimeAdapter);
|
||||
videoMimeAdapter.addAll(
|
||||
SAME_AS_INPUT_OPTION,
|
||||
MimeTypes.VIDEO_H263,
|
||||
MimeTypes.VIDEO_H264,
|
||||
MimeTypes.VIDEO_H265,
|
||||
MimeTypes.VIDEO_MP4V,
|
||||
MimeTypes.VIDEO_AV1);
|
||||
|
||||
CheckBox enableDebugTracingCheckBox =
|
||||
exportSettingsDialogView.findViewById(R.id.enable_debug_tracing_checkbox);
|
||||
enableDebugTracingCheckBox.setOnCheckedChangeListener(
|
||||
(buttonView, isChecked) -> DebugTraceUtil.enableTracing = isChecked);
|
||||
|
||||
// Connect producing fragmented MP4 to using Media3 Muxer
|
||||
CheckBox useMedia3MuxerCheckBox =
|
||||
exportSettingsDialogView.findViewById(R.id.use_media3_muxer_checkbox);
|
||||
CheckBox produceFragmentedMp4CheckBox =
|
||||
exportSettingsDialogView.findViewById(R.id.produce_fragmented_mp4_checkbox);
|
||||
useMedia3MuxerCheckBox.setOnCheckedChangeListener(
|
||||
(buttonView, isChecked) -> {
|
||||
if (!isChecked) {
|
||||
produceFragmentedMp4CheckBox.setChecked(false);
|
||||
}
|
||||
});
|
||||
produceFragmentedMp4CheckBox.setOnCheckedChangeListener(
|
||||
(buttonView, isChecked) -> {
|
||||
if (isChecked) {
|
||||
useMedia3MuxerCheckBox.setChecked(true);
|
||||
}
|
||||
});
|
||||
|
||||
AlertDialog dialog = alertDialogBuilder.create();
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
private void exportComposition(View exportSettingsDialogView) {
|
||||
// Cancel and clean up files from any ongoing export.
|
||||
cancelExport();
|
||||
|
||||
@ -323,8 +389,33 @@ public final class CompositionPreviewActivity extends AppCompatActivity {
|
||||
}
|
||||
String filePath = outputFile.getAbsolutePath();
|
||||
|
||||
Transformer.Builder transformerBuilder = new Transformer.Builder(/* context= */ this);
|
||||
|
||||
Spinner audioMimeTypeSpinner = exportSettingsDialogView.findViewById(R.id.audio_mime_spinner);
|
||||
String selectedAudioMimeType = String.valueOf(audioMimeTypeSpinner.getSelectedItem());
|
||||
if (!SAME_AS_INPUT_OPTION.equals(selectedAudioMimeType)) {
|
||||
transformerBuilder.setAudioMimeType(selectedAudioMimeType);
|
||||
}
|
||||
|
||||
Spinner videoMimeTypeSpinner = exportSettingsDialogView.findViewById(R.id.video_mime_spinner);
|
||||
String selectedVideoMimeType = String.valueOf(videoMimeTypeSpinner.getSelectedItem());
|
||||
if (!SAME_AS_INPUT_OPTION.equals(selectedVideoMimeType)) {
|
||||
transformerBuilder.setVideoMimeType(selectedVideoMimeType);
|
||||
}
|
||||
|
||||
CheckBox useMedia3MuxerCheckBox =
|
||||
exportSettingsDialogView.findViewById(R.id.use_media3_muxer_checkbox);
|
||||
CheckBox produceFragmentedMp4CheckBox =
|
||||
exportSettingsDialogView.findViewById(R.id.produce_fragmented_mp4_checkbox);
|
||||
if (useMedia3MuxerCheckBox.isChecked()) {
|
||||
transformerBuilder.setMuxerFactory(
|
||||
new InAppMuxer.Factory.Builder()
|
||||
.setOutputFragmentedMp4(produceFragmentedMp4CheckBox.isChecked())
|
||||
.build());
|
||||
}
|
||||
|
||||
transformer =
|
||||
new Transformer.Builder(/* context= */ this)
|
||||
transformerBuilder
|
||||
.addListener(
|
||||
new Transformer.Listener() {
|
||||
@Override
|
||||
@ -333,6 +424,7 @@ public final class CompositionPreviewActivity extends AppCompatActivity {
|
||||
long elapsedTimeMs = exportStopwatch.elapsed(TimeUnit.MILLISECONDS);
|
||||
String details =
|
||||
getString(R.string.export_completed, elapsedTimeMs / 1000.f, filePath);
|
||||
Log.d(TAG, DebugTraceUtil.generateTraceSummary());
|
||||
Log.i(TAG, details);
|
||||
exportInformationTextView.setText(details);
|
||||
|
||||
@ -361,6 +453,7 @@ public final class CompositionPreviewActivity extends AppCompatActivity {
|
||||
Toast.LENGTH_LONG)
|
||||
.show();
|
||||
Log.e(TAG, "Export error", exportException);
|
||||
Log.d(TAG, DebugTraceUtil.generateTraceSummary());
|
||||
exportInformationTextView.setText(R.string.export_error);
|
||||
}
|
||||
})
|
||||
|
110
demos/composition/src/main/res/layout/export_settings.xml
Normal file
110
demos/composition/src/main/res/layout/export_settings.xml
Normal file
@ -0,0 +1,110 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2024 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/export_settings_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="8dp">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:layout_marginTop="12dp">
|
||||
<TextView
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/output_audio_mime_type"/>
|
||||
<Spinner
|
||||
android:id="@+id/audio_mime_spinner"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:gravity="end"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"/>
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginBottom="12dp">
|
||||
<TextView
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/output_video_mime_type"/>
|
||||
<Spinner
|
||||
android:id="@+id/video_mime_spinner"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
android:gravity="end"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"/>
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical">
|
||||
<TextView
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/enable_debug_tracing"/>
|
||||
<CheckBox
|
||||
android:id="@+id/enable_debug_tracing_checkbox"
|
||||
android:layout_gravity="end"
|
||||
android:checked="false"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"/>
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical">
|
||||
<TextView
|
||||
android:text="@string/use_media3_muxer"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1" />
|
||||
<CheckBox
|
||||
android:id="@+id/use_media3_muxer_checkbox"
|
||||
android:layout_gravity="end"
|
||||
android:checked="false"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"/>
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical">
|
||||
<TextView
|
||||
android:text="@string/produce_fragmented_mp4"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1" />
|
||||
<CheckBox
|
||||
android:id="@+id/produce_fragmented_mp4_checkbox"
|
||||
android:layout_gravity="end"
|
||||
android:checked="false"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
@ -29,4 +29,11 @@
|
||||
<string name="output_video_resolution" translatable="false">Output video resolution</string>
|
||||
<string name="hdr_mode" translatable="false">HDR mode</string>
|
||||
<string name="ok" translatable="false">OK</string>
|
||||
<string name="cancel" translatable="false">Cancel</string>
|
||||
<string name="export_settings" translatable="false">Export Settings</string>
|
||||
<string name="output_audio_mime_type" translatable="false">Output audio MIME type</string>
|
||||
<string name="output_video_mime_type" translatable="false">Output video MIME type</string>
|
||||
<string name="enable_debug_tracing" translatable="false">Enable debug tracing</string>
|
||||
<string name="use_media3_muxer" translatable="false">Use Media3 muxer</string>
|
||||
<string name="produce_fragmented_mp4" translatable="false">Produce fragmented MP4</string>
|
||||
</resources>
|
||||
|
Loading…
x
Reference in New Issue
Block a user