From aec4fe738709b3ca564c5309d8623bfbf1298c33 Mon Sep 17 00:00:00 2001 From: huangdarwin Date: Wed, 28 Sep 2022 13:42:36 +0000 Subject: [PATCH] HDR: Add tests for tone mapping. Also, add checks for output file color. PiperOrigin-RevId: 477439139 --- .../mh/SetHdrEditingTransformationTest.java | 48 ++---- .../SetHdrToSdrToneMapTransformationTest.java | 155 ++++++++++++++++++ .../transformer/mh/analysis/FileTestUtil.java | 58 +++++++ 3 files changed, 224 insertions(+), 37 deletions(-) create mode 100644 libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/SetHdrToSdrToneMapTransformationTest.java create mode 100644 libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/analysis/FileTestUtil.java diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/SetHdrEditingTransformationTest.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/SetHdrEditingTransformationTest.java index 9a32a70d68..8ce23e9469 100644 --- a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/SetHdrEditingTransformationTest.java +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/SetHdrEditingTransformationTest.java @@ -20,18 +20,16 @@ import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.transformer.AndroidTestUtil.MP4_ASSET_1080P_1_SECOND_HDR10_VIDEO_SDR_CONTAINER; import static androidx.media3.transformer.AndroidTestUtil.MP4_ASSET_1080P_4_SECOND_HDR10; import static androidx.media3.transformer.AndroidTestUtil.recordTestSkipped; +import static androidx.media3.transformer.mh.analysis.FileTestUtil.assertFileHasColorTransfer; import static com.google.common.truth.Truth.assertThat; import android.content.Context; -import android.media.MediaFormat; import android.net.Uri; -import androidx.annotation.Nullable; import androidx.media3.common.C; import androidx.media3.common.ColorInfo; import androidx.media3.common.MediaItem; -import androidx.media3.common.util.MediaFormatUtil; +import androidx.media3.common.util.Log; import androidx.media3.common.util.Util; -import androidx.media3.test.utils.DecodeOneFrameTestUtil; import androidx.media3.transformer.EncoderUtil; import androidx.media3.transformer.TransformationException; import androidx.media3.transformer.TransformationRequest; @@ -44,11 +42,11 @@ import java.util.concurrent.atomic.AtomicBoolean; import org.junit.Test; import org.junit.runner.RunWith; -// TODO(b/239172735): Add a SetToneMappingTransformationTest for when we request tone mapping. // TODO(b/239172735): Add HLG tests after finding a shareable HLG file. /** {@link Transformer} instrumentation test for applying an HDR frame edit. */ @RunWith(AndroidJUnit4.class) public class SetHdrEditingTransformationTest { + public static final String TAG = "SetHdrEditingTransformationTest"; private static final ColorInfo HDR10_DEFAULT_COLOR_INFO = new ColorInfo( C.COLOR_SPACE_BT2020, @@ -72,9 +70,11 @@ public class SetHdrEditingTransformationTest { new TransformerAndroidTestRunner.Builder(context, transformer) .build() .run(testId, MediaItem.fromUri(Uri.parse(MP4_ASSET_1080P_4_SECOND_HDR10))); - checkHasColorTransfer(transformationTestResult, C.COLOR_TRANSFER_ST2084); + Log.i(TAG, "Transformed."); + assertFileHasColorTransfer(transformationTestResult.filePath, C.COLOR_TRANSFER_ST2084); return; } catch (TransformationException exception) { + Log.i(TAG, checkNotNull(exception.getCause()).toString()); assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class); assertThat(exception.errorCode) .isEqualTo(TransformationException.ERROR_CODE_HDR_EDITING_UNSUPPORTED); @@ -110,7 +110,7 @@ public class SetHdrEditingTransformationTest { new TransformerAndroidTestRunner.Builder(context, transformer) .build() .run(testId, MediaItem.fromUri(Uri.parse(MP4_ASSET_1080P_4_SECOND_HDR10))); - checkHasColorTransfer(transformationTestResult, C.COLOR_TRANSFER_ST2084); + assertFileHasColorTransfer(transformationTestResult.filePath, C.COLOR_TRANSFER_ST2084); } @Test @@ -122,7 +122,7 @@ public class SetHdrEditingTransformationTest { recordTestSkipped( context, testId, - /* reason= */ "Skipping on this device due to presence of HDR10 editing support"); + /* reason= */ "Skipping on this device due to presence of HDR10 editing support."); return; } @@ -154,8 +154,10 @@ public class SetHdrEditingTransformationTest { new TransformerAndroidTestRunner.Builder(context, transformer) .build() .run(testId, MediaItem.fromUri(Uri.parse(MP4_ASSET_1080P_4_SECOND_HDR10))); - checkHasColorTransfer(transformationTestResult, C.COLOR_TRANSFER_SDR); + Log.i(TAG, "Tone mapped."); + assertFileHasColorTransfer(transformationTestResult.filePath, C.COLOR_TRANSFER_SDR); } catch (TransformationException exception) { + Log.i(TAG, checkNotNull(exception.getCause()).toString()); assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class); // TODO(b/245364266): After fixing the bug, replace the API version check with a check that // isToneMappingFallbackApplied.get() is true. @@ -176,8 +178,6 @@ public class SetHdrEditingTransformationTest { } return; } - - assertThat(isToneMappingFallbackApplied.get()).isTrue(); } @Test @@ -208,30 +208,4 @@ public class SetHdrEditingTransformationTest { private static boolean deviceSupportsHdrEditing(String mimeType, ColorInfo colorInfo) { return !EncoderUtil.getSupportedEncoderNamesForHdrEditing(mimeType, colorInfo).isEmpty(); } - - private static void checkHasColorTransfer( - TransformationTestResult transformationTestResult, @C.ColorTransfer int expectedColorTransfer) - throws Exception { - if (Util.SDK_INT < 29) { - // Skipping on this API version due to lack of support for MediaFormat#getInteger, which is - // required for MediaFormatUtil#getColorInfo. - return; - } - DecodeOneFrameTestUtil.decodeOneCacheFileFrame( - checkNotNull(transformationTestResult.filePath), - new DecodeOneFrameTestUtil.Listener() { - @Override - public void onContainerExtracted(MediaFormat mediaFormat) { - @Nullable ColorInfo extractedColor = MediaFormatUtil.getColorInfo(mediaFormat); - assertThat(checkNotNull(extractedColor).colorTransfer).isEqualTo(expectedColorTransfer); - } - - @Override - public void onFrameDecoded(MediaFormat mediaFormat) { - @Nullable ColorInfo decodedColor = MediaFormatUtil.getColorInfo(mediaFormat); - assertThat(checkNotNull(decodedColor).colorTransfer).isEqualTo(expectedColorTransfer); - } - }, - /* surface= */ null); - } } diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/SetHdrToSdrToneMapTransformationTest.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/SetHdrToSdrToneMapTransformationTest.java new file mode 100644 index 0000000000..5479f0e239 --- /dev/null +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/SetHdrToSdrToneMapTransformationTest.java @@ -0,0 +1,155 @@ +/* + * 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.common.util.Assertions.checkNotNull; +import static androidx.media3.transformer.AndroidTestUtil.MP4_ASSET_1080P_4_SECOND_HDR10; +import static androidx.media3.transformer.mh.analysis.FileTestUtil.assertFileHasColorTransfer; +import static com.google.common.truth.Truth.assertThat; + +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.common.util.Util; +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; + +// TODO(b/239172735): Add HLG tests after finding a shareable HLG file. +/** {@link Transformer} instrumentation test for applying an HDR to SDR tone mapping edit. */ +@RunWith(AndroidJUnit4.class) +public class SetHdrToSdrToneMapTransformationTest { + public static final String TAG = "SetHdrToSdrToneMapTransformationTest"; + + @Test + public void transform_toneMapNoRequestedTranscode_hdr10File_toneMapsOrThrows() throws Exception { + String testId = "transform_toneMapNoRequestedTranscode_hdr10File_toneMapsOrThrows"; + Context context = ApplicationProvider.getApplicationContext(); + + Transformer transformer = + new Transformer.Builder(context) + .setTransformationRequest( + new TransformationRequest.Builder().setEnableRequestSdrToneMapping(true).build()) + .addListener( + new Transformer.Listener() { + @Override + public void onFallbackApplied( + MediaItem inputMediaItem, + TransformationRequest originalTransformationRequest, + TransformationRequest fallbackTransformationRequest) { + // Tone mapping flag shouldn't change in fallback when tone mapping is + // requested. + assertThat(originalTransformationRequest.enableRequestSdrToneMapping) + .isEqualTo(fallbackTransformationRequest.enableRequestSdrToneMapping); + } + }) + .build(); + + try { + TransformationTestResult transformationTestResult = + new TransformerAndroidTestRunner.Builder(context, transformer) + .build() + .run(testId, MediaItem.fromUri(Uri.parse(MP4_ASSET_1080P_4_SECOND_HDR10))); + Log.i(TAG, "Tone mapped."); + assertFileHasColorTransfer(transformationTestResult.filePath, C.COLOR_TRANSFER_SDR); + return; + } catch (TransformationException exception) { + Log.i(TAG, checkNotNull(exception.getCause()).toString()); + assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class); + if (Util.SDK_INT < 31) { + assertThat(exception.errorCode) + .isEqualTo(TransformationException.ERROR_CODE_HDR_EDITING_UNSUPPORTED); + assertThat(exception) + .hasCauseThat() + .hasMessageThat() + .isEqualTo("HDR editing and tone mapping not supported under API 31."); + } else { + assertThat(exception.errorCode) + .isEqualTo(TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); + assertThat(exception) + .hasCauseThat() + .hasMessageThat() + .isEqualTo("Tone-mapping requested but not supported by the decoder"); + } + return; + } + } + + @Test + public void transform_toneMapAndTranscode_hdr10File_toneMapsOrThrows() throws Exception { + String testId = "transform_toneMapAndTranscode_hdr10File_toneMapsOrThrows"; + Context context = ApplicationProvider.getApplicationContext(); + + Transformer transformer = + new Transformer.Builder(context) + .setTransformationRequest( + new TransformationRequest.Builder() + .setEnableRequestSdrToneMapping(true) + .setRotationDegrees(180) + .build()) + .addListener( + new Transformer.Listener() { + @Override + public void onFallbackApplied( + MediaItem inputMediaItem, + TransformationRequest originalTransformationRequest, + TransformationRequest fallbackTransformationRequest) { + // Tone mapping flag shouldn't change in fallback when tone mapping is + // requested. + assertThat(originalTransformationRequest.enableRequestSdrToneMapping) + .isEqualTo(fallbackTransformationRequest.enableRequestSdrToneMapping); + } + }) + .build(); + + try { + TransformationTestResult transformationTestResult = + new TransformerAndroidTestRunner.Builder(context, transformer) + .build() + .run(testId, MediaItem.fromUri(Uri.parse(MP4_ASSET_1080P_4_SECOND_HDR10))); + Log.i(TAG, "Tone mapped."); + assertFileHasColorTransfer(transformationTestResult.filePath, C.COLOR_TRANSFER_SDR); + return; + } catch (TransformationException exception) { + Log.i(TAG, checkNotNull(exception.getCause()).toString()); + assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class); + if (Util.SDK_INT < 31) { + assertThat(exception.errorCode) + .isEqualTo(TransformationException.ERROR_CODE_HDR_EDITING_UNSUPPORTED); + assertThat(exception) + .hasCauseThat() + .hasMessageThat() + .isEqualTo("HDR editing and tone mapping not supported under API 31."); + } else { + assertThat(exception.errorCode) + .isEqualTo(TransformationException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED); + assertThat(exception) + .hasCauseThat() + .hasMessageThat() + .isEqualTo("Tone-mapping requested but not supported by the decoder"); + } + return; + } + } +} diff --git a/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/analysis/FileTestUtil.java b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/analysis/FileTestUtil.java new file mode 100644 index 0000000000..7347bee3fc --- /dev/null +++ b/libraries/transformer/src/androidTest/java/androidx/media3/transformer/mh/analysis/FileTestUtil.java @@ -0,0 +1,58 @@ +/* + * 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.analysis; + +import static androidx.media3.common.util.Assertions.checkNotNull; +import static com.google.common.truth.Truth.assertThat; + +import android.media.MediaFormat; +import androidx.annotation.Nullable; +import androidx.media3.common.C; +import androidx.media3.common.ColorInfo; +import androidx.media3.common.util.MediaFormatUtil; +import androidx.media3.common.util.Util; +import androidx.media3.test.utils.DecodeOneFrameTestUtil; + +/** Utilities for reading color info from a file. */ +public class FileTestUtil { + public static void assertFileHasColorTransfer( + @Nullable String filePath, @C.ColorTransfer int expectedColorTransfer) throws Exception { + if (Util.SDK_INT < 29) { + // Skipping on this API version due to lack of support for MediaFormat#getInteger, which is + // required for MediaFormatUtil#getColorInfo. + return; + } + DecodeOneFrameTestUtil.decodeOneCacheFileFrame( + checkNotNull(filePath), + new DecodeOneFrameTestUtil.Listener() { + @Override + public void onContainerExtracted(MediaFormat mediaFormat) { + @Nullable ColorInfo extractedColor = MediaFormatUtil.getColorInfo(mediaFormat); + assertThat(checkNotNull(extractedColor).colorTransfer).isEqualTo(expectedColorTransfer); + } + + @Override + public void onFrameDecoded(MediaFormat mediaFormat) { + @Nullable ColorInfo decodedColor = MediaFormatUtil.getColorInfo(mediaFormat); + assertThat(checkNotNull(decodedColor).colorTransfer).isEqualTo(expectedColorTransfer); + } + }, + /* surface= */ null); + } + + private FileTestUtil() {} +}