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.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Formats.Heif.Av1;
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 uint currentWord;
@ -175,11 +177,12 @@ internal ref struct Av1BitStreamReader
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.
Span<uint> span = this.data.Slice(this.bitOffset >> WordSize, tileDataSize);
this.bitOffset += tileDataSize << 8;
int spanLength = tileDataSize >> WordSizeInBytesLog2;
Span<uint> span = this.data.Slice(this.bitOffset >> WordSizeLog2, spanLength);
this.bitOffset += tileDataSize << Log2Of8;
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.
/// </summary>
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
{
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 FilterLevelU { get; internal set; }
@ -14,4 +20,10 @@ internal class ObuLoopFilterParameters
public int SharpnessLevel { 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.AllowScreenContentTools = sequenceHeader.ForceScreenContentTools == 1;
frameInfo.AllowScreenContentTools = sequenceHeader.ForceScreenContentTools == 2;
if (frameInfo.AllowScreenContentTools)
{
frameInfo.AllowScreenContentTools = reader.ReadBoolean();
@ -936,7 +936,7 @@ internal class ObuReader
}
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);
ReadLoopRestorationParameters(ref reader, sequenceHeader, frameInfo, planesCount);
ReadTransformMode(ref reader, frameInfo);
@ -1024,7 +1024,7 @@ internal class ObuReader
int tileGroupEnd = tileCount - 1;
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);
tileGroupEnd = (int)reader.ReadLiteral(tileBits);
}
@ -1196,8 +1196,9 @@ internal class ObuReader
/// <summary>
/// 5.9.11. Loop filter params syntax
/// </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];
if (frameInfo.CodedLossless || frameInfo.AllowIntraBlockCopy)
{
@ -1220,8 +1221,25 @@ internal class ObuReader
frameInfo.LoopFilterParameters.ReferenceDeltaModeEnabled = reader.ReadBoolean();
if (frameInfo.LoopFilterParameters.ReferenceDeltaModeEnabled)
{
// TODO: Implement.
throw new NotImplementedException();
frameInfo.LoopFilterParameters.ReferenceDeltaModeUpdate = reader.ReadBoolean();
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