HDR: Add fallback MH tests.
Test that HDR editing succeeds on devices supporting HDR editing, tone maps on devices supporting tone mapping, and throws exceptions on all other devices. Also, only restrict HDR editing and tone mapping support to API 31+ only when transcoding, not for all transformations. PiperOrigin-RevId: 472958965
This commit is contained in:
parent
8b7638bed3
commit
0d8fd3d4fc
@ -84,6 +84,8 @@ public final class AndroidTestUtil {
|
|||||||
.setFrameRate(30.472f)
|
.setFrameRate(30.472f)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
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 String MP4_ASSET_1080P_1_SECOND_HDR10_VIDEO_SDR_CONTAINER =
|
public static final String MP4_ASSET_1080P_1_SECOND_HDR10_VIDEO_SDR_CONTAINER =
|
||||||
"asset:///media/mp4/hdr10-video-with-sdr-container.mp4";
|
"asset:///media/mp4/hdr10-video-with-sdr-container.mp4";
|
||||||
|
|
||||||
|
@ -15,31 +15,168 @@
|
|||||||
*/
|
*/
|
||||||
package androidx.media3.transformer.mh;
|
package androidx.media3.transformer.mh;
|
||||||
|
|
||||||
|
import static androidx.media3.common.MimeTypes.VIDEO_H265;
|
||||||
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.recordTestSkipped;
|
import static androidx.media3.transformer.AndroidTestUtil.recordTestSkipped;
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import androidx.media3.common.C;
|
||||||
|
import androidx.media3.common.ColorInfo;
|
||||||
import androidx.media3.common.MediaItem;
|
import androidx.media3.common.MediaItem;
|
||||||
import androidx.media3.common.util.Util;
|
import androidx.media3.common.util.Util;
|
||||||
|
import androidx.media3.transformer.EncoderUtil;
|
||||||
|
import androidx.media3.transformer.TransformationException;
|
||||||
import androidx.media3.transformer.TransformationRequest;
|
import androidx.media3.transformer.TransformationRequest;
|
||||||
import androidx.media3.transformer.Transformer;
|
import androidx.media3.transformer.Transformer;
|
||||||
import androidx.media3.transformer.TransformerAndroidTestRunner;
|
import androidx.media3.transformer.TransformerAndroidTestRunner;
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
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.
|
||||||
/** {@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 {
|
||||||
|
private static final ColorInfo HDR10_DEFAULT_COLOR_INFO =
|
||||||
|
new ColorInfo(
|
||||||
|
C.COLOR_SPACE_BT2020,
|
||||||
|
C.COLOR_RANGE_LIMITED,
|
||||||
|
C.COLOR_TRANSFER_ST2084,
|
||||||
|
/* hdrStaticInfo= */ null);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void transform_noRequestedTranscode_hdr10File_transformsOrThrows() throws Exception {
|
||||||
|
String testId = "transform_noRequestedTranscode_hdr10File_transformsOrThrows";
|
||||||
|
Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
|
||||||
|
Transformer transformer =
|
||||||
|
new Transformer.Builder(context)
|
||||||
|
.setTransformationRequest(
|
||||||
|
new TransformationRequest.Builder().experimental_setEnableHdrEditing(true).build())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
try {
|
||||||
|
new TransformerAndroidTestRunner.Builder(context, transformer)
|
||||||
|
.build()
|
||||||
|
.run(testId, MediaItem.fromUri(Uri.parse(MP4_ASSET_1080P_4_SECOND_HDR10)));
|
||||||
|
return;
|
||||||
|
} catch (TransformationException exception) {
|
||||||
|
assertThat(exception).hasCauseThat().isInstanceOf(IllegalArgumentException.class);
|
||||||
|
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.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void transformAndTranscode_hdr10File_whenHdrEditingIsSupported() throws Exception {
|
||||||
|
String testId = "transformAndTranscode_hdr10File_whenHdrEditingIsSupported";
|
||||||
|
Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
if (!deviceSupportsHdrEditing(VIDEO_H265, HDR10_DEFAULT_COLOR_INFO)) {
|
||||||
|
recordTestSkipped(
|
||||||
|
context,
|
||||||
|
testId,
|
||||||
|
/* reason= */ "Skipping on this device due to lack of HDR10 editing support.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Transformer transformer =
|
||||||
|
new Transformer.Builder(context)
|
||||||
|
.setTransformationRequest(
|
||||||
|
new TransformationRequest.Builder()
|
||||||
|
.experimental_setEnableHdrEditing(true)
|
||||||
|
.setRotationDegrees(180)
|
||||||
|
.build())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
new TransformerAndroidTestRunner.Builder(context, transformer)
|
||||||
|
.build()
|
||||||
|
.run(testId, MediaItem.fromUri(Uri.parse(MP4_ASSET_1080P_4_SECOND_HDR10)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void transformAndTranscode_hdr10File_toneMapsOrThrows_whenHdrEditingUnsupported()
|
||||||
|
throws Exception {
|
||||||
|
String testId = "transformAndTranscode_hdr10File_toneMapsOrThrows_whenHdrEditingUnsupported";
|
||||||
|
Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
if (deviceSupportsHdrEditing(VIDEO_H265, HDR10_DEFAULT_COLOR_INFO)) {
|
||||||
|
recordTestSkipped(
|
||||||
|
context,
|
||||||
|
testId,
|
||||||
|
/* reason= */ "Skipping on this device due to presence of HDR10 editing support");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AtomicBoolean isToneMappingFallbackApplied = new AtomicBoolean();
|
||||||
|
Transformer transformer =
|
||||||
|
new Transformer.Builder(context)
|
||||||
|
.setTransformationRequest(
|
||||||
|
new TransformationRequest.Builder()
|
||||||
|
.experimental_setEnableHdrEditing(true)
|
||||||
|
.setRotationDegrees(180)
|
||||||
|
.build())
|
||||||
|
.addListener(
|
||||||
|
new Transformer.Listener() {
|
||||||
|
@Override
|
||||||
|
public void onFallbackApplied(
|
||||||
|
MediaItem inputMediaItem,
|
||||||
|
TransformationRequest originalTransformationRequest,
|
||||||
|
TransformationRequest fallbackTransformationRequest) {
|
||||||
|
assertThat(originalTransformationRequest.enableRequestSdrToneMapping).isFalse();
|
||||||
|
if (fallbackTransformationRequest.enableRequestSdrToneMapping) {
|
||||||
|
isToneMappingFallbackApplied.set(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.build();
|
||||||
|
|
||||||
|
try {
|
||||||
|
new TransformerAndroidTestRunner.Builder(context, transformer)
|
||||||
|
.build()
|
||||||
|
.run(testId, MediaItem.fromUri(Uri.parse(MP4_ASSET_1080P_4_SECOND_HDR10)));
|
||||||
|
} catch (TransformationException exception) {
|
||||||
|
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.
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
assertThat(isToneMappingFallbackApplied.get()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void transformUnexpectedColorInfo() throws Exception {
|
public void transformUnexpectedColorInfo() throws Exception {
|
||||||
|
String testId = "transformUnexpectedColorInfo";
|
||||||
Context context = ApplicationProvider.getApplicationContext();
|
Context context = ApplicationProvider.getApplicationContext();
|
||||||
if (Util.SDK_INT < 29) {
|
if (Util.SDK_INT < 29) {
|
||||||
recordTestSkipped(
|
recordTestSkipped(
|
||||||
context,
|
context,
|
||||||
"SetHdrEditingTransformationTest",
|
testId,
|
||||||
/* reason= */ "Skipping on this API version due to lack of support for"
|
/* reason= */ "Skipping on this API version due to lack of support for"
|
||||||
+ " MediaFormat#getInteger(String, int).");
|
+ " MediaFormat#getInteger(String, int).");
|
||||||
return;
|
return;
|
||||||
@ -53,7 +190,11 @@ public class SetHdrEditingTransformationTest {
|
|||||||
new TransformerAndroidTestRunner.Builder(context, transformer)
|
new TransformerAndroidTestRunner.Builder(context, transformer)
|
||||||
.build()
|
.build()
|
||||||
.run(
|
.run(
|
||||||
/* testId= */ "transformUnexpectedColorInfo",
|
testId,
|
||||||
MediaItem.fromUri(Uri.parse(MP4_ASSET_1080P_1_SECOND_HDR10_VIDEO_SDR_CONTAINER)));
|
MediaItem.fromUri(Uri.parse(MP4_ASSET_1080P_1_SECOND_HDR10_VIDEO_SDR_CONTAINER)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean deviceSupportsHdrEditing(String mimeType, ColorInfo colorInfo) {
|
||||||
|
return !EncoderUtil.getSupportedEncoderNamesForHdrEditing(mimeType, colorInfo).isEmpty();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,12 +17,10 @@
|
|||||||
package androidx.media3.transformer;
|
package androidx.media3.transformer;
|
||||||
|
|
||||||
import static androidx.media3.common.util.Assertions.checkNotNull;
|
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||||
import static androidx.media3.common.util.Util.SDK_INT;
|
|
||||||
import static androidx.media3.exoplayer.source.SampleStream.FLAG_REQUIRE_FORMAT;
|
import static androidx.media3.exoplayer.source.SampleStream.FLAG_REQUIRE_FORMAT;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import androidx.media3.common.C;
|
import androidx.media3.common.C;
|
||||||
import androidx.media3.common.ColorInfo;
|
|
||||||
import androidx.media3.common.DebugViewProvider;
|
import androidx.media3.common.DebugViewProvider;
|
||||||
import androidx.media3.common.Effect;
|
import androidx.media3.common.Effect;
|
||||||
import androidx.media3.common.Format;
|
import androidx.media3.common.Format;
|
||||||
@ -99,15 +97,6 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Format inputFormat = checkNotNull(formatHolder.format);
|
Format inputFormat = checkNotNull(formatHolder.format);
|
||||||
if (SDK_INT < 31 && ColorInfo.isTransferHdr(inputFormat.colorInfo)) {
|
|
||||||
throw TransformationException.createForCodec(
|
|
||||||
new IllegalArgumentException("HDR editing not supported under API 31."),
|
|
||||||
/* isVideo= */ true,
|
|
||||||
/* isDecoder= */ false,
|
|
||||||
inputFormat,
|
|
||||||
/* mediaCodecName= */ null,
|
|
||||||
TransformationException.ERROR_CODE_HDR_EDITING_UNSUPPORTED);
|
|
||||||
}
|
|
||||||
if (shouldTranscode(inputFormat)) {
|
if (shouldTranscode(inputFormat)) {
|
||||||
samplePipeline =
|
samplePipeline =
|
||||||
new VideoTranscodingSamplePipeline(
|
new VideoTranscodingSamplePipeline(
|
||||||
|
@ -18,6 +18,7 @@ package androidx.media3.transformer;
|
|||||||
|
|
||||||
import static androidx.media3.common.util.Assertions.checkNotNull;
|
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||||
import static androidx.media3.common.util.Assertions.checkState;
|
import static androidx.media3.common.util.Assertions.checkState;
|
||||||
|
import static androidx.media3.common.util.Util.SDK_INT;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.media.MediaCodec;
|
import android.media.MediaCodec;
|
||||||
@ -75,6 +76,16 @@ import org.checkerframework.dataflow.qual.Pure;
|
|||||||
Transformer.AsyncErrorListener asyncErrorListener,
|
Transformer.AsyncErrorListener asyncErrorListener,
|
||||||
DebugViewProvider debugViewProvider)
|
DebugViewProvider debugViewProvider)
|
||||||
throws TransformationException {
|
throws TransformationException {
|
||||||
|
if (SDK_INT < 31 && ColorInfo.isTransferHdr(inputFormat.colorInfo)) {
|
||||||
|
throw TransformationException.createForCodec(
|
||||||
|
new IllegalArgumentException("HDR editing and tone mapping not supported under API 31."),
|
||||||
|
/* isVideo= */ true,
|
||||||
|
/* isDecoder= */ false,
|
||||||
|
inputFormat,
|
||||||
|
/* mediaCodecName= */ null,
|
||||||
|
TransformationException.ERROR_CODE_HDR_EDITING_UNSUPPORTED);
|
||||||
|
}
|
||||||
|
|
||||||
decoderInputBuffer =
|
decoderInputBuffer =
|
||||||
new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DISABLED);
|
new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_DISABLED);
|
||||||
encoderOutputBuffer =
|
encoderOutputBuffer =
|
||||||
|
Loading…
x
Reference in New Issue
Block a user