Browse Source

Fix bug in ObuFrameHeader parsing

pull/2633/head
Ynse Hoornenborg 2 years ago
parent
commit
215ca668fb
  1. 13
      src/ImageSharp/Formats/Heif/Av1/Av1BitStreamReader.cs
  2. 5
      src/ImageSharp/Formats/Heif/Av1/Av1Constants.cs
  3. 12
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuLoopFilterParameters.cs
  4. 30
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReader.cs

13
src/ImageSharp/Formats/Heif/Av1/Av1BitStreamReader.cs

@ -1,14 +1,16 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Formats.Heif.Av1; namespace SixLabors.ImageSharp.Formats.Heif.Av1;
internal ref struct Av1BitStreamReader internal ref struct Av1BitStreamReader
{ {
private const int WordSize = 32; private const int WordSize = 1 << WordSizeLog2;
private const int WordSizeLog2 = 5;
private const int WordSizeInBytesLog2 = WordSizeLog2 - Log2Of8;
private const int Log2Of8 = 3;
private readonly Span<uint> data; private readonly Span<uint> data;
private uint currentWord; private uint currentWord;
@ -175,11 +177,12 @@ internal ref struct Av1BitStreamReader
public Span<byte> GetSymbolReader(int tileDataSize) public Span<byte> GetSymbolReader(int tileDataSize)
{ {
DebugGuard.IsTrue((this.bitOffset & (WordSize - 1)) == 0, "Symbol reading needs to start on byte boundary."); DebugGuard.IsTrue((this.bitOffset & 0x7) == 0, "Symbol reading needs to start on byte boundary.");
// TODO: Pass exact byte iso Word start. // TODO: Pass exact byte iso Word start.
Span<uint> span = this.data.Slice(this.bitOffset >> WordSize, tileDataSize); int spanLength = tileDataSize >> WordSizeInBytesLog2;
this.bitOffset += tileDataSize << 8; Span<uint> span = this.data.Slice(this.bitOffset >> WordSizeLog2, spanLength);
this.bitOffset += tileDataSize << Log2Of8;
return MemoryMarshal.Cast<uint, byte>(span); return MemoryMarshal.Cast<uint, byte>(span);
} }
} }

5
src/ImageSharp/Formats/Heif/Av1/Av1Constants.cs

@ -118,4 +118,9 @@ internal static class Av1Constants
/// Number of segments allowed in segmentation map. /// Number of segments allowed in segmentation map.
/// </summary> /// </summary>
public const int MaxSegments = 8; public const int MaxSegments = 8;
/// <summary>
/// Number of reference frame types (including intra type).
/// </summary>
public const int TotalReferencesPerFrame = 8;
} }

12
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuLoopFilterParameters.cs

@ -5,6 +5,12 @@ namespace SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
internal class ObuLoopFilterParameters internal class ObuLoopFilterParameters
{ {
public ObuLoopFilterParameters()
{
this.ReferenceDeltas = [1, 0, 0, 0, 0, -1, -1, -1];
this.ModeDeltas = [0, 0];
}
public int[] FilterLevel { get; internal set; } = new int[2]; public int[] FilterLevel { get; internal set; } = new int[2];
public int FilterLevelU { get; internal set; } public int FilterLevelU { get; internal set; }
@ -14,4 +20,10 @@ internal class ObuLoopFilterParameters
public int SharpnessLevel { get; internal set; } public int SharpnessLevel { get; internal set; }
public bool ReferenceDeltaModeEnabled { get; internal set; } public bool ReferenceDeltaModeEnabled { get; internal set; }
public bool ReferenceDeltaModeUpdate { get; internal set; }
public int[] ReferenceDeltas { get; }
public int[] ModeDeltas { get; }
} }

30
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReader.cs

@ -714,7 +714,7 @@ internal class ObuReader
} }
frameInfo.DisableCdfUpdate = reader.ReadBoolean(); frameInfo.DisableCdfUpdate = reader.ReadBoolean();
frameInfo.AllowScreenContentTools = sequenceHeader.ForceScreenContentTools == 1; frameInfo.AllowScreenContentTools = sequenceHeader.ForceScreenContentTools == 2;
if (frameInfo.AllowScreenContentTools) if (frameInfo.AllowScreenContentTools)
{ {
frameInfo.AllowScreenContentTools = reader.ReadBoolean(); frameInfo.AllowScreenContentTools = reader.ReadBoolean();
@ -936,7 +936,7 @@ internal class ObuReader
} }
frameInfo.AllLossless = frameInfo.CodedLossless && frameInfo.FrameSize.FrameWidth == frameInfo.FrameSize.SuperResolutionUpscaledWidth; frameInfo.AllLossless = frameInfo.CodedLossless && frameInfo.FrameSize.FrameWidth == frameInfo.FrameSize.SuperResolutionUpscaledWidth;
ReadLoopFilterParameters(ref reader, sequenceHeader, frameInfo, planesCount); this.ReadLoopFilterParameters(ref reader, planesCount);
ReadCdefParameters(ref reader, sequenceHeader, frameInfo, planesCount); ReadCdefParameters(ref reader, sequenceHeader, frameInfo, planesCount);
ReadLoopRestorationParameters(ref reader, sequenceHeader, frameInfo, planesCount); ReadLoopRestorationParameters(ref reader, sequenceHeader, frameInfo, planesCount);
ReadTransformMode(ref reader, frameInfo); ReadTransformMode(ref reader, frameInfo);
@ -1024,7 +1024,7 @@ internal class ObuReader
int tileGroupEnd = tileCount - 1; int tileGroupEnd = tileCount - 1;
if (tileCount != 1 && tileStartAndEndPresentFlag) if (tileCount != 1 && tileStartAndEndPresentFlag)
{ {
int tileBits = Av1Math.Log2(tileInfo.TileColumnCount) + Av1Math.Log2(tileInfo.TileRowCount); int tileBits = tileInfo.TileColumnCountLog2 + tileInfo.TileRowCountLog2;
tileGroupStart = (int)reader.ReadLiteral(tileBits); tileGroupStart = (int)reader.ReadLiteral(tileBits);
tileGroupEnd = (int)reader.ReadLiteral(tileBits); tileGroupEnd = (int)reader.ReadLiteral(tileBits);
} }
@ -1196,8 +1196,9 @@ internal class ObuReader
/// <summary> /// <summary>
/// 5.9.11. Loop filter params syntax /// 5.9.11. Loop filter params syntax
/// </summary> /// </summary>
private static void ReadLoopFilterParameters(ref Av1BitStreamReader reader, ObuSequenceHeader sequenceHeader, ObuFrameHeader frameInfo, int planesCount) private void ReadLoopFilterParameters(ref Av1BitStreamReader reader, int planesCount)
{ {
ObuFrameHeader frameInfo = this.FrameHeader!;
frameInfo.LoopFilterParameters.FilterLevel = new int[2]; frameInfo.LoopFilterParameters.FilterLevel = new int[2];
if (frameInfo.CodedLossless || frameInfo.AllowIntraBlockCopy) if (frameInfo.CodedLossless || frameInfo.AllowIntraBlockCopy)
{ {
@ -1220,8 +1221,25 @@ internal class ObuReader
frameInfo.LoopFilterParameters.ReferenceDeltaModeEnabled = reader.ReadBoolean(); frameInfo.LoopFilterParameters.ReferenceDeltaModeEnabled = reader.ReadBoolean();
if (frameInfo.LoopFilterParameters.ReferenceDeltaModeEnabled) if (frameInfo.LoopFilterParameters.ReferenceDeltaModeEnabled)
{ {
// TODO: Implement. frameInfo.LoopFilterParameters.ReferenceDeltaModeUpdate = reader.ReadBoolean();
throw new NotImplementedException(); if (frameInfo.LoopFilterParameters.ReferenceDeltaModeUpdate)
{
for (int i = 0; i < Av1Constants.TotalReferencesPerFrame; i++)
{
if (reader.ReadBoolean())
{
frameInfo.LoopFilterParameters.ReferenceDeltas[i] = reader.ReadSignedFromUnsigned(7);
}
}
for (int i = 0; i < 2; i++)
{
if (reader.ReadBoolean())
{
frameInfo.LoopFilterParameters.ModeDeltas[i] = reader.ReadSignedFromUnsigned(7);
}
}
}
} }
} }

Loading…
Cancel
Save