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
This commit is contained in:
parent
92816023f1
commit
65a2a3a0a0
@ -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}.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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() {}
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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<byte[]> 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);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user