HDR: Implement ForceInterpretHdrVideoAsSdr

Also, document that we tone map when no HDR features are explicitly set

PiperOrigin-RevId: 487310971
This commit is contained in:
huangdarwin 2022-11-09 20:05:24 +00:00 committed by microkatz
parent 3c74e076fe
commit 2ff5dab003
12 changed files with 226 additions and 24 deletions

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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";

View File

@ -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;
}
}
}
}

View File

@ -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;

View File

@ -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;
}

View File

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

View File

@ -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;
}

View File

@ -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;

View File

@ -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 =