From 65a2a3a0a073c6dd8b47a044609f4be1abdd19c9 Mon Sep 17 00:00:00 2001 From: huangdarwin Date: Thu, 28 Jul 2022 21:07:43 +0000 Subject: [PATCH] HDR: Centralize getting Colorinfo from MediaFormat * Sets KEY_HDR_STATIC_INFO from MediaFormat in the DefaultCodec. * Adds checks in mediaparser to ensure color space, range, and transfer are valid values. PiperOrigin-RevId: 463921325 --- .../main/java/androidx/media3/common/C.java | 3 + .../androidx/media3/common/ColorInfo.java | 4 +- .../media3/common/util/MediaFormatUtil.java | 73 +++++++++++++++++++ .../mediaparser/OutputConsumerAdapterV30.java | 35 +-------- .../media3/transformer/DefaultCodec.java | 37 +--------- 5 files changed, 86 insertions(+), 66 deletions(-) diff --git a/libraries/common/src/main/java/androidx/media3/common/C.java b/libraries/common/src/main/java/androidx/media3/common/C.java index fa8c8288b0..517dbc5810 100644 --- a/libraries/common/src/main/java/androidx/media3/common/C.java +++ b/libraries/common/src/main/java/androidx/media3/common/C.java @@ -1044,6 +1044,7 @@ public final class C { */ @UnstableApi public static final int STEREO_MODE_STEREO_MESH = 3; + // LINT.IfChange(color_space) /** * Video colorspaces. One of {@link Format#NO_VALUE}, {@link #COLOR_SPACE_BT709}, {@link * #COLOR_SPACE_BT601} or {@link #COLOR_SPACE_BT2020}. @@ -1067,6 +1068,7 @@ public final class C { */ @UnstableApi public static final int COLOR_SPACE_BT2020 = MediaFormat.COLOR_STANDARD_BT2020; + // LINT.IfChange(color_transfer) /** * Video color transfer characteristics. One of {@link Format#NO_VALUE}, {@link * #COLOR_TRANSFER_SDR}, {@link #COLOR_TRANSFER_ST2084} or {@link #COLOR_TRANSFER_HLG}. @@ -1090,6 +1092,7 @@ public final class C { */ @UnstableApi public static final int COLOR_TRANSFER_HLG = MediaFormat.COLOR_TRANSFER_HLG; + // LINT.IfChange(color_range) /** * Video color range. One of {@link Format#NO_VALUE}, {@link #COLOR_RANGE_LIMITED} or {@link * #COLOR_RANGE_FULL}. diff --git a/libraries/common/src/main/java/androidx/media3/common/ColorInfo.java b/libraries/common/src/main/java/androidx/media3/common/ColorInfo.java index 7021acfff0..db10f7f4b9 100644 --- a/libraries/common/src/main/java/androidx/media3/common/ColorInfo.java +++ b/libraries/common/src/main/java/androidx/media3/common/ColorInfo.java @@ -77,7 +77,9 @@ public final class ColorInfo implements Bundleable { /** Returns whether the {@code ColorInfo} uses an HDR {@link C.ColorTransfer}. */ public static boolean isHdr(@Nullable ColorInfo colorInfo) { - return colorInfo != null && colorInfo.colorTransfer != C.COLOR_TRANSFER_SDR; + return colorInfo != null + && colorInfo.colorTransfer != Format.NO_VALUE + && colorInfo.colorTransfer != C.COLOR_TRANSFER_SDR; } /** diff --git a/libraries/common/src/main/java/androidx/media3/common/util/MediaFormatUtil.java b/libraries/common/src/main/java/androidx/media3/common/util/MediaFormatUtil.java index 6b62f15247..90c5d4dd41 100644 --- a/libraries/common/src/main/java/androidx/media3/common/util/MediaFormatUtil.java +++ b/libraries/common/src/main/java/androidx/media3/common/util/MediaFormatUtil.java @@ -15,6 +15,8 @@ */ package androidx.media3.common.util; +import static androidx.media3.common.util.Util.SDK_INT; + import android.annotation.SuppressLint; import android.media.AudioFormat; import android.media.MediaFormat; @@ -191,6 +193,51 @@ public final class MediaFormatUtil { } } + /** + * Creates and returns a {@code ColorInfo}, if a valid instance is described in the {@link + * MediaFormat}. + */ + @Nullable + public static ColorInfo getColorInfo(MediaFormat mediaFormat) { + if (SDK_INT < 29) { + return null; + } + int colorSpace = + mediaFormat.getInteger(MediaFormat.KEY_COLOR_STANDARD, /* defaultValue= */ Format.NO_VALUE); + int colorRange = + mediaFormat.getInteger(MediaFormat.KEY_COLOR_RANGE, /* defaultValue= */ Format.NO_VALUE); + int colorTransfer = + mediaFormat.getInteger(MediaFormat.KEY_COLOR_TRANSFER, /* defaultValue= */ Format.NO_VALUE); + @Nullable + ByteBuffer hdrStaticInfoByteBuffer = mediaFormat.getByteBuffer(MediaFormat.KEY_HDR_STATIC_INFO); + @Nullable + byte[] hdrStaticInfo = + hdrStaticInfoByteBuffer != null ? getArray(hdrStaticInfoByteBuffer) : null; + if (!isValidColorSpace(colorSpace)) { + colorSpace = Format.NO_VALUE; + } + if (!isValidColorRange(colorRange)) { + colorRange = Format.NO_VALUE; + } + if (!isValidColorTransfer(colorTransfer)) { + colorTransfer = Format.NO_VALUE; + } + + if (colorSpace != Format.NO_VALUE + || colorRange != Format.NO_VALUE + || colorTransfer != Format.NO_VALUE + || hdrStaticInfo != null) { + return new ColorInfo(colorSpace, colorRange, colorTransfer, hdrStaticInfo); + } + return null; + } + + public static byte[] getArray(ByteBuffer byteBuffer) { + byte[] array = new byte[byteBuffer.remaining()]; + byteBuffer.get(array); + return array; + } + // Internal methods. private static void setBooleanAsInt(MediaFormat format, String key, int value) { @@ -253,5 +300,31 @@ public final class MediaFormatUtil { mediaFormat.setInteger(MediaFormat.KEY_PCM_ENCODING, mediaFormatPcmEncoding); } + /** Whether this is a valid {@link C.ColorSpace} instance. */ + private static boolean isValidColorSpace(int colorSpace) { + // LINT.IfChange(color_space) + return colorSpace == C.COLOR_SPACE_BT709 + || colorSpace == C.COLOR_SPACE_BT601 + || colorSpace == C.COLOR_SPACE_BT2020 + || colorSpace == Format.NO_VALUE; + } + + /** Whether this is a valid {@link C.ColorRange} instance. */ + private static boolean isValidColorRange(int colorRange) { + // LINT.IfChange(color_range) + return colorRange == C.COLOR_RANGE_LIMITED + || colorRange == C.COLOR_RANGE_FULL + || colorRange == Format.NO_VALUE; + } + + /** Whether this is a valid {@link C.ColorTransfer} instance. */ + private static boolean isValidColorTransfer(int colorTransfer) { + // LINT.IfChange(color_transfer) + return colorTransfer == C.COLOR_TRANSFER_SDR + || colorTransfer == C.COLOR_TRANSFER_ST2084 + || colorTransfer == C.COLOR_TRANSFER_HLG + || colorTransfer == Format.NO_VALUE; + } + private MediaFormatUtil() {} } diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/mediaparser/OutputConsumerAdapterV30.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/mediaparser/OutputConsumerAdapterV30.java index 1b6a07874b..fdb0f7696f 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/mediaparser/OutputConsumerAdapterV30.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/mediaparser/OutputConsumerAdapterV30.java @@ -42,7 +42,6 @@ import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import androidx.media3.common.C; import androidx.media3.common.C.SelectionFlags; -import androidx.media3.common.ColorInfo; import androidx.media3.common.DataReader; import androidx.media3.common.DrmInitData; import androidx.media3.common.DrmInitData.SchemeData; @@ -50,6 +49,7 @@ import androidx.media3.common.Format; import androidx.media3.common.MimeTypes; import androidx.media3.common.util.Assertions; import androidx.media3.common.util.Log; +import androidx.media3.common.util.MediaFormatUtil; import androidx.media3.common.util.TimestampAdjuster; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; @@ -474,7 +474,7 @@ public final class OutputConsumerAdapterV30 implements MediaParser.OutputConsume .setChannelCount( mediaFormat.getInteger( MediaFormat.KEY_CHANNEL_COUNT, /* defaultValue= */ Format.NO_VALUE)) - .setColorInfo(getColorInfo(mediaFormat)) + .setColorInfo(MediaFormatUtil.getColorInfo(mediaFormat)) .setSampleMimeType(mediaFormatMimeType) .setCodecs(mediaFormat.getString(MediaFormat.KEY_CODECS_STRING)) .setFrameRate( @@ -572,40 +572,11 @@ public final class OutputConsumerAdapterV30 implements MediaParser.OutputConsume if (byteBuffer == null) { break; } - initData.add(getArray(byteBuffer)); + initData.add(MediaFormatUtil.getArray(byteBuffer)); } return initData; } - @Nullable - private static ColorInfo getColorInfo(MediaFormat mediaFormat) { - @Nullable - ByteBuffer hdrStaticInfoByteBuffer = mediaFormat.getByteBuffer(MediaFormat.KEY_HDR_STATIC_INFO); - @Nullable - byte[] hdrStaticInfo = - hdrStaticInfoByteBuffer != null ? getArray(hdrStaticInfoByteBuffer) : null; - int colorTransfer = - mediaFormat.getInteger(MediaFormat.KEY_COLOR_TRANSFER, /* defaultValue= */ Format.NO_VALUE); - int colorRange = - mediaFormat.getInteger(MediaFormat.KEY_COLOR_RANGE, /* defaultValue= */ Format.NO_VALUE); - int colorStandard = - mediaFormat.getInteger(MediaFormat.KEY_COLOR_STANDARD, /* defaultValue= */ Format.NO_VALUE); - - if (hdrStaticInfo != null - || colorTransfer != Format.NO_VALUE - || colorRange != Format.NO_VALUE - || colorStandard != Format.NO_VALUE) { - return new ColorInfo(colorStandard, colorRange, colorTransfer, hdrStaticInfo); - } - return null; - } - - private static byte[] getArray(ByteBuffer byteBuffer) { - byte[] array = new byte[byteBuffer.remaining()]; - byteBuffer.get(array); - return array; - } - private static String getMimeType(String parserName) { switch (parserName) { case PARSER_NAME_MATROSKA: diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultCodec.java b/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultCodec.java index 7366bc71c2..7168177b19 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultCodec.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/DefaultCodec.java @@ -32,6 +32,7 @@ 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.MediaFormatUtil; import androidx.media3.common.util.TraceUtil; import androidx.media3.common.util.UnstableApi; import androidx.media3.decoder.DecoderInputBuffer; @@ -317,7 +318,7 @@ public final class DefaultCodec implements Codec { } if (outputBufferIndex < 0) { if (outputBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { - outputFormat = getFormat(mediaCodec.getOutputFormat()); + outputFormat = convertToFormat(mediaCodec.getOutputFormat()); if (!isColorTransferEqual(configuredOutputColor, outputFormat.colorInfo)) { // TODO(b/237674316): These exceptions throw when the container ColorInfo doesn't match // the video ColorInfo. Instead of throwing when seeing unexpected ColorInfos, consider @@ -412,7 +413,7 @@ public final class DefaultCodec implements Codec { return TransformationException.createForUnexpected(cause); } - private static Format getFormat(MediaFormat mediaFormat) { + private static Format convertToFormat(MediaFormat mediaFormat) { ImmutableList.Builder csdBuffers = new ImmutableList.Builder<>(); int csdIndex = 0; while (true) { @@ -432,7 +433,7 @@ public final class DefaultCodec implements Codec { formatBuilder .setWidth(mediaFormat.getInteger(MediaFormat.KEY_WIDTH)) .setHeight(mediaFormat.getInteger(MediaFormat.KEY_HEIGHT)) - .setColorInfo(getColorInfo(mediaFormat)); + .setColorInfo(MediaFormatUtil.getColorInfo(mediaFormat)); } else if (MimeTypes.isAudio(mimeType)) { // TODO(b/178685617): Only set the PCM encoding for audio/raw, once we have a way to // simulate more realistic codec input/output formats in tests. @@ -472,34 +473,4 @@ public final class DefaultCodec implements Codec { return SDK_INT < 29 || context.getApplicationContext().getApplicationInfo().targetSdkVersion < 29; } - - @Nullable - private static ColorInfo getColorInfo(MediaFormat mediaFormat) { - if (SDK_INT < 29) { - return null; - } - // TODO(b/227624622): Set hdrStaticInfo accordingly using KEY_HDR_STATIC_INFO. - int colorSpace = mediaFormat.getInteger(MediaFormat.KEY_COLOR_STANDARD, Format.NO_VALUE); - int colorRange = mediaFormat.getInteger(MediaFormat.KEY_COLOR_RANGE, Format.NO_VALUE); - int colorTransfer = mediaFormat.getInteger(MediaFormat.KEY_COLOR_TRANSFER, Format.NO_VALUE); - if (colorSpace != C.COLOR_SPACE_BT709 - && colorSpace != C.COLOR_SPACE_BT601 - && colorSpace != C.COLOR_SPACE_BT2020 - && colorSpace != Format.NO_VALUE) { - return null; - } - if (colorRange != C.COLOR_RANGE_LIMITED - && colorRange != C.COLOR_RANGE_FULL - && colorRange != Format.NO_VALUE) { - return null; - } - if (colorTransfer != C.COLOR_TRANSFER_SDR - && colorTransfer != C.COLOR_TRANSFER_ST2084 - && colorTransfer != C.COLOR_TRANSFER_HLG - && colorTransfer != Format.NO_VALUE) { - return null; - } - - return new ColorInfo(colorSpace, colorRange, colorTransfer, /* hdrStaticInfo= */ null); - } }