diff --git a/HEIF_IMPLEMENTATION_PLAN.md b/HEIF_IMPLEMENTATION_PLAN.md index 0644a3201..991674172 100644 --- a/HEIF_IMPLEMENTATION_PLAN.md +++ b/HEIF_IMPLEMENTATION_PLAN.md @@ -113,6 +113,7 @@ This snapshot pins or classifies the available references and failures; it does | `Av1CodecConfiguration`, `HeifItem.Av1CodecConfiguration`, `Av1HeifItemDecoder`, and AV1 grid configuration checks | AV1-ISOBMFF sections 2.3.3 and 2.3.4 codec-configuration record syntax and semantics; AVIF sections 2.1, 2.2.1, and 2.2.3 AV1 image-item, item-configuration, and HDR metadata constraints; AV1 sections 5.8.3, 5.8.4, 6.7.3, and 6.7.4 HDR metadata syntax and semantics; ISOBMFF mastering-display and content-light image properties; ITU-T H.274 section 8.9 mastering-display field semantics; MIAF section 7.3.11.4.1 grid input constraints | libavif `src/read.c` functions `avifParseCodecConfiguration`, `avifDecoderItemValidateProperties`, `avifReadCodecConfigProperty`, `avifParseContentLightLevelInformation`, and `avifSkipMasteringDisplayColourVolume` at `092276ce89098ead06db80975173191e5fee1826`; libaom `av1/decoder/obu.c` functions `read_metadata`, `read_metadata_hdr_cll`, and `read_metadata_hdr_mdcv` at `03087864cf4bea6abb0d28f95cf7843511413d8f` | Associate exactly one `av1C` property with each decoded `av01` image item, validate the fixed record and its bit depth/chroma fields against the item's AV1 sequence header and optional `pixi` channel depths, require matching configurations across grid tiles, and report the encoded image precision and monochrome shape through `HeifMetadata`. Validate low-overhead OBU framing, require exactly one sequence header in the image item, allow at most one first-position sequence header in `configOBUs`, and compare a repeated header's extension and payload exactly while ignoring only its legal size-field representation. Decode `clli` and `mdcv` as still-image item properties, validate matching HDR CLL and HDR MDCV metadata OBUs from the combined configuration/item sequence, and account for the different primary order and fixed-point precision of the ISOBMFF and AV1 MDCV representations. Expose the effective HDR values without adding sample groups, tracks, or media metadata. Related still-image HDR properties remain required. Consume but do not retain presentation-delay syntax, and introduce no sample entry, sample description, track, timing, or generic decoder-configuration model. | | `HevcCodecConfiguration`, `HevcNalUnitArray`, and `HeifItem.HevcCodecConfiguration` | ISO/IEC 14496-15 `HEVCDecoderConfigurationRecord`, HEVC NAL-unit header syntax, and HEVC image-item configuration requirements | HM `source/Lib/TLibDecoder/NALread.cpp` and parameter-header paths at `9c1f298659ab0cee9dc13d23d0304221575410b9`; Android `libhevc` v1.6.0 decoder NAL and parameter-header paths at `c83a76b084498d55f252f48b2e3786804cdf24b7`; independently produced HEIC fixtures for `hvcC` record layout | Associate exactly one `hvcC` property with each `hvc1` image item; validate the fixed profile, level, chroma, bit-depth, reserved, length-size, array, and NAL-header fields within the property boundary; and retain only the image description plus bounded configuration NAL units required to decode that item. Consume but do not retain average-frame-rate or temporal-layer presentation fields. Do not add visual sample entries, sample descriptions, tracks, timing, access-unit timelines, or a generic decoder-configuration model. BSD and Apache-2.0 notice preservation and separate HEVC patent/release clearance remain final integration gates. | | `HevcNalUnit`, `HevcNalUnitHeader`, `HevcRbspDecoder`, and `HevcBitReader` | HEVC sections 7.3.1.1 and 7.3.1.2 NAL-unit and header syntax, section 7.3.2.11 RBSP trailing bits, and section 9.1 Exp-Golomb parsing | HM `source/Lib/TLibDecoder/NALread.cpp` and `SyntaxElementParser.cpp` at `9c1f298659ab0cee9dc13d23d0304221575410b9`; Android `libhevc` NAL extraction and bitstream paths at `c83a76b084498d55f252f48b2e3786804cdf24b7` | Validate the fixed NAL header, remove only legal emulation-prevention bytes, and provide bounded fixed-width, flag, unsigned/signed Exp-Golomb, and RBSP-trailing-bit reads. Configuration arrays immediately use the shared parser. The primitives consume only NAL units delivered by a supported HEIF image item or its `hvcC` property and introduce no Annex B API, access-unit model, timeline, track, sample table, or generic ISO BMFF surface. | +| `HevcProfileTierLevel`, `HevcVideoParameterSet`, and `HevcCodecConfiguration.VideoParameterSets` | HEVC sections 7.3.2.1 video parameter sets, 7.3.3 profile-tier-level syntax, and E.2.2 hypothetical-reference-decoder syntax; ISO/IEC 14496-15 `HEVCDecoderConfigurationRecord` matching semantics | HM `source/Lib/TLibDecoder/TDecCAVLC.cpp` functions `parseVPS`, `parsePTL`, `parseProfileTier`, and `parseHrdParameters` at `9c1f298659ab0cee9dc13d23d0304221575410b9`; Android `libhevc` `decoder/ihevcd_parse_headers.c` profile-tier-level and VPS paths at `c83a76b084498d55f252f48b2e3786804cdf24b7` | Retain the base-layer VPS identifier, temporal-sublayer count, nesting flag, and exact general profile/tier/constraint/level fields. Validate profile, tier, compatibility, level, temporal count, and nesting against `hvcC`, while tolerating the independently observed legacy-muxer practice of zeroing some or all profile-specific constraint bits in the configuration record; SPS validation remains authoritative for chroma and bit depth. Consume but do not retain sublayer ordering, timing, and HRD syntax. Reject multilayer and layer-set state because the supported contract is one independently coded image item; add no layer-selection, access-unit, DPB, scheduling, track, or sample model. | | `HeifContentColorVolume`, `HeifItem.ContentColorVolume`, and `HeifDecoderCore` content color-volume parsing and presentation | HEIF content color-volume item property; AVIF 1.2 content color-volume requirements; ITU-T H.274 (V4) content colour volume syntax and semantics | libavif `src/read.c` function `avifSkipContentColourVolume` at `092276ce89098ead06db80975173191e5fee1826`; official ITU-T H.274 (V4), January 2026 | Decode only the bounded per-image `cclv` property: require zero cancellation, persistence, and reserved bits; preserve optional signed G/B/R primary coordinates and normalized minimum, maximum, and average luminance values; and validate their registered ranges and ordering. Expose the effective grid-or-tile still-image value through `HeifMetadata`. Do not add SEI persistence, retained video state, tracks, samples, timing, or a generic ISO BMFF color-volume box model. | | `HeifAmbientViewingEnvironment`, `HeifReferenceViewingEnvironment`, `HeifNominalDiffuseWhite`, and their per-item presentation metadata | ISOBMFF ambient viewing environment; ITU-T H.274 (V4) section 8.13; HEIF Amendment 1 sections 6.5.44 and 6.5.45; AVIF 1.2 image-item box requirements | libavif `src/read.c` functions `avifSkipAmbientViewingEnvironment`, `avifSkipReferenceViewingEnvironment`, and `avifSkipNominalDiffuseWhite` at `092276ce89098ead06db80975173191e5fee1826`; official ITU-T H.274 (V4), January 2026 | Decode the fixed-size `amve`, version-zero `reve`, and version-zero `ndwt` properties only when associated with the presented still-image item. Preserve physical illuminance and luminance units, distinct surround/periphery chromaticities, and the coded zero that requests the standard nominal diffuse-white default. Validate registered coordinate ranges and duplicate associations. Retain no video-SEI persistence, visual sample entry, display pipeline, track, timing, or generic viewing-environment box model. | | `GridHeifItemDecoder` and `HeifDecoderCore` grid/thumbnail selection | ISO/IEC 23008-12 section 6.6.2.3 image-grid syntax and MIAF grid-cell constraints | libavif `src/read.c` functions `avifParseImageGridBox`, `avifDecoderDataAllocateImagePlanes`, and `avifDecoderDataCopyTileToImage` at `092276ce89098ead06db80975173191e5fee1826` | Parse version-zero 16-bit and 32-bit grid descriptors, preserve row-major `dimg` order, require the declared tile count and one coding format, validate canvas coverage and edge overlap, and crop only the rightmost column and bottom row while copying through ImageSharp pixel buffers. A primary grid whose tile codec is unavailable may use only a decodable thumbnail that explicitly references that grid. | diff --git a/src/ImageSharp/Formats/Heif/Hevc/HevcBitReader.cs b/src/ImageSharp/Formats/Heif/Hevc/HevcBitReader.cs index d0e5b6196..39cf978a8 100644 --- a/src/ImageSharp/Formats/Heif/Hevc/HevcBitReader.cs +++ b/src/ImageSharp/Formats/Heif/Hevc/HevcBitReader.cs @@ -86,6 +86,34 @@ internal ref struct HevcBitReader /// The flag extends beyond the bounded HEVC syntax. public bool ReadFlag() => this.ReadBits(1) != 0; + /// + /// Determines whether unread syntax remains before the raw byte sequence payload trailing bits. + /// + /// + /// when the unread bits contain syntax before the stop bit; otherwise, + /// . + /// + public bool HasMoreRbspData() + { + int bitsRemaining = this.BitsRemaining; + if (bitsRemaining == 0) + { + return false; + } + + if (bitsRemaining > 8) + { + return true; + } + + int savedBitPosition = this.bitPosition; + uint remainingValue = this.ReadBits(bitsRemaining); + this.bitPosition = savedBitPosition; + + // At most one partial byte can contain only rbsp_stop_one_bit followed by alignment zeros. + return remainingValue != 1U << (bitsRemaining - 1); + } + /// /// Reads an unsigned exponential-Golomb value. /// diff --git a/src/ImageSharp/Formats/Heif/Hevc/HevcCodecConfiguration.cs b/src/ImageSharp/Formats/Heif/Hevc/HevcCodecConfiguration.cs index c7551222d..90497202c 100644 --- a/src/ImageSharp/Formats/Heif/Hevc/HevcCodecConfiguration.cs +++ b/src/ImageSharp/Formats/Heif/Hevc/HevcCodecConfiguration.cs @@ -70,6 +70,8 @@ internal sealed class HevcCodecConfiguration // to reach the image item's NAL length width without retaining playback state in the still-image model. offset += 2; byte temporalAndLengthFields = data[offset++]; + int temporalLayerCount = (temporalAndLengthFields >> 3) & 7; + bool temporalIdNested = (temporalAndLengthFields & 4) != 0; this.NalUnitLengthSize = (temporalAndLengthFields & 3) + 1; int arrayCount = data[offset++]; @@ -133,6 +135,35 @@ internal sealed class HevcCodecConfiguration { throw new InvalidImageContentException("The HEVC codec configuration contains unexpected trailing data."); } + + List videoParameterSets = new(); + foreach (HevcNalUnitArray nalUnitArray in this.nalUnitArrays) + { + const byte videoParameterSetNalUnitType = 32; + if (nalUnitArray.NalUnitType != videoParameterSetNalUnitType) + { + continue; + } + + foreach (HevcNalUnit nalUnit in nalUnitArray.NalUnits) + { + HevcVideoParameterSet videoParameterSet = new(nalUnit); + + // Legacy HEIC muxers commonly preserve only the original four source/packing constraint bits in + // hvcC and zero later profile-specific constraint bits. SPS validation provides the authoritative + // chroma and bit-depth checks, so do not reject otherwise matching Range Extensions images here. + if (!videoParameterSet.ProfileTierLevel.Matches(this) + || (temporalLayerCount != 0 && videoParameterSet.MaxSubLayers != temporalLayerCount) + || (temporalLayerCount != 0 && videoParameterSet.TemporalIdNestingFlag != temporalIdNested)) + { + throw new InvalidImageContentException("The HEVC video parameter set does not match its codec configuration."); + } + + videoParameterSets.Add(videoParameterSet); + } + } + + this.VideoParameterSets = videoParameterSets; } /// @@ -201,6 +232,11 @@ internal sealed class HevcCodecConfiguration /// public IReadOnlyList NalUnitArrays => this.nalUnitArrays; + /// + /// Gets the validated video parameter sets carried by the codec-configuration property. + /// + public IReadOnlyList VideoParameterSets { get; } + /// /// Validates the associated pixel-information property against the coded luma and chroma sample precisions. /// diff --git a/src/ImageSharp/Formats/Heif/Hevc/HevcProfileTierLevel.cs b/src/ImageSharp/Formats/Heif/Hevc/HevcProfileTierLevel.cs new file mode 100644 index 000000000..66d1e401e --- /dev/null +++ b/src/ImageSharp/Formats/Heif/Hevc/HevcProfileTierLevel.cs @@ -0,0 +1,115 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Formats.Heif.Hevc; + +/// +/// Contains the general HEVC profile, tier, constraint, and level description declared by a parameter set. +/// +internal sealed class HevcProfileTierLevel +{ + /// + /// Initializes a new instance of the class. + /// + /// The parameter-set raw byte sequence payload reader. + /// The highest declared temporal sublayer index. + /// + /// The profile-tier-level syntax is truncated or contains nonzero reserved bits. + /// + public HevcProfileTierLevel(ref HevcBitReader reader, int maxSubLayersMinusOne) + { + DebugGuard.MustBeBetweenOrEqualTo(maxSubLayersMinusOne, 0, 6, nameof(maxSubLayersMinusOne)); + + this.ProfileSpace = (byte)reader.ReadBits(2); + this.TierFlag = reader.ReadFlag(); + this.ProfileIdc = (byte)reader.ReadBits(5); + this.ProfileCompatibilityFlags = reader.ReadBits(32); + + // The configuration record carries these 48 bits verbatim. Preserve their exact ordering so the + // parameter set can be checked without reinterpreting profile-specific constraint layouts. + this.ConstraintIndicatorFlags = ((ulong)reader.ReadBits(16) << 32) | reader.ReadBits(32); + this.LevelIdc = (byte)reader.ReadBits(8); + + Span subLayerProfilePresent = stackalloc bool[6]; + Span subLayerLevelPresent = stackalloc bool[6]; + for (int subLayer = 0; subLayer < maxSubLayersMinusOne; subLayer++) + { + subLayerProfilePresent[subLayer] = reader.ReadFlag(); + subLayerLevelPresent[subLayer] = reader.ReadFlag(); + } + + if (maxSubLayersMinusOne > 0) + { + for (int subLayer = maxSubLayersMinusOne; subLayer < 8; subLayer++) + { + if (reader.ReadBits(2) != 0) + { + throw new InvalidImageContentException("The HEVC profile-tier-level syntax has nonzero reserved bits."); + } + } + } + + for (int subLayer = 0; subLayer < maxSubLayersMinusOne; subLayer++) + { + if (subLayerProfilePresent[subLayer]) + { + // A sublayer profile repeats the fixed 88-bit profile and constraint structure. It is consumed + // for alignment but not retained because one still-image item has no temporal playback model. + reader.ReadBits(2); + reader.ReadFlag(); + reader.ReadBits(5); + reader.ReadBits(32); + reader.ReadBits(16); + reader.ReadBits(32); + } + + if (subLayerLevelPresent[subLayer]) + { + reader.ReadBits(8); + } + } + } + + /// + /// Gets the namespace of the declared profile identifier. + /// + public byte ProfileSpace { get; } + + /// + /// Gets a value indicating whether the high tier is declared. + /// + public bool TierFlag { get; } + + /// + /// Gets the five-bit profile identifier. + /// + public byte ProfileIdc { get; } + + /// + /// Gets the profile-compatibility flags. + /// + public uint ProfileCompatibilityFlags { get; } + + /// + /// Gets the 48-bit profile-constraint flags. + /// + public ulong ConstraintIndicatorFlags { get; } + + /// + /// Gets the eight-bit level identifier. + /// + public byte LevelIdc { get; } + + /// + /// Determines whether this parameter-set description is compatible with an image item's codec-configuration + /// property. + /// + /// The associated HEVC codec configuration. + /// when the general profile, tier, compatibility, and level fields match. + public bool Matches(HevcCodecConfiguration configuration) + => this.ProfileSpace == configuration.GeneralProfileSpace + && this.TierFlag == configuration.GeneralTierFlag + && this.ProfileIdc == configuration.GeneralProfileIdc + && this.ProfileCompatibilityFlags == configuration.GeneralProfileCompatibilityFlags + && this.LevelIdc == configuration.GeneralLevelIdc; +} diff --git a/src/ImageSharp/Formats/Heif/Hevc/HevcVideoParameterSet.cs b/src/ImageSharp/Formats/Heif/Hevc/HevcVideoParameterSet.cs new file mode 100644 index 000000000..92ed599a9 --- /dev/null +++ b/src/ImageSharp/Formats/Heif/Hevc/HevcVideoParameterSet.cs @@ -0,0 +1,251 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Formats.Heif.Hevc; + +/// +/// Contains the bounded HEVC video-parameter-set fields required to validate and decode one still-image item. +/// +internal sealed class HevcVideoParameterSet +{ + /// + /// Initializes a new instance of the class. + /// + /// The decoded video-parameter-set NAL unit. + /// + /// The NAL unit is not a supported, conforming base-layer video parameter set. + /// + public HevcVideoParameterSet(HevcNalUnit nalUnit) + { + const byte videoParameterSetNalUnitType = 32; + if (nalUnit.Header.NalUnitType != videoParameterSetNalUnitType + || nalUnit.Header.LayerId != 0 + || nalUnit.Header.TemporalId != 0) + { + throw new InvalidImageContentException("The HEVC video parameter set has an invalid NAL-unit header."); + } + + HevcBitReader reader = new(nalUnit.Rbsp.Span); + this.Id = (byte)reader.ReadBits(4); + + bool baseLayerInternal = reader.ReadFlag(); + bool baseLayerAvailable = reader.ReadFlag(); + if (!baseLayerInternal || !baseLayerAvailable) + { + throw new InvalidImageContentException("The HEVC video parameter set does not make its base layer available."); + } + + int maxLayersMinusOne = (int)reader.ReadBits(6); + if (maxLayersMinusOne != 0) + { + // HEIF auxiliary images are separate image items. Importing an HEVC multilayer selection model would + // exceed the one-presented-image contract and is not part of the exposed still-picture profiles. + throw new InvalidImageContentException("Layered HEVC video parameter sets are not supported for still-image items."); + } + + int maxSubLayersMinusOne = (int)reader.ReadBits(3); + if (maxSubLayersMinusOne > 6) + { + throw new InvalidImageContentException("The HEVC video parameter set declares too many temporal sublayers."); + } + + this.MaxSubLayers = maxSubLayersMinusOne + 1; + this.TemporalIdNestingFlag = reader.ReadFlag(); + if (maxSubLayersMinusOne == 0 && !this.TemporalIdNestingFlag) + { + throw new InvalidImageContentException("The HEVC video parameter set has invalid temporal nesting."); + } + + if (reader.ReadBits(16) != ushort.MaxValue) + { + throw new InvalidImageContentException("The HEVC video parameter set has invalid reserved bits."); + } + + this.ProfileTierLevel = new HevcProfileTierLevel(ref reader, maxSubLayersMinusOne); + + bool subLayerOrderingInfoPresent = reader.ReadFlag(); + int firstOrderingSubLayer = subLayerOrderingInfoPresent ? 0 : maxSubLayersMinusOne; + for (int subLayer = firstOrderingSubLayer; subLayer <= maxSubLayersMinusOne; subLayer++) + { + uint maxDecodedPictureBufferingMinusOne = reader.ReadUnsignedExpGolomb(); + uint maxNumReorderPictures = reader.ReadUnsignedExpGolomb(); + reader.ReadUnsignedExpGolomb(); + if (maxNumReorderPictures > maxDecodedPictureBufferingMinusOne) + { + throw new InvalidImageContentException("The HEVC video parameter set has invalid sublayer ordering limits."); + } + } + + uint maxLayerId = reader.ReadBits(6); + uint numLayerSetsMinusOne = reader.ReadUnsignedExpGolomb(); + if (maxLayerId != 0 || numLayerSetsMinusOne != 0) + { + throw new InvalidImageContentException("HEVC layer sets are not supported for still-image items."); + } + + bool timingInfoPresent = reader.ReadFlag(); + if (timingInfoPresent) + { + // Timing and hypothetical-reference-decoder values are required for bit alignment but do not describe + // the pixels of the one image item, so they are deliberately consumed without retained playback state. + reader.ReadBits(32); + reader.ReadBits(32); + if (reader.ReadFlag()) + { + reader.ReadUnsignedExpGolomb(); + } + + uint hrdParameterCount = reader.ReadUnsignedExpGolomb(); + if (hrdParameterCount > 1024) + { + throw new InvalidImageContentException("The HEVC video parameter set declares too many HRD parameter sets."); + } + + bool nalHrdParametersPresent = false; + bool vclHrdParametersPresent = false; + bool subPictureHrdParametersPresent = false; + for (uint hrdIndex = 0; hrdIndex < hrdParameterCount; hrdIndex++) + { + uint layerSetIndex = reader.ReadUnsignedExpGolomb(); + if (layerSetIndex != 0) + { + throw new InvalidImageContentException("The HEVC HRD parameters reference an unsupported layer set."); + } + + bool commonInformationPresent = hrdIndex == 0 || reader.ReadFlag(); + SkipHrdParameters( + ref reader, + commonInformationPresent, + maxSubLayersMinusOne, + ref nalHrdParametersPresent, + ref vclHrdParametersPresent, + ref subPictureHrdParametersPresent); + } + } + + if (reader.ReadFlag()) + { + while (reader.HasMoreRbspData()) + { + reader.ReadFlag(); + } + } + + reader.ReadRbspTrailingBits(); + } + + /// + /// Gets the four-bit video-parameter-set identifier. + /// + public byte Id { get; } + + /// + /// Gets the declared number of temporal sublayers. + /// + public int MaxSubLayers { get; } + + /// + /// Gets a value indicating whether temporal identifiers are nested. + /// + public bool TemporalIdNestingFlag { get; } + + /// + /// Gets the general profile, tier, constraint, and level description. + /// + public HevcProfileTierLevel ProfileTierLevel { get; } + + /// + /// Consumes hypothetical-reference-decoder syntax without adding playback state to the still-image model. + /// + /// The video-parameter-set raw byte sequence payload reader. + /// Whether common HRD flags are coded for this parameter set. + /// The highest declared temporal sublayer index. + /// The effective NAL HRD presence flag. + /// The effective VCL HRD presence flag. + /// The effective sub-picture HRD presence flag. + /// The HRD syntax is truncated or exceeds its registered bounds. + private static void SkipHrdParameters( + ref HevcBitReader reader, + bool commonInformationPresent, + int maxSubLayersMinusOne, + ref bool nalHrdParametersPresent, + ref bool vclHrdParametersPresent, + ref bool subPictureHrdParametersPresent) + { + if (commonInformationPresent) + { + nalHrdParametersPresent = reader.ReadFlag(); + vclHrdParametersPresent = reader.ReadFlag(); + subPictureHrdParametersPresent = false; + if (nalHrdParametersPresent || vclHrdParametersPresent) + { + subPictureHrdParametersPresent = reader.ReadFlag(); + if (subPictureHrdParametersPresent) + { + reader.ReadBits(8); + reader.ReadBits(5); + reader.ReadFlag(); + reader.ReadBits(5); + } + + reader.ReadBits(4); + reader.ReadBits(4); + if (subPictureHrdParametersPresent) + { + reader.ReadBits(4); + } + + reader.ReadBits(5); + reader.ReadBits(5); + reader.ReadBits(5); + } + } + + for (int subLayer = 0; subLayer <= maxSubLayersMinusOne; subLayer++) + { + bool fixedPictureRateGeneral = reader.ReadFlag(); + bool fixedPictureRateWithinCvs = fixedPictureRateGeneral || reader.ReadFlag(); + bool lowDelayHrd = false; + if (fixedPictureRateWithinCvs) + { + reader.ReadUnsignedExpGolomb(); + } + else + { + lowDelayHrd = reader.ReadFlag(); + } + + uint cpbCountMinusOne = 0; + if (!lowDelayHrd) + { + cpbCountMinusOne = reader.ReadUnsignedExpGolomb(); + if (cpbCountMinusOne > 31) + { + throw new InvalidImageContentException("The HEVC HRD syntax declares too many coded-picture buffers."); + } + } + + for (int hrdKind = 0; hrdKind < 2; hrdKind++) + { + bool parametersPresent = hrdKind == 0 ? nalHrdParametersPresent : vclHrdParametersPresent; + if (!parametersPresent) + { + continue; + } + + for (uint cpbIndex = 0; cpbIndex <= cpbCountMinusOne; cpbIndex++) + { + reader.ReadUnsignedExpGolomb(); + reader.ReadUnsignedExpGolomb(); + if (subPictureHrdParametersPresent) + { + reader.ReadUnsignedExpGolomb(); + reader.ReadUnsignedExpGolomb(); + } + + reader.ReadFlag(); + } + } + } + } +}