Skip to content

Commit 65d4202

Browse files
committed
Add support to fetch ColorInfo from hvcc box in AtomParsers
#minor-release PiperOrigin-RevId: 517086016 (cherry picked from commit 8a5fcf8)
1 parent 60e0546 commit 65d4202

File tree

4 files changed

+81
-7
lines changed

4 files changed

+81
-7
lines changed

libraries/extractor/src/main/java/androidx/media3/extractor/HevcConfig.java

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package androidx.media3.extractor;
1717

1818
import androidx.annotation.Nullable;
19+
import androidx.media3.common.C;
1920
import androidx.media3.common.Format;
2021
import androidx.media3.common.ParserException;
2122
import androidx.media3.common.util.CodecSpecificDataUtil;
@@ -61,6 +62,9 @@ public static HevcConfig parse(ParsableByteArray data) throws ParserException {
6162
int bufferPosition = 0;
6263
int width = Format.NO_VALUE;
6364
int height = Format.NO_VALUE;
65+
@C.ColorSpace int colorSpace = Format.NO_VALUE;
66+
@C.ColorRange int colorRange = Format.NO_VALUE;
67+
@C.ColorTransfer int colorTransfer = Format.NO_VALUE;
6468
float pixelWidthHeightRatio = 1;
6569
@Nullable String codecs = null;
6670
for (int i = 0; i < numberOfArrays; i++) {
@@ -84,6 +88,9 @@ public static HevcConfig parse(ParsableByteArray data) throws ParserException {
8488
buffer, bufferPosition, bufferPosition + nalUnitLength);
8589
width = spsData.width;
8690
height = spsData.height;
91+
colorSpace = spsData.colorSpace;
92+
colorRange = spsData.colorRange;
93+
colorTransfer = spsData.colorTransfer;
8794
pixelWidthHeightRatio = spsData.pixelWidthHeightRatio;
8895
codecs =
8996
CodecSpecificDataUtil.buildHevcCodecString(
@@ -102,7 +109,15 @@ public static HevcConfig parse(ParsableByteArray data) throws ParserException {
102109
List<byte[]> initializationData =
103110
csdLength == 0 ? Collections.emptyList() : Collections.singletonList(buffer);
104111
return new HevcConfig(
105-
initializationData, lengthSizeMinusOne + 1, width, height, pixelWidthHeightRatio, codecs);
112+
initializationData,
113+
lengthSizeMinusOne + 1,
114+
width,
115+
height,
116+
pixelWidthHeightRatio,
117+
codecs,
118+
colorSpace,
119+
colorRange,
120+
colorTransfer);
106121
} catch (ArrayIndexOutOfBoundsException e) {
107122
throw ParserException.createForMalformedContainer("Error parsing HEVC config", e);
108123
}
@@ -129,6 +144,22 @@ public static HevcConfig parse(ParsableByteArray data) throws ParserException {
129144
/** The pixel width to height ratio. */
130145
public final float pixelWidthHeightRatio;
131146

147+
/**
148+
* The {@link C.ColorSpace} of the video or {@link Format#NO_VALUE} if unknown or not applicable.
149+
*/
150+
public final @C.ColorSpace int colorSpace;
151+
152+
/**
153+
* The {@link C.ColorRange} of the video or {@link Format#NO_VALUE} if unknown or not applicable.
154+
*/
155+
public final @C.ColorRange int colorRange;
156+
157+
/**
158+
* The {@link C.ColorTransfer} of the video or {@link Format#NO_VALUE} if unknown or not
159+
* applicable.
160+
*/
161+
public final @C.ColorTransfer int colorTransfer;
162+
132163
/**
133164
* An RFC 6381 codecs string representing the video format, or {@code null} if not known.
134165
*
@@ -142,12 +173,18 @@ private HevcConfig(
142173
int width,
143174
int height,
144175
float pixelWidthHeightRatio,
145-
@Nullable String codecs) {
176+
@Nullable String codecs,
177+
@C.ColorSpace int colorSpace,
178+
@C.ColorRange int colorRange,
179+
@C.ColorTransfer int colorTransfer) {
146180
this.initializationData = initializationData;
147181
this.nalUnitLengthFieldLength = nalUnitLengthFieldLength;
148182
this.width = width;
149183
this.height = height;
150184
this.pixelWidthHeightRatio = pixelWidthHeightRatio;
151185
this.codecs = codecs;
186+
this.colorSpace = colorSpace;
187+
this.colorRange = colorRange;
188+
this.colorTransfer = colorTransfer;
152189
}
153190
}

libraries/extractor/src/main/java/androidx/media3/extractor/NalUnitUtil.java

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
import androidx.annotation.Nullable;
2121
import androidx.media3.common.C;
22+
import androidx.media3.common.ColorInfo;
23+
import androidx.media3.common.Format;
2224
import androidx.media3.common.MimeTypes;
2325
import androidx.media3.common.util.Assertions;
2426
import androidx.media3.common.util.Log;
@@ -110,6 +112,9 @@ public static final class H265SpsData {
110112
public final int width;
111113
public final int height;
112114
public final float pixelWidthHeightRatio;
115+
public final @C.ColorSpace int colorSpace;
116+
public final @C.ColorRange int colorRange;
117+
public final @C.ColorTransfer int colorTransfer;
113118

114119
public H265SpsData(
115120
int generalProfileSpace,
@@ -121,7 +126,10 @@ public H265SpsData(
121126
int seqParameterSetId,
122127
int width,
123128
int height,
124-
float pixelWidthHeightRatio) {
129+
float pixelWidthHeightRatio,
130+
@C.ColorSpace int colorSpace,
131+
@C.ColorRange int colorRange,
132+
@C.ColorTransfer int colorTransfer) {
125133
this.generalProfileSpace = generalProfileSpace;
126134
this.generalTierFlag = generalTierFlag;
127135
this.generalProfileIdc = generalProfileIdc;
@@ -132,6 +140,9 @@ public H265SpsData(
132140
this.width = width;
133141
this.height = height;
134142
this.pixelWidthHeightRatio = pixelWidthHeightRatio;
143+
this.colorSpace = colorSpace;
144+
this.colorRange = colorRange;
145+
this.colorTransfer = colorTransfer;
135146
}
136147
}
137148

@@ -488,6 +499,10 @@ public static H265SpsData parseH265SpsNalUnit(byte[] nalData, int nalOffset, int
488499
public static H265SpsData parseH265SpsNalUnitPayload(
489500
byte[] nalData, int nalOffset, int nalLimit) {
490501
ParsableNalUnitBitArray data = new ParsableNalUnitBitArray(nalData, nalOffset, nalLimit);
502+
// HDR related metadata.
503+
@C.ColorSpace int colorSpace = Format.NO_VALUE;
504+
@C.ColorRange int colorRange = Format.NO_VALUE;
505+
@C.ColorTransfer int colorTransfer = Format.NO_VALUE;
491506
data.skipBits(4); // sps_video_parameter_set_id
492507
int maxSubLayersMinus1 = data.readBits(3);
493508
data.skipBit(); // sps_temporal_id_nesting_flag
@@ -594,10 +609,17 @@ public static H265SpsData parseH265SpsNalUnitPayload(
594609
data.skipBit(); // overscan_appropriate_flag
595610
}
596611
if (data.readBit()) { // video_signal_type_present_flag
597-
data.skipBits(4); // video_format, video_full_range_flag
612+
data.skipBits(3); // video_format
613+
boolean fullRangeFlag = data.readBit(); // video_full_range_flag
598614
if (data.readBit()) { // colour_description_present_flag
599-
// colour_primaries, transfer_characteristics, matrix_coeffs
600-
data.skipBits(24);
615+
int colorPrimaries = data.readBits(8); // colour_primaries
616+
int transferCharacteristics = data.readBits(8); // transfer_characteristics
617+
data.skipBits(8); // matrix_coeffs
618+
619+
colorSpace = ColorInfo.isoColorPrimariesToColorSpace(colorPrimaries);
620+
colorRange = fullRangeFlag ? C.COLOR_RANGE_FULL : C.COLOR_RANGE_LIMITED;
621+
colorTransfer =
622+
ColorInfo.isoTransferCharacteristicsToColorTransfer(transferCharacteristics);
601623
}
602624
}
603625
if (data.readBit()) { // chroma_loc_info_present_flag
@@ -622,7 +644,10 @@ public static H265SpsData parseH265SpsNalUnitPayload(
622644
seqParameterSetId,
623645
frameWidth,
624646
frameHeight,
625-
pixelWidthHeightRatio);
647+
pixelWidthHeightRatio,
648+
colorSpace,
649+
colorRange,
650+
colorTransfer);
626651
}
627652

628653
/**

libraries/extractor/src/main/java/androidx/media3/extractor/mp4/AtomParsers.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1164,6 +1164,15 @@ private static void parseVideoSampleEntry(
11641164
pixelWidthHeightRatio = hevcConfig.pixelWidthHeightRatio;
11651165
}
11661166
codecs = hevcConfig.codecs;
1167+
// Modify these values only if they have not already been set. If 'Atom.TYPE_colr' atom is
1168+
// present, these values may be overridden.
1169+
if (colorSpace == Format.NO_VALUE
1170+
&& colorRange == Format.NO_VALUE
1171+
&& colorTransfer == Format.NO_VALUE) {
1172+
colorSpace = hevcConfig.colorSpace;
1173+
colorRange = hevcConfig.colorRange;
1174+
colorTransfer = hevcConfig.colorTransfer;
1175+
}
11671176
} else if (childAtomType == Atom.TYPE_dvcC || childAtomType == Atom.TYPE_dvvC) {
11681177
@Nullable DolbyVisionConfig dolbyVisionConfig = DolbyVisionConfig.parse(parent);
11691178
if (dolbyVisionConfig != null) {

libraries/extractor/src/test/java/androidx/media3/extractor/NalUnitUtilTest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,9 @@ public void parseH265SpsNalUnitPayload_exoghi_10316() {
194194
assertThat(spsData.pixelWidthHeightRatio).isEqualTo(1);
195195
assertThat(spsData.seqParameterSetId).isEqualTo(0);
196196
assertThat(spsData.width).isEqualTo(3840);
197+
assertThat(spsData.colorSpace).isEqualTo(6);
198+
assertThat(spsData.colorRange).isEqualTo(2);
199+
assertThat(spsData.colorTransfer).isEqualTo(6);
197200
}
198201

199202
private static byte[] buildTestData() {

0 commit comments

Comments
 (0)