HDR: Implement ForceInterpretHdrVideoAsSdr
Also, document that we tone map when no HDR features are explicitly set PiperOrigin-RevId: 487310971
This commit is contained in:
parent
3c74e076fe
commit
2ff5dab003
@ -68,6 +68,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
|
||||
public static final String ENABLE_FALLBACK = "enable_fallback";
|
||||
public static final String ENABLE_DEBUG_PREVIEW = "enable_debug_preview";
|
||||
public static final String ENABLE_REQUEST_SDR_TONE_MAPPING = "enable_request_sdr_tone_mapping";
|
||||
public static final String FORCE_INTERPRET_HDR_VIDEO_AS_SDR = "force_interpret_hdr_video_as_sdr";
|
||||
public static final String ENABLE_HDR_EDITING = "enable_hdr_editing";
|
||||
public static final String DEMO_EFFECTS_SELECTIONS = "demo_effects_selections";
|
||||
public static final String PERIODIC_VIGNETTE_CENTER_X = "periodic_vignette_center_x";
|
||||
@ -153,6 +154,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
|
||||
private @MonotonicNonNull CheckBox enableFallbackCheckBox;
|
||||
private @MonotonicNonNull CheckBox enableDebugPreviewCheckBox;
|
||||
private @MonotonicNonNull CheckBox enableRequestSdrToneMappingCheckBox;
|
||||
private @MonotonicNonNull CheckBox forceInterpretHdrVideoAsSdrCheckBox;
|
||||
private @MonotonicNonNull CheckBox enableHdrEditingCheckBox;
|
||||
private @MonotonicNonNull Button selectDemoEffectsButton;
|
||||
private boolean @MonotonicNonNull [] demoEffectsSelections;
|
||||
@ -248,6 +250,8 @@ public final class ConfigurationActivity extends AppCompatActivity {
|
||||
enableRequestSdrToneMappingCheckBox = findViewById(R.id.request_sdr_tone_mapping_checkbox);
|
||||
enableRequestSdrToneMappingCheckBox.setEnabled(isRequestSdrToneMappingSupported());
|
||||
findViewById(R.id.request_sdr_tone_mapping).setEnabled(isRequestSdrToneMappingSupported());
|
||||
forceInterpretHdrVideoAsSdrCheckBox =
|
||||
findViewById(R.id.force_interpret_hdr_video_as_sdr_checkbox);
|
||||
enableHdrEditingCheckBox = findViewById(R.id.hdr_editing_checkbox);
|
||||
|
||||
demoEffectsSelections = new boolean[DEMO_EFFECTS.length];
|
||||
@ -306,6 +310,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
|
||||
"enableFallbackCheckBox",
|
||||
"enableDebugPreviewCheckBox",
|
||||
"enableRequestSdrToneMappingCheckBox",
|
||||
"forceInterpretHdrVideoAsSdrCheckBox",
|
||||
"enableHdrEditingCheckBox",
|
||||
"demoEffectsSelections"
|
||||
})
|
||||
@ -346,6 +351,8 @@ public final class ConfigurationActivity extends AppCompatActivity {
|
||||
bundle.putBoolean(ENABLE_DEBUG_PREVIEW, enableDebugPreviewCheckBox.isChecked());
|
||||
bundle.putBoolean(
|
||||
ENABLE_REQUEST_SDR_TONE_MAPPING, enableRequestSdrToneMappingCheckBox.isChecked());
|
||||
bundle.putBoolean(
|
||||
FORCE_INTERPRET_HDR_VIDEO_AS_SDR, forceInterpretHdrVideoAsSdrCheckBox.isChecked());
|
||||
bundle.putBoolean(ENABLE_HDR_EDITING, enableHdrEditingCheckBox.isChecked());
|
||||
bundle.putBooleanArray(DEMO_EFFECTS_SELECTIONS, demoEffectsSelections);
|
||||
bundle.putInt(COLOR_FILTER_SELECTION, colorFilterSelection);
|
||||
@ -585,6 +592,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
|
||||
"rotateSpinner",
|
||||
"enableDebugPreviewCheckBox",
|
||||
"enableRequestSdrToneMappingCheckBox",
|
||||
"forceInterpretHdrVideoAsSdrCheckBox",
|
||||
"enableHdrEditingCheckBox",
|
||||
"selectDemoEffectsButton"
|
||||
})
|
||||
@ -606,6 +614,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
|
||||
"rotateSpinner",
|
||||
"enableDebugPreviewCheckBox",
|
||||
"enableRequestSdrToneMappingCheckBox",
|
||||
"forceInterpretHdrVideoAsSdrCheckBox",
|
||||
"enableHdrEditingCheckBox",
|
||||
"selectDemoEffectsButton"
|
||||
})
|
||||
@ -626,6 +635,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
|
||||
"rotateSpinner",
|
||||
"enableDebugPreviewCheckBox",
|
||||
"enableRequestSdrToneMappingCheckBox",
|
||||
"forceInterpretHdrVideoAsSdrCheckBox",
|
||||
"enableHdrEditingCheckBox",
|
||||
"selectDemoEffectsButton"
|
||||
})
|
||||
@ -638,6 +648,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
|
||||
enableDebugPreviewCheckBox.setEnabled(isVideoEnabled);
|
||||
enableRequestSdrToneMappingCheckBox.setEnabled(
|
||||
isRequestSdrToneMappingSupported() && isVideoEnabled);
|
||||
forceInterpretHdrVideoAsSdrCheckBox.setEnabled(isVideoEnabled);
|
||||
enableHdrEditingCheckBox.setEnabled(isVideoEnabled);
|
||||
selectDemoEffectsButton.setEnabled(isVideoEnabled);
|
||||
|
||||
@ -648,6 +659,7 @@ public final class ConfigurationActivity extends AppCompatActivity {
|
||||
findViewById(R.id.rotate).setEnabled(isVideoEnabled);
|
||||
findViewById(R.id.request_sdr_tone_mapping)
|
||||
.setEnabled(isRequestSdrToneMappingSupported() && isVideoEnabled);
|
||||
findViewById(R.id.force_interpret_hdr_video_as_sdr).setEnabled(isVideoEnabled);
|
||||
findViewById(R.id.hdr_editing).setEnabled(isVideoEnabled);
|
||||
}
|
||||
|
||||
|
@ -272,6 +272,8 @@ public final class TransformerActivity extends AppCompatActivity {
|
||||
|
||||
requestBuilder.setEnableRequestSdrToneMapping(
|
||||
bundle.getBoolean(ConfigurationActivity.ENABLE_REQUEST_SDR_TONE_MAPPING));
|
||||
requestBuilder.experimental_setForceInterpretHdrVideoAsSdr(
|
||||
bundle.getBoolean(ConfigurationActivity.FORCE_INTERPRET_HDR_VIDEO_AS_SDR));
|
||||
requestBuilder.experimental_setEnableHdrEditing(
|
||||
bundle.getBoolean(ConfigurationActivity.ENABLE_HDR_EDITING));
|
||||
transformerBuilder
|
||||
|
@ -217,6 +217,16 @@
|
||||
android:id="@+id/hdr_editing_checkbox"
|
||||
android:layout_gravity="end" />
|
||||
</TableRow>
|
||||
<TableRow
|
||||
android:layout_weight="1">
|
||||
<TextView
|
||||
android:layout_gravity="center_vertical"
|
||||
android:id="@+id/force_interpret_hdr_video_as_sdr"
|
||||
android:text="@string/force_interpret_hdr_video_as_sdr" />
|
||||
<CheckBox
|
||||
android:id="@+id/force_interpret_hdr_video_as_sdr_checkbox"
|
||||
android:layout_gravity="end" />
|
||||
</TableRow>
|
||||
</TableLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
<Button
|
||||
|
@ -31,7 +31,8 @@
|
||||
<string name="enable_debug_preview" translatable="false">Enable debug preview</string>
|
||||
<string name="trim" translatable="false">Trim</string>
|
||||
<string name="request_sdr_tone_mapping" translatable="false">Request SDR tone-mapping (API 31+)</string>
|
||||
<string name="hdr_editing" translatable="false">[Experimental] HDR editing</string>
|
||||
<string name="force_interpret_hdr_video_as_sdr" translatable="false">[Experimental] Force interpret HDR video as SDR (API 29+)</string>
|
||||
<string name="hdr_editing" translatable="false">[Experimental] HDR editing (API 31+)</string>
|
||||
<string name="select_demo_effects" translatable="false">Add demo effects</string>
|
||||
<string name="periodic_vignette_options" translatable="false">Periodic vignette options</string>
|
||||
<string name="no_media_pipe_error" translatable="false">Failed to load MediaPipe processor. Check the README for instructions.</string>
|
||||
|
@ -23,6 +23,8 @@ import static androidx.media3.common.util.Assertions.checkState;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.media3.common.C;
|
||||
import androidx.media3.common.ColorInfo;
|
||||
import androidx.media3.common.Format;
|
||||
import androidx.media3.common.MimeTypes;
|
||||
import androidx.media3.common.util.Log;
|
||||
@ -86,6 +88,19 @@ public final class AndroidTestUtil {
|
||||
|
||||
public static final String MP4_ASSET_1080P_4_SECOND_HDR10 =
|
||||
"https://storage.googleapis.com/exoplayer-test-media-1/mp4/samsung-s21-hdr-hdr10.mp4";
|
||||
public static final Format MP4_ASSET_1080P_4_SECOND_HDR10_FORMAT =
|
||||
new Format.Builder()
|
||||
.setSampleMimeType(VIDEO_H265)
|
||||
.setWidth(1920)
|
||||
.setHeight(1080)
|
||||
.setFrameRate(23.517f)
|
||||
.setColorInfo(
|
||||
new ColorInfo(
|
||||
C.COLOR_SPACE_BT2020,
|
||||
C.COLOR_RANGE_LIMITED,
|
||||
C.COLOR_TRANSFER_ST2084,
|
||||
/* hdrStaticInfo= */ null))
|
||||
.build();
|
||||
public static final String MP4_ASSET_1080P_1_SECOND_HDR10_VIDEO_SDR_CONTAINER =
|
||||
"asset:///media/mp4/hdr10-video-with-sdr-container.mp4";
|
||||
|
||||
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
package androidx.media3.transformer.mh;
|
||||
|
||||
import static androidx.media3.transformer.AndroidTestUtil.MP4_ASSET_1080P_4_SECOND_HDR10;
|
||||
import static androidx.media3.transformer.AndroidTestUtil.MP4_ASSET_1080P_4_SECOND_HDR10_FORMAT;
|
||||
import static androidx.media3.transformer.mh.analysis.FileUtil.assertFileHasColorTransfer;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import androidx.media3.common.C;
|
||||
import androidx.media3.common.MediaItem;
|
||||
import androidx.media3.common.util.Log;
|
||||
import androidx.media3.transformer.AndroidTestUtil;
|
||||
import androidx.media3.transformer.TransformationException;
|
||||
import androidx.media3.transformer.TransformationRequest;
|
||||
import androidx.media3.transformer.TransformationTestResult;
|
||||
import androidx.media3.transformer.Transformer;
|
||||
import androidx.media3.transformer.TransformerAndroidTestRunner;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* {@link Transformer} instrumentation test for {@linkplain
|
||||
* TransformationRequest#forceInterpretHdrVideoAsSdr forcing HDR contents to be interpreted as SDR}.
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class SetForceInterpretHdrVideoAsSdrTest {
|
||||
public static final String TAG = "SetForceInterpretHdrVideoAsSdrTest";
|
||||
|
||||
@Test
|
||||
public void forceInterpretHdrVideoAsSdrTest_hdr10File_transformsOrThrows() throws Exception {
|
||||
String testId = "forceInterpretHdrVideoAsSdrTest_hdr10File_transformsOrThrows";
|
||||
Context context = ApplicationProvider.getApplicationContext();
|
||||
|
||||
if (AndroidTestUtil.skipAndLogIfInsufficientCodecSupport(
|
||||
context,
|
||||
testId,
|
||||
/* decodingFormat= */ MP4_ASSET_1080P_4_SECOND_HDR10_FORMAT,
|
||||
/* encodingFormat= */ null)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Transformer transformer =
|
||||
new Transformer.Builder(context)
|
||||
.setTransformationRequest(
|
||||
new TransformationRequest.Builder()
|
||||
.experimental_setForceInterpretHdrVideoAsSdr(true)
|
||||
.build())
|
||||
.build();
|
||||
try {
|
||||
TransformationTestResult transformationTestResult =
|
||||
new TransformerAndroidTestRunner.Builder(context, transformer)
|
||||
.build()
|
||||
.run(testId, MediaItem.fromUri(Uri.parse(MP4_ASSET_1080P_4_SECOND_HDR10)));
|
||||
assertFileHasColorTransfer(transformationTestResult.filePath, C.COLOR_TRANSFER_SDR);
|
||||
Log.i(TAG, "Transformed.");
|
||||
} catch (TransformationException exception) {
|
||||
if (exception.errorCode != TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED
|
||||
&& exception.errorCode != TransformationException.ERROR_CODE_HDR_DECODING_UNSUPPORTED) {
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -79,7 +79,7 @@ public class SetHdrEditingTest {
|
||||
Log.i(TAG, checkNotNull(exception.getCause()).toString());
|
||||
assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class);
|
||||
assertThat(exception.errorCode)
|
||||
.isEqualTo(TransformationException.ERROR_CODE_HDR_EDITING_UNSUPPORTED);
|
||||
.isEqualTo(TransformationException.ERROR_CODE_HDR_ENCODING_UNSUPPORTED);
|
||||
}
|
||||
}
|
||||
|
||||
@ -156,7 +156,7 @@ public class SetHdrEditingTest {
|
||||
assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class);
|
||||
assertThat(exception.errorCode)
|
||||
.isAnyOf(
|
||||
TransformationException.ERROR_CODE_HDR_EDITING_UNSUPPORTED,
|
||||
TransformationException.ERROR_CODE_HDR_ENCODING_UNSUPPORTED,
|
||||
TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED);
|
||||
assertThat(isFallbackListenerInvoked.get()).isFalse();
|
||||
return;
|
||||
|
@ -80,7 +80,7 @@ public class SetHdrToSdrToneMapTest {
|
||||
assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class);
|
||||
assertThat(exception.errorCode)
|
||||
.isAnyOf(
|
||||
TransformationException.ERROR_CODE_HDR_EDITING_UNSUPPORTED,
|
||||
TransformationException.ERROR_CODE_HDR_ENCODING_UNSUPPORTED,
|
||||
TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED);
|
||||
return;
|
||||
}
|
||||
@ -126,7 +126,7 @@ public class SetHdrToSdrToneMapTest {
|
||||
assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class);
|
||||
assertThat(exception.errorCode)
|
||||
.isAnyOf(
|
||||
TransformationException.ERROR_CODE_HDR_EDITING_UNSUPPORTED,
|
||||
TransformationException.ERROR_CODE_HDR_ENCODING_UNSUPPORTED,
|
||||
TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED);
|
||||
return;
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ public final class TransformationException extends Exception {
|
||||
ERROR_CODE_ENCODER_INIT_FAILED,
|
||||
ERROR_CODE_ENCODING_FAILED,
|
||||
ERROR_CODE_OUTPUT_FORMAT_UNSUPPORTED,
|
||||
ERROR_CODE_HDR_EDITING_UNSUPPORTED,
|
||||
ERROR_CODE_HDR_ENCODING_UNSUPPORTED,
|
||||
ERROR_CODE_FRAME_PROCESSING_FAILED,
|
||||
ERROR_CODE_MUXING_FAILED,
|
||||
})
|
||||
@ -139,6 +139,8 @@ public final class TransformationException extends Exception {
|
||||
public static final int ERROR_CODE_DECODING_FAILED = 3002;
|
||||
/** Caused by trying to decode content whose format is not supported. */
|
||||
public static final int ERROR_CODE_DECODING_FORMAT_UNSUPPORTED = 3003;
|
||||
/** Caused by the decoder not supporting HDR formats. */
|
||||
public static final int ERROR_CODE_HDR_DECODING_UNSUPPORTED = 3004;
|
||||
|
||||
// Encoding errors (4xxx).
|
||||
|
||||
@ -154,7 +156,7 @@ public final class TransformationException extends Exception {
|
||||
*/
|
||||
public static final int ERROR_CODE_OUTPUT_FORMAT_UNSUPPORTED = 4003;
|
||||
/** Caused by the encoder not supporting HDR formats. */
|
||||
public static final int ERROR_CODE_HDR_EDITING_UNSUPPORTED = 4004;
|
||||
public static final int ERROR_CODE_HDR_ENCODING_UNSUPPORTED = 4004;
|
||||
|
||||
// Video editing errors (5xxx).
|
||||
|
||||
@ -180,10 +182,11 @@ public final class TransformationException extends Exception {
|
||||
.put("ERROR_CODE_DECODER_INIT_FAILED", ERROR_CODE_DECODER_INIT_FAILED)
|
||||
.put("ERROR_CODE_DECODING_FAILED", ERROR_CODE_DECODING_FAILED)
|
||||
.put("ERROR_CODE_DECODING_FORMAT_UNSUPPORTED", ERROR_CODE_DECODING_FORMAT_UNSUPPORTED)
|
||||
.put("ERROR_CODE_HDR_DECODING_UNSUPPORTED", ERROR_CODE_HDR_DECODING_UNSUPPORTED)
|
||||
.put("ERROR_CODE_ENCODER_INIT_FAILED", ERROR_CODE_ENCODER_INIT_FAILED)
|
||||
.put("ERROR_CODE_ENCODING_FAILED", ERROR_CODE_ENCODING_FAILED)
|
||||
.put("ERROR_CODE_OUTPUT_FORMAT_UNSUPPORTED", ERROR_CODE_OUTPUT_FORMAT_UNSUPPORTED)
|
||||
.put("ERROR_CODE_HDR_EDITING_UNSUPPORTED", ERROR_CODE_HDR_EDITING_UNSUPPORTED)
|
||||
.put("ERROR_CODE_HDR_ENCODING_UNSUPPORTED", ERROR_CODE_HDR_ENCODING_UNSUPPORTED)
|
||||
.put("ERROR_CODE_FRAME_PROCESSING_FAILED", ERROR_CODE_FRAME_PROCESSING_FAILED)
|
||||
.put("ERROR_CODE_MUXING_FAILED", ERROR_CODE_MUXING_FAILED)
|
||||
.buildOrThrow();
|
||||
|
@ -42,6 +42,7 @@ public final class TransformationRequest {
|
||||
@Nullable private String audioMimeType;
|
||||
@Nullable private String videoMimeType;
|
||||
private boolean enableRequestSdrToneMapping;
|
||||
private boolean forceInterpretHdrVideoAsSdr;
|
||||
private boolean enableHdrEditing;
|
||||
|
||||
/**
|
||||
@ -65,6 +66,7 @@ public final class TransformationRequest {
|
||||
this.audioMimeType = transformationRequest.audioMimeType;
|
||||
this.videoMimeType = transformationRequest.videoMimeType;
|
||||
this.enableRequestSdrToneMapping = transformationRequest.enableRequestSdrToneMapping;
|
||||
this.forceInterpretHdrVideoAsSdr = transformationRequest.forceInterpretHdrVideoAsSdr;
|
||||
this.enableHdrEditing = transformationRequest.enableHdrEditing;
|
||||
}
|
||||
|
||||
@ -218,31 +220,78 @@ public final class TransformationRequest {
|
||||
* supported, high dynamic range (HDR) input will be tone-mapped into an SDR opto-electrical
|
||||
* transfer function before processing.
|
||||
*
|
||||
* <p>The default value is {@code true}, which corresponds to tone-mapping output if possible.
|
||||
*
|
||||
* <p>The setting has no effect if the input is already in SDR, or if tone-mapping is not
|
||||
* supported. Currently tone-mapping is only guaranteed to be supported from Android T onwards.
|
||||
*
|
||||
* <p>Setting this as {@code true} will set {@linkplain #experimental_setEnableHdrEditing} and
|
||||
* {@linkplain #forceInterpretHdrVideoAsSdr} to {@code false}.
|
||||
*
|
||||
* @param enableRequestSdrToneMapping Whether to request tone-mapping down to SDR.
|
||||
* @return This builder.
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
public Builder setEnableRequestSdrToneMapping(boolean enableRequestSdrToneMapping) {
|
||||
this.enableRequestSdrToneMapping = enableRequestSdrToneMapping;
|
||||
if (enableRequestSdrToneMapping) {
|
||||
forceInterpretHdrVideoAsSdr = false;
|
||||
enableHdrEditing = false;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to interpret HDR video as SDR, resulting in washed out video.
|
||||
*
|
||||
* <p>The default value is {@code false}, with {@link #setEnableRequestSdrToneMapping} being
|
||||
* applied.
|
||||
*
|
||||
* <p>Use of this flag may result in {@code
|
||||
* TransformationException.ERROR_CODE_HDR_DECODING_UNSUPPORTED} or {@code
|
||||
* ERROR_CODE_DECODING_FORMAT_UNSUPPORTED}.
|
||||
*
|
||||
* <p>This method is experimental, and will be renamed or removed in a future release.
|
||||
*
|
||||
* <p>If enabled, HDR information will be interpreted as SDR, which is much more widely
|
||||
* supported than tone mapping or HDR editing. However, as HDR transfer functions and metadata
|
||||
* will be ignored, contents will be displayed incorrectly, likely with a washed out look.
|
||||
*
|
||||
* <p>The setting has no effect if the input is already in SDR.
|
||||
*
|
||||
* <p>Setting this as {@code true} will set {@linkplain #experimental_setEnableHdrEditing} and
|
||||
* {@linkplain #forceInterpretHdrVideoAsSdr} to {@code false}.
|
||||
*
|
||||
* @param forceInterpretHdrVideoAsSdr Whether to interpret HDR contents as SDR.
|
||||
* @return This builder.
|
||||
*/
|
||||
// TODO(http://b/258246130): Use IntDef to select between tone mapping, HDR editing, and this.
|
||||
@CanIgnoreReturnValue
|
||||
public Builder experimental_setForceInterpretHdrVideoAsSdr(
|
||||
boolean forceInterpretHdrVideoAsSdr) {
|
||||
this.forceInterpretHdrVideoAsSdr = forceInterpretHdrVideoAsSdr;
|
||||
if (forceInterpretHdrVideoAsSdr) {
|
||||
enableRequestSdrToneMapping = false;
|
||||
enableHdrEditing = false;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to allow processing high dynamic range (HDR) input video streams as HDR.
|
||||
*
|
||||
* <p>The default value is {@code false}, with {@link #setEnableRequestSdrToneMapping} being
|
||||
* applied.
|
||||
*
|
||||
* <p>This method is experimental, and will be renamed or removed in a future release. The HDR
|
||||
* editing feature is under development and is intended for developing/testing HDR support. HDR
|
||||
* editing can't be enabled at the same time as {@linkplain
|
||||
* #setEnableRequestSdrToneMapping(boolean) SDR tone-mapping}.
|
||||
* editing feature is under development and is intended for developing/testing HDR support.
|
||||
*
|
||||
* <p>Setting this as {@code true} will set {@linkplain #experimental_setEnableHdrEditing} and
|
||||
* {@linkplain #forceInterpretHdrVideoAsSdr} to {@code false}.
|
||||
*
|
||||
* <p>With this flag enabled, HDR streams will correctly edit in HDR, convert via tone-mapping
|
||||
* to SDR, or throw an error, based on the device's HDR support. Without both this flag and
|
||||
* {@linkplain #setEnableRequestSdrToneMapping(boolean) SDR tone-mapping} as false, HDR streams
|
||||
* will be incorrectly interpreted as SDR streams, with no conversion. SDR streams will be
|
||||
* interpreted the same way regardless of this flag's state.
|
||||
* to SDR, or throw an error, based on the device's HDR support. SDR streams will be interpreted
|
||||
* the same way regardless of this flag's state.
|
||||
*
|
||||
* @param enableHdrEditing Whether to attempt to process any input video stream as a high
|
||||
* dynamic range (HDR) signal.
|
||||
@ -251,6 +300,10 @@ public final class TransformationRequest {
|
||||
@CanIgnoreReturnValue
|
||||
public Builder experimental_setEnableHdrEditing(boolean enableHdrEditing) {
|
||||
this.enableHdrEditing = enableHdrEditing;
|
||||
if (enableHdrEditing) {
|
||||
enableRequestSdrToneMapping = false;
|
||||
forceInterpretHdrVideoAsSdr = false;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -265,6 +318,7 @@ public final class TransformationRequest {
|
||||
audioMimeType,
|
||||
videoMimeType,
|
||||
enableRequestSdrToneMapping,
|
||||
forceInterpretHdrVideoAsSdr,
|
||||
enableHdrEditing);
|
||||
}
|
||||
}
|
||||
@ -318,6 +372,9 @@ public final class TransformationRequest {
|
||||
/** Whether to request tone-mapping to standard dynamic range (SDR). */
|
||||
public final boolean enableRequestSdrToneMapping;
|
||||
|
||||
/** Whether to force interpreting HDR video as SDR. */
|
||||
public final boolean forceInterpretHdrVideoAsSdr;
|
||||
|
||||
/**
|
||||
* Whether to attempt to process any input video stream as a high dynamic range (HDR) signal.
|
||||
*
|
||||
@ -334,8 +391,12 @@ public final class TransformationRequest {
|
||||
@Nullable String audioMimeType,
|
||||
@Nullable String videoMimeType,
|
||||
boolean enableRequestSdrToneMapping,
|
||||
boolean forceInterpretHdrVideoAsSdr,
|
||||
boolean enableHdrEditing) {
|
||||
checkArgument(!forceInterpretHdrVideoAsSdr || !enableRequestSdrToneMapping);
|
||||
checkArgument(!enableHdrEditing || !forceInterpretHdrVideoAsSdr);
|
||||
checkArgument(!enableHdrEditing || !enableRequestSdrToneMapping);
|
||||
|
||||
this.flattenForSlowMotion = flattenForSlowMotion;
|
||||
this.scaleX = scaleX;
|
||||
this.scaleY = scaleY;
|
||||
@ -344,6 +405,7 @@ public final class TransformationRequest {
|
||||
this.audioMimeType = audioMimeType;
|
||||
this.videoMimeType = videoMimeType;
|
||||
this.enableRequestSdrToneMapping = enableRequestSdrToneMapping;
|
||||
this.forceInterpretHdrVideoAsSdr = forceInterpretHdrVideoAsSdr;
|
||||
this.enableHdrEditing = enableHdrEditing;
|
||||
}
|
||||
|
||||
@ -364,6 +426,7 @@ public final class TransformationRequest {
|
||||
&& Util.areEqual(audioMimeType, that.audioMimeType)
|
||||
&& Util.areEqual(videoMimeType, that.videoMimeType)
|
||||
&& enableRequestSdrToneMapping == that.enableRequestSdrToneMapping
|
||||
&& forceInterpretHdrVideoAsSdr == that.forceInterpretHdrVideoAsSdr
|
||||
&& enableHdrEditing == that.enableHdrEditing;
|
||||
}
|
||||
|
||||
@ -377,6 +440,7 @@ public final class TransformationRequest {
|
||||
result = 31 * result + (audioMimeType != null ? audioMimeType.hashCode() : 0);
|
||||
result = 31 * result + (videoMimeType != null ? videoMimeType.hashCode() : 0);
|
||||
result = 31 * result + (enableRequestSdrToneMapping ? 1 : 0);
|
||||
result = 31 * result + (forceInterpretHdrVideoAsSdr ? 1 : 0);
|
||||
result = 31 * result + (enableHdrEditing ? 1 : 0);
|
||||
return result;
|
||||
}
|
||||
|
@ -131,6 +131,9 @@ import com.google.common.collect.ImmutableList;
|
||||
if (transformationRequest.enableRequestSdrToneMapping) {
|
||||
return true;
|
||||
}
|
||||
if (transformationRequest.forceInterpretHdrVideoAsSdr) {
|
||||
return true;
|
||||
}
|
||||
if (transformationRequest.videoMimeType != null
|
||||
&& !transformationRequest.videoMimeType.equals(inputFormat.sampleMimeType)) {
|
||||
return true;
|
||||
|
@ -85,15 +85,27 @@ import org.checkerframework.dataflow.qual.Pure;
|
||||
transformationRequest.flattenForSlowMotion,
|
||||
muxerWrapper);
|
||||
|
||||
if (ColorInfo.isTransferHdr(inputFormat.colorInfo)
|
||||
&& (SDK_INT < 31 || deviceNeedsNoToneMappingWorkaround())) {
|
||||
throw TransformationException.createForCodec(
|
||||
new IllegalArgumentException("HDR editing and tone mapping not supported."),
|
||||
/* isVideo= */ true,
|
||||
/* isDecoder= */ false,
|
||||
inputFormat,
|
||||
/* mediaCodecName= */ null,
|
||||
TransformationException.ERROR_CODE_HDR_EDITING_UNSUPPORTED);
|
||||
if (ColorInfo.isTransferHdr(inputFormat.colorInfo)) {
|
||||
if (transformationRequest.forceInterpretHdrVideoAsSdr) {
|
||||
if (SDK_INT < 29) {
|
||||
throw TransformationException.createForCodec(
|
||||
new IllegalArgumentException("Interpreting HDR video as SDR is not supported."),
|
||||
/* isVideo= */ true,
|
||||
/* isDecoder= */ true,
|
||||
inputFormat,
|
||||
/* mediaCodecName= */ null,
|
||||
TransformationException.ERROR_CODE_HDR_DECODING_UNSUPPORTED);
|
||||
}
|
||||
inputFormat = inputFormat.buildUpon().setColorInfo(ColorInfo.SDR_BT709_LIMITED).build();
|
||||
} else if (SDK_INT < 31 || deviceNeedsNoToneMappingWorkaround()) {
|
||||
throw TransformationException.createForCodec(
|
||||
new IllegalArgumentException("HDR editing and tone mapping is not supported."),
|
||||
/* isVideo= */ true,
|
||||
/* isDecoder= */ false,
|
||||
inputFormat,
|
||||
/* mediaCodecName= */ null,
|
||||
TransformationException.ERROR_CODE_HDR_ENCODING_UNSUPPORTED);
|
||||
}
|
||||
}
|
||||
|
||||
decoderInputBuffer =
|
||||
|
Loading…
x
Reference in New Issue
Block a user