Fallback to hevc transcoding for hdr AV1 files

PiperOrigin-RevId: 631362735
This commit is contained in:
tofunmi 2024-05-07 03:31:40 -07:00 committed by Copybara-Service
parent 4aa15e9463
commit b2d30a5722
4 changed files with 66 additions and 8 deletions

View file

@ -230,6 +230,21 @@ public final class AndroidTestUtil {
.setCodecs("hvc1.2.4.L153") .setCodecs("hvc1.2.4.L153")
.build(); .build();
public static final String MP4_ASSET_AV1_2_SECOND_HDR10 = "asset:///media/mp4/hdr10-av1.mp4";
public static final Format MP4_ASSET_AV1_2_SECOND_HDR10_FORMAT =
new Format.Builder()
.setSampleMimeType(VIDEO_AV1)
.setWidth(1920)
.setHeight(1080)
.setFrameRate(59.94f)
.setColorInfo(
new ColorInfo.Builder()
.setColorSpace(C.COLOR_SPACE_BT2020)
.setColorRange(C.COLOR_RANGE_LIMITED)
.setColorTransfer(C.COLOR_TRANSFER_ST2084)
.build())
.build();
// This file needs alternative MIME type, meaning the decoder needs to be configured with // This file needs alternative MIME type, meaning the decoder needs to be configured with
// video/hevc instead of video/dolby-vision. // video/hevc instead of video/dolby-vision.
public static final String MP4_ASSET_DOLBY_VISION_HDR = "asset:///media/mp4/dolbyVision-hdr.MOV"; public static final String MP4_ASSET_DOLBY_VISION_HDR = "asset:///media/mp4/dolbyVision-hdr.MOV";

View file

@ -22,6 +22,8 @@ import static androidx.media3.transformer.AndroidTestUtil.MP4_ASSET_1080P_5_SECO
import static androidx.media3.transformer.AndroidTestUtil.MP4_ASSET_1080P_5_SECOND_HLG10_FORMAT; import static androidx.media3.transformer.AndroidTestUtil.MP4_ASSET_1080P_5_SECOND_HLG10_FORMAT;
import static androidx.media3.transformer.AndroidTestUtil.MP4_ASSET_720P_4_SECOND_HDR10; import static androidx.media3.transformer.AndroidTestUtil.MP4_ASSET_720P_4_SECOND_HDR10;
import static androidx.media3.transformer.AndroidTestUtil.MP4_ASSET_720P_4_SECOND_HDR10_FORMAT; import static androidx.media3.transformer.AndroidTestUtil.MP4_ASSET_720P_4_SECOND_HDR10_FORMAT;
import static androidx.media3.transformer.AndroidTestUtil.MP4_ASSET_AV1_2_SECOND_HDR10;
import static androidx.media3.transformer.AndroidTestUtil.MP4_ASSET_AV1_2_SECOND_HDR10_FORMAT;
import static androidx.media3.transformer.AndroidTestUtil.MP4_ASSET_DOLBY_VISION_HDR; import static androidx.media3.transformer.AndroidTestUtil.MP4_ASSET_DOLBY_VISION_HDR;
import static androidx.media3.transformer.AndroidTestUtil.MP4_ASSET_DOLBY_VISION_HDR_FORMAT; import static androidx.media3.transformer.AndroidTestUtil.MP4_ASSET_DOLBY_VISION_HDR_FORMAT;
import static androidx.media3.transformer.AndroidTestUtil.assumeFormatsSupported; import static androidx.media3.transformer.AndroidTestUtil.assumeFormatsSupported;
@ -30,6 +32,7 @@ import static androidx.media3.transformer.Composition.HDR_MODE_KEEP_HDR;
import static androidx.media3.transformer.Composition.HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL; import static androidx.media3.transformer.Composition.HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL;
import static androidx.media3.transformer.mh.HdrCapabilitiesUtil.assumeDeviceDoesNotSupportHdrEditing; import static androidx.media3.transformer.mh.HdrCapabilitiesUtil.assumeDeviceDoesNotSupportHdrEditing;
import static androidx.media3.transformer.mh.HdrCapabilitiesUtil.assumeDeviceSupportsHdrEditing; import static androidx.media3.transformer.mh.HdrCapabilitiesUtil.assumeDeviceSupportsHdrEditing;
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import android.content.Context; import android.content.Context;
@ -37,10 +40,12 @@ import android.net.Uri;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.MediaItem; import androidx.media3.common.MediaItem;
import androidx.media3.common.MimeTypes;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import androidx.media3.effect.DefaultVideoFrameProcessor; import androidx.media3.effect.DefaultVideoFrameProcessor;
import androidx.media3.transformer.Composition; import androidx.media3.transformer.Composition;
import androidx.media3.transformer.EditedMediaItem; import androidx.media3.transformer.EditedMediaItem;
import androidx.media3.transformer.EncoderUtil;
import androidx.media3.transformer.ExportException; import androidx.media3.transformer.ExportException;
import androidx.media3.transformer.ExportTestResult; import androidx.media3.transformer.ExportTestResult;
import androidx.media3.transformer.TransformationRequest; import androidx.media3.transformer.TransformationRequest;
@ -51,6 +56,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.junit.AssumptionViolatedException;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
@ -210,6 +216,46 @@ public final class HdrEditingTest {
assertThat(actualColorTransfer).isEqualTo(C.COLOR_TRANSFER_HLG); assertThat(actualColorTransfer).isEqualTo(C.COLOR_TRANSFER_HLG);
} }
@Test
public void
exportAndTranscode_av1FileWithAv1HdrEditingUnsupportedAndHevcHdrEditingSupported_fallsBackToH265()
throws Exception {
Context context = ApplicationProvider.getApplicationContext();
Format format = MP4_ASSET_AV1_2_SECOND_HDR10_FORMAT;
if (EncoderUtil.getSupportedEncodersForHdrEditing(MimeTypes.VIDEO_H265, format.colorInfo)
.isEmpty()) {
String skipReason = "No H265 HDR editing support for " + format.colorInfo;
recordTestSkipped(getApplicationContext(), testId, skipReason);
throw new AssumptionViolatedException(skipReason);
}
if (!EncoderUtil.getSupportedEncodersForHdrEditing(MimeTypes.VIDEO_AV1, format.colorInfo)
.isEmpty()) {
String skipReason = "AV1 HDR editing support for " + format.colorInfo;
recordTestSkipped(getApplicationContext(), testId, skipReason);
throw new AssumptionViolatedException(skipReason);
}
assumeFormatsSupported(
context,
testId,
/* inputFormat= */ format,
/* outputFormat= */ format.buildUpon().setSampleMimeType(MimeTypes.VIDEO_H265).build());
Transformer transformer = new Transformer.Builder(context).build();
MediaItem mediaItem = MediaItem.fromUri(Uri.parse(MP4_ASSET_AV1_2_SECOND_HDR10));
EditedMediaItem editedMediaItem =
new EditedMediaItem.Builder(mediaItem).setEffects(FORCE_TRANSCODE_VIDEO_EFFECTS).build();
ExportTestResult exportTestResult =
new TransformerAndroidTestRunner.Builder(context, transformer)
.build()
.run(testId, editedMediaItem);
Format outputFormat =
retrieveTrackFormat(context, exportTestResult.filePath, C.TRACK_TYPE_VIDEO);
assertThat(outputFormat.colorInfo.colorTransfer).isEqualTo(C.COLOR_TRANSFER_ST2084);
assertThat(outputFormat.sampleMimeType).isEqualTo(MimeTypes.VIDEO_H265);
}
@Test @Test
public void exportAndTranscodeHdr_ignoringSdrWorkingColorSpace_whenHdrEditingIsSupported() public void exportAndTranscodeHdr_ignoringSdrWorkingColorSpace_whenHdrEditingIsSupported()
throws Exception { throws Exception {

View file

@ -50,7 +50,6 @@ import androidx.media3.common.util.Util;
import androidx.media3.decoder.DecoderInputBuffer; import androidx.media3.decoder.DecoderInputBuffer;
import androidx.media3.effect.DebugTraceUtil; import androidx.media3.effect.DebugTraceUtil;
import androidx.media3.effect.VideoCompositorSettings; import androidx.media3.effect.VideoCompositorSettings;
import androidx.media3.exoplayer.mediacodec.MediaCodecUtil;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.MoreExecutors;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -275,16 +274,14 @@ import org.checkerframework.dataflow.qual.Pure;
ImmutableList<MediaCodecInfo> hdrEncoders = ImmutableList<MediaCodecInfo> hdrEncoders =
getSupportedEncodersForHdrEditing(requestedOutputMimeType, inputFormat.colorInfo); getSupportedEncodersForHdrEditing(requestedOutputMimeType, inputFormat.colorInfo);
if (hdrEncoders.isEmpty()) { if (hdrEncoders.isEmpty()) {
@Nullable // Fallback H.265/HEVC codecs for HDR content to avoid tonemapping.
String alternativeMimeType = MediaCodecUtil.getAlternativeCodecMimeType(inputFormat); hdrEncoders =
if (alternativeMimeType != null) { getSupportedEncodersForHdrEditing(MimeTypes.VIDEO_H265, inputFormat.colorInfo);
requestedOutputMimeType = alternativeMimeType;
hdrEncoders =
getSupportedEncodersForHdrEditing(alternativeMimeType, inputFormat.colorInfo);
}
} }
if (hdrEncoders.isEmpty()) { if (hdrEncoders.isEmpty()) {
hdrMode = HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL; hdrMode = HDR_MODE_TONE_MAP_HDR_TO_SDR_USING_OPEN_GL;
} else {
requestedOutputMimeType = MimeTypes.VIDEO_H265;
} }
} }