Add HDR & Resolution Height settings to demo-composition
Added UI and logic implementation for HDR mode and Resolution Height to be used as settings for both previewing and exporting. PiperOrigin-RevId: 684011852
This commit is contained in:
parent
c744fe9f8f
commit
d5baa4ce59
@ -15,9 +15,16 @@
|
|||||||
*/
|
*/
|
||||||
package androidx.media3.demo.composition;
|
package androidx.media3.demo.composition;
|
||||||
|
|
||||||
|
import static androidx.media3.transformer.Composition.HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR;
|
||||||
|
import static androidx.media3.transformer.Composition.HDR_MODE_KEEP_HDR;
|
||||||
|
import static androidx.media3.transformer.Composition.HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC;
|
||||||
|
import static androidx.media3.transformer.Composition.HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.Spinner;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
@ -33,6 +40,8 @@ import androidx.media3.common.audio.SonicAudioProcessor;
|
|||||||
import androidx.media3.common.util.Clock;
|
import androidx.media3.common.util.Clock;
|
||||||
import androidx.media3.common.util.Log;
|
import androidx.media3.common.util.Log;
|
||||||
import androidx.media3.common.util.Util;
|
import androidx.media3.common.util.Util;
|
||||||
|
import androidx.media3.effect.LanczosResample;
|
||||||
|
import androidx.media3.effect.Presentation;
|
||||||
import androidx.media3.effect.RgbFilter;
|
import androidx.media3.effect.RgbFilter;
|
||||||
import androidx.media3.transformer.Composition;
|
import androidx.media3.transformer.Composition;
|
||||||
import androidx.media3.transformer.CompositionPlayer;
|
import androidx.media3.transformer.CompositionPlayer;
|
||||||
@ -50,6 +59,7 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||||||
import com.google.common.base.Stopwatch;
|
import com.google.common.base.Stopwatch;
|
||||||
import com.google.common.base.Ticker;
|
import com.google.common.base.Ticker;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -66,6 +76,17 @@ public final class CompositionPreviewActivity extends AppCompatActivity {
|
|||||||
private static final String TAG = "CompPreviewActivity";
|
private static final String TAG = "CompPreviewActivity";
|
||||||
private static final String AUDIO_URI =
|
private static final String AUDIO_URI =
|
||||||
"https://storage.googleapis.com/exoplayer-test-media-0/play.mp3";
|
"https://storage.googleapis.com/exoplayer-test-media-0/play.mp3";
|
||||||
|
private static final String SAME_AS_INPUT_OPTION = "same as input";
|
||||||
|
private static final ImmutableMap<String, @Composition.HdrMode Integer> HDR_MODE_DESCRIPTIONS =
|
||||||
|
new ImmutableMap.Builder<String, @Composition.HdrMode Integer>()
|
||||||
|
.put("Keep HDR", HDR_MODE_KEEP_HDR)
|
||||||
|
.put("MediaCodec tone-map HDR to SDR", HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_MEDIACODEC)
|
||||||
|
.put("OpenGL tone-map HDR to SDR", HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL)
|
||||||
|
.put("Force Interpret HDR as SDR", HDR_MODE_EXPERIMENTAL_FORCE_INTERPRET_HDR_AS_SDR)
|
||||||
|
.build();
|
||||||
|
private static final ImmutableList<String> RESOLUTION_HEIGHTS =
|
||||||
|
ImmutableList.of(
|
||||||
|
SAME_AS_INPUT_OPTION, "144", "240", "360", "480", "720", "1080", "1440", "2160");
|
||||||
|
|
||||||
private ArrayList<String> sequenceAssetTitles;
|
private ArrayList<String> sequenceAssetTitles;
|
||||||
private boolean[] selectedMediaItems;
|
private boolean[] selectedMediaItems;
|
||||||
@ -103,6 +124,19 @@ public final class CompositionPreviewActivity extends AppCompatActivity {
|
|||||||
backgroundAudioCheckBox.setOnCheckedChangeListener(
|
backgroundAudioCheckBox.setOnCheckedChangeListener(
|
||||||
(compoundButton, checked) -> includeBackgroundAudioTrack = checked);
|
(compoundButton, checked) -> includeBackgroundAudioTrack = checked);
|
||||||
|
|
||||||
|
ArrayAdapter<String> resolutionHeightAdapter =
|
||||||
|
new ArrayAdapter<>(/* context= */ this, R.layout.spinner_item);
|
||||||
|
resolutionHeightAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||||
|
Spinner resolutionHeightSpinner = findViewById(R.id.resolution_height_spinner);
|
||||||
|
resolutionHeightSpinner.setAdapter(resolutionHeightAdapter);
|
||||||
|
resolutionHeightAdapter.addAll(RESOLUTION_HEIGHTS);
|
||||||
|
|
||||||
|
ArrayAdapter<String> hdrModeAdapter = new ArrayAdapter<>(this, R.layout.spinner_item);
|
||||||
|
hdrModeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||||
|
Spinner hdrModeSpinner = findViewById(R.id.hdr_mode_spinner);
|
||||||
|
hdrModeSpinner.setAdapter(hdrModeAdapter);
|
||||||
|
hdrModeAdapter.addAll(HDR_MODE_DESCRIPTIONS.keySet());
|
||||||
|
|
||||||
AppCompatCheckBox applyVideoEffectsCheckBox = findViewById(R.id.apply_video_effects_checkbox);
|
AppCompatCheckBox applyVideoEffectsCheckBox = findViewById(R.id.apply_video_effects_checkbox);
|
||||||
applyVideoEffectsCheckBox.setOnCheckedChangeListener(
|
applyVideoEffectsCheckBox.setOnCheckedChangeListener(
|
||||||
((compoundButton, checked) -> appliesVideoEffects = checked));
|
((compoundButton, checked) -> appliesVideoEffects = checked));
|
||||||
@ -150,12 +184,19 @@ public final class CompositionPreviewActivity extends AppCompatActivity {
|
|||||||
String[] presetUris = getResources().getStringArray(/* id= */ R.array.preset_uris);
|
String[] presetUris = getResources().getStringArray(/* id= */ R.array.preset_uris);
|
||||||
int[] presetDurationsUs = getResources().getIntArray(/* id= */ R.array.preset_durations);
|
int[] presetDurationsUs = getResources().getIntArray(/* id= */ R.array.preset_durations);
|
||||||
List<EditedMediaItem> mediaItems = new ArrayList<>();
|
List<EditedMediaItem> mediaItems = new ArrayList<>();
|
||||||
ImmutableList<Effect> videoEffects =
|
ImmutableList.Builder<Effect> videoEffectsBuilder = new ImmutableList.Builder<>();
|
||||||
appliesVideoEffects
|
if (appliesVideoEffects) {
|
||||||
? ImmutableList.of(
|
videoEffectsBuilder.add(MatrixTransformationFactory.createDizzyCropEffect());
|
||||||
MatrixTransformationFactory.createDizzyCropEffect(),
|
videoEffectsBuilder.add(RgbFilter.createGrayscaleFilter());
|
||||||
RgbFilter.createGrayscaleFilter())
|
}
|
||||||
: ImmutableList.of();
|
Spinner resolutionHeightSpinner = findViewById(R.id.resolution_height_spinner);
|
||||||
|
String selectedResolutionHeight = String.valueOf(resolutionHeightSpinner.getSelectedItem());
|
||||||
|
if (!SAME_AS_INPUT_OPTION.equals(selectedResolutionHeight)) {
|
||||||
|
int resolutionHeight = Integer.parseInt(selectedResolutionHeight);
|
||||||
|
videoEffectsBuilder.add(LanczosResample.scaleToFit(10000, resolutionHeight));
|
||||||
|
videoEffectsBuilder.add(Presentation.createForHeight(resolutionHeight));
|
||||||
|
}
|
||||||
|
ImmutableList<Effect> videoEffects = videoEffectsBuilder.build();
|
||||||
// Preview requires all sequences to be the same duration, so calculate main sequence duration
|
// Preview requires all sequences to be the same duration, so calculate main sequence duration
|
||||||
// and limit background sequence duration to match.
|
// and limit background sequence duration to match.
|
||||||
long videoSequenceDurationUs = 0;
|
long videoSequenceDurationUs = 0;
|
||||||
@ -187,11 +228,15 @@ public final class CompositionPreviewActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
SonicAudioProcessor sampleRateChanger = new SonicAudioProcessor();
|
SonicAudioProcessor sampleRateChanger = new SonicAudioProcessor();
|
||||||
sampleRateChanger.setOutputSampleRateHz(8_000);
|
sampleRateChanger.setOutputSampleRateHz(8_000);
|
||||||
|
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(/* sequences= */ compositionSequences)
|
||||||
.setEffects(
|
.setEffects(
|
||||||
new Effects(
|
new Effects(
|
||||||
/* audioProcessors= */ ImmutableList.of(sampleRateChanger),
|
/* audioProcessors= */ ImmutableList.of(sampleRateChanger),
|
||||||
/* videoEffects= */ ImmutableList.of()))
|
/* videoEffects= */ ImmutableList.of()))
|
||||||
|
.setHdrMode(selectedHdrMode)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,7 +283,7 @@ public final class CompositionPreviewActivity extends AppCompatActivity {
|
|||||||
new AlertDialog.Builder(/* context= */ this)
|
new AlertDialog.Builder(/* context= */ this)
|
||||||
.setTitle(R.string.select_preset_title)
|
.setTitle(R.string.select_preset_title)
|
||||||
.setMultiChoiceItems(presetDescriptions, selectedMediaItems, this::selectPresetInDialog)
|
.setMultiChoiceItems(presetDescriptions, selectedMediaItems, this::selectPresetInDialog)
|
||||||
.setPositiveButton(android.R.string.ok, /* listener= */ null)
|
.setPositiveButton(R.string.ok, /* listener= */ null)
|
||||||
.setCancelable(false)
|
.setCancelable(false)
|
||||||
.create()
|
.create()
|
||||||
.show();
|
.show();
|
||||||
|
@ -111,7 +111,49 @@
|
|||||||
android:text="@string/add_background_audio"
|
android:text="@string/add_background_audio"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintBottom_toTopOf="@id/preview_button" />
|
app:layout_constraintBottom_toTopOf="@id/resolution_height_setting" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/resolution_height_setting"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/hdr_mode_setting">
|
||||||
|
<TextView
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/output_video_resolution"/>
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/resolution_height_spinner"
|
||||||
|
android:layout_gravity="end|center_vertical"
|
||||||
|
android:gravity="end"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="wrap_content"/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/hdr_mode_setting"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/preview_button">
|
||||||
|
<TextView
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/hdr_mode" />
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/hdr_mode_spinner"
|
||||||
|
android:layout_gravity="end|center_vertical"
|
||||||
|
android:gravity="end"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="wrap_content"/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatButton
|
<androidx.appcompat.widget.AppCompatButton
|
||||||
android:id="@+id/composition_export_button"
|
android:id="@+id/composition_export_button"
|
||||||
|
25
demos/composition/src/main/res/layout/spinner_item.xml
Normal file
25
demos/composition/src/main/res/layout/spinner_item.xml
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?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.
|
||||||
|
-->
|
||||||
|
<TextView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:gravity="start|center_vertical"
|
||||||
|
android:paddingLeft="4dp"
|
||||||
|
android:paddingRight="4dp"
|
||||||
|
android:layout_marginLeft="4dp"
|
||||||
|
android:layout_marginRight="4dp"
|
||||||
|
android:textIsSelectable="false" />
|
@ -26,4 +26,7 @@
|
|||||||
<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>
|
<string name="add_background_audio" translatable="false">Add background audio</string>
|
||||||
|
<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>
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user