Skip to content

Commit

Permalink
Fix parsing of H.265 sequence parameter sets
Browse files Browse the repository at this point in the history
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
(cherry picked from commit 2fe6726)
  • Loading branch information
andrewlewis authored and tianyif committed Jul 28, 2023
1 parent 0d60d6a commit 5875d4f
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -621,8 +621,8 @@ public static H265SpsData parseH265SpsNalUnitPayload(
}
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);
Expand Down Expand Up @@ -944,12 +944,14 @@ private static void skipShortTermReferencePictureSets(ParsableNalUnitBitArray bi
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]
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,11 +200,40 @@ public void parseH265SpsNalUnitPayload_exoghi_10316() {
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;
Expand Down

0 comments on commit 5875d4f

Please sign in to comment.