Populate HevcConfig with number of temporal layers

The number of temporal sub-layers is required for
H.265 non-reference frame identification as
only frames from the highest temporal sub-layer can be
discarded.

PiperOrigin-RevId: 713242894
This commit is contained in:
dancho 2025-01-08 04:27:54 -08:00 committed by Copybara-Service
parent b3e18729d3
commit 281a0e7ac8
2 changed files with 12 additions and 0 deletions

View File

@ -95,6 +95,7 @@ public final class HevcConfig {
// Concatenate the codec-specific data into a single buffer. // Concatenate the codec-specific data into a single buffer.
data.setPosition(csdStartPosition); data.setPosition(csdStartPosition);
byte[] buffer = new byte[csdLength]; byte[] buffer = new byte[csdLength];
int maxSubLayers = Format.NO_VALUE;
int bufferPosition = 0; int bufferPosition = 0;
int width = Format.NO_VALUE; int width = Format.NO_VALUE;
int height = Format.NO_VALUE; int height = Format.NO_VALUE;
@ -131,6 +132,7 @@ public final class HevcConfig {
NalUnitUtil.H265SpsData spsData = NalUnitUtil.H265SpsData spsData =
NalUnitUtil.parseH265SpsNalUnit( NalUnitUtil.parseH265SpsNalUnit(
buffer, bufferPosition, bufferPosition + nalUnitLength, currentVpsData); buffer, bufferPosition, bufferPosition + nalUnitLength, currentVpsData);
maxSubLayers = spsData.maxSubLayersMinus1 + 1;
width = spsData.width; width = spsData.width;
height = spsData.height; height = spsData.height;
bitdepthLuma = spsData.bitDepthLumaMinus8 + 8; bitdepthLuma = spsData.bitDepthLumaMinus8 + 8;
@ -172,6 +174,7 @@ public final class HevcConfig {
return new HevcConfig( return new HevcConfig(
initializationData, initializationData,
lengthSizeMinusOne + 1, lengthSizeMinusOne + 1,
maxSubLayers,
width, width,
height, height,
bitdepthLuma, bitdepthLuma,
@ -200,6 +203,9 @@ public final class HevcConfig {
/** The length of the NAL unit length field in the bitstream's container, in bytes. */ /** The length of the NAL unit length field in the bitstream's container, in bytes. */
public final int nalUnitLengthFieldLength; public final int nalUnitLengthFieldLength;
/** The {@code sps_max_sub_layers_minus1 + 1} value: the number of temporal sub-layers. */
public final int maxSubLayers;
/** The width of each decoded frame, or {@link Format#NO_VALUE} if unknown. */ /** The width of each decoded frame, or {@link Format#NO_VALUE} if unknown. */
public final int width; public final int width;
@ -258,6 +264,7 @@ public final class HevcConfig {
private HevcConfig( private HevcConfig(
List<byte[]> initializationData, List<byte[]> initializationData,
int nalUnitLengthFieldLength, int nalUnitLengthFieldLength,
int maxSubLayers,
int width, int width,
int height, int height,
int bitdepthLuma, int bitdepthLuma,
@ -272,6 +279,7 @@ public final class HevcConfig {
@Nullable NalUnitUtil.H265VpsData vpsData) { @Nullable NalUnitUtil.H265VpsData vpsData) {
this.initializationData = initializationData; this.initializationData = initializationData;
this.nalUnitLengthFieldLength = nalUnitLengthFieldLength; this.nalUnitLengthFieldLength = nalUnitLengthFieldLength;
this.maxSubLayers = maxSubLayers;
this.width = width; this.width = width;
this.height = height; this.height = height;
this.bitdepthLuma = bitdepthLuma; this.bitdepthLuma = bitdepthLuma;

View File

@ -477,6 +477,7 @@ public final class HevcConfigTest {
ParsableByteArray data = new ParsableByteArray(HVCC_BOX_PAYLOAD); ParsableByteArray data = new ParsableByteArray(HVCC_BOX_PAYLOAD);
HevcConfig hevcConfig = HevcConfig.parse(data); HevcConfig hevcConfig = HevcConfig.parse(data);
assertThat(hevcConfig.maxSubLayers).isEqualTo(1);
assertThat(hevcConfig.codecs).isEqualTo("hvc1.1.6.L153.B0"); assertThat(hevcConfig.codecs).isEqualTo("hvc1.1.6.L153.B0");
assertThat(hevcConfig.nalUnitLengthFieldLength).isEqualTo(4); assertThat(hevcConfig.nalUnitLengthFieldLength).isEqualTo(4);
} }
@ -487,6 +488,7 @@ public final class HevcConfigTest {
ParsableByteArray data = new ParsableByteArray(HVCC_BOX_PAYLOAD_WITH_SET_RESERVED_BIT); ParsableByteArray data = new ParsableByteArray(HVCC_BOX_PAYLOAD_WITH_SET_RESERVED_BIT);
HevcConfig hevcConfig = HevcConfig.parse(data); HevcConfig hevcConfig = HevcConfig.parse(data);
assertThat(hevcConfig.maxSubLayers).isEqualTo(1);
assertThat(hevcConfig.codecs).isEqualTo("hvc1.1.6.L153.B0"); assertThat(hevcConfig.codecs).isEqualTo("hvc1.1.6.L153.B0");
assertThat(hevcConfig.nalUnitLengthFieldLength).isEqualTo(4); assertThat(hevcConfig.nalUnitLengthFieldLength).isEqualTo(4);
} }
@ -496,12 +498,14 @@ public final class HevcConfigTest {
ParsableByteArray hevcData = new ParsableByteArray(HVCC_BOX_PAYLOAD_MV_HEVC); ParsableByteArray hevcData = new ParsableByteArray(HVCC_BOX_PAYLOAD_MV_HEVC);
HevcConfig hevcConfig = HevcConfig.parse(hevcData); HevcConfig hevcConfig = HevcConfig.parse(hevcData);
assertThat(hevcConfig.maxSubLayers).isEqualTo(1);
assertThat(hevcConfig.codecs).isEqualTo("hvc1.1.6.L120.B0"); assertThat(hevcConfig.codecs).isEqualTo("hvc1.1.6.L120.B0");
assertThat(hevcConfig.nalUnitLengthFieldLength).isEqualTo(4); assertThat(hevcConfig.nalUnitLengthFieldLength).isEqualTo(4);
ParsableByteArray lhevcData = new ParsableByteArray(LHVC_BOX_PAYLOAD_MV_HEVC); ParsableByteArray lhevcData = new ParsableByteArray(LHVC_BOX_PAYLOAD_MV_HEVC);
HevcConfig lhevcConfig = HevcConfig.parseLayered(lhevcData, hevcConfig.vpsData); HevcConfig lhevcConfig = HevcConfig.parseLayered(lhevcData, hevcConfig.vpsData);
assertThat(lhevcConfig.maxSubLayers).isEqualTo(8);
assertThat(lhevcConfig.codecs).isEqualTo("hvc1.6.40.L120.BF.80"); assertThat(lhevcConfig.codecs).isEqualTo("hvc1.6.40.L120.BF.80");
assertThat(lhevcConfig.nalUnitLengthFieldLength).isEqualTo(4); assertThat(lhevcConfig.nalUnitLengthFieldLength).isEqualTo(4);
} }