diff --git a/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuFrameHeader.cs b/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuFrameHeader.cs index ffe384e688..b145a7a846 100644 --- a/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuFrameHeader.cs +++ b/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuFrameHeader.cs @@ -71,6 +71,8 @@ internal class ObuFrameHeader internal bool ShowableFrame { get; set; } + internal uint FrameToShowMapIdx { get; set; } + internal bool ErrorResilientMode { get; set; } internal bool AllowScreenContentTools { get; set; } diff --git a/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuOperatingPoint.cs b/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuOperatingPoint.cs index be3ad61f53..a398124e39 100644 --- a/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuOperatingPoint.cs +++ b/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuOperatingPoint.cs @@ -11,7 +11,7 @@ internal class ObuOperatingPoint internal int SequenceTier { get; set; } - internal bool IsDecoderModelPresent { get; set; } + internal bool IsDecoderModelInfoPresent { get; set; } internal bool IsInitialDisplayDelayPresent { get; set; } diff --git a/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReader.cs b/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReader.cs index 2c2075f5df..9c2d791060 100644 --- a/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReader.cs +++ b/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReader.cs @@ -281,7 +281,7 @@ internal class ObuReader } operatingPoint.SequenceTier = 0; - operatingPoint.IsDecoderModelPresent = false; + operatingPoint.IsDecoderModelInfoPresent = false; operatingPoint.IsInitialDisplayDelayPresent = false; } else @@ -289,11 +289,16 @@ internal class ObuReader sequenceHeader.TimingInfoPresentFlag = reader.ReadBoolean(); if (sequenceHeader.TimingInfoPresentFlag) { + ReadTimingInfo(ref reader, sequenceHeader); sequenceHeader.DecoderModelInfoPresentFlag = reader.ReadBoolean(); if (sequenceHeader.DecoderModelInfoPresentFlag) { ReadDecoderModelInfo(ref reader, sequenceHeader); } + else + { + sequenceHeader.DecoderModelInfoPresentFlag = false; + } } sequenceHeader.InitialDisplayDelayPresentFlag = reader.ReadBoolean(); @@ -315,15 +320,15 @@ internal class ObuReader if (sequenceHeader.DecoderModelInfoPresentFlag) { - sequenceHeader.OperatingPoint[i].IsDecoderModelPresent = reader.ReadBoolean(); - if (sequenceHeader.OperatingPoint[i].IsDecoderModelPresent) + sequenceHeader.OperatingPoint[i].IsDecoderModelInfoPresent = reader.ReadBoolean(); + if (sequenceHeader.OperatingPoint[i].IsDecoderModelInfoPresent) { // TODO: operating_parameters_info( i ) } } else { - sequenceHeader.OperatingPoint[i].IsDecoderModelPresent = false; + sequenceHeader.OperatingPoint[i].IsDecoderModelInfoPresent = false; } if (sequenceHeader.InitialDisplayDelayPresentFlag) @@ -543,6 +548,24 @@ internal class ObuReader FramePresentationTimeLength = reader.ReadLiteral(5) + 1 }; + /// + /// 5.5.3. Timing info syntax. + /// + private static void ReadTimingInfo(ref Av1BitStreamReader reader, ObuSequenceHeader sequenceHeader) + { + sequenceHeader.TimingInfo = new ObuTimingInfo + { + NumUnitsInDisplayTick = reader.ReadLiteral(32), + TimeScale = reader.ReadLiteral(32), + EqualPictureInterval = reader.ReadBoolean() + }; + + if (sequenceHeader.TimingInfo.EqualPictureInterval) + { + sequenceHeader.TimingInfo.NumTicksPerPicture = reader.ReadUnsignedVariableLength() + 1; + } + } + private static void ReadBitDepth(ref Av1BitStreamReader reader, ObuColorConfig colorConfig, ObuSequenceHeader sequenceHeader) { bool hasHighBitDepth = reader.ReadBoolean(); @@ -863,6 +886,16 @@ internal class ObuReader frameInfo.ShowableFrame = false; frameInfo.ErrorResilientMode = true; } + else + { + frameInfo.ShowExistingFrame = reader.ReadBoolean(); + if (frameInfo.ShowExistingFrame) + { + frameInfo.FrameToShowMapIdx = reader.ReadLiteral(3); + } + + // TODO: There is still some parts not implemented here + } if (frameInfo.FrameType == ObuFrameType.KeyFrame && frameInfo.ShowFrame) { diff --git a/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuSequenceHeader.cs b/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuSequenceHeader.cs index e7ce1b4e5c..b1afb7c7e3 100644 --- a/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuSequenceHeader.cs +++ b/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuSequenceHeader.cs @@ -25,7 +25,7 @@ internal class ObuSequenceHeader public bool TimingInfoPresentFlag { get; set; } - public object? TimingInfo { get; set; } + public ObuTimingInfo? TimingInfo { get; set; } public bool IsFrameIdNumbersPresent { get; set; } diff --git a/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuTimingInfo.cs b/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuTimingInfo.cs new file mode 100644 index 0000000000..d366157e78 --- /dev/null +++ b/src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuTimingInfo.cs @@ -0,0 +1,33 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit; + +internal class ObuTimingInfo +{ + /// + /// Gets or sets NumUnitsInDisplayTick. NumUnitsInDisplayTick is the number of time units of a clock operating at the frequency TimeScale Hz that + /// corresponds to one increment of a clock tick counter. A display clock tick, in seconds, is equal to + /// NumUnitsInDisplayTick divided by TimeScale. + /// + public uint NumUnitsInDisplayTick { get; set; } + + /// + /// Gets or sets TimeScale. TimeScale is the number of time units that pass in one second. + /// It is a requirement of bitstream conformance that TimeScale is greater than 0. + /// + public uint TimeScale { get; set; } + + /// + /// Gets or sets a value indicating whether that pictures should be displayed according to their output order with the + /// number of ticks between two consecutive pictures (without dropping frames) specified by NumTicksPerPicture. + /// EqualPictureInterval equal to false indicates that the interval between two consecutive pictures is not specified. + /// + public bool EqualPictureInterval { get; set; } + + /// + /// Gets or sets NumTicksPerPicture. NumTicksPerPicture specifies the number of clock ticks corresponding to output time between two + /// consecutive pictures in the output order. + /// + public uint NumTicksPerPicture { get; set; } +}