Skip to content

Commit

Permalink
Add support to fetch ColorInfo from hvcc box in AtomParsers
Browse files Browse the repository at this point in the history
#minor-release

PiperOrigin-RevId: 517086016
(cherry picked from commit 8a5fcf8)
  • Loading branch information
rohitjoins committed Apr 18, 2023
1 parent 60e0546 commit 65d4202
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package androidx.media3.extractor;

import androidx.annotation.Nullable;
import androidx.media3.common.C;
import androidx.media3.common.Format;
import androidx.media3.common.ParserException;
import androidx.media3.common.util.CodecSpecificDataUtil;
Expand Down Expand Up @@ -61,6 +62,9 @@ public static HevcConfig parse(ParsableByteArray data) throws ParserException {
int bufferPosition = 0;
int width = Format.NO_VALUE;
int height = Format.NO_VALUE;
@C.ColorSpace int colorSpace = Format.NO_VALUE;
@C.ColorRange int colorRange = Format.NO_VALUE;
@C.ColorTransfer int colorTransfer = Format.NO_VALUE;
float pixelWidthHeightRatio = 1;
@Nullable String codecs = null;
for (int i = 0; i < numberOfArrays; i++) {
Expand All @@ -84,6 +88,9 @@ public static HevcConfig parse(ParsableByteArray data) throws ParserException {
buffer, bufferPosition, bufferPosition + nalUnitLength);
width = spsData.width;
height = spsData.height;
colorSpace = spsData.colorSpace;
colorRange = spsData.colorRange;
colorTransfer = spsData.colorTransfer;
pixelWidthHeightRatio = spsData.pixelWidthHeightRatio;
codecs =
CodecSpecificDataUtil.buildHevcCodecString(
Expand All @@ -102,7 +109,15 @@ public static HevcConfig parse(ParsableByteArray data) throws ParserException {
List<byte[]> initializationData =
csdLength == 0 ? Collections.emptyList() : Collections.singletonList(buffer);
return new HevcConfig(
initializationData, lengthSizeMinusOne + 1, width, height, pixelWidthHeightRatio, codecs);
initializationData,
lengthSizeMinusOne + 1,
width,
height,
pixelWidthHeightRatio,
codecs,
colorSpace,
colorRange,
colorTransfer);
} catch (ArrayIndexOutOfBoundsException e) {
throw ParserException.createForMalformedContainer("Error parsing HEVC config", e);
}
Expand All @@ -129,6 +144,22 @@ public static HevcConfig parse(ParsableByteArray data) throws ParserException {
/** The pixel width to height ratio. */
public final float pixelWidthHeightRatio;

/**
* The {@link C.ColorSpace} of the video or {@link Format#NO_VALUE} if unknown or not applicable.
*/
public final @C.ColorSpace int colorSpace;

/**
* The {@link C.ColorRange} of the video or {@link Format#NO_VALUE} if unknown or not applicable.
*/
public final @C.ColorRange int colorRange;

/**
* The {@link C.ColorTransfer} of the video or {@link Format#NO_VALUE} if unknown or not
* applicable.
*/
public final @C.ColorTransfer int colorTransfer;

/**
* An RFC 6381 codecs string representing the video format, or {@code null} if not known.
*
Expand All @@ -142,12 +173,18 @@ private HevcConfig(
int width,
int height,
float pixelWidthHeightRatio,
@Nullable String codecs) {
@Nullable String codecs,
@C.ColorSpace int colorSpace,
@C.ColorRange int colorRange,
@C.ColorTransfer int colorTransfer) {
this.initializationData = initializationData;
this.nalUnitLengthFieldLength = nalUnitLengthFieldLength;
this.width = width;
this.height = height;
this.pixelWidthHeightRatio = pixelWidthHeightRatio;
this.codecs = codecs;
this.colorSpace = colorSpace;
this.colorRange = colorRange;
this.colorTransfer = colorTransfer;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

import androidx.annotation.Nullable;
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.Assertions;
import androidx.media3.common.util.Log;
Expand Down Expand Up @@ -110,6 +112,9 @@ public static final class H265SpsData {
public final int width;
public final int height;
public final float pixelWidthHeightRatio;
public final @C.ColorSpace int colorSpace;
public final @C.ColorRange int colorRange;
public final @C.ColorTransfer int colorTransfer;

public H265SpsData(
int generalProfileSpace,
Expand All @@ -121,7 +126,10 @@ public H265SpsData(
int seqParameterSetId,
int width,
int height,
float pixelWidthHeightRatio) {
float pixelWidthHeightRatio,
@C.ColorSpace int colorSpace,
@C.ColorRange int colorRange,
@C.ColorTransfer int colorTransfer) {
this.generalProfileSpace = generalProfileSpace;
this.generalTierFlag = generalTierFlag;
this.generalProfileIdc = generalProfileIdc;
Expand All @@ -132,6 +140,9 @@ public H265SpsData(
this.width = width;
this.height = height;
this.pixelWidthHeightRatio = pixelWidthHeightRatio;
this.colorSpace = colorSpace;
this.colorRange = colorRange;
this.colorTransfer = colorTransfer;
}
}

Expand Down Expand Up @@ -488,6 +499,10 @@ public static H265SpsData parseH265SpsNalUnit(byte[] nalData, int nalOffset, int
public static H265SpsData parseH265SpsNalUnitPayload(
byte[] nalData, int nalOffset, int nalLimit) {
ParsableNalUnitBitArray data = new ParsableNalUnitBitArray(nalData, nalOffset, nalLimit);
// HDR related metadata.
@C.ColorSpace int colorSpace = Format.NO_VALUE;
@C.ColorRange int colorRange = Format.NO_VALUE;
@C.ColorTransfer int colorTransfer = Format.NO_VALUE;
data.skipBits(4); // sps_video_parameter_set_id
int maxSubLayersMinus1 = data.readBits(3);
data.skipBit(); // sps_temporal_id_nesting_flag
Expand Down Expand Up @@ -594,10 +609,17 @@ public static H265SpsData parseH265SpsNalUnitPayload(
data.skipBit(); // overscan_appropriate_flag
}
if (data.readBit()) { // video_signal_type_present_flag
data.skipBits(4); // video_format, video_full_range_flag
data.skipBits(3); // video_format
boolean fullRangeFlag = data.readBit(); // video_full_range_flag
if (data.readBit()) { // colour_description_present_flag
// colour_primaries, transfer_characteristics, matrix_coeffs
data.skipBits(24);
int colorPrimaries = data.readBits(8); // colour_primaries
int transferCharacteristics = data.readBits(8); // transfer_characteristics
data.skipBits(8); // matrix_coeffs

colorSpace = ColorInfo.isoColorPrimariesToColorSpace(colorPrimaries);
colorRange = fullRangeFlag ? C.COLOR_RANGE_FULL : C.COLOR_RANGE_LIMITED;
colorTransfer =
ColorInfo.isoTransferCharacteristicsToColorTransfer(transferCharacteristics);
}
}
if (data.readBit()) { // chroma_loc_info_present_flag
Expand All @@ -622,7 +644,10 @@ public static H265SpsData parseH265SpsNalUnitPayload(
seqParameterSetId,
frameWidth,
frameHeight,
pixelWidthHeightRatio);
pixelWidthHeightRatio,
colorSpace,
colorRange,
colorTransfer);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1164,6 +1164,15 @@ private static void parseVideoSampleEntry(
pixelWidthHeightRatio = hevcConfig.pixelWidthHeightRatio;
}
codecs = hevcConfig.codecs;
// Modify these values only if they have not already been set. If 'Atom.TYPE_colr' atom is
// present, these values may be overridden.
if (colorSpace == Format.NO_VALUE
&& colorRange == Format.NO_VALUE
&& colorTransfer == Format.NO_VALUE) {
colorSpace = hevcConfig.colorSpace;
colorRange = hevcConfig.colorRange;
colorTransfer = hevcConfig.colorTransfer;
}
} else if (childAtomType == Atom.TYPE_dvcC || childAtomType == Atom.TYPE_dvvC) {
@Nullable DolbyVisionConfig dolbyVisionConfig = DolbyVisionConfig.parse(parent);
if (dolbyVisionConfig != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ public void parseH265SpsNalUnitPayload_exoghi_10316() {
assertThat(spsData.pixelWidthHeightRatio).isEqualTo(1);
assertThat(spsData.seqParameterSetId).isEqualTo(0);
assertThat(spsData.width).isEqualTo(3840);
assertThat(spsData.colorSpace).isEqualTo(6);
assertThat(spsData.colorRange).isEqualTo(2);
assertThat(spsData.colorTransfer).isEqualTo(6);
}

private static byte[] buildTestData() {
Expand Down

0 comments on commit 65d4202

Please sign in to comment.