From 136110fe5eecb7ebba30fa3f915e0da552df5c03 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Fri, 28 Jun 2024 20:26:08 +0200 Subject: [PATCH] Adjustments in ReadSequenceHeader() for case when image is not ReducedStillPictureHeader (still incomplete) --- .../OpenBitstreamUnit/ObuOperatingPoint.cs | 12 +++ .../Heif/Av1/OpenBitstreamUnit/ObuReader.cs | 84 +++++++++++++++---- .../OpenBitstreamUnit/ObuSequenceHeader.cs | 2 + 3 files changed, 81 insertions(+), 17 deletions(-) diff --git a/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuOperatingPoint.cs b/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuOperatingPoint.cs index a1401b1aa8..be3ad61f53 100644 --- a/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuOperatingPoint.cs +++ b/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuOperatingPoint.cs @@ -14,4 +14,16 @@ internal class ObuOperatingPoint internal bool IsDecoderModelPresent { get; set; } internal bool IsInitialDisplayDelayPresent { get; set; } + + internal uint InitialDisplayDelay { get; set; } + + /// + /// Gets or sets of sets the Idc bitmask. The bitmask that indicates which spatial and temporal layers should be decoded for + /// operating point i.Bit k is equal to 1 if temporal layer k should be decoded(for k between 0 and 7). Bit j+8 is equal to 1 if + /// spatial layer j should be decoded(for j between 0 and 3). + /// However, if operating_point_idc[i] is equal to 0 then the coded video sequence has no scalability information in OBU + /// extension headers and the operating point applies to the entire coded video sequence.This means that all OBUs must be decoded. + /// It is a requirement of bitstream conformance that operating_point_idc[i] is not equal to operating_point_idc[j] for j = 0..(i- 1). + /// + internal uint Idc { get; set; } } diff --git a/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReader.cs b/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReader.cs index 83feaddb69..9dada5c37a 100644 --- a/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReader.cs +++ b/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReader.cs @@ -265,27 +265,77 @@ internal class ObuReader sequenceHeader.IsStillPicture = reader.ReadBoolean(); sequenceHeader.IsReducedStillPictureHeader = reader.ReadBoolean(); - if (!sequenceHeader.IsStillPicture || !sequenceHeader.IsReducedStillPictureHeader) + if (sequenceHeader.IsReducedStillPictureHeader) { - throw new ImageFormatException("Not a picture header, is this a movie file ??"); - } + sequenceHeader.TimingInfo = null; + sequenceHeader.DecoderModelInfoPresentFlag = false; + sequenceHeader.InitialDisplayDelayPresentFlag = false; + sequenceHeader.OperatingPoint = new ObuOperatingPoint[1]; + ObuOperatingPoint operatingPoint = new(); + sequenceHeader.OperatingPoint[0] = operatingPoint; + operatingPoint.OperatorIndex = 0; + operatingPoint.SequenceLevelIndex = (int)reader.ReadLiteral(Av1Constants.LevelBits); + if (!IsValidSequenceLevel(sequenceHeader.OperatingPoint[0].SequenceLevelIndex)) + { + throw new ImageFormatException("Invalid sequence level."); + } - sequenceHeader.TimingInfo = null; - sequenceHeader.DecoderModelInfoPresentFlag = false; - sequenceHeader.InitialDisplayDelayPresentFlag = false; - sequenceHeader.OperatingPoint = new ObuOperatingPoint[1]; - ObuOperatingPoint operatingPoint = new(); - sequenceHeader.OperatingPoint[0] = operatingPoint; - operatingPoint.OperatorIndex = 0; - operatingPoint.SequenceLevelIndex = (int)reader.ReadLiteral(Av1Constants.LevelBits); - if (!IsValidSequenceLevel(sequenceHeader.OperatingPoint[0].SequenceLevelIndex)) - { - throw new ImageFormatException("Invalid sequence level."); + operatingPoint.SequenceTier = 0; + operatingPoint.IsDecoderModelPresent = false; + operatingPoint.IsInitialDisplayDelayPresent = false; } + else + { + sequenceHeader.TimingInfoPresentFlag = reader.ReadBoolean(); + if (sequenceHeader.TimingInfoPresentFlag) + { + sequenceHeader.DecoderModelInfoPresentFlag = reader.ReadBoolean(); + if (sequenceHeader.DecoderModelInfoPresentFlag) + { + // TODO: read decoder_model_info( ) + } + } + + sequenceHeader.InitialDisplayDelayPresentFlag = reader.ReadBoolean(); + uint operatingPointsCnt = reader.ReadLiteral(5) + 1; + sequenceHeader.OperatingPoint = new ObuOperatingPoint[operatingPointsCnt]; + for (int i = 0; i < operatingPointsCnt; i++) + { + sequenceHeader.OperatingPoint[i] = new ObuOperatingPoint(); + sequenceHeader.OperatingPoint[i].Idc = reader.ReadLiteral(12); + sequenceHeader.OperatingPoint[i].SequenceLevelIndex = (int)reader.ReadLiteral(5); + if (sequenceHeader.OperatingPoint[i].SequenceLevelIndex > 7) + { + sequenceHeader.OperatingPoint[i].SequenceTier = (int)reader.ReadLiteral(1); + } + else + { + sequenceHeader.OperatingPoint[i].SequenceTier = 0; + } + + if (sequenceHeader.DecoderModelInfoPresentFlag) + { + sequenceHeader.OperatingPoint[i].IsDecoderModelPresent = reader.ReadBoolean(); + if (sequenceHeader.OperatingPoint[i].IsDecoderModelPresent) + { + // TODO: operating_parameters_info( i ) + } + } + else + { + sequenceHeader.OperatingPoint[i].IsDecoderModelPresent = false; + } - operatingPoint.SequenceTier = 0; - operatingPoint.IsDecoderModelPresent = false; - operatingPoint.IsInitialDisplayDelayPresent = false; + if (sequenceHeader.InitialDisplayDelayPresentFlag) + { + sequenceHeader.OperatingPoint[i].IsInitialDisplayDelayPresent = reader.ReadBoolean(); + if (sequenceHeader.OperatingPoint[i].IsInitialDisplayDelayPresent) + { + sequenceHeader.OperatingPoint[i].InitialDisplayDelay = reader.ReadLiteral(4) + 1; + } + } + } + } // Video related flags removed diff --git a/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuSequenceHeader.cs b/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuSequenceHeader.cs index 0b970091af..40d84c4819 100644 --- a/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuSequenceHeader.cs +++ b/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuSequenceHeader.cs @@ -21,6 +21,8 @@ internal class ObuSequenceHeader public bool DecoderModelInfoPresentFlag { get; set; } + public bool TimingInfoPresentFlag { get; set; } + public object? TimingInfo { get; set; } public bool IsFrameIdNumbersPresent { get; set; }