diff --git a/src/ImageSharp/Formats/Heif/Av1/Av1Constants.cs b/src/ImageSharp/Formats/Heif/Av1/Av1Constants.cs
index 089415d25c..dc0e9e68b2 100644
--- a/src/ImageSharp/Formats/Heif/Av1/Av1Constants.cs
+++ b/src/ImageSharp/Formats/Heif/Av1/Av1Constants.cs
@@ -2,6 +2,7 @@
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
+using SixLabors.ImageSharp.Formats.Heif.Av1.Tiling;
namespace SixLabors.ImageSharp.Formats.Heif.Av1;
@@ -187,4 +188,18 @@ internal static class Av1Constants
// Number of transform sizes that use extended transforms.
public const int ExtendedTransformCount = 4;
+
+ public const int MaxVarTransform = 2;
+
+ ///
+ /// Maximum number of transform blocks per depth
+ ///
+ public const int MaxTransformBlockCount = 16;
+
+ ///
+ /// Number of items in the enumeration.
+ ///
+ public const int PlaneTypeCount = 2;
+
+ public const int MaxTransformUnitCount = 16;
}
diff --git a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1BlockGeometry.cs b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1BlockGeometry.cs
index 104099eea8..a6e24821d6 100644
--- a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1BlockGeometry.cs
+++ b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1BlockGeometry.cs
@@ -9,16 +9,47 @@ internal partial class Av1TileWriter
{
internal class Av1BlockGeometry
{
+ public Av1BlockGeometry()
+ {
+ this.TransformOrigin = new Point[Av1Constants.MaxVarTransform + 1][];
+ for (int i = 0; i < this.TransformOrigin.Length; i++)
+ {
+ this.TransformOrigin[i] = new Point[Av1Constants.MaxTransformBlockCount];
+ }
+ }
+
public Av1BlockSize BlockSize { get; internal set; }
+ public Av1BlockSize BlockSizeUv { get; internal set; }
+
+ ///
+ /// Gets or sets the Origin point from lop left of the superblock.
+ ///
public Point Origin { get; internal set; }
public bool HasUv { get; internal set; }
+ ///
+ /// Gets or sets the blocks width.
+ ///
public int BlockWidth { get; internal set; }
+ ///
+ /// Gets or sets the blocks height.
+ ///
public int BlockHeight { get; internal set; }
- public required Av1TransformSize[] TransformSize { get; internal set; }
+ public int[] TransformBlockCount { get; } = new int[Av1Constants.MaxVarTransform + 1];
+
+ public Av1TransformSize[] TransformSize { get; } = new Av1TransformSize[Av1Constants.MaxVarTransform + 1];
+
+ public Av1TransformSize[] TransformSizeUv { get; } = new Av1TransformSize[Av1Constants.MaxVarTransform + 1];
+
+ public Point[][] TransformOrigin { get; private set; }
+
+ ///
+ /// Gets or sets the block index in md scan.
+ ///
+ public int BlockIndex { get; set; }
}
}
diff --git a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1BlockStruct.cs b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1BlockStruct.cs
index 53ee7ef8bb..44bceded44 100644
--- a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1BlockStruct.cs
+++ b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1BlockStruct.cs
@@ -5,4 +5,15 @@ namespace SixLabors.ImageSharp.Formats.Heif.Av1.Tiling;
internal class Av1BlockStruct
{
+ public Av1TransformUnit[] TransformBlocks { get; } = new Av1TransformUnit[Av1Constants.MaxTransformUnitCount];
+
+ public required Av1MacroBlockD av1xd { get; set; }
+
+ public int MdScanIndex { get; set; }
+
+ public int QIndex { get; set; }
+
+ public int SegmentId { get; set; }
+
+ public Av1FilterIntraMode FilterIntraMode { get; set; }
}
diff --git a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1EntropyCodingContext.cs b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1EntropyCodingContext.cs
index 05c501d4d9..ead8f44623 100644
--- a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1EntropyCodingContext.cs
+++ b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1EntropyCodingContext.cs
@@ -10,5 +10,9 @@ internal partial class Av1TileWriter
public required Av1MacroBlockModeInfo MacroBlockModeInfo { get; internal set; }
public Point SuperblockOrigin { get; internal set; }
+
+ public int CodedAreaSuperblock { get; internal set; }
+
+ public int CodedAreaSuperblockUv { get; internal set; }
}
}
diff --git a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1MacroBlockD.cs b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1MacroBlockD.cs
index da1469173b..62dd3972bb 100644
--- a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1MacroBlockD.cs
+++ b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1MacroBlockD.cs
@@ -3,20 +3,17 @@
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Tiling;
-internal partial class Av1TileWriter
+internal class Av1MacroBlockD
{
- internal class Av1MacroBlockD
- {
- public required Av1BlockModeInfo ModeInfo { get; internal set; }
+ public required Av1BlockModeInfo ModeInfo { get; internal set; }
- public required Av1TileInfo Tile { get; internal set; }
+ public required Av1TileInfo Tile { get; internal set; }
- public bool IsUpAvailable { get; }
+ public bool IsUpAvailable { get; }
- public bool IsLeftAvailable { get; }
+ public bool IsLeftAvailable { get; }
- public Av1MacroBlockModeInfo? AboveMacroBlock { get; internal set; }
+ public Av1MacroBlockModeInfo? AboveMacroBlock { get; internal set; }
- public Av1MacroBlockModeInfo? LeftMacroBlock { get; internal set; }
- }
+ public Av1MacroBlockModeInfo? LeftMacroBlock { get; internal set; }
}
diff --git a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1NeighborArrayUnit.cs b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1NeighborArrayUnit.cs
index 0aa6a68b09..7607d1bffd 100644
--- a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1NeighborArrayUnit.cs
+++ b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1NeighborArrayUnit.cs
@@ -1,11 +1,168 @@
-// Copyright (c) Six Labors.
+// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
+using System.Numerics;
+using System.Runtime.CompilerServices;
+
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Tiling;
-internal partial class Av1TileWriter
+internal class Av1NeighborArrayUnit
+ where T : struct, IMinMaxValue
{
- internal class Av1NeighborArrayUnit
+ public static readonly T InvalidNeighborData = T.MaxValue;
+
+ [Flags]
+ public enum UnitMask
+ {
+ Left = 1,
+ Top = 2,
+ TopLeft = 4,
+ }
+
+ private readonly T[] left;
+ private readonly T[] top;
+ private readonly T[] topLeft;
+
+ public Av1NeighborArrayUnit(int leftSize, int topSize, int topLeftSize)
+ {
+ this.left = new T[leftSize];
+ this.top = new T[topSize];
+ this.topLeft = new T[topLeftSize];
+ }
+
+ public Span Left => this.left;
+
+ public Span Top => this.top;
+
+ public Span TopLeft => this.topLeft;
+
+ public required int GranularityNormalLog2 { get; set; }
+
+ public required int GranularityTopLeftLog2 { get; set; }
+
+ public int UnitSize { get; private set; }
+
+ public int GetLeftIndex(Point loc) => loc.Y >> this.GranularityNormalLog2;
+
+ public int GetTopIndex(Point loc) => loc.X >> this.GranularityNormalLog2;
+
+ public int GetTopLeftIndex(Point loc)
+ => this.left.Length + (loc.X >> this.GranularityTopLeftLog2) - (loc.Y >> this.GranularityTopLeftLog2);
+
+ public void UnitModeWrite(Span value, Point origin, Size blockSize, UnitMask mask)
{
+ int idx, j;
+
+ int count;
+ int na_offset;
+ int na_unit_size;
+
+ na_unit_size = this.UnitSize;
+
+ if ((mask & UnitMask.Top) == UnitMask.Top)
+ {
+ // Top Neighbor Array
+ // ----------12345678---------------------
+ // ^ ^
+ // | |
+ // | |
+ // xxxxxxxx
+ // x x
+ // x x
+ // 12345678
+ //
+ // The top neighbor array is updated with the samples from the
+ // bottom row of the source block
+ //
+ // Index = org_x
+ na_offset = this.GetTopIndex(origin);
+
+ ref T dst_ptr = ref this.Top[na_offset * na_unit_size];
+
+ count = blockSize.Width >> this.GranularityNormalLog2;
+
+ for (idx = 0; idx < count; ++idx)
+ {
+ /* svt_memcpy less that 10 bytes*/
+ for (j = 0; j < na_unit_size; ++j)
+ {
+ dst_ptr = value[j];
+ dst_ptr = Unsafe.Add(ref dst_ptr, 1);
+ }
+ }
+ }
+
+ if ((mask & UnitMask.Left) == UnitMask.Left)
+ {
+ // Left Neighbor Array
+ //
+ // |
+ // |
+ // 1 xxxxxxx1
+ // 2 <---- x 2
+ // 3 <---- x 3
+ // 4 xxxxxxx4
+ // |
+ // |
+ //
+ // The left neighbor array is updated with the samples from the
+ // right column of the source block
+ //
+ // Index = org_y
+ na_offset = this.GetLeftIndex(origin);
+
+ ref T dst_ptr = ref this.Left[na_offset * na_unit_size];
+
+ count = blockSize.Height >> this.GranularityNormalLog2;
+
+ for (idx = 0; idx < count; ++idx)
+ {
+ /* svt_memcpy less that 10 bytes*/
+ for (j = 0; j < na_unit_size; ++j)
+ {
+ dst_ptr = value[j];
+ dst_ptr = Unsafe.Add(ref dst_ptr, 1);
+ }
+ }
+ }
+
+ if ((mask & UnitMask.TopLeft) == UnitMask.TopLeft)
+ {
+ // Top-left Neighbor Array
+ //
+ // 4-5--6--7------------
+ // 3 \ \
+ // 2 \ \
+ // 1 \ \
+ // |\ xxxxxx7
+ // | \ x 6
+ // | \ x 5
+ // | \1x2x3x4
+ // |
+ //
+ // The top-left neighbor array is updated with the reversed samples
+ // from the right column and bottom row of the source block
+ //
+ // Index = org_x - org_y
+ Point topLeft = origin;
+ topLeft.Offset(0, blockSize.Height - 1);
+ na_offset = this.GetTopLeftIndex(topLeft);
+
+ // Copy bottom-row + right-column
+ // *Note - start from the bottom-left corner
+ ref T dst_ptr = ref this.TopLeft[na_offset * na_unit_size];
+
+ count = ((blockSize.Width + blockSize.Height) >> this.GranularityTopLeftLog2) - 1;
+
+ for (idx = 0; idx < count; ++idx)
+ {
+ /* svt_memcpy less that 10 bytes*/
+ for (j = 0; j < na_unit_size; ++j)
+ {
+ dst_ptr = value[j];
+ dst_ptr = Unsafe.Add(ref dst_ptr, 1);
+ }
+ }
+ }
}
}
diff --git a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1PictureParentControlSet.cs b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1PictureParentControlSet.cs
index 6bbc651eac..bf79f5a5c3 100644
--- a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1PictureParentControlSet.cs
+++ b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1PictureParentControlSet.cs
@@ -16,5 +16,7 @@ internal partial class Av1TileWriter
public required int[] PreviousQIndex { get; internal set; }
public int PaletteLevel { get; internal set; }
+ public int AlignedWidth { get; internal set; }
+ public int AlignedHeight { get; internal set; }
}
}
diff --git a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TransformUnit.cs b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TransformUnit.cs
new file mode 100644
index 0000000000..6670f99eda
--- /dev/null
+++ b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TransformUnit.cs
@@ -0,0 +1,13 @@
+// Copyright (c) Six Labors.
+// Licensed under the Six Labors Split License.
+
+using SixLabors.ImageSharp.Formats.Heif.Av1.Transform;
+
+namespace SixLabors.ImageSharp.Formats.Heif.Av1.Tiling;
+
+internal class Av1TransformUnit
+{
+ public ushort[] NzCoefficientCount { get; } = new ushort[3];
+
+ public Av1TransformType[] TransformType { get; } = new Av1TransformType[Av1Constants.PlaneTypeCount];
+}