Fix parsing of H.265 sequence parameter sets

Fix short term reference picture list parsing. Before this change, `deltaPocS0`
was derived by adding one to the value of the syntax element
`delta_poc_s0_minus1`, but (maybe surprising) the specification actually says
that `DeltaPocS0[stRpsIdx][i]` should be assigned the negation
`-(delta_poc_s0_minus1[i] + 1)` on the first iteration, then that value added
to the previous value on previous iterations. See equations (7-67) to (7-70) in
the 2021-08 version of the H.265/HEVC specification.

Also read the number of long term reference pictures once rather than on every
loop iteration (subsection 7.3.2.2.1).

PiperOrigin-RevId: 551852999
This commit is contained in:
andrewlewis 2023-07-28 16:00:13 +01:00 committed by Rohit Singh
parent 415b17c1e1
commit ddb0f86604
3 changed files with 39 additions and 7 deletions

View File

@ -92,6 +92,7 @@
* Video:
* Allow `MediaCodecVideoRenderer` to use a custom
`VideoFrameProcessor.Factory`.
* H.265/HEVC: Fix parsing SPS short and long term reference picture info.
* Text:
* CEA-608: Change cue truncation logic to only consider visible text.
Previously indent and tab offset were included when limiting the cue

View File

@ -625,8 +625,8 @@ public final class NalUnitUtil {
}
skipShortTermReferencePictureSets(data);
if (data.readBit()) { // long_term_ref_pics_present_flag
// num_long_term_ref_pics_sps
for (int i = 0; i < data.readUnsignedExpGolombCodedInt(); i++) {
int numLongTermRefPicsSps = data.readUnsignedExpGolombCodedInt();
for (int i = 0; i < numLongTermRefPicsSps; i++) {
int ltRefPicPocLsbSpsLength = log2MaxPicOrderCntLsbMinus4 + 4;
// lt_ref_pic_poc_lsb_sps[i], used_by_curr_pic_lt_sps_flag[i]
data.skipBits(ltRefPicPocLsbSpsLength + 1);
@ -948,12 +948,14 @@ public final class NalUnitUtil {
numPositivePics = bitArray.readUnsignedExpGolombCodedInt();
deltaPocS0 = new int[numNegativePics];
for (int i = 0; i < numNegativePics; i++) {
deltaPocS0[i] = bitArray.readUnsignedExpGolombCodedInt() + 1;
deltaPocS0[i] =
(i > 0 ? deltaPocS0[i - 1] : 0) - (bitArray.readUnsignedExpGolombCodedInt() + 1);
bitArray.skipBit(); // used_by_curr_pic_s0_flag[i]
}
deltaPocS1 = new int[numPositivePics];
for (int i = 0; i < numPositivePics; i++) {
deltaPocS1[i] = bitArray.readUnsignedExpGolombCodedInt() + 1;
deltaPocS1[i] =
(i > 0 ? deltaPocS1[i - 1] : 0) + (bitArray.readUnsignedExpGolombCodedInt() + 1);
bitArray.skipBit(); // used_by_curr_pic_s1_flag[i]
}
}

View File

@ -202,11 +202,40 @@ public final class NalUnitUtilTest {
assertThat(spsData.colorTransfer).isEqualTo(6);
}
/** Regression test for [Internal: b/292170736]. */
@Test
public void parseH265SpsNalUnitPayload_withShortTermRefPicSets() {
byte[] spsNalUnitPayload =
new byte[] {
1, 2, 96, 0, 0, 3, 0, 0, 3, 0, 0, 3, 0, 0, 3, 0, -106, -96, 2, 28, -128, 30, 4, -39, 111,
-110, 76, -114, -65, -7, -13, 101, 33, -51, 66, 68, 2, 65, 0, 0, 3, 0, 1, 0, 0, 3, 0, 29,
8
};
NalUnitUtil.H265SpsData spsData =
NalUnitUtil.parseH265SpsNalUnitPayload(spsNalUnitPayload, 0, spsNalUnitPayload.length);
assertThat(spsData.constraintBytes).isEqualTo(new int[] {0, 0, 0, 0, 0, 0});
assertThat(spsData.generalLevelIdc).isEqualTo(150);
assertThat(spsData.generalProfileCompatibilityFlags).isEqualTo(6);
assertThat(spsData.generalProfileIdc).isEqualTo(2);
assertThat(spsData.generalProfileSpace).isEqualTo(0);
assertThat(spsData.generalTierFlag).isFalse();
assertThat(spsData.width).isEqualTo(1080);
assertThat(spsData.height).isEqualTo(1920);
assertThat(spsData.pixelWidthHeightRatio).isEqualTo(1);
assertThat(spsData.seqParameterSetId).isEqualTo(0);
assertThat(spsData.chromaFormatIdc).isEqualTo(1);
assertThat(spsData.bitDepthLumaMinus8).isEqualTo(2);
assertThat(spsData.bitDepthChromaMinus8).isEqualTo(2);
assertThat(spsData.colorSpace).isEqualTo(6);
assertThat(spsData.colorRange).isEqualTo(2);
assertThat(spsData.colorTransfer).isEqualTo(6);
}
private static byte[] buildTestData() {
byte[] data = new byte[20];
for (int i = 0; i < data.length; i++) {
data[i] = (byte) 0xFF;
}
Arrays.fill(data, (byte) 0xFF);
// Insert an incomplete NAL unit start code.
data[TEST_PARTIAL_NAL_POSITION] = 0;
data[TEST_PARTIAL_NAL_POSITION + 1] = 0;