From 88e1464eb44a7838f1264723bc58eba872a111b9 Mon Sep 17 00:00:00 2001 From: Ynse Hoornenborg Date: Wed, 11 Dec 2024 21:22:28 +0100 Subject: [PATCH] Introduce BlockGeometry factory --- .../Heif/Av1/Av1BlockSizeExtensions.cs | 11 + .../Heif/Av1/ModeDecision/Av1BlockGeometry.cs | 111 ++ .../ModeDecision/Av1BlockGeometryFactory.cs | 989 ++++++++++++++++++ .../Heif/Av1/ModeDecision/Av1GeometryIndex.cs | 16 + .../Heif/Av1/Tiling/Av1BlockGeometry.cs | 62 -- .../Formats/Heif/Av1/Tiling/Av1TileWriter.cs | 18 +- 6 files changed, 1134 insertions(+), 73 deletions(-) create mode 100644 src/ImageSharp/Formats/Heif/Av1/ModeDecision/Av1BlockGeometry.cs create mode 100644 src/ImageSharp/Formats/Heif/Av1/ModeDecision/Av1BlockGeometryFactory.cs create mode 100644 src/ImageSharp/Formats/Heif/Av1/ModeDecision/Av1GeometryIndex.cs delete mode 100644 src/ImageSharp/Formats/Heif/Av1/Tiling/Av1BlockGeometry.cs 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(); }