mirror of
https://github.com/samsonjs/media.git
synced 2026-04-04 11:05:47 +00:00
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
(cherry picked from commit ddb0f86604)
This commit is contained in:
parent
ab2505d1a9
commit
50db5207cb
3 changed files with 40 additions and 7 deletions
|
|
@ -18,6 +18,8 @@
|
|||
* Audio Offload:
|
||||
* Prepend Ogg ID Header and Comment Header Pages to bitstream for
|
||||
offloaded Opus playback in accordance with RFC 7845.
|
||||
* Video:
|
||||
* 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
|
||||
|
|
|
|||
|
|
@ -618,8 +618,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);
|
||||
|
|
@ -941,12 +941,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…
Reference in a new issue