HDR: Add tests for tone mapping.
Also, add checks for output file color. PiperOrigin-RevId: 477439139
This commit is contained in:
parent
bb811f0da5
commit
aec4fe7387
@ -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_1_SECOND_HDR10_VIDEO_SDR_CONTAINER;
|
||||||
import static androidx.media3.transformer.AndroidTestUtil.MP4_ASSET_1080P_4_SECOND_HDR10;
|
import static androidx.media3.transformer.AndroidTestUtil.MP4_ASSET_1080P_4_SECOND_HDR10;
|
||||||
import static androidx.media3.transformer.AndroidTestUtil.recordTestSkipped;
|
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 static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.media.MediaFormat;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.media3.common.C;
|
import androidx.media3.common.C;
|
||||||
import androidx.media3.common.ColorInfo;
|
import androidx.media3.common.ColorInfo;
|
||||||
import androidx.media3.common.MediaItem;
|
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.common.util.Util;
|
||||||
import androidx.media3.test.utils.DecodeOneFrameTestUtil;
|
|
||||||
import androidx.media3.transformer.EncoderUtil;
|
import androidx.media3.transformer.EncoderUtil;
|
||||||
import androidx.media3.transformer.TransformationException;
|
import androidx.media3.transformer.TransformationException;
|
||||||
import androidx.media3.transformer.TransformationRequest;
|
import androidx.media3.transformer.TransformationRequest;
|
||||||
@ -44,11 +42,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
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.
|
// TODO(b/239172735): Add HLG tests after finding a shareable HLG file.
|
||||||
/** {@link Transformer} instrumentation test for applying an HDR frame edit. */
|
/** {@link Transformer} instrumentation test for applying an HDR frame edit. */
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class SetHdrEditingTransformationTest {
|
public class SetHdrEditingTransformationTest {
|
||||||
|
public static final String TAG = "SetHdrEditingTransformationTest";
|
||||||
private static final ColorInfo HDR10_DEFAULT_COLOR_INFO =
|
private static final ColorInfo HDR10_DEFAULT_COLOR_INFO =
|
||||||
new ColorInfo(
|
new ColorInfo(
|
||||||
C.COLOR_SPACE_BT2020,
|
C.COLOR_SPACE_BT2020,
|
||||||
@ -72,9 +70,11 @@ public class SetHdrEditingTransformationTest {
|
|||||||
new TransformerAndroidTestRunner.Builder(context, transformer)
|
new TransformerAndroidTestRunner.Builder(context, transformer)
|
||||||
.build()
|
.build()
|
||||||
.run(testId, MediaItem.fromUri(Uri.parse(MP4_ASSET_1080P_4_SECOND_HDR10)));
|
.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;
|
return;
|
||||||
} catch (TransformationException exception) {
|
} catch (TransformationException exception) {
|
||||||
|
Log.i(TAG, checkNotNull(exception.getCause()).toString());
|
||||||
assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class);
|
assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class);
|
||||||
assertThat(exception.errorCode)
|
assertThat(exception.errorCode)
|
||||||
.isEqualTo(TransformationException.ERROR_CODE_HDR_EDITING_UNSUPPORTED);
|
.isEqualTo(TransformationException.ERROR_CODE_HDR_EDITING_UNSUPPORTED);
|
||||||
@ -110,7 +110,7 @@ public class SetHdrEditingTransformationTest {
|
|||||||
new TransformerAndroidTestRunner.Builder(context, transformer)
|
new TransformerAndroidTestRunner.Builder(context, transformer)
|
||||||
.build()
|
.build()
|
||||||
.run(testId, MediaItem.fromUri(Uri.parse(MP4_ASSET_1080P_4_SECOND_HDR10)));
|
.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
|
@Test
|
||||||
@ -122,7 +122,7 @@ public class SetHdrEditingTransformationTest {
|
|||||||
recordTestSkipped(
|
recordTestSkipped(
|
||||||
context,
|
context,
|
||||||
testId,
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,8 +154,10 @@ public class SetHdrEditingTransformationTest {
|
|||||||
new TransformerAndroidTestRunner.Builder(context, transformer)
|
new TransformerAndroidTestRunner.Builder(context, transformer)
|
||||||
.build()
|
.build()
|
||||||
.run(testId, MediaItem.fromUri(Uri.parse(MP4_ASSET_1080P_4_SECOND_HDR10)));
|
.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) {
|
} catch (TransformationException exception) {
|
||||||
|
Log.i(TAG, checkNotNull(exception.getCause()).toString());
|
||||||
assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class);
|
assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class);
|
||||||
// TODO(b/245364266): After fixing the bug, replace the API version check with a check that
|
// TODO(b/245364266): After fixing the bug, replace the API version check with a check that
|
||||||
// isToneMappingFallbackApplied.get() is true.
|
// isToneMappingFallbackApplied.get() is true.
|
||||||
@ -176,8 +178,6 @@ public class SetHdrEditingTransformationTest {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
assertThat(isToneMappingFallbackApplied.get()).isTrue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -208,30 +208,4 @@ public class SetHdrEditingTransformationTest {
|
|||||||
private static boolean deviceSupportsHdrEditing(String mimeType, ColorInfo colorInfo) {
|
private static boolean deviceSupportsHdrEditing(String mimeType, ColorInfo colorInfo) {
|
||||||
return !EncoderUtil.getSupportedEncoderNamesForHdrEditing(mimeType, colorInfo).isEmpty();
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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() {}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user