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:
parent
415b17c1e1
commit
ddb0f86604
@ -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
|
||||
|
@ -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]
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user