diff --git a/src/ImageSharp/Formats/Heif/Av1/Av1BlockSizeExtensions.cs b/src/ImageSharp/Formats/Heif/Av1/Av1BlockSizeExtensions.cs
index 6029d4fddc..1863ed8dec 100644
--- a/src/ImageSharp/Formats/Heif/Av1/Av1BlockSizeExtensions.cs
+++ b/src/ImageSharp/Formats/Heif/Av1/Av1BlockSizeExtensions.cs
@@ -52,10 +52,21 @@ internal static class Av1BlockSizeExtensions
private static readonly int[] PelsLog2Count =
[4, 5, 5, 6, 7, 7, 8, 9, 9, 10, 11, 11, 12, 13, 13, 14, 6, 6, 8, 8, 10, 10];
+ private static readonly Av1BlockSize[][] HeightWidthToSize = [
+ [Av1BlockSize.Block4x4, Av1BlockSize.Block4x8, Av1BlockSize.Block4x16, Av1BlockSize.Invalid, Av1BlockSize.Invalid, Av1BlockSize.Invalid],
+ [Av1BlockSize.Block8x4, Av1BlockSize.Block8x8, Av1BlockSize.Block8x16, Av1BlockSize.Block8x32, Av1BlockSize.Invalid, Av1BlockSize.Invalid],
+ [Av1BlockSize.Block16x4, Av1BlockSize.Block16x8, Av1BlockSize.Block16x16, Av1BlockSize.Block16x32, Av1BlockSize.Block16x64, Av1BlockSize.Invalid],
+ [Av1BlockSize.Invalid, Av1BlockSize.Block32x8, Av1BlockSize.Block32x16, Av1BlockSize.Block32x32, Av1BlockSize.Block32x64, Av1BlockSize.Invalid],
+ [Av1BlockSize.Invalid, Av1BlockSize.Invalid, Av1BlockSize.Block64x16, Av1BlockSize.Block64x32, Av1BlockSize.Block64x64, Av1BlockSize.Block64x128],
+ [Av1BlockSize.Invalid, Av1BlockSize.Invalid, Av1BlockSize.Invalid, Av1BlockSize.Invalid, Av1BlockSize.Block128x64, Av1BlockSize.Block128x128]
+ ];
+
public static int Get4x4WideCount(this Av1BlockSize blockSize) => SizeWide[(int)blockSize];
public static int Get4x4HighCount(this Av1BlockSize blockSize) => SizeHigh[(int)blockSize];
+ public static Av1BlockSize FromWidthAndHeight(uint widthLog2, uint heightLog2) => HeightWidthToSize[heightLog2][widthLog2];
+
///
/// Returns the width of the block in samples.
///
diff --git a/src/ImageSharp/Formats/Heif/Av1/ModeDecision/Av1BlockGeometry.cs b/src/ImageSharp/Formats/Heif/Av1/ModeDecision/Av1BlockGeometry.cs
new file mode 100644
index 0000000000..af5acbd86c
--- /dev/null
+++ b/src/ImageSharp/Formats/Heif/Av1/ModeDecision/Av1BlockGeometry.cs
@@ -0,0 +1,111 @@
+// Copyright (c) Six Labors.
+// Licensed under the Six Labors Split License.
+
+using SixLabors.ImageSharp.Formats.Heif.Av1.Transform;
+
+namespace SixLabors.ImageSharp.Formats.Heif.Av1.ModeDecision;
+
+internal class Av1BlockGeometry
+{
+ private Av1BlockSize blockSize;
+ private Av1BlockSize blockSizeUv;
+
+ public Av1BlockGeometry()
+ {
+ this.RedunancyList = [];
+ 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 => this.blockSize;
+ internal set
+ {
+ this.blockSize = value;
+ this.BlockWidth = value.GetWidth();
+ this.BlockHeight = value.GetHeight();
+ }
+ }
+
+ public Av1BlockSize BlockSizeUv
+ {
+ get => this.blockSizeUv;
+ internal set
+ {
+ this.blockSizeUv = value;
+ this.BlockWidthUv = value.GetWidth();
+ this.BlockHeightUv = value.GetHeight();
+ }
+ }
+
+ ///
+ /// 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 the blocks width.
+ ///
+ public int BlockWidth { get; private set; }
+
+ ///
+ /// Gets the blocks height.
+ ///
+ public int BlockHeight { get; private 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 blocks index in the Mode Decision scan.
+ ///
+ public int ModeDecisionIndex { get; set; }
+
+ ///
+ /// Gets or sets the offset to the next nsq block (skip remaining d2 blocks).
+ ///
+ public int NextDepthOffset { get; set; }
+
+ ///
+ /// Gets or sets the offset to the next d1 sq block
+ ///
+ public int Depth1Offset { get; set; }
+
+ ///
+ /// Gets a value indicating whether this block is redundant to another.
+ ///
+ public bool IsRedundant => this.RedunancyList.Count > 0;
+
+ ///
+ /// Gets or sets the list where the block is redundant.
+ ///
+ public List RedunancyList { get; internal set; }
+
+ ///
+ /// Gets or sets the non square index within a partition 0..totns-1
+ ///
+ public int NonSquareIndex { get; internal set; }
+
+ public int TotalNonSuareCount { get; internal set; }
+
+ public int BlockWidthUv { get; private set; }
+
+ public int BlockHeightUv { get; private set; }
+
+ public int Depth { get; internal set; }
+
+ public int SequenceSize { get; internal set; }
+
+ public bool IsLastQuadrant { get; internal set; }
+}
diff --git a/src/ImageSharp/Formats/Heif/Av1/ModeDecision/Av1BlockGeometryFactory.cs b/src/ImageSharp/Formats/Heif/Av1/ModeDecision/Av1BlockGeometryFactory.cs
new file mode 100644
index 0000000000..6563895bb3
--- /dev/null
+++ b/src/ImageSharp/Formats/Heif/Av1/ModeDecision/Av1BlockGeometryFactory.cs
@@ -0,0 +1,989 @@
+// Copyright (c) Six Labors.
+// Licensed under the Six Labors Split License.
+
+using SixLabors.ImageSharp.Formats.Heif.Av1.Transform;
+
+namespace SixLabors.ImageSharp.Formats.Heif.Av1.ModeDecision;
+
+internal class Av1BlockGeometryFactory
+{
+ private const int MaxBlocksAllocated = 4421;
+ private const int NotUsedValue = 0;
+ private static readonly int[][][] NonSkipQuarterOffMult =
+ [
+
+ // 9 means not used.
+ // | x | | y |
+ /*P=0*/ [[0, 9, 9, 9], [0, 9, 9, 9]],
+ /*P=1*/ [[0, 0, 9, 9], [0, 2, 9, 9]],
+ /*P=2*/ [[0, 2, 9, 9], [0, 0, 9, 9]],
+
+ /*P=7*/ [[0, 0, 0, 0], [0, 1, 2, 3]],
+ /*P=8*/ [[0, 1, 2, 3], [0, 0, 0, 0]],
+
+ /*P=3*/ [[0, 2, 0, 9], [0, 0, 2, 9]],
+ /*P=4*/ [[0, 0, 2, 9], [0, 2, 2, 9]],
+ /*P=5*/ [[0, 0, 2, 9], [0, 2, 0, 9]],
+ /*P=6*/ [[0, 2, 2, 9], [0, 0, 2, 9]]
+ ];
+
+ private static readonly uint[][][] NonSkipSizeMult =
+ [
+
+ // 9 means not used.
+ // | h | | v |
+ /*P=0*/ [[4, 9, 9, 9], [4, 9, 9, 9]],
+ /*P=1*/ [[4, 4, 9, 9], [2, 2, 9, 9]],
+ /*P=2*/ [[2, 2, 9, 9], [4, 4, 9, 9]],
+
+ /*P=7*/ [[4, 4, 4, 4], [1, 1, 1, 1]],
+ /*P=8*/ [[1, 1, 1, 1], [4, 4, 4, 4]],
+
+ /*P=3*/ [[2, 2, 4, 9], [2, 2, 2, 9]],
+ /*P=4*/ [[4, 2, 2, 9], [2, 2, 2, 9]],
+ /*P=5*/ [[2, 2, 2, 9], [2, 2, 4, 9]],
+ /*P=6*/ [[2, 2, 2, 9], [4, 2, 2, 9]]
+ ];
+
+ // gives the index of next quadrant child within a depth
+ private static readonly int[][] NonSkipDepthOffset =
+ [
+ [85, 21, 5, 1, NotUsedValue, NotUsedValue],
+ [105, 25, 5, 1, NotUsedValue, NotUsedValue],
+ [169, 41, 9, 1, NotUsedValue, NotUsedValue],
+ [425, 105, 25, 5, NotUsedValue, NotUsedValue],
+ [681, 169, 41, 9, 1, NotUsedValue],
+ [849, 209, 49, 9, 1, NotUsedValue],
+ [1101, 269, 61, 9, 1, NotUsedValue],
+ [4421, 1101, 269, 61, 9, 1],
+ [2377, 593, 145, 33, 5, NotUsedValue]
+ ];
+
+ // gives the next depth block(first qudrant child) from a given parent square
+ private static readonly int[][] Depth1DepthOffset =
+ [
+ [1, 1, 1, 1, 1, NotUsedValue],
+ [5, 5, 1, 1, 1, NotUsedValue],
+ [5, 5, 5, 1, 1, NotUsedValue],
+ [5, 5, 5, 5, 1, NotUsedValue],
+ [5, 5, 5, 5, 1, NotUsedValue],
+ [13, 13, 13, 5, 1, NotUsedValue],
+ [25, 25, 25, 5, 1, NotUsedValue],
+ [17, 25, 25, 25, 5, 1],
+ [5, 13, 13, 13, 5, NotUsedValue]
+ ];
+
+ private static Av1GeometryIndex geometryIndex;
+ private static int maxSuperblock;
+ private static int maxDepth;
+ private static int maxPart;
+
+ // private static int maxActiveBlockCount;
+ private readonly Av1BlockGeometry[] blockGeometryModeDecisionScan;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// SVT: md_scan_all_blks
+ public Av1BlockGeometryFactory(Av1GeometryIndex geom)
+ {
+ this.blockGeometryModeDecisionScan = new Av1BlockGeometry[MaxBlocksAllocated];
+ int max_block_count;
+ geometryIndex = geom;
+ byte min_nsq_bsize;
+ if (geom == Av1GeometryIndex.Geometry0)
+ {
+ maxSuperblock = 64;
+ maxDepth = 4;
+ maxPart = 1;
+ max_block_count = 85;
+ min_nsq_bsize = 16;
+ }
+ else if (geom == Av1GeometryIndex.Geometry1)
+ {
+ maxSuperblock = 64;
+ maxDepth = 4;
+ maxPart = 3;
+ max_block_count = 105;
+ min_nsq_bsize = 16;
+ }
+ else if (geom == Av1GeometryIndex.Geometry2)
+ {
+ maxSuperblock = 64;
+ maxDepth = 4;
+ maxPart = 3;
+ max_block_count = 169;
+ min_nsq_bsize = 8;
+ }
+ else if (geom == Av1GeometryIndex.Geometry3)
+ {
+ maxSuperblock = 64;
+ maxDepth = 4;
+ maxPart = 3;
+ max_block_count = 425;
+ min_nsq_bsize = 0;
+ }
+ else if (geom == Av1GeometryIndex.Geometry4)
+ {
+ maxSuperblock = 64;
+ maxDepth = 5;
+ maxPart = 3;
+ max_block_count = 681;
+ min_nsq_bsize = 0;
+ }
+ else if (geom == Av1GeometryIndex.Geometry5)
+ {
+ maxSuperblock = 64;
+ maxDepth = 5;
+ maxPart = 5;
+ max_block_count = 849;
+ min_nsq_bsize = 0;
+ }
+ else if (geom == Av1GeometryIndex.Geometry6)
+ {
+ maxSuperblock = 64;
+ maxDepth = 5;
+ maxPart = 9;
+ max_block_count = 1101;
+ min_nsq_bsize = 0;
+ }
+ else if (geom == Av1GeometryIndex.Geometry7)
+ {
+ maxSuperblock = 128;
+ maxDepth = 6;
+ maxPart = 9;
+ max_block_count = 4421;
+ min_nsq_bsize = 0;
+ }
+ else
+ {
+ maxSuperblock = 128;
+ maxDepth = 5;
+ maxPart = 5;
+ max_block_count = 2377;
+ min_nsq_bsize = 0;
+ }
+
+ // (0)compute total number of blocks using the information provided
+ // maxActiveBlockCount = CountTotalNumberOfActiveBlocks(min_nsq_bsize);
+
+ // if (maxActiveBlockCount != max_block_count)
+ // SVT_LOG(" \n\n Error %i blocks\n\n ", maxActiveBlockCount);
+ // (2) Construct md scan blk_geom_mds: use info from dps
+ int idx_mds = 0;
+ this.ScanAllBlocks(ref idx_mds, maxSuperblock, 0, 0, false, 0, min_nsq_bsize);
+ LogRedundancySimilarity(max_block_count);
+ }
+
+ ///
+ /// SVT: count_total_num_of_active_blks
+ ///
+ private static int CountTotalNumberOfActiveBlocks(int min_nsq_bsize)
+ {
+ int depth_scan_idx = 0;
+
+ for (int depthIterator = 0; depthIterator < maxDepth; depthIterator++)
+ {
+ int totalSquareCount = 1 << depthIterator;
+ int sequenceSize = depthIterator == 0 ? maxSuperblock
+ : depthIterator == 1 ? maxSuperblock / 2
+ : depthIterator == 2 ? maxSuperblock / 4
+ : depthIterator == 3 ? maxSuperblock / 8
+ : depthIterator == 4 ? maxSuperblock / 16 : maxSuperblock / 32;
+
+ int max_part_updated = sequenceSize == 128 ? Math.Min(maxPart, maxPart < 9 && maxPart > 3 ? 3 : 7)
+ : sequenceSize == 8 ? Math.Min(maxPart, 3)
+ : sequenceSize == 4 ? 1 : maxPart;
+ if (sequenceSize <= min_nsq_bsize)
+ {
+ max_part_updated = 1;
+ }
+
+ for (int squareIteratorY = 0; squareIteratorY < totalSquareCount; squareIteratorY++)
+ {
+ for (int squareIteratorX = 0; squareIteratorX < totalSquareCount; squareIteratorX++)
+ {
+ for (int partitionIterator = 0; partitionIterator < max_part_updated; partitionIterator++)
+ {
+ int tot_num_ns_per_part = GetNonSquareCountPerPart(partitionIterator, sequenceSize);
+ depth_scan_idx += tot_num_ns_per_part;
+ }
+ }
+ }
+ }
+
+ return depth_scan_idx;
+ }
+
+ ///
+ /// SVT: get_num_ns_per_part
+ ///
+ private static int GetNonSquareCountPerPart(int partitionIterator, int sequenceSize)
+ {
+ int tot_num_ns_per_part = partitionIterator < 1 ? 1 : partitionIterator < 3 ? 2 : partitionIterator < 5 && sequenceSize < 128 ? 4 : 3;
+ return tot_num_ns_per_part;
+ }
+
+ ///
+ /// SVT: log_redundancy_similarity
+ ///
+ private static void LogRedundancySimilarity(int max_block_count)
+ {
+ for (int blockIterator = 0; blockIterator < max_block_count; blockIterator++)
+ {
+ Av1BlockGeometry cur_geom = GetBlockGeometryByModeDecisionScanIndex(blockIterator);
+ cur_geom.RedunancyList.Clear();
+
+ for (int searchIterator = 0; searchIterator < max_block_count; searchIterator++)
+ {
+ Av1BlockGeometry search_geom = GetBlockGeometryByModeDecisionScanIndex(searchIterator);
+
+ if (cur_geom.BlockSize == search_geom.BlockSize &&
+ cur_geom.Origin == search_geom.Origin &&
+ searchIterator != blockIterator)
+ {
+ if (cur_geom.NonSquareIndex == 0 && search_geom.NonSquareIndex == 0 && cur_geom.RedunancyList.Count < 3)
+ {
+ cur_geom.RedunancyList.Add(search_geom.ModeDecisionIndex);
+ }
+ }
+ }
+ }
+ }
+
+ ///
+ /// SVT: get_blk_geom_mds
+ ///
+ public static Av1BlockGeometry GetBlockGeometryByModeDecisionScanIndex(int modeDecisionScanIndex) => throw new NotImplementedException();
+
+ private void ScanAllBlocks(ref int index, int sequenceSize, int x, int y, bool isLastQuadrant, byte quadIterator, byte minNonSquareBlockSize)
+ {
+ // The input block is the parent square block of size sq_size located at pos (x,y)
+ Guard.MustBeLessThanOrEqualTo(quadIterator, (byte)3, nameof(quadIterator));
+
+ int halfsize = sequenceSize / 2;
+ int quartsize = sequenceSize / 4;
+
+ int max_part_updated = sequenceSize == 128 ? Math.Min(maxPart, maxPart is < 9 and > 3 ? 3 : 7)
+ : sequenceSize == 8 ? Math.Min(maxPart, 3)
+ : sequenceSize == 4 ? 1 : maxPart;
+ if (sequenceSize <= minNonSquareBlockSize)
+ {
+ max_part_updated = 1;
+ }
+
+ int sqi_mds = index;
+
+ for (int partitionIterator = 0; partitionIterator < max_part_updated; partitionIterator++)
+ {
+ int tot_num_ns_per_part = GetNonSquareCountPerPart(partitionIterator, sequenceSize);
+
+ for (int nonSquareIterator = 0; nonSquareIterator < tot_num_ns_per_part; nonSquareIterator++)
+ {
+ this.blockGeometryModeDecisionScan[index].Depth = sequenceSize == maxSuperblock / 1 ? 0
+ : sequenceSize == maxSuperblock / 2 ? 1
+ : sequenceSize == maxSuperblock / 4 ? 2
+ : sequenceSize == maxSuperblock / 8 ? 3
+ : sequenceSize == maxSuperblock / 16 ? 4 : 5;
+
+ this.blockGeometryModeDecisionScan[index].SequenceSize = sequenceSize;
+ this.blockGeometryModeDecisionScan[index].IsLastQuadrant = isLastQuadrant;
+
+ // part_it >= 3 for 128x128 blocks corresponds to HA/HB/VA/VB shapes since H4/V4 are not allowed
+ // for 128x128 blocks. Therefore, need to offset part_it by 2 to not index H4/V4 shapes.
+ int part_it_idx = partitionIterator >= 3 && sequenceSize == 128 ? partitionIterator + 2 : partitionIterator;
+ this.blockGeometryModeDecisionScan[index].Origin = new Point(
+ x + (quartsize * NonSkipQuarterOffMult[part_it_idx][0][nonSquareIterator]),
+ y + (quartsize * NonSkipQuarterOffMult[part_it_idx][1][nonSquareIterator]));
+
+ // These properties aren't used.
+ // this.blockGeometryModeDecisionScan[index].Shape = (Part)part_it_idx;
+ // this.blockGeometryModeDecisionScan[index].QuadIndex = quadIterator;
+ // this.blockGeometryModeDecisionScan[index].d1i = depth1Iterator++;
+ // this.blockGeometryModeDecisionScan[index].sqi_mds = sqi_mds;
+ // this.blockGeometryModeDecisionScan[index].svt_aom_geom_idx = svt_aom_geom_idx;
+ /*
+ this.blockGeometryModeDecisionScan[index].parent_depth_idx_mds = sqi_mds == 0
+ ? 0
+ : (sqi_mds + (3 - quad_it) * ns_depth_offset[svt_aom_geom_idx][this.blockGeometryModeDecisionScan[index].Depth]) -
+ parent_depth_offset[svt_aom_geom_idx][this.blockGeometryModeDecisionScan[index].Depth];*/
+ this.blockGeometryModeDecisionScan[index].Depth1Offset =
+ Depth1DepthOffset[(int)geometryIndex][this.blockGeometryModeDecisionScan[index].Depth];
+ this.blockGeometryModeDecisionScan[index].NextDepthOffset =
+ NonSkipDepthOffset[(int)geometryIndex][this.blockGeometryModeDecisionScan[index].Depth];
+ this.blockGeometryModeDecisionScan[index].TotalNonSuareCount = tot_num_ns_per_part;
+ this.blockGeometryModeDecisionScan[index].NonSquareIndex = nonSquareIterator;
+ uint blockWidth = (uint)quartsize * NonSkipSizeMult[part_it_idx][0][nonSquareIterator];
+ uint blockHeight = (uint)quartsize * NonSkipSizeMult[part_it_idx][1][nonSquareIterator];
+ this.blockGeometryModeDecisionScan[index].BlockSize =
+ Av1BlockSizeExtensions.FromWidthAndHeight(Av1Math.Log2_32(blockWidth) - 2u, Av1Math.Log2_32(blockHeight) - 2u);
+ this.blockGeometryModeDecisionScan[index].BlockSizeUv = this.blockGeometryModeDecisionScan[index].BlockSize.GetSubsampled(true, true);
+
+ // this.blockGeometryModeDecisionScan[index].BlockWidthUv = Math.Max(4, this.blockGeometryModeDecisionScan[index].BlockWidth >> 1);
+ // this.blockGeometryModeDecisionScan[index].BlockHeightUv = Math.Max(4, this.blockGeometryModeDecisionScan[index].BlockHeight >> 1);
+ this.blockGeometryModeDecisionScan[index].HasUv = true;
+
+ if (this.blockGeometryModeDecisionScan[index].BlockWidth == 4 && this.blockGeometryModeDecisionScan[index].BlockHeight == 4)
+ {
+ this.blockGeometryModeDecisionScan[index].HasUv = isLastQuadrant;
+ }
+ else if ((this.blockGeometryModeDecisionScan[index].BlockWidth >> 1) < this.blockGeometryModeDecisionScan[index].BlockWidthUv ||
+ (this.blockGeometryModeDecisionScan[index].BlockHeight >> 1) < this.blockGeometryModeDecisionScan[index].BlockHeightUv)
+ {
+ int num_blk_same_uv = 1;
+ if (this.blockGeometryModeDecisionScan[index].BlockWidth >> 1 < 4)
+ {
+ num_blk_same_uv *= 2;
+ }
+
+ if (this.blockGeometryModeDecisionScan[index].BlockHeight >> 1 < 4)
+ {
+ num_blk_same_uv *= 2;
+ }
+
+ // if (this.blockGeometryModeDecisionScan[index].nsi % 2 == 0)
+ // if (this.blockGeometryModeDecisionScan[index].nsi != (this.blockGeometryModeDecisionScan[index].totns-1) )
+ if (this.blockGeometryModeDecisionScan[index].NonSquareIndex != (num_blk_same_uv - 1) &&
+ this.blockGeometryModeDecisionScan[index].NonSquareIndex != ((2 * num_blk_same_uv) - 1))
+ {
+ this.blockGeometryModeDecisionScan[index].HasUv = false;
+ }
+ }
+
+ // tx_depth 1 geom settings
+ int tx_depth = 0;
+ this.blockGeometryModeDecisionScan[index].TransformBlockCount[tx_depth] = this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block128x128
+ ? 4
+ : this.blockGeometryModeDecisionScan[index].BlockSize is Av1BlockSize.Block128x64 or Av1BlockSize.Block64x128
+ ? 2
+ : 1;
+ for (int transformBlockIterator = 0; transformBlockIterator < this.blockGeometryModeDecisionScan[index].TransformBlockCount[tx_depth]; transformBlockIterator++)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] =
+ GetTransformSize(this.blockGeometryModeDecisionScan[index].BlockSize, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] =
+ GetTransformSize(this.blockGeometryModeDecisionScan[index].BlockSize, 1);
+ if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block128x128)
+ {
+ int offsetx = (transformBlockIterator is 0 or 2) ? 0 : 64;
+ int offsety = (transformBlockIterator is 0 or 1) ? 0 : 64;
+ Size offset = new(offsetx, offsety);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block128x64)
+ {
+ int offsetx = (transformBlockIterator == 0) ? 0 : 64;
+ int offsety = 0;
+ Size offset = new(offsetx, offsety);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block64x128)
+ {
+ int offsetx = 0;
+ int offsety = (transformBlockIterator == 0) ? 0 : 64;
+ Size offset = new(offsetx, offsety);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else
+ {
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin;
+ }
+
+ /*if (this.blockGeometryModeDecisionScan[index].bsize == BLOCK_16X8)
+ SVT_LOG("");
+ this.blockGeometryModeDecisionScan[index].tx_width[tx_depth] =
+ tx_size_wide[this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth]];
+ this.blockGeometryModeDecisionScan[index].tx_height[tx_depth] =
+ tx_size_high[this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth]];
+ this.blockGeometryModeDecisionScan[index].tx_width_uv[tx_depth] =
+ tx_size_wide[this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth]];
+ this.blockGeometryModeDecisionScan[index].tx_height_uv[tx_depth] =
+ tx_size_high[this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth]];*/
+ }
+
+ // tx_depth 1 geom settings
+ tx_depth = 1;
+ this.blockGeometryModeDecisionScan[index].TransformBlockCount[tx_depth] = this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block128x128
+ ? 4
+ : this.blockGeometryModeDecisionScan[index].BlockSize is Av1BlockSize.Block128x64 or Av1BlockSize.Block64x128
+ ? 2
+ : 1;
+
+ if (this.blockGeometryModeDecisionScan[index].BlockSize is Av1BlockSize.Block64x64 or
+ Av1BlockSize.Block32x32 or
+ Av1BlockSize.Block16x16 or
+ Av1BlockSize.Block8x8)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformBlockCount[tx_depth] = 4;
+ }
+
+ if (this.blockGeometryModeDecisionScan[index].BlockSize is Av1BlockSize.Block64x32 or
+ Av1BlockSize.Block32x64 or
+ Av1BlockSize.Block32x16 or
+ Av1BlockSize.Block16x32 or
+ Av1BlockSize.Block16x8 or
+ Av1BlockSize.Block8x16)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformBlockCount[tx_depth] = 2;
+ }
+
+ if (this.blockGeometryModeDecisionScan[index].BlockSize is Av1BlockSize.Block64x16 or
+ Av1BlockSize.Block16x64 or
+ Av1BlockSize.Block32x8 or
+ Av1BlockSize.Block8x32 or
+ Av1BlockSize.Block16x4 or
+ Av1BlockSize.Block4x16)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformBlockCount[tx_depth] = 2;
+ }
+
+ for (int transformBlockIterator = 0; transformBlockIterator < this.blockGeometryModeDecisionScan[index].TransformBlockCount[tx_depth]; transformBlockIterator++)
+ {
+ if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block64x64)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(Av1BlockSize.Block32x32, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] = this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+ int[] offsetx = [0, 32, 0, 32];
+ int[] offsety = [0, 0, 32, 32];
+
+ // 0 1
+ // 2 3
+ Size offset = new(offsetx[transformBlockIterator], offsety[transformBlockIterator]);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block64x32)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(Av1BlockSize.Block32x32, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] = this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+ int[] offsetx = [0, 32];
+ int[] offsety = [0, 0];
+
+ // 0 1
+ Size offset = new(offsetx[transformBlockIterator], offsety[transformBlockIterator]);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block32x64)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(Av1BlockSize.Block32x32, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] = this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+ int[] offsetx = [0, 0];
+ int[] offsety = [0, 32];
+
+ // 0 1
+ Size offset = new(offsetx[transformBlockIterator], offsety[transformBlockIterator]);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block32x32)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(Av1BlockSize.Block16x16, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] = this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+ int[] offsetx = [0, 16, 0, 16];
+ int[] offsety = [0, 0, 16, 16];
+
+ // 0 1
+ // 2 3
+ Size offset = new(offsetx[transformBlockIterator], offsety[transformBlockIterator]);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block32x16)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(Av1BlockSize.Block16x16, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] = this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+ int[] offsetx = [0, 16];
+ int[] offsety = [0, 0];
+
+ // 0 1
+ Size offset = new(offsetx[transformBlockIterator], offsety[transformBlockIterator]);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block16x32)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(Av1BlockSize.Block16x16, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] = this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+ int[] offsetx = [0, 0];
+ int[] offsety = [0, 16];
+
+ // 0 1
+ Size offset = new(offsetx[transformBlockIterator], offsety[transformBlockIterator]);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block16x16)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(Av1BlockSize.Block8x8, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] = this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+ int[] offsetx = [0, 8, 0, 8];
+ int[] offsety = [0, 0, 8, 8];
+
+ // 0 1
+ // 2 3
+ Size offset = new(offsetx[transformBlockIterator], offsety[transformBlockIterator]);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block16x8)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(Av1BlockSize.Block8x8, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] = this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+ int[] offsetx = [0, 8];
+ int[] offsety = [0, 0];
+
+ // 0 1
+ Size offset = new(offsetx[transformBlockIterator], offsety[transformBlockIterator]);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block8x16)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(Av1BlockSize.Block8x8, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] = this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+ int[] offsetx = [0, 0];
+ int[] offsety = [0, 8];
+
+ // 0 1
+ Size offset = new(offsetx[transformBlockIterator], offsety[transformBlockIterator]);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block8x8)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(Av1BlockSize.Block4x4, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] = this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+ int[] offsetx = [0, 4, 0, 4];
+ int[] offsety = [0, 0, 4, 4];
+
+ // 0 1
+ // 2 3
+ Size offset = new(offsetx[transformBlockIterator], offsety[transformBlockIterator]);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block64x16)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(Av1BlockSize.Block32x16, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] = this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+
+ int[] offsetx = [0, 32];
+ int[] offsety = [0, 0];
+ Size offset = new(offsetx[transformBlockIterator], offsety[transformBlockIterator]);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block16x64)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(Av1BlockSize.Block16x32, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] = this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+
+ int[] offsetx = [0, 0];
+ int[] offsety = [0, 32];
+ Size offset = new(offsetx[transformBlockIterator], offsety[transformBlockIterator]);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block32x8)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(Av1BlockSize.Block16x8, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] = this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+
+ int[] offsetx = [0, 16];
+ int[] offsety = [0, 0];
+ Size offset = new(offsetx[transformBlockIterator], offsety[transformBlockIterator]);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block8x32)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(Av1BlockSize.Block8x16, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] = this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+
+ // 0 1 2 3
+ int[] offsetx = [0, 0];
+ int[] offsety = [0, 16];
+ Size offset = new(offsetx[transformBlockIterator], offsety[transformBlockIterator]);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block16x4)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(Av1BlockSize.Block8x4, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] = this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+
+ int[] offsetx = [0, 8];
+ int[] offsety = [0, 0];
+
+ Size offset = new(offsetx[transformBlockIterator], offsety[transformBlockIterator]);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block4x16)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(Av1BlockSize.Block4x8, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] = this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+
+ int[] offsetx = [0, 0];
+ int[] offsety = [0, 8];
+ Size offset = new(offsetx[transformBlockIterator], offsety[transformBlockIterator]);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else
+ {
+ if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block128x128)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(
+ this.blockGeometryModeDecisionScan[index].BlockSize, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] =
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+
+ int offsetx = (transformBlockIterator is 0 or 2) ? 0 : 64;
+ int offsety = (transformBlockIterator is 0 or 1) ? 0 : 64;
+ Size offset = new(offsetx, offsety);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block128x64)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(
+ this.blockGeometryModeDecisionScan[index].BlockSize, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] =
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+
+ int offsetx = (transformBlockIterator is 0) ? 0 : 64;
+ int offsety = 0;
+ Size offset = new(offsetx, offsety);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block64x128)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(
+ this.blockGeometryModeDecisionScan[index].BlockSize, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] =
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+ int offsetx = 0;
+ int offsety = (transformBlockIterator is 0) ? 0 : 64;
+ Size offset = new(offsetx, offsety);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(
+ this.blockGeometryModeDecisionScan[index].BlockSize, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] =
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin;
+ }
+ }
+
+ /*this.blockGeometryModeDecisionScan[index].tx_width[tx_depth] =
+ tx_size_wide[this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth]];
+ this.blockGeometryModeDecisionScan[index].tx_height[tx_depth] =
+ tx_size_high[this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth]];
+ this.blockGeometryModeDecisionScan[index].tx_width_uv[tx_depth] = this.blockGeometryModeDecisionScan[index].tx_width_uv[0];
+ this.blockGeometryModeDecisionScan[index].tx_height_uv[tx_depth] = this.blockGeometryModeDecisionScan[index].tx_height_uv[0];*/
+ }
+
+ // tx_depth 2 geom settings
+ tx_depth = 2;
+
+ this.blockGeometryModeDecisionScan[index].TransformBlockCount[tx_depth] = this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block128x128
+ ? 4
+ : this.blockGeometryModeDecisionScan[index].BlockSize is Av1BlockSize.Block128x64 or
+ Av1BlockSize.Block64x128
+ ? 2
+ : 1;
+
+ if (this.blockGeometryModeDecisionScan[index].BlockSize is Av1BlockSize.Block64x64 or
+ Av1BlockSize.Block32x32 or
+ Av1BlockSize.Block16x16)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformBlockCount[tx_depth] = 16;
+ }
+
+ if (this.blockGeometryModeDecisionScan[index].BlockSize is Av1BlockSize.Block64x32 or
+ Av1BlockSize.Block32x64 or
+ Av1BlockSize.Block32x16 or
+ Av1BlockSize.Block16x32 or
+ Av1BlockSize.Block16x8 or
+ Av1BlockSize.Block8x16)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformBlockCount[tx_depth] = 8;
+ }
+
+ if (this.blockGeometryModeDecisionScan[index].BlockSize is Av1BlockSize.Block64x16 or
+ Av1BlockSize.Block16x64 or
+ Av1BlockSize.Block32x8 or
+ Av1BlockSize.Block8x32 or
+ Av1BlockSize.Block16x4 or
+ Av1BlockSize.Block4x16)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformBlockCount[tx_depth] = 4;
+ }
+
+ for (int transformBlockIterator = 0; transformBlockIterator < this.blockGeometryModeDecisionScan[index].TransformBlockCount[tx_depth]; transformBlockIterator++)
+ {
+ if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block64x64)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(Av1BlockSize.Block16x16, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] = this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+
+ int[] offsetx_intra = [0, 16, 32, 48, 0, 16, 32, 48, 0, 16, 32, 48, 0, 16, 32, 48];
+ int[] offsety_intra = [0, 0, 0, 0, 16, 16, 16, 16, 32, 32, 32, 32, 48, 48, 48, 48];
+ Size offset = new(offsetx_intra[transformBlockIterator], offsety_intra[transformBlockIterator]);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block64x32)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(Av1BlockSize.Block16x16, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] = this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+
+ int[] offsetx_intra = [0, 16, 32, 48, 0, 16, 32, 48];
+ int[] offsety_intra = [0, 0, 0, 0, 16, 16, 16, 16];
+ Size offset = new(offsetx_intra[transformBlockIterator], offsety_intra[transformBlockIterator]);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block32x64)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(Av1BlockSize.Block16x16, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] = this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+
+ int[] offsetx_intra = [0, 16, 0, 16, 0, 16, 0, 16];
+ int[] offsety_intra = [0, 0, 16, 16, 32, 32, 48, 48];
+
+ Size offset = new(offsetx_intra[transformBlockIterator], offsety_intra[transformBlockIterator]);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block32x32)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(Av1BlockSize.Block8x8, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] = this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+
+ int[] offsetx_intra = [0, 8, 16, 24, 0, 8, 16, 24, 0, 8, 16, 24, 0, 8, 16, 24];
+ int[] offsety_intra = [0, 0, 0, 0, 8, 8, 8, 8, 16, 16, 16, 16, 24, 24, 24, 24];
+
+ Size offset = new(offsetx_intra[transformBlockIterator], offsety_intra[transformBlockIterator]);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block32x16)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(Av1BlockSize.Block8x8, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] = this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+
+ int[] offsetx_intra = [0, 8, 16, 24, 0, 8, 16, 24];
+ int[] offsety_intra = [0, 0, 0, 0, 8, 8, 8, 8];
+
+ Size offset = new(offsetx_intra[transformBlockIterator], offsety_intra[transformBlockIterator]);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block16x32)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(Av1BlockSize.Block8x8, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] = this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+
+ int[] offsetx_intra = [0, 8, 0, 8, 0, 8, 0, 8];
+ int[] offsety_intra = [0, 0, 8, 8, 16, 16, 24, 24];
+ Size offset = new(offsetx_intra[transformBlockIterator], offsety_intra[transformBlockIterator]);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block16x8)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(Av1BlockSize.Block4x4, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] = this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+
+ int[] offsetx_intra = [0, 4, 8, 12, 0, 4, 8, 12];
+ int[] offsety_intra = [0, 0, 0, 0, 4, 4, 4, 4];
+ Size offset = new(offsetx_intra[transformBlockIterator], offsety_intra[transformBlockIterator]);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block8x16)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(Av1BlockSize.Block4x4, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] = this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+
+ int[] offsetx_intra = [0, 4, 0, 4, 0, 4, 0, 4];
+ int[] offsety_intra = [0, 0, 4, 4, 8, 8, 12, 12];
+ Size offset = new(offsetx_intra[transformBlockIterator], offsety_intra[transformBlockIterator]);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block16x16)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(Av1BlockSize.Block4x4, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] = this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+
+ int[] offsetx_intra = [0, 4, 8, 12, 0, 4, 8, 12, 0, 4, 8, 12, 0, 4, 8, 12];
+ int[] offsety_intra = [0, 0, 0, 0, 4, 4, 4, 4, 8, 8, 8, 8, 12, 12, 12, 12];
+ Size offset = new(offsetx_intra[transformBlockIterator], offsety_intra[transformBlockIterator]);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block64x16)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(Av1BlockSize.Block16x16, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] = this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+
+ // 0 1 2 3
+ int[] offsetx = [0, 16, 32, 48];
+ int[] offsety = [0, 0, 0, 0];
+ Size offset = new(offsetx[transformBlockIterator], offsety[transformBlockIterator]);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block16x64)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(Av1BlockSize.Block16x16, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] = this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+
+ // 0 1 2 3
+ int[] offsetx = [0, 0, 0, 0];
+ int[] offsety = [0, 16, 32, 48];
+ Size offset = new(offsetx[transformBlockIterator], offsety[transformBlockIterator]);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block32x8)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(Av1BlockSize.Block8x8, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] = this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+
+ // 0 1 2 3
+ int[] offsetx = [0, 8, 16, 24];
+ int[] offsety = [0, 0, 0, 0];
+ Size offset = new(offsetx[transformBlockIterator], offsety[transformBlockIterator]);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block8x32)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(Av1BlockSize.Block8x8, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] = this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+
+ // 0 1 2 3
+ int[] offsetx = [0, 0, 0, 0];
+ int[] offsety = [0, 8, 16, 24];
+ Size offset = new(offsetx[transformBlockIterator], offsety[transformBlockIterator]);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block16x4)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(Av1BlockSize.Block4x4, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] = this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+
+ // 0 1 2 3
+ int[] offsetx = [0, 4, 8, 12];
+ int[] offsety = [0, 0, 0, 0];
+ Size offset = new(offsetx[transformBlockIterator], offsety[transformBlockIterator]);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block4x16)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(Av1BlockSize.Block4x4, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] = this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+
+ // 0 1 2 3
+ int[] offsetx = [0, 0, 0, 0];
+ int[] offsety = [0, 4, 8, 12];
+ Size offset = new(offsetx[transformBlockIterator], offsety[transformBlockIterator]);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else
+ {
+ if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block128x128)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(
+ this.blockGeometryModeDecisionScan[index].BlockSize, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] =
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+ int offsetx = (transformBlockIterator is 0 or 2) ? 0 : 64;
+ int offsety = (transformBlockIterator is 0 or 1) ? 0 : 64;
+ Size offset = new(offsetx, offsety);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block128x64)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(
+ this.blockGeometryModeDecisionScan[index].BlockSize, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] =
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+ int offsetx = (transformBlockIterator is 0) ? 0 : 64;
+ int offsety = 0;
+ Size offset = new(offsetx, offsety);
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin + offset;
+ }
+ else if (this.blockGeometryModeDecisionScan[index].BlockSize == Av1BlockSize.Block64x128)
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(
+ this.blockGeometryModeDecisionScan[index].BlockSize, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] =
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+ int offsetx = 0;
+ int offsety = (transformBlockIterator is 0) ? 0 : 64;
+ Size offset = new(offsetx, offsety);
+ }
+ else
+ {
+ this.blockGeometryModeDecisionScan[index].TransformSize[tx_depth] = GetTransformSize(
+ this.blockGeometryModeDecisionScan[index].BlockSize, 0);
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[tx_depth] =
+ this.blockGeometryModeDecisionScan[index].TransformSizeUv[0];
+ this.blockGeometryModeDecisionScan[index].TransformOrigin[tx_depth][transformBlockIterator] =
+ this.blockGeometryModeDecisionScan[index].Origin;
+ }
+ }
+
+ /*this.blockGeometryModeDecisionScan[index].tx_width[tx_depth] =
+ tx_size_wide[this.blockGeometryModeDecisionScan[index].txsize[tx_depth]];
+ this.blockGeometryModeDecisionScan[index].tx_height[tx_depth] =
+ tx_size_high[this.blockGeometryModeDecisionScan[index].txsize[tx_depth]];
+ this.blockGeometryModeDecisionScan[index].tx_width_uv[tx_depth] = this.blockGeometryModeDecisionScan[index].tx_width_uv[0];
+ this.blockGeometryModeDecisionScan[index].tx_height_uv[tx_depth] = this.blockGeometryModeDecisionScan[index].tx_height_uv[0];*/
+ }
+
+ this.blockGeometryModeDecisionScan[index].ModeDecisionIndex = index;
+ index += 1;
+ }
+ }
+ }
+
+ ///
+ /// SVT: av1_get_tx_size
+ ///
+ private static Av1TransformSize GetTransformSize(Av1BlockSize blockSize, int plane)
+ {
+ // const MbModeInfo* mbmi = xd->mi[0];
+ // if (xd->lossless[mbmi->segment_id]) return TX_4X4;
+ if (plane == 0)
+ {
+ return blockSize.GetMaximumTransformSize();
+ }
+
+ // const MacroblockdPlane *pd = &xd->plane[plane];
+ bool subsampling_x = plane > 0;
+ bool subsampling_y = plane > 0;
+ return blockSize.GetMaxUvTransformSize(subsampling_x, subsampling_y);
+ }
+}
diff --git a/src/ImageSharp/Formats/Heif/Av1/ModeDecision/Av1GeometryIndex.cs b/src/ImageSharp/Formats/Heif/Av1/ModeDecision/Av1GeometryIndex.cs
new file mode 100644
index 0000000000..5392c3f20d
--- /dev/null
+++ b/src/ImageSharp/Formats/Heif/Av1/ModeDecision/Av1GeometryIndex.cs
@@ -0,0 +1,16 @@
+// Copyright (c) Six Labors.
+// Licensed under the Six Labors Split License.
+
+namespace SixLabors.ImageSharp.Formats.Heif.Av1.ModeDecision;
+
+internal enum Av1GeometryIndex
+{
+ Geometry0,
+ Geometry1,
+ Geometry2,
+ Geometry3,
+ Geometry4,
+ Geometry5,
+ Geometry6,
+ Geometry7,
+}
diff --git a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1BlockGeometry.cs b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1BlockGeometry.cs
deleted file mode 100644
index 0252ba2195..0000000000
--- a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1BlockGeometry.cs
+++ /dev/null
@@ -1,62 +0,0 @@
-// 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 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 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 blocks index in the Mode Decision scan.
- ///
- public int ModeDecisionIndex { get; set; }
-
- ///
- /// Gets or sets the offset to the next nsq block (skip remaining d2 blocks).
- ///
- public int NextDepthSequenceOffset { get; set; }
-
- ///
- /// Gets or sets the offset to the next d1 sq block
- ///
- public int NextDepth1Offset { get; set; }
-}
diff --git a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileWriter.cs b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileWriter.cs
index 4eacf17704..b5885f7774 100644
--- a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileWriter.cs
+++ b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileWriter.cs
@@ -3,6 +3,7 @@
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Formats.Heif.Av1.Entropy;
+using SixLabors.ImageSharp.Formats.Heif.Av1.ModeDecision;
using SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
using SixLabors.ImageSharp.Formats.Heif.Av1.Prediction;
using SixLabors.ImageSharp.Formats.Heif.Av1.Transform;
@@ -37,7 +38,7 @@ internal partial class Av1TileWriter
{
bool code_blk_cond = true; // Code cu only if it is inside the picture
Av1EncoderBlockStruct blk_ptr = superblock.FinalBlocks[final_blk_index];
- Av1BlockGeometry blk_geom = GetBlockGeometryByModeDecisionScanIndex(blk_index);
+ Av1BlockGeometry blk_geom = Av1BlockGeometryFactory.GetBlockGeometryByModeDecisionScanIndex(blk_index);
Av1BlockSize bsize = blk_geom.BlockSize;
Point blockOrigin = blk_geom.Origin;
@@ -234,16 +235,16 @@ internal partial class Av1TileWriter
if (superblock.CodingUnitPartitionTypes[blk_index] != Av1PartitionType.Split)
{
final_blk_index++;
- blk_index += blk_geom.NextDepthSequenceOffset;
+ blk_index += blk_geom.NextDepthOffset;
}
else
{
- blk_index += blk_geom.NextDepth1Offset;
+ blk_index += blk_geom.Depth1Offset;
}
}
else
{
- blk_index += blk_geom.NextDepth1Offset;
+ blk_index += blk_geom.Depth1Offset;
}
}
while (blk_index < scs.MaxBlockCount);
@@ -623,7 +624,7 @@ internal partial class Av1TileWriter
Av1NeighborArrayUnit luma_dc_sign_level_coeff_na)
{
// Removed any code related to INTER frames.
- Av1BlockGeometry blockGeometry = GetBlockGeometryByModeDecisionScanIndex(blk_ptr.ModeDecisionScanIndex);
+ Av1BlockGeometry blockGeometry = Av1BlockGeometryFactory.GetBlockGeometryByModeDecisionScanIndex(blk_ptr.ModeDecisionScanIndex);
int tx_depth = mbmi.Block.TransformDepth;
int txb_count = blockGeometry.TransformBlockCount[mbmi.Block.TransformDepth];
ObuFrameHeader frameHeader = pcs.Parent.FrameHeader;
@@ -700,7 +701,7 @@ internal partial class Av1TileWriter
Av1NeighborArrayUnit cr_dc_sign_level_coeff_na,
Av1NeighborArrayUnit cb_dc_sign_level_coeff_na)
{
- Av1BlockGeometry blockGeometry = GetBlockGeometryByModeDecisionScanIndex(blk_ptr.ModeDecisionScanIndex);
+ Av1BlockGeometry blockGeometry = Av1BlockGeometryFactory.GetBlockGeometryByModeDecisionScanIndex(blk_ptr.ModeDecisionScanIndex);
if (!blockGeometry.HasUv)
{
@@ -1044,9 +1045,4 @@ internal partial class Av1TileWriter
int left_skip = (left_mi != null && left_mi.Block.Skip) ? 1 : 0;
writer.WriteSkip(skip, above_skip + left_skip);
}
-
- ///
- /// SVT: get_blk_geom_mds
- ///
- private static Av1BlockGeometry GetBlockGeometryByModeDecisionScanIndex(int modeDecisionScanIndex) => throw new NotImplementedException();
}