diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1BlockDecoder.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1BlockDecoder.cs index d6de4628c..990b98ece 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1BlockDecoder.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1BlockDecoder.cs @@ -10,47 +10,93 @@ using SixLabors.ImageSharp.Formats.Heif.Av1.Tiling; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform; +/// +/// Reconstructs AV1 transform blocks by combining prediction, inverse quantization, and inverse transforms. +/// internal class Av1BlockDecoder { + /// + /// The sequence-level syntax that determines superblock size, plane layout, and sample depth. + /// private readonly ObuSequenceHeader sequenceHeader; + /// + /// The current frame syntax that determines quantization, lossless segments, and reconstruction geometry. + /// private readonly ObuFrameHeader frameHeader; + /// + /// The reconstructed Y, U, and V sample planes receiving prediction and residual output. + /// private readonly Av1FrameBuffer frameBuffer; + /// + /// Indicates whether transform traversal must also populate loop-filter parameters. + /// private readonly bool isLoopFilterEnabled; + /// + /// The next packed coefficient position for each plane in the current superblock. + /// private readonly int[] currentCoefficientIndex; + /// + /// Accumulates reconstructed luma samples until a chroma-from-luma prediction block can consume them. + /// private readonly Av1ChromaFromLumaContext chromaFromLumaContext; + /// + /// Initializes a new instance of the class. + /// + /// The decoded sequence header. + /// The decoded frame header. + /// The frame buffer receiving reconstructed samples. public Av1BlockDecoder(ObuSequenceHeader sequenceHeader, ObuFrameHeader frameHeader, Av1FrameBuffer frameBuffer) { this.sequenceHeader = sequenceHeader; this.frameHeader = frameHeader; this.frameBuffer = frameBuffer; int ySize = (1 << this.sequenceHeader.SuperblockSizeLog2) * (1 << this.sequenceHeader.SuperblockSizeLog2); + + // One scratch plane is reused for every transform unit. Its maximum size must cover a complete superblock + // across all coded planes, with chroma dimensions reduced independently by their subsampling axes. int inverseQuantizationSize = ySize + (this.sequenceHeader.ColorConfig.SubSamplingX ? ySize >> 2 : ySize) + (this.sequenceHeader.ColorConfig.SubSamplingY ? ySize >> 2 : ySize); + this.CurrentInverseQuantizationCoefficients = new int[inverseQuantizationSize]; this.isLoopFilterEnabled = false; this.currentCoefficientIndex = new int[3]; this.chromaFromLumaContext = new(sequenceHeader.ColorConfig); } + /// + /// Gets the reusable raster-order coefficient buffer populated by inverse quantization. + /// public int[] CurrentInverseQuantizationCoefficients { get; private set; } + /// + /// Resets the per-plane packed coefficient cursors before reconstructing a superblock. + /// + /// The superblock whose coefficient streams will be consumed. public void UpdateSuperblock(Av1SuperblockInfo superblockInfo) { + // Each superblock owns independent packed coefficient streams for Y, U, and V. The first value for each + // transform unit stores its coefficient count, so DecodeBlock advances a plane cursor as units are consumed. this.currentCoefficientIndex[0] = 0; this.currentCoefficientIndex[1] = 0; this.currentCoefficientIndex[2] = 0; } /// - /// SVT: svt_aom_decode_block + /// Reconstructs every luma and chroma transform unit belonging to one decoded AV1 block. /// + /// The decoded prediction, segmentation, skip, and transform state. + /// The block origin in units of four luma samples. + /// The decoded block size. + /// The owning superblock's transform and coefficient storage. + /// The tile boundaries used to determine neighbor availability. + /// Corresponds to svt_aom_decode_block in the original WIP reference. public void DecodeBlock(Av1BlockModeInfo modeInfo, Point modeInfoPosition, Av1BlockSize blockSize, Av1SuperblockInfo superblockInfo, Av1TileInfo tileInfo) { ObuColorConfig colorConfig = this.sequenceHeader.ColorConfig; @@ -69,6 +115,8 @@ internal class Av1BlockDecoder if (hasChroma) { + // A one-unit luma edge maps to the same chroma sample as the adjacent unit on a subsampled axis. In that + // case the usable chroma neighbor is two mode-info units away rather than immediately above or left. if (colorConfig.SubSamplingY && blockSize.Get4x4HighCount() == 1) { partitionInfo.AvailableAboveForChroma = modeInfoPosition.Y - 2 >= tileInfo.ModeInfoRowStart; @@ -88,8 +136,9 @@ internal class Av1BlockDecoder bool isLossless = this.frameHeader.LosslessArray[modeInfo.SegmentId]; bool isLosslessBlock = isLossless && ((blockSize >= Av1BlockSize.Block64x64) && (blockSize <= Av1BlockSize.Block128x128)); int chromaTransformUnitCount = isLosslessBlock - ? (maxBlocksWide * maxBlocksHigh) >> ((colorConfig.SubSamplingX ? 1 : 0) + (colorConfig.SubSamplingY ? 1 : 0)) - : modeInfo.TransformUnitsCount[(int)Av1Plane.U]; + ? (maxBlocksWide * maxBlocksHigh) >> ((colorConfig.SubSamplingX ? 1 : 0) + (colorConfig.SubSamplingY ? 1 : 0)) + : modeInfo.TransformUnitsCount[(int)Av1Plane.U]; + bool highBitDepth = this.frameBuffer.BytesPerSample == 2; int loopFilterStride = this.frameHeader.ModeInfoStride; Av1PredictionDecoder predictionDecoder = new(this.sequenceHeader, this.frameHeader); @@ -105,6 +154,8 @@ internal class Av1BlockDecoder continue; } + // Luma transform descriptors occupy their own stream. U and V share one stream, with the V descriptors + // following the U descriptors for this block, so the V base includes the complete U transform-unit count. int transformInfoIndex = plane switch { 2 => superblockInfo.TransformInfoIndexUv + modeInfo.FirstTransformLocation[plane - 1] + chromaTransformUnitCount, @@ -130,9 +181,13 @@ internal class Av1BlockDecoder Point pixelPosition = new( (modeInfoPosition.X >> subX) << Av1Constants.ModeInfoSizeLog2, (modeInfoPosition.Y >> subY) << Av1Constants.ModeInfoSizeLog2); + Span blockReconstructionBuffer = default; Span highBitDepthBlockReconstructionBuffer = default; int reconstructionStride; + + // Prediction reads the row immediately above the destination through negative-relative neighbor offsets. + // The frame-buffer helpers therefore return a span beginning one logical sample row before the block. if (highBitDepth) { highBitDepthBlockReconstructionBuffer = this.frameBuffer.DeriveBlockPointer16((Av1Plane)plane, pixelPosition, subX, subY, out reconstructionStride); @@ -151,6 +206,8 @@ internal class Av1BlockDecoder transformSize = transformInfo[0].Size; Span coefficients = superblockInfo.GetCoefficients((Av1Plane)plane)[this.currentCoefficientIndex[plane]..]; + // Transform offsets are stored in mode-info units. Reconstruction strides are expressed in logical + // samples for both storage pipelines, so no byte scaling is applied to the high-bit-depth offset. transformBlockOffset = ((transformInfo[0].OffsetY * reconstructionStride) + transformInfo[0].OffsetX) << Av1Constants.ModeInfoSizeLog2; if (highBitDepth) { @@ -224,6 +281,8 @@ internal class Av1BlockDecoder modeInfo, coefficients, quantizationCoefficients, transformType, transformSize, (Av1Plane)plane); if (numberOfCoefficients != 0) { + // The packed coefficient stream prefixes every transform unit with its decoded coefficient + // count. Advance past that prefix as well as the coefficient values before the next unit. this.currentCoefficientIndex[plane] += numberOfCoefficients + 1; if (highBitDepth) @@ -259,6 +318,8 @@ internal class Av1BlockDecoder // Store Luma for CFL if required! if (plane == (int)Av1Plane.Y && StoreChromaFromLumaRequired(colorConfig, partitionInfo)) { + // The predictor span begins on the previous row; CFL storage consumes reconstructed samples from + // the transform block itself, hence the explicit one-stride advance for both sample pipelines. if (highBitDepth) { this.chromaFromLumaContext.Store( @@ -285,12 +346,23 @@ internal class Av1BlockDecoder } } - // increment transform pointer + // Transform descriptors are stored in the same traversal order as their packed coefficient groups. transformInfo = transformInfo[1..]; } } } + /// + /// Derives a byte-addressed reconstruction span beginning one row before a block. + /// + /// The frame buffer containing the destination planes. + /// The zero-based Y, U, or V plane index. + /// The horizontal block origin in plane samples. + /// The vertical block origin in plane samples. + /// The resulting span beginning one row before the block. + /// The number of logical samples between rows. + /// The chroma horizontal subsampling shift. + /// The chroma vertical subsampling shift. private static void DeriveBlockPointers(Av1FrameBuffer frameBuffer, int plane, int blockColumnInPixels, int blockRowInPixels, out Span blockReconstructionBuffer, out int reconstructionStride, int subX, int subY) { int blockOffset; @@ -314,13 +386,13 @@ internal class Av1BlockDecoder break; } - // Deviation from SVT, return PREVIOUS row in Block Reconstruction Buffer. + // Prediction addresses above samples relative to the returned span, so expose the previous row as index zero. blockOffset -= reconstructionStride; Guard.MustBeGreaterThanOrEqualTo(blockOffset, 0, nameof(blockOffset)); if (frameBuffer.BitDepth != Av1BitDepth.EightBit || frameBuffer.Is16BitPipeline) { - // 16bit pipeline + // The legacy byte view represents each high-bit-depth sample with two adjacent storage elements. blockOffset *= 2; if (plane == 0) { @@ -352,6 +424,14 @@ internal class Av1BlockDecoder } } + /// + /// Determines whether reconstructed luma samples must be retained for a later chroma-from-luma prediction. + /// + /// The sequence color-plane configuration. + /// The current block and its prediction modes. + /// + /// when chroma is present and the current luma block can contribute to a chroma-from-luma block. + /// private static bool StoreChromaFromLumaRequired(ObuColorConfig colorConfig, Av1PartitionInfo partitionInfo) => !colorConfig.IsMonochrome && (!partitionInfo.IsChroma || partitionInfo.ModeInfo.UvMode == Av1PredictionMode.UvChromaFromLuma); diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1CoefficientShape.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1CoefficientShape.cs index a4f9efc6e..b1e62deb1 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1CoefficientShape.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1CoefficientShape.cs @@ -3,6 +3,9 @@ namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform; +/// +/// Identifies how much of a transform coefficient plane the encoder evaluates. +/// internal enum Av1CoefficientShape { Default, diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1ForwardTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1ForwardTransformer.cs index 6494027cf..38f40b71b 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1ForwardTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1ForwardTransformer.cs @@ -7,11 +7,24 @@ using SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform; +/// +/// Converts spatial residual samples into AV1 transform coefficients. +/// internal class Av1ForwardTransformer { + /// + /// The fixed-point representation of sqrt(2) at fractional bits. + /// private const int NewSqrt = 5793; + + /// + /// The number of fractional bits used by . + /// private const int NewSqrtBitCount = 12; + /// + /// Maps each concrete transform-function enum value to its managed one-dimensional implementation. + /// private static readonly IAv1Transformer1d?[] Transformers = [ new Av1Dct4Forward1dTransformer(), @@ -31,8 +44,20 @@ internal class Av1ForwardTransformer null ]; + /// + /// The transposed intermediate coefficient plane shared by the current encoder transform pipeline. + /// private static readonly int[] TemporaryCoefficientsBuffer = new int[Av1Constants.MaxTransformSize * Av1Constants.MaxTransformSize]; + /// + /// Resolves and applies the configured two-dimensional AV1 forward transform. + /// + /// The spatial residual samples. + /// The destination transform coefficients. + /// The number of input samples between rows. + /// The compound transform type. + /// The transform-block dimensions. + /// The source sample bit depth. internal static void Transform2d(Span input, Span coefficients, uint stride, Av1TransformType transformType, Av1TransformSize transformSize, int bitDepth) { Av1Transform2dFlipConfiguration config = new(transformType, transformSize); @@ -41,6 +66,18 @@ internal class Av1ForwardTransformer Transform2d(columnTransformer, rowTransformer, input, coefficients, stride, config, bitDepth); } + /// + /// Applies a two-dimensional transform using explicitly selected column and row functions. + /// + /// The column-transform implementation type. + /// The row-transform implementation type. + /// The column-transform implementation. + /// The row-transform implementation. + /// The spatial residual samples. + /// The destination transform coefficients. + /// The number of input samples between rows. + /// The per-axis transform, flip, shift, and range configuration. + /// The source sample bit depth. internal static void Transform2d(TColumn? transformFunctionColumn, TRow? transformFunctionRow, Span input, Span coefficients, uint stride, Av1Transform2dFlipConfiguration config, int bitDepth) where TColumn : IAv1Transformer1d where TRow : IAv1Transformer1d @@ -55,24 +92,36 @@ internal class Av1ForwardTransformer } } + /// + /// Gets the managed implementation for a concrete one-dimensional transform function. + /// + /// The concrete transform function and length. + /// The transform implementation, or for an invalid function. private static IAv1Transformer1d? GetTransformer(Av1TransformFunctionType transformerType) => Transformers[(int)transformerType]; /// - /// SVT: av1_tranform_two_d_core_c + /// Applies the separable column and row stages, including normative flips, shifts, and rectangular scaling. /// + /// The column-transform implementation type. + /// The row-transform implementation type. + /// The column-transform implementation. + /// The row-transform implementation. + /// The spatial residual samples. + /// The number of input samples between rows. + /// The destination transform coefficients and temporary axis buffers. + /// The per-axis transform, flip, shift, and range configuration. + /// The transposed intermediate coefficient plane. + /// The source sample bit depth. + /// Corresponds to av1_tranform_two_d_core_c in the original WIP reference. private static void Transform2dCore(TColumn transformFunctionColumn, TRow transformFunctionRow, Span input, uint inputStride, Span output, Av1Transform2dFlipConfiguration config, Span buf, int bitDepth) where TColumn : IAv1Transformer1d where TRow : IAv1Transformer1d { int c, r; - // Note when assigning txfm_size_col, we use the txfm_size from the - // row configuration and vice versa. This is intentionally done to - // accurately perform rectangular transforms. When the transform is - // rectangular, the number of columns will be the same as the - // txfm_size stored in the row cfg struct. It will make no difference - // for square transforms. + // The row configuration's size is the number of columns, while the column configuration's size is the + // number of rows. Keeping those axis names explicit is essential for rectangular transforms. int transformColumnCount = config.TransformSize.GetWidth(); int transformRowCount = config.TransformSize.GetHeight(); int transformCount = transformColumnCount * transformRowCount; @@ -90,9 +139,8 @@ internal class Av1ForwardTransformer int cosBitColumn = config.CosBitColumn; int cosBitRow = config.CosBitRow; - // ASSERT(txfm_func_col != NULL); - // ASSERT(txfm_func_row != NULL); - // use output buffer as temp buffer + // Reuse the output prefix for per-axis input/output vectors. The complete transformed rows overwrite this + // scratch only after every column has been transposed into the separate intermediate buffer. Span tempInSpan = output[..transformRowCount]; Span tempOutSpan = output.Slice(transformRowCount, transformRowCount); ref int tempIn = ref tempInSpan[0]; @@ -173,6 +221,12 @@ internal class Av1ForwardTransformer } } + /// + /// Applies a signed fixed-point shift to a contiguous transform-stage vector. + /// + /// A reference to the first transform-stage value. + /// The number of values to update. + /// A positive rounded-right shift or a negative exact-left shift. private static void RoundShiftArray(ref int arr, int size, int bit) { if (bit == 0) @@ -202,8 +256,12 @@ internal class Av1ForwardTransformer } /// - /// SVT: get_rect_tx_log_ratio + /// Gets the signed base-two ratio between transform columns and rows. /// + /// The transform width. + /// The transform height. + /// Zero for square transforms, positive when wider, or negative when taller. + /// Corresponds to get_rect_tx_log_ratio in the original WIP reference. public static int GetRectangularRatio(int col, int row) { if (col == row) diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1ForwardTransformerFactory.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1ForwardTransformerFactory.cs index c8664655d..6b3ec7cf6 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1ForwardTransformerFactory.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1ForwardTransformerFactory.cs @@ -5,8 +5,24 @@ using SixLabors.ImageSharp.Formats.Heif.Av1.Tiling; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform; +/// +/// Selects the forward-transform coefficient shape used by AV1 encoder mode decision. +/// internal static class Av1ForwardTransformerFactory { + /// + /// Applies the encoder-selected coefficient-shape transform to a residual block. + /// + /// The spatial residual samples. + /// The number of residual samples between rows. + /// The destination transform coefficients. + /// The number of coefficient positions between rows. + /// The transform-block dimensions. + /// The accumulated energy outside the retained coefficient shape. + /// The source sample bit depth. + /// The compound transform type. + /// The luma or chroma component class. + /// The subset of coefficients evaluated by mode decision. internal static void EstimateTransform( Span residualBuffer, uint residualStride, @@ -36,6 +52,18 @@ internal static class Av1ForwardTransformerFactory } } + /// + /// Applies the complete two-dimensional transform without discarding coefficients. + /// + /// The spatial residual samples. + /// The number of residual samples between rows. + /// The destination transform coefficients. + /// The number of coefficient positions between rows. + /// The transform-block dimensions. + /// The accumulated energy outside the retained coefficient shape. + /// The source sample bit depth. + /// The compound transform type. + /// The luma or chroma component class. private static void EstimateTransformDefault( Span residualBuffer, uint residualStride, @@ -48,9 +76,45 @@ internal static class Av1ForwardTransformerFactory Av1PlaneType componentType) => Av1ForwardTransformer.Transform2d(residualBuffer, coefficientBuffer, residualStride, transformType, transformSize, bitDepth); + /// + /// Applies the half-coefficient transform shape and measures the discarded coefficient energy. + /// + /// The spatial residual samples. + /// The number of residual samples between rows. + /// The destination transform coefficients. + /// The number of coefficient positions between rows. + /// The transform-block dimensions. + /// The accumulated energy outside the retained coefficient shape. + /// The source sample bit depth. + /// The compound transform type. + /// The luma or chroma component class. private static void EstimateTransformN2(Span residualBuffer, uint residualStride, Span coefficientBuffer, uint coefficientStride, Av1TransformSize transformSize, ref ulong threeQuadEnergy, int bitDepth, Av1TransformType transformType, Av1PlaneType componentType) => throw new NotImplementedException(); + /// + /// Applies the quarter-coefficient transform shape and measures the discarded coefficient energy. + /// + /// The spatial residual samples. + /// The number of residual samples between rows. + /// The destination transform coefficients. + /// The number of coefficient positions between rows. + /// The transform-block dimensions. + /// The accumulated energy outside the retained coefficient shape. + /// The source sample bit depth. + /// The compound transform type. + /// The luma or chroma component class. private static void EstimateTransformN4(Span residualBuffer, uint residualStride, Span coefficientBuffer, uint coefficientStride, Av1TransformSize transformSize, ref ulong threeQuadEnergy, int bitDepth, Av1TransformType transformType, Av1PlaneType componentType) => throw new NotImplementedException(); + /// + /// Evaluates only the transform's DC coefficient and measures the discarded coefficient energy. + /// + /// The spatial residual samples. + /// The number of residual samples between rows. + /// The destination transform coefficients. + /// The number of coefficient positions between rows. + /// The transform-block dimensions. + /// The accumulated energy outside the retained coefficient shape. + /// The source sample bit depth. + /// The compound transform type. + /// The luma or chroma component class. private static void EstimateTransformOnlyDc(Span residualBuffer, uint residualStride, Span coefficientBuffer, uint coefficientStride, Av1TransformSize transformSize, ref ulong threeQuadEnergy, int bitDepth, Av1TransformType transformType, Av1PlaneType componentType) => throw new NotImplementedException(); } diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1Inverse2dTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1Inverse2dTransformer.cs index c885ca8d3..fb69c7bac 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1Inverse2dTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1Inverse2dTransformer.cs @@ -5,13 +5,28 @@ using System.ComponentModel; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform; +/// +/// Applies separable two-dimensional AV1 inverse transforms and adds their residuals to predicted samples. +/// internal class Av1Inverse2dTransformer { + /// + /// The lossless Walsh-Hadamard coefficient shift used by the retained reference implementation. + /// private const int UnitQuantizationShift = 2; /// - /// SVT: inv_txfm2d_add_c + /// Applies a separable inverse transform and adds its residual to high-bit-depth predicted samples. /// + /// The dequantized coefficients in raster order. + /// The predicted samples read by reconstruction. + /// The number of read samples between rows. + /// The destination reconstructed samples. + /// The number of destination samples between rows. + /// The per-axis transform, flip, shift, and range configuration. + /// The intermediate plane and two per-axis scratch vectors. + /// The coded sample bit depth. + /// Corresponds to inv_txfm2d_add_c in the original WIP reference. internal static void Transform2dAdd( Span input, Span outputForRead, @@ -22,12 +37,8 @@ internal class Av1Inverse2dTransformer Span transformFunctionBuffer, int bitDepth) { - // Note when assigning txfm_size_col, we use the txfm_size from the - // row configuration and vice versa. This is intentionally done to - // accurately perform rectangular transforms. When the transform is - // rectangular, the number of columns will be the same as the - // txfm_size stored in the row cfg struct. It will make no difference - // for square transforms. + // The row configuration's size is the transform width, while the column configuration's size is its height. + // Keeping those axis names explicit is essential for rectangular transforms. int transformWidth = config.TransformSize.GetWidth(); int transformHeight = config.TransformSize.GetHeight(); @@ -43,8 +54,8 @@ internal class Av1Inverse2dTransformer Guard.NotNull(functionColumn); Guard.NotNull(functionRow); - // txfm_buf's length is txfm_size_row * txfm_size_col + 2 * MAX(txfm_size_row, txfm_size_col) - // it is used for intermediate data buffering + // Partition the caller-provided buffer into a full intermediate plane and two vectors sized for the longer + // axis. This avoids allocating within each reconstructed transform block. int bufferOffset = Math.Max(transformHeight, transformWidth); Guard.MustBeSizedAtLeast(transformFunctionBuffer, (transformHeight * transformWidth) + (2 * bufferOffset), nameof(transformFunctionBuffer)); Span tempIn = transformFunctionBuffer; @@ -139,8 +150,16 @@ internal class Av1Inverse2dTransformer } /// - /// SVT: inv_txfm2d_add_c + /// Applies a separable inverse transform and adds its residual to eight-bit predicted samples. /// + /// The dequantized coefficients in raster order. + /// The predicted samples read by reconstruction. + /// The number of read samples between rows. + /// The destination reconstructed samples. + /// The number of destination samples between rows. + /// The per-axis transform, flip, shift, and range configuration. + /// The intermediate plane and two per-axis scratch vectors. + /// Corresponds to inv_txfm2d_add_c in the original WIP reference. internal static void Transform2dAdd( Span input, Span outputForRead, @@ -152,12 +171,8 @@ internal class Av1Inverse2dTransformer { const int bitDepth = 8; - // Note when assigning txfm_size_col, we use the txfm_size from the - // row configuration and vice versa. This is intentionally done to - // accurately perform rectangular transforms. When the transform is - // rectangular, the number of columns will be the same as the - // txfm_size stored in the row cfg struct. It will make no difference - // for square transforms. + // The row configuration's size is the transform width, while the column configuration's size is its height. + // Keeping those axis names explicit is essential for rectangular transforms. int transformWidth = config.TransformSize.GetWidth(); int transformHeight = config.TransformSize.GetHeight(); @@ -173,8 +188,8 @@ internal class Av1Inverse2dTransformer Guard.NotNull(functionColumn); Guard.NotNull(functionRow); - // txfm_buf's length is txfm_size_row * txfm_size_col + 2 * MAX(txfm_size_row, txfm_size_col) - // it is used for intermediate data buffering + // Partition the caller-provided buffer into a full intermediate plane and two vectors sized for the longer + // axis. This avoids allocating within each reconstructed transform block. int bufferOffset = Math.Max(transformHeight, transformWidth); Guard.MustBeSizedAtLeast(transformFunctionBuffer, (transformHeight * transformWidth) + (2 * bufferOffset), nameof(transformFunctionBuffer)); Span tempIn = transformFunctionBuffer; diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1InverseTransformMath.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1InverseTransformMath.cs index 38ba0adbc..fcd050850 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1InverseTransformMath.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1InverseTransformMath.cs @@ -5,11 +5,24 @@ using System; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform; +/// +/// Contains fixed-point constants and quantizer lookup tables shared by AV1 inverse transforms. +/// internal static class Av1InverseTransformMath { + /// + /// The fixed-point representation of 1 / sqrt(2) at fractional bits. + /// public const int NewInverseSqrt2 = 2896; + + /// + /// The number of fractional bits used by . + /// public const int NewSqrt2BitCount = 12; + /// + /// Gets the normative AC dequantizer value indexed by bit-depth category and quantizer index. + /// public static readonly int[,] AcQLookup = new int[3, 256] { { @@ -64,6 +77,9 @@ internal static class Av1InverseTransformMath } }; + /// + /// Contains the normative DC dequantizer values indexed by bit-depth category and quantizer index. + /// private static readonly int[,] DcQLookup = new int[3, 256] { { @@ -117,25 +133,49 @@ internal static class Av1InverseTransformMath } }; + /// + /// Gets a clipped DC dequantizer value. + /// + /// The segment quantizer index. + /// The plane-specific DC quantizer delta. + /// The coded sample bit depth. + /// The DC dequantizer value. public static int GetDcQuantization(int qIndex, int delta, Av1BitDepth bitDepth) => DcQLookup[(int)bitDepth, Av1Math.Clip3(0, 255, qIndex + delta)]; + /// + /// Gets a clipped AC dequantizer value. + /// + /// The segment quantizer index. + /// The plane-specific AC quantizer delta. + /// The coded sample bit depth. + /// The AC dequantizer value. public static int GetAcQuantization(int qIndex, int delta, Av1BitDepth bitDepth) => AcQLookup[(int)bitDepth, Av1Math.Clip3(0, 255, qIndex + delta)]; + /// + /// Gets the encoder zero-bin factor selected by quantizer magnitude and sample bit depth. + /// + /// The base quantizer index. + /// The coded sample bit depth. + /// The zero-bin factor. public static int GetQzbinFactor(int q, Av1BitDepth bitDepth) { int quant = GetDcQuantization(q, 0, bitDepth); - // Bit hack to get to: - // EightBit => 148 - // TenBit => 592 - // TwelveBit => 2368 + // Scaling the eight-bit threshold by four for every two added sample bits preserves the quantizer decision + // at equal normalized signal levels: 148 for 8-bit, 592 for 10-bit, and 2368 for 12-bit. int shift = (int)bitDepth << 1; int threshold = (1 << shift) * 148; return q == 0 ? 64 : (quant < threshold ? 84 : 80); } + /// + /// Computes the fixed-point multiplier and shift used to replace division by a quantizer. + /// + /// Receives the reciprocal multiplier without its implicit leading bit. + /// Receives the reciprocal scaling shift. + /// The positive quantizer divisor. public static void InvertQuantization(out int quantization, out int shift, int d) { uint t; @@ -151,18 +191,37 @@ internal static class Av1InverseTransformMath shift = 1 << (16 - l); } + /// + /// Adds an inverse-transform residual to an eight-bit predicted sample and clips the result. + /// + /// The predicted sample. + /// The inverse-transform residual. + /// The reconstructed eight-bit sample. public static byte ClipPixelAdd(byte dest, long trans) { trans = CheckRange(trans, 8); return (byte)ClipPixelHighBitDepth(dest + trans, 8); } + /// + /// Adds an inverse-transform residual to a high-bit-depth predicted sample and clips the result. + /// + /// The predicted sample stored in the signed transform representation. + /// The inverse-transform residual. + /// The coded sample bit depth. + /// The reconstructed sample stored in the signed transform representation. public static short ClipPixelAdd(short dest, long trans, int bitDepth) { trans = CheckRange(trans, bitDepth); return ClipPixelHighBitDepth(dest + trans, bitDepth); } + /// + /// Clips a reconstructed sample to the unsigned range selected by its bit depth. + /// + /// The unclipped reconstructed sample. + /// The coded sample bit depth. + /// The clipped sample stored in the signed transform representation. private static short ClipPixelHighBitDepth(long val, int bd) => bd switch { 10 => (short)Av1Math.Clamp(val, 0, 1023), @@ -170,6 +229,12 @@ internal static class Av1InverseTransformMath _ => (short)Av1Math.Clamp(val, 0, 255), }; + /// + /// Applies a signed fixed-point shift to the requested prefix of an integer buffer. + /// + /// The transform-stage values. + /// The number of values to update. + /// A positive rounded-right shift or a negative exact-left shift. public static void RoundShiftArray(Span arr, int size, int bit) { int i; @@ -196,6 +261,12 @@ internal static class Av1InverseTransformMath } } + /// + /// Clamps a transform-stage buffer to a signed range of the specified bit width. + /// + /// The transform-stage values. + /// The number of values to clamp. + /// The signed range width in bits. internal static void ClampBuffer(Span buffer, int size, byte bit) { for (int i = 0; i < size; i++) @@ -204,6 +275,12 @@ internal static class Av1InverseTransformMath } } + /// + /// Clamps one transform-stage value to a signed range of the specified bit width. + /// + /// The value to clamp. + /// The signed range width in bits. + /// The clamped value. private static int ClampValue(int value, byte bit) { if (bit <= 0) @@ -211,11 +288,17 @@ internal static class Av1InverseTransformMath return value; // Do nothing for invalid clamp bit. } - long max_value = (1L << (bit - 1)) - 1; - long min_value = -(1L << (bit - 1)); - return (int)Av1Math.Clamp(value, min_value, max_value); + long maximum = (1L << (bit - 1)) - 1; + long minimum = -(1L << (bit - 1)); + return (int)Av1Math.Clamp(value, minimum, maximum); } + /// + /// Restricts an inverse-transform residual to the intermediate range permitted for the sample bit depth. + /// + /// The inverse-transform residual. + /// The coded sample bit depth. + /// The range-limited residual. private static long CheckRange(long input, int bd) { // AV1 TX case @@ -223,11 +306,16 @@ internal static class Av1InverseTransformMath // - 10 bit: signed 18 bit integer // - 12 bit: signed 20 bit integer // - max quantization error = 1828 << (bd - 8) - int int_max = (1 << (7 + bd)) - 1 + (914 << (bd - 7)); - int int_min = -int_max - 1; - return Av1Math.Clamp(input, int_min, int_max); + int maximum = (1 << (7 + bd)) - 1 + (914 << (bd - 7)); + int minimum = -maximum - 1; + return Av1Math.Clamp(input, minimum, maximum); } + /// + /// Gets the maximum coded coefficient count retained for a transform size. + /// + /// The signaled transform size. + /// The maximum coefficient end position represented by AV1 syntax. internal static int GetMaxEndOfBuffer(Av1TransformSize transformSize) { if (transformSize is Av1TransformSize.Size64x64 or Av1TransformSize.Size64x32 or Av1TransformSize.Size32x64) diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1InverseTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1InverseTransformer.cs index 49bbdd2e6..071ecb5a7 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1InverseTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1InverseTransformer.cs @@ -3,11 +3,23 @@ namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform; +/// +/// Reconstructs decoded AV1 transform coefficients into prediction sample buffers. +/// internal class Av1InverseTransformer { /// - /// SVT: svt_aom_inv_transform_recon8bit + /// Reconstructs an eight-bit transform block in place by adding its inverse-transform residual. /// + /// The dequantized transform coefficients. + /// The predicted samples and reconstruction destination. + /// The number of samples between rows. + /// The transform-block dimensions. + /// The compound transform type. + /// The zero-based Y, U, or V plane index. + /// The decoded coefficient end position. + /// Whether the segment uses lossless transform rules. + /// Corresponds to svt_aom_inv_transform_recon8bit in the original WIP reference. public static void Reconstruct8Bit(Span coefficientsBuffer, Span reconstructionBuffer, int reconstructionStride, Av1TransformSize transformSize, Av1TransformType transformType, int plane, int numberOfCoefficients, bool isLossless) { Av1TransformFunctionParameters transformFunctionParameters = new() @@ -25,8 +37,19 @@ internal class Av1InverseTransformer } /// - /// SVT: svt_aom_inv_transform_recon8bit + /// Reconstructs an eight-bit transform block from a separate prediction buffer. /// + /// The dequantized transform coefficients. + /// The predicted samples read by reconstruction. + /// The number of prediction samples between rows. + /// The destination reconstructed samples. + /// The number of destination samples between rows. + /// The transform-block dimensions. + /// The compound transform type. + /// The zero-based Y, U, or V plane index. + /// The decoded coefficient end position. + /// Whether the segment uses lossless transform rules. + /// Corresponds to svt_aom_inv_transform_recon8bit in the original WIP reference. public static void Reconstruct8Bit(Span coefficientsBuffer, Span reconstructionBufferRead, int reconstructionReadStride, Span reconstructionBufferWrite, int reconstructionWriteStride, Av1TransformSize transformSize, Av1TransformType transformType, int plane, int numberOfCoefficients, bool isLossless) { Av1TransformFunctionParameters transformFunctionParameters = new() @@ -39,9 +62,8 @@ internal class Av1InverseTransformer Is16BitPipeline = false }; - /* When output pointers to read and write are differents, - * then kernel copy also all buffer from read to write, - * and cannot be limited by End Of Buffer calculations. */ + // Separate prediction and destination buffers require every sample to be copied or reconstructed. Restricting + // traversal to the coded coefficient end position would leave the untouched prediction region unwritten. transformFunctionParameters.EndOfBuffer = Av1InverseTransformMath.GetMaxEndOfBuffer(transformSize); Av1InverseTransformerFactory.InverseTransformAdd( @@ -49,8 +71,18 @@ internal class Av1InverseTransformer } /// - /// AV1: 7.11.2 Reconstruct. + /// Reconstructs a high-bit-depth transform block in place by adding its inverse-transform residual. /// + /// The dequantized transform coefficients. + /// The predicted samples and reconstruction destination. + /// The number of logical samples between rows. + /// The transform-block dimensions. + /// The compound transform type. + /// The zero-based Y, U, or V plane index. + /// The decoded coefficient end position. + /// Whether the segment uses lossless transform rules. + /// The coded sample bit depth. + /// Implements the reconstruction operation in AV1 section 7.11.2. public static void ReconstructHighBitDepth(Span coefficientsBuffer, Span reconstructionBuffer, int reconstructionStride, Av1TransformSize transformSize, Av1TransformType transformType, int plane, int numberOfCoefficients, bool isLossless, Av1BitDepth bitDepth) { Av1TransformFunctionParameters transformFunctionParameters = new() diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1InverseTransformerFactory.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1InverseTransformerFactory.cs index 83c08625f..655315cc8 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1InverseTransformerFactory.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1InverseTransformerFactory.cs @@ -5,32 +5,60 @@ using SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Inverse; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform; +/// +/// Selects and runs the AV1 inverse-transform pipeline for byte or high-bit-depth sample storage. +/// internal static class Av1InverseTransformerFactory { /// - /// SVT: svt_av1_inv_txfm_add + /// Applies an inverse transform and adds its residual to eight-bit predicted samples. /// + /// The dequantized transform coefficients. + /// The predicted samples read by reconstruction. + /// The number of read samples between rows. + /// The destination reconstructed samples. + /// The number of destination samples between rows. + /// The transform type, dimensions, bit depth, and pipeline selection. + /// Corresponds to svt_av1_inv_txfm_add in the original WIP reference. public static unsafe void InverseTransformAdd(Span coefficients, Span readBuffer, int readStride, Span writeBuffer, int writeStride, Av1TransformFunctionParameters transformFunctionParameters) { Guard.MustBeLessThanOrEqualTo(transformFunctionParameters.BitDepth, 8, nameof(transformFunctionParameters)); Guard.IsFalse(transformFunctionParameters.Is16BitPipeline, nameof(transformFunctionParameters), "Calling 8-bit pipeline while 16-bit is requested."); int width = transformFunctionParameters.TransformSize.GetWidth(); int height = transformFunctionParameters.TransformSize.GetHeight(); + + // The 2-D transform needs one complete intermediate plane plus one input and output vector for the longer axis. Span buffer = new int[(width * height) + (2 * Math.Max(width, height))]; Av1Transform2dFlipConfiguration config = new(transformFunctionParameters.TransformType, transformFunctionParameters.TransformSize); Av1Inverse2dTransformer.Transform2dAdd(coefficients, readBuffer, readStride, writeBuffer, writeStride, config, buffer); } + /// + /// Applies an inverse transform and adds its residual to high-bit-depth predicted samples. + /// + /// The dequantized transform coefficients. + /// The predicted samples read by reconstruction. + /// The number of read samples between rows. + /// The destination reconstructed samples. + /// The number of destination samples between rows. + /// The transform type, dimensions, bit depth, and pipeline selection. public static unsafe void InverseTransformAdd(Span coefficients, Span readBuffer, int readStride, Span writeBuffer, int writeStride, Av1TransformFunctionParameters transformFunctionParameters) { Guard.IsTrue(transformFunctionParameters.Is16BitPipeline, nameof(transformFunctionParameters), "Calling 16-bit pipeline while 8-bit is requested."); int width = transformFunctionParameters.TransformSize.GetWidth(); int height = transformFunctionParameters.TransformSize.GetHeight(); + + // The 2-D transform needs one complete intermediate plane plus one input and output vector for the longer axis. Span buffer = new int[(width * height) + (2 * Math.Max(width, height))]; Av1Transform2dFlipConfiguration config = new(transformFunctionParameters.TransformType, transformFunctionParameters.TransformSize); Av1Inverse2dTransformer.Transform2dAdd(coefficients, readBuffer, readStride, writeBuffer, writeStride, config, buffer, transformFunctionParameters.BitDepth); } + /// + /// Creates the inverse-transform implementation for a concrete function and length. + /// + /// The concrete transform function. + /// The transform implementation, or for an invalid function. internal static IAv1Transformer1d? GetTransformer(Av1TransformFunctionType type) => type switch { Av1TransformFunctionType.Dct4 => new Av1Dct4Inverse1dTransformer(), diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1ScanOrder.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1ScanOrder.cs index b2c258740..7c056a8b9 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1ScanOrder.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1ScanOrder.cs @@ -3,12 +3,30 @@ namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform; +/// +/// Describes the forward scan, inverse scan, and entropy-neighbor mapping for an AV1 transform size. +/// internal readonly struct Av1ScanOrder { + /// + /// The coefficient positions in coded traversal order. + /// private readonly short[] scan; + + /// + /// The coded position of each raster-order coefficient. + /// private readonly short[] inverseScan; + + /// + /// The coefficient-neighbor mapping used to derive entropy contexts. + /// private readonly short[] neighbors; + /// + /// Initializes a new instance of the struct when only coefficient traversal is required. + /// + /// The coefficient positions in coded traversal order. public Av1ScanOrder(short[] scan) { this.scan = scan; @@ -16,6 +34,12 @@ internal readonly struct Av1ScanOrder this.neighbors = []; } + /// + /// Initializes a new instance of the struct with complete entropy-context mappings. + /// + /// The coefficient positions in coded traversal order. + /// The coded position of each raster-order coefficient. + /// The coefficient neighbors used to derive entropy contexts. public Av1ScanOrder(short[] scan, short[] inverseScan, short[] neighbors) { this.scan = scan; @@ -23,9 +47,18 @@ internal readonly struct Av1ScanOrder this.neighbors = neighbors; } + /// + /// Gets the coefficient positions in coded traversal order. + /// public ReadOnlySpan Scan => this.scan; + /// + /// Gets the coded position of each raster-order coefficient. + /// public ReadOnlySpan InverseScan => this.inverseScan; + /// + /// Gets the coefficient-neighbor mapping used for entropy contexts. + /// public ReadOnlySpan Neighbors => this.neighbors; } diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1ScanOrderConstants.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1ScanOrderConstants.cs index 4f7ea2d2d..e52326422 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1ScanOrderConstants.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1ScanOrderConstants.cs @@ -3,9 +3,19 @@ namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform; +/// +/// Contains the normative coefficient scan orders and quantization-matrix dimensions for AV1 transform blocks. +/// internal static class Av1ScanOrderConstants { + /// + /// The number of bits used to signal a quantization-matrix level. + /// public const int QuantizationMatrixLevelBitCount = 4; + + /// + /// The number of quantization-matrix levels, including the flat matrix. + /// public const int QuantizationMatrixLevelCount = 1 << QuantizationMatrixLevelBitCount; private static readonly short[] DefaultScan4x4 = [0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15]; @@ -446,6 +456,9 @@ internal static class Av1ScanOrderConstants private static readonly short[] MatrixRowScan8x32Neighbors = []; private static readonly short[] MatrixRowScan32x8Neighbors = []; + /// + /// Maps transform size and compound transform type to coefficient and entropy-neighbor traversal tables. + /// private static readonly Av1ScanOrder[][] ScanOrders = [ @@ -840,6 +853,12 @@ internal static class Av1ScanOrderConstants ] ]; + /// + /// Gets the coefficient traversal and entropy-neighbor mappings for a transform block. + /// + /// The transform-block dimensions. + /// The compound transform type. + /// The selected scan order. public static Av1ScanOrder GetScanOrder(Av1TransformSize transformSize, Av1TransformType transformType) => ScanOrders[(int)transformSize][(int)transformType]; } diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1SinusConstants.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1SinusConstants.cs index 994a7637c..615f8a1fa 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1SinusConstants.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1SinusConstants.cs @@ -3,11 +3,22 @@ namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform; +/// +/// Contains the fixed-point sine and cosine tables used by the normative AV1 transform stages. +/// internal static class Av1SinusConstants { + /// + /// The smallest supported number of fractional bits in a cosine lookup table. + /// public const int MinimumCosinusBit = 10; - // av1_cospi_arr[i][j] = (int32_t)round(cos(M_PI*j/128) * (1<<(cos_bit_min+i))); + /// + /// Fixed-point cosine values indexed by precision minus and angle step. + /// + /// + /// Each value is round(cos(pi * angle / 128) * 2^precision). + /// private static readonly int[][] CosinusPiArray = [ [ @@ -54,8 +65,13 @@ internal static class Av1SinusConstants ] ]; - // svt_aom_eb_av1_sinpi_arr_data[i][j] = (int32_t)round((sqrt(2) * sin(j*Pi/9) * 2 / 3) * (1 - // << (cos_bit_min + i))) modified so that elements j=1,2 sum to element j=4. + /// + /// Fixed-point sine values indexed by precision minus and angle step. + /// + /// + /// Values follow round((sqrt(2) * sin(angle * pi / 9) * 2 / 3) * 2^precision), adjusted so + /// the first two nonzero elements sum to the fourth. + /// private static readonly int[][] SinusPiArray = [ [0, 330, 621, 836, 951], @@ -67,6 +83,9 @@ internal static class Av1SinusConstants [0, 21133, 39716, 53510, 60849] ]; + /// + /// One quadrant of the signed cosine table used by directional intra prediction. + /// private static readonly int[] Cosinus128Lookup = [ 4096, 4095, 4091, 4085, 4076, 4065, 4052, 4036, 4017, 3996, 3973, 3948, 3920, 3889, 3857, 3822, @@ -78,18 +97,38 @@ internal static class Av1SinusConstants 799, 700, 601, 501, 401, 301, 201, 101, 0 ]; + /// + /// Gets the transform cosine table for a fixed-point precision. + /// + /// The number of fractional bits. + /// The cosine table for the requested precision. public static Span CosinusPi(int n) => CosinusPiArray[n - MinimumCosinusBit]; + /// + /// Gets the transform sine table for a fixed-point precision. + /// + /// The number of fractional bits. + /// The sine table for the requested precision. public static Span SinusPi(int n) => SinusPiArray[n - MinimumCosinusBit]; /// /// Spec: 7.13.2.1 Butterfly functions /// + /// + /// Gets a directional-prediction sine value for an angle in 128-step circle units. + /// + /// The signed angle. + /// The signed fixed-point sine value. public static int Sinus128(int angle) => Cosinus128(angle - 64); /// /// Spec: 7.13.2.1 Butterfly functions /// + /// + /// Gets a directional-prediction cosine value for an angle in 128-step circle units. + /// + /// The signed angle. + /// The signed fixed-point cosine value. public static int Cosinus128(int angle) { int angle2 = angle & 255; diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1Transform2dFlipConfiguration.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1Transform2dFlipConfiguration.cs index ccbc283c2..65f74a040 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1Transform2dFlipConfiguration.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1Transform2dFlipConfiguration.cs @@ -3,11 +3,24 @@ namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform; +/// +/// Resolves an AV1 compound transform into its per-axis functions, flips, shifts, and stage ranges. +/// internal class Av1Transform2dFlipConfiguration { + /// + /// The maximum number of fixed-point stages in any supported one-dimensional transform. + /// public const int MaxStageNumber = 12; + + /// + /// The base-two logarithm of the smallest supported transform dimension. + /// private const int SmallestTransformSizeLog2 = 2; + /// + /// Maps each compound transform type to the function applied down the transform columns. + /// private static readonly Av1TransformType1d[] VerticalType = [ Av1TransformType1d.Dct, @@ -28,6 +41,9 @@ internal class Av1Transform2dFlipConfiguration Av1TransformType1d.Identity, ]; + /// + /// Maps each compound transform type to the function applied across the transform rows. + /// private static readonly Av1TransformType1d[] HorizontalType = [ Av1TransformType1d.Dct, @@ -48,6 +64,9 @@ internal class Av1Transform2dFlipConfiguration Av1TransformType1d.FlipAdst, ]; + /// + /// Contains the three normative fixed-point shifts for every transform size. + /// private static readonly int[][] ShiftMap = [ [2, 0, 0], // 4x4 @@ -71,12 +90,21 @@ internal class Av1Transform2dFlipConfiguration [2, -4, 0], // 64x16 ]; + /// + /// Selects column-transform cosine precision by width and height logarithm. + /// private static readonly int[][] CosBitColumnMap = [[13, 13, 13, 0, 0], [13, 13, 13, 12, 0], [13, 13, 13, 12, 13], [0, 13, 13, 12, 13], [0, 0, 13, 12, 13]]; + /// + /// Selects row-transform cosine precision by width and height logarithm. + /// private static readonly int[][] CosBitRowMap = [[13, 13, 12, 0, 0], [13, 13, 13, 12, 0], [13, 13, 12, 13, 12], [0, 12, 13, 12, 11], [0, 0, 12, 11, 10]]; + /// + /// Maps a transform dimension and one-dimensional type to its concrete staged function. + /// private static readonly Av1TransformFunctionType[][] TransformFunctionTypeMap = [ [Av1TransformFunctionType.Dct4, Av1TransformFunctionType.Adst4, Av1TransformFunctionType.Adst4, Av1TransformFunctionType.Identity4], @@ -86,6 +114,9 @@ internal class Av1Transform2dFlipConfiguration [Av1TransformFunctionType.Dct64, Av1TransformFunctionType.Invalid, Av1TransformFunctionType.Invalid, Av1TransformFunctionType.Identity64] ]; + /// + /// Contains the number of fixed-point stages executed by each concrete transform function. + /// private static readonly int[] StageNumberList = [ 4, // TXFM_TYPE_DCT4 @@ -104,6 +135,9 @@ internal class Av1Transform2dFlipConfiguration 1, // TXFM_TYPE_IDENTITY64 ]; + /// + /// Contains twice the non-scaled bit range required after every transform stage. + /// private static readonly int[][] RangeMulti2List = [ [0, 2, 3, 3], // fdct4_range_mult2 @@ -122,8 +156,16 @@ internal class Av1Transform2dFlipConfiguration [5], // fidtx64_range_mult2 ]; + /// + /// The three fixed-point shifts applied before the column transform, between axes, and after the row transform. + /// private int[] shift; + /// + /// Initializes a new instance of the class. + /// + /// The compound horizontal and vertical transform type. + /// The transform-block dimensions. public Av1Transform2dFlipConfiguration(Av1TransformType transformType, Av1TransformSize transformSize) { // SVT: svt_av1_get_inv_txfm_cfg @@ -133,13 +175,13 @@ internal class Av1Transform2dFlipConfiguration this.SetFlip(transformType); this.TransformTypeColumn = VerticalType[(int)transformType]; this.TransformTypeRow = HorizontalType[(int)transformType]; - int txw_idx = transformSize.GetBlockWidthLog2() - SmallestTransformSizeLog2; - int txh_idx = transformSize.GetBlockHeightLog2() - SmallestTransformSizeLog2; + int transformWidthIndex = transformSize.GetBlockWidthLog2() - SmallestTransformSizeLog2; + int transformHeightIndex = transformSize.GetBlockHeightLog2() - SmallestTransformSizeLog2; this.shift = ShiftMap[(int)transformSize]; - this.CosBitColumn = CosBitColumnMap[txw_idx][txh_idx]; - this.CosBitRow = CosBitRowMap[txw_idx][txh_idx]; - this.TransformFunctionTypeColumn = TransformFunctionTypeMap[txh_idx][(int)this.TransformTypeColumn]; - this.TransformFunctionTypeRow = TransformFunctionTypeMap[txw_idx][(int)this.TransformTypeRow]; + this.CosBitColumn = CosBitColumnMap[transformWidthIndex][transformHeightIndex]; + this.CosBitRow = CosBitRowMap[transformWidthIndex][transformHeightIndex]; + this.TransformFunctionTypeColumn = TransformFunctionTypeMap[transformHeightIndex][(int)this.TransformTypeColumn]; + this.TransformFunctionTypeRow = TransformFunctionTypeMap[transformWidthIndex][(int)this.TransformTypeRow]; this.StageNumberColumn = this.TransformFunctionTypeColumn != Av1TransformFunctionType.Invalid ? StageNumberList[(int)this.TransformFunctionTypeColumn] : -1; this.StageNumberRow = this.TransformFunctionTypeRow != Av1TransformFunctionType.Invalid ? StageNumberList[(int)this.TransformFunctionTypeRow] : -1; this.StageRangeColumn = new byte[12]; @@ -147,40 +189,89 @@ internal class Av1Transform2dFlipConfiguration this.NonScaleRange(); } + /// + /// Gets the fixed-point cosine precision used by the column transform. + /// public int CosBitColumn { get; } + /// + /// Gets the fixed-point cosine precision used by the row transform. + /// public int CosBitRow { get; } + /// + /// Gets the one-dimensional transform type applied down columns. + /// public Av1TransformType1d TransformTypeColumn { get; } + /// + /// Gets the one-dimensional transform type applied across rows. + /// public Av1TransformType1d TransformTypeRow { get; } + /// + /// Gets the concrete staged transform function applied down columns. + /// public Av1TransformFunctionType TransformFunctionTypeColumn { get; } + /// + /// Gets the concrete staged transform function applied across rows. + /// public Av1TransformFunctionType TransformFunctionTypeRow { get; } + /// + /// Gets the number of fixed-point stages in the column transform. + /// public int StageNumberColumn { get; } + /// + /// Gets the number of fixed-point stages in the row transform. + /// public int StageNumberRow { get; } + /// + /// Gets the transform-block dimensions. + /// public Av1TransformSize TransformSize { get; } + /// + /// Gets the compound horizontal and vertical transform type. + /// public Av1TransformType TransformType { get; } + /// + /// Gets a value indicating whether column input is traversed from bottom to top. + /// public bool FlipUpsideDown { get; private set; } + /// + /// Gets a value indicating whether row output is written from right to left. + /// public bool FlipLeftToRight { get; private set; } + /// + /// Gets the three fixed-point shifts applied by the two-dimensional transform pipeline. + /// public Span Shift => this.shift; + /// + /// Gets the allowed signed-bit range after each column-transform stage. + /// public byte[] StageRangeColumn { get; } + /// + /// Gets the allowed signed-bit range after each row-transform stage. + /// public byte[] StageRangeRow { get; } /// - /// SVT: svt_av1_gen_fwd_stage_range - /// SVT: svt_av1_gen_inv_stage_range + /// Adds input bit depth and inter-stage shifts to the non-scaled stage ranges. /// + /// The coded sample bit depth. + /// + /// Corresponds to svt_av1_gen_fwd_stage_range and svt_av1_gen_inv_stage_range + /// in the original WIP reference. + /// public void GenerateStageRange(int bitDepth) { // Take the shift from the larger dimension in the rectangular case. @@ -200,8 +291,10 @@ internal class Av1Transform2dFlipConfiguration } /// - /// SVT: is_txfm_allowed + /// Determines whether the transform type is permitted for the configured dimensions. /// + /// when the transform combination is valid for the transform size. + /// Corresponds to is_txfm_allowed in the original WIP reference. public bool IsAllowed() { Av1TransformType[] supportedTypes = @@ -249,14 +342,29 @@ internal class Av1Transform2dFlipConfiguration return supportedTypes.Contains(this.TransformType); } + /// + /// Replaces the three transform-pipeline shifts. + /// + /// The pre-column-transform shift. + /// The shift between the column and row transforms. + /// The post-row-transform shift. internal void SetShift(int shift0, int shift1, int shift2) => this.shift = [shift0, shift1, shift2]; + /// + /// Overrides the axis traversal directions. + /// + /// Whether column input is traversed from bottom to top. + /// Whether row output is written from right to left. internal void SetFlip(bool upsideDown, bool leftToRight) { this.FlipUpsideDown = upsideDown; this.FlipLeftToRight = leftToRight; } + /// + /// Derives the axis traversal directions encoded by a compound transform type. + /// + /// The compound transform type. private void SetFlip(Av1TransformType transformType) { switch (transformType) @@ -299,26 +407,27 @@ internal class Av1Transform2dFlipConfiguration } /// - /// SVT: set_fwd_txfm_non_scale_range + /// Initializes the per-stage signed-bit ranges before input depth and pipeline shifts are applied. /// + /// Corresponds to set_fwd_txfm_non_scale_range in the original WIP reference. private void NonScaleRange() { if (this.TransformFunctionTypeColumn != Av1TransformFunctionType.Invalid) { - Span range_mult2_col = RangeMulti2List[(int)this.TransformFunctionTypeColumn]; - int stage_num_col = this.StageNumberColumn; - for (int i = 0; i < stage_num_col; ++i) + Span columnRangeTimesTwo = RangeMulti2List[(int)this.TransformFunctionTypeColumn]; + int columnStageCount = this.StageNumberColumn; + for (int i = 0; i < columnStageCount; ++i) { - this.StageRangeColumn[i] = (byte)((range_mult2_col[i] + 1) >> 1); + this.StageRangeColumn[i] = (byte)((columnRangeTimesTwo[i] + 1) >> 1); } if (this.TransformFunctionTypeRow != Av1TransformFunctionType.Invalid) { - int stage_num_row = this.StageNumberRow; - Span range_mult2_row = RangeMulti2List[(int)this.TransformFunctionTypeRow]; - for (int i = 0; i < stage_num_row; ++i) + int rowStageCount = this.StageNumberRow; + Span rowRangeTimesTwo = RangeMulti2List[(int)this.TransformFunctionTypeRow]; + for (int i = 0; i < rowStageCount; ++i) { - this.StageRangeRow[i] = (byte)((range_mult2_col[this.StageNumberColumn - 1] + range_mult2_row[i] + 1) >> 1); + this.StageRangeRow[i] = (byte)((columnRangeTimesTwo[this.StageNumberColumn - 1] + rowRangeTimesTwo[i] + 1) >> 1); } } } diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformClass.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformClass.cs index afc035482..1d96f3ea0 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformClass.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformClass.cs @@ -3,6 +3,9 @@ namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform; +/// +/// Classifies AV1 transforms by the axes along which non-identity transforms operate. +/// internal enum Av1TransformClass { Class2D = 0, diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformFunctionParameters.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformFunctionParameters.cs index ae24e659c..7d13e626f 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformFunctionParameters.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformFunctionParameters.cs @@ -3,17 +3,38 @@ namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform; +/// +/// Carries the syntax and sample-storage parameters required to reconstruct one AV1 transform block. +/// internal class Av1TransformFunctionParameters { + /// + /// Gets or sets the compound transform type. + /// public Av1TransformType TransformType { get; internal set; } + /// + /// Gets or sets the transform-block dimensions. + /// public Av1TransformSize TransformSize { get; internal set; } + /// + /// Gets or sets the number of coefficient positions represented by the decoded coefficient buffer. + /// public int EndOfBuffer { get; internal set; } + /// + /// Gets or sets a value indicating whether the coded segment uses the AV1 lossless transform rules. + /// public bool IsLossless { get; internal set; } + /// + /// Gets or sets the decoded sample bit depth. + /// public int BitDepth { get; internal set; } + /// + /// Gets or sets a value indicating whether reconstructed samples use the 16-bit storage pipeline. + /// public bool Is16BitPipeline { get; internal set; } } diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformFunctionType.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformFunctionType.cs index cd118454f..cd06fd235 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformFunctionType.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformFunctionType.cs @@ -3,6 +3,9 @@ namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform; +/// +/// Identifies a concrete one-dimensional AV1 transform function and length. +/// internal enum Av1TransformFunctionType { Dct4, diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformMode.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformMode.cs index a838dfc86..e56fccca6 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformMode.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformMode.cs @@ -3,6 +3,9 @@ namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform; +/// +/// Identifies how transform-block sizes are selected within an AV1 frame. +/// internal enum Av1TransformMode : byte { Only4x4 = 0, diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformSetType.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformSetType.cs index 627a14e7b..244228f00 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformSetType.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformSetType.cs @@ -3,6 +3,9 @@ namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform; +/// +/// Identifies the set of transform combinations allowed for an AV1 block. +/// internal enum Av1TransformSetType { /// diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformSize.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformSize.cs index f4af96c5b..6ea115a73 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformSize.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformSize.cs @@ -3,6 +3,9 @@ namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform; +/// +/// Identifies every square and rectangular transform-block size defined by AV1. +/// internal enum Av1TransformSize : byte { Size4x4 = 0, diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformSizeExtensions.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformSizeExtensions.cs index 06562e12d..483322391 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformSizeExtensions.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformSizeExtensions.cs @@ -3,11 +3,20 @@ namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform; +/// +/// Provides dimensions, block mappings, scaling values, and subdivision rules for AV1 transform sizes. +/// internal static class Av1TransformSizeExtensions { + /// + /// The coefficient count for each transform-size enum value. + /// private static readonly int[] Size2d = [ 16, 64, 256, 1024, 4096, 32, 32, 128, 128, 512, 512, 2048, 2048, 64, 64, 256, 256, 1024, 1024]; + /// + /// The transform size produced by one level of subdivision for each transform-size enum value. + /// private static readonly Av1TransformSize[] SubTransformSize = [ Av1TransformSize.Size4x4, // TX_4X4 Av1TransformSize.Size4x4, // TX_8X8 @@ -30,13 +39,19 @@ internal static class Av1TransformSizeExtensions Av1TransformSize.Size32x16, // TX_64X16 ]; - // Transform block width in units. + /// + /// Transform widths in units of four samples. + /// private static readonly int[] WideUnit = [1, 2, 4, 8, 16, 1, 2, 2, 4, 4, 8, 8, 16, 1, 4, 2, 8, 4, 16]; - // Transform block height in unit + /// + /// Transform heights in units of four samples. + /// private static readonly int[] HighUnit = [1, 2, 4, 8, 16, 2, 1, 4, 2, 8, 4, 16, 8, 4, 1, 8, 2, 16, 4]; - // Transform size conversion into Block Size + /// + /// Maps each transform size to the block size with matching dimensions. + /// private static readonly Av1BlockSize[] BlockSize = [ Av1BlockSize.Block4x4, // TX_4X4 Av1BlockSize.Block8x8, // TX_8X8 @@ -59,6 +74,9 @@ internal static class Av1TransformSizeExtensions Av1BlockSize.Block64x16, // TX_64X16 ]; + /// + /// Maps each transform size to the square transform based on its smaller dimension. + /// private static readonly Av1TransformSize[] SquareMap = [ Av1TransformSize.Size4x4, // TX_4X4 Av1TransformSize.Size8x8, // TX_8X8 @@ -81,6 +99,9 @@ internal static class Av1TransformSizeExtensions Av1TransformSize.Size16x16, // TX_64X16 ]; + /// + /// Maps each transform size to the square transform based on its larger dimension. + /// private static readonly Av1TransformSize[] SquareUpMap = [ Av1TransformSize.Size4x4, // TX_4X4 Av1TransformSize.Size8x8, // TX_8X8 @@ -103,8 +124,9 @@ internal static class Av1TransformSizeExtensions Av1TransformSize.Size64x64, // TX_64X16 ]; - // This is computed as: - // min(transform_width_log2, 5) + min(transform_height_log2, 5) - 4. + /// + /// Contains min(log2(width), 5) + min(log2(height), 5) - 4 for each transform size. + /// private static readonly int[] Log2Minus4 = [ 0, // TX_4X4 2, // TX_8X8 @@ -127,42 +149,106 @@ internal static class Av1TransformSizeExtensions 5, // TX_64X16 ]; - // Transform block width in log2 + /// + /// Transform widths expressed as base-two logarithms of sample counts. + /// private static readonly int[] BlockWidthLog2 = [ 2, 3, 4, 5, 6, 2, 3, 3, 4, 4, 5, 5, 6, 2, 4, 3, 5, 4, 6, ]; - // Transform block height in log2 + /// + /// Transform heights expressed as base-two logarithms of sample counts. + /// private static readonly int[] BlockHeightLog2 = [ 2, 3, 4, 5, 6, 3, 2, 4, 3, 5, 4, 6, 5, 4, 2, 5, 3, 6, 4, ]; + /// + /// Gets the number of coefficient positions in a transform block. + /// + /// The transform size. + /// The transform width multiplied by its height. public static int GetSize2d(this Av1TransformSize size) => Size2d[(int)size]; + /// + /// Gets the inverse-quantization scale category for a transform size. + /// + /// The transform size. + /// Zero for up to 256 coefficients, one for up to 1024, or two for larger transforms. public static int GetScale(this Av1TransformSize size) { int pels = Size2d[(int)size]; return (pels > 1024) ? 2 : (pels > 256) ? 1 : 0; } + /// + /// Gets the transform width in samples. + /// + /// The transform size. + /// The transform width in samples. public static int GetWidth(this Av1TransformSize size) => WideUnit[(int)size] << 2; + /// + /// Gets the transform height in samples. + /// + /// The transform size. + /// The transform height in samples. public static int GetHeight(this Av1TransformSize size) => HighUnit[(int)size] << 2; + /// + /// Gets the transform width in units of four samples. + /// + /// The transform size. + /// The number of four-sample columns. public static int Get4x4WideCount(this Av1TransformSize size) => WideUnit[(int)size]; + /// + /// Gets the transform height in units of four samples. + /// + /// The transform size. + /// The number of four-sample rows. public static int Get4x4HighCount(this Av1TransformSize size) => HighUnit[(int)size]; + /// + /// Gets the next smaller transform size used when a transform block is subdivided. + /// + /// The transform size. + /// The transform's subdivision size. public static Av1TransformSize GetSubSize(this Av1TransformSize size) => SubTransformSize[(int)size]; + /// + /// Gets the square transform based on the smaller dimension of a rectangular transform. + /// + /// The transform size. + /// The corresponding square transform size. public static Av1TransformSize GetSquareSize(this Av1TransformSize size) => SquareMap[(int)size]; + /// + /// Gets the square transform based on the larger dimension of a rectangular transform. + /// + /// The transform size. + /// The corresponding enclosing square transform size. public static Av1TransformSize GetSquareUpSize(this Av1TransformSize size) => SquareUpMap[(int)size]; + /// + /// Gets the block size having the same dimensions as a transform size. + /// + /// The transform size. + /// The dimensionally equivalent block size. public static Av1BlockSize ToBlockSize(this Av1TransformSize transformSize) => BlockSize[(int)transformSize]; + /// + /// Gets the capped sum of the transform-dimension logarithms minus four. + /// + /// The transform size. + /// The context value used by AV1 transform syntax. public static int GetLog2Minus4(this Av1TransformSize size) => Log2Minus4[(int)size]; + /// + /// Gets the transform size used by coefficient and quantization tables that cap dimensions at 32 samples. + /// + /// The signaled transform size. + /// The adjusted transform size. public static Av1TransformSize GetAdjusted(this Av1TransformSize size) => size switch { Av1TransformSize.Size64x64 or Av1TransformSize.Size64x32 or Av1TransformSize.Size32x64 => Av1TransformSize.Size32x32, @@ -171,10 +257,25 @@ internal static class Av1TransformSizeExtensions _ => size }; + /// + /// Gets the base-two logarithm of the transform width in samples. + /// + /// The transform size. + /// The base-two width logarithm. public static int GetBlockWidthLog2(this Av1TransformSize size) => BlockWidthLog2[(int)size]; + /// + /// Gets the base-two logarithm of the transform height in samples. + /// + /// The transform size. + /// The base-two height logarithm. public static int GetBlockHeightLog2(this Av1TransformSize size) => BlockHeightLog2[(int)size]; + /// + /// Gets the signed base-two ratio between transform width and height. + /// + /// The transform size. + /// Zero for square transforms, positive when wider, or negative when taller. public static int GetRectangleLogRatio(this Av1TransformSize size) { int col = GetWidth(size); diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformType.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformType.cs index 96867d2ab..368c234c0 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformType.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformType.cs @@ -3,6 +3,9 @@ namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform; +/// +/// Identifies the horizontal and vertical transform combination signaled for an AV1 transform block. +/// internal enum Av1TransformType : byte { /// diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformType1d.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformType1d.cs index a20149319..a47836789 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformType1d.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformType1d.cs @@ -3,6 +3,9 @@ namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform; +/// +/// Identifies the one-dimensional transform applied along one axis of an AV1 transform block. +/// internal enum Av1TransformType1d { Dct, diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformTypeExtensions.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformTypeExtensions.cs index c03b3b440..d073393a5 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformTypeExtensions.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformTypeExtensions.cs @@ -3,8 +3,14 @@ namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform; +/// +/// Provides AV1 transform-class and transform-set lookups for compound transform types. +/// internal static class Av1TransformTypeExtensions { + /// + /// Maps each compound transform type to its entropy-context transform class. + /// private static readonly Av1TransformClass[] Type2Class = [ Av1TransformClass.Class2D, // DCT_DCT Av1TransformClass.Class2D, // ADST_DCT @@ -24,6 +30,9 @@ internal static class Av1TransformTypeExtensions Av1TransformClass.ClassHorizontal, // H_FLIPADST ]; + /// + /// Indicates which compound transform types are enabled by each transform-set type. + /// private static readonly bool[][] ExtendedTransformUsed = [ [true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false], [true, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false], @@ -33,8 +42,19 @@ internal static class Av1TransformTypeExtensions [true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true], ]; + /// + /// Gets the entropy-context class of a compound transform type. + /// + /// The compound transform type. + /// The two-dimensional, horizontal, or vertical transform class. public static Av1TransformClass ToClass(this Av1TransformType transformType) => Type2Class[(int)transformType]; + /// + /// Determines whether a compound transform type belongs to an allowed transform set. + /// + /// The compound transform type. + /// The allowed transform set. + /// when the transform is enabled by the set. public static bool IsExtendedSetUsed(this Av1TransformType transformType, Av1TransformSetType setType) => ExtendedTransformUsed[(int)setType][(int)transformType]; } diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Adst16Forward1dTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Adst16Forward1dTransformer.cs index fbd8bb36a..296756a19 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Adst16Forward1dTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Adst16Forward1dTransformer.cs @@ -5,8 +5,12 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; +/// +/// Applies the 16-point AV1 forward asymmetric discrete sine transform to a one-dimensional residual vector. +/// internal class Av1Adst16Forward1dTransformer : IAv1Transformer1d { + /// public void Transform(Span input, Span output, int cosBit, Span stageRange) { Guard.MustBeSizedAtLeast(input, 16, nameof(input)); @@ -14,6 +18,12 @@ internal class Av1Adst16Forward1dTransformer : IAv1Transformer1d TransformScalar(ref input[0], ref output[0], cosBit); } + /// + /// Applies the staged 16-point fixed-point forward ADST. + /// + /// A reference to the first input value. + /// A reference to the first output coefficient. + /// The cosine-table fixed-point precision. private static void TransformScalar(ref int input, ref int output, int cosBit) { Span temp0 = stackalloc int[16]; diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Adst32Forward1dTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Adst32Forward1dTransformer.cs index 80a06f6b2..d34498661 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Adst32Forward1dTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Adst32Forward1dTransformer.cs @@ -5,8 +5,12 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; +/// +/// Applies the 32-point AV1 forward asymmetric discrete sine transform to a one-dimensional residual vector. +/// internal class Av1Adst32Forward1dTransformer : IAv1Transformer1d { + /// public void Transform(Span input, Span output, int cosBit, Span stageRange) { Guard.MustBeSizedAtLeast(input, 32, nameof(input)); @@ -14,6 +18,12 @@ internal class Av1Adst32Forward1dTransformer : IAv1Transformer1d TransformScalar(ref input[0], ref output[0], cosBit); } + /// + /// Applies the staged 32-point fixed-point forward ADST. + /// + /// A reference to the first input value. + /// A reference to the first output coefficient. + /// The cosine-table fixed-point precision. private static void TransformScalar(ref int input, ref int outputRef, int cosBit) { Span temp0 = stackalloc int[32]; diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Adst4Forward1dTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Adst4Forward1dTransformer.cs index f3ab6926b..4aa514c44 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Adst4Forward1dTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Adst4Forward1dTransformer.cs @@ -5,8 +5,12 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; +/// +/// Applies the four-point AV1 forward asymmetric discrete sine transform to a one-dimensional residual vector. +/// internal class Av1Adst4Forward1dTransformer : IAv1Transformer1d { + /// public void Transform(Span input, Span output, int cosBit, Span stageRange) { Guard.MustBeSizedAtLeast(input, 4, nameof(input)); @@ -14,6 +18,12 @@ internal class Av1Adst4Forward1dTransformer : IAv1Transformer1d TransformScalar(ref input[0], ref output[0], cosBit); } + /// + /// Applies the staged four-point fixed-point forward ADST. + /// + /// A reference to the first input value. + /// A reference to the first output coefficient. + /// The cosine-table fixed-point precision. private static void TransformScalar(ref int input, ref int output, int cosBit) { Span sinpi = Av1SinusConstants.SinusPi(cosBit); diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Adst8Forward1dTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Adst8Forward1dTransformer.cs index b0aac3656..796d9da60 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Adst8Forward1dTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Adst8Forward1dTransformer.cs @@ -5,8 +5,12 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; +/// +/// Applies the eight-point AV1 forward asymmetric discrete sine transform to a one-dimensional residual vector. +/// internal class Av1Adst8Forward1dTransformer : IAv1Transformer1d { + /// public void Transform(Span input, Span output, int cosBit, Span stageRange) { Guard.MustBeSizedAtLeast(input, 8, nameof(input)); @@ -14,6 +18,12 @@ internal class Av1Adst8Forward1dTransformer : IAv1Transformer1d TransformScalar(ref input[0], ref output[0], cosBit); } + /// + /// Applies the staged eight-point fixed-point forward ADST. + /// + /// A reference to the first input value. + /// A reference to the first output coefficient. + /// The cosine-table fixed-point precision. private static void TransformScalar(ref int input, ref int output, int cosBit) { Span temp0 = stackalloc int[8]; diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Dct16Forward1dTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Dct16Forward1dTransformer.cs index 5b1eb0602..3bf694532 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Dct16Forward1dTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Dct16Forward1dTransformer.cs @@ -5,8 +5,12 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; +/// +/// Applies the 16-point AV1 forward discrete cosine transform to a one-dimensional residual vector. +/// internal class Av1Dct16Forward1dTransformer : IAv1Transformer1d { + /// public void Transform(Span input, Span output, int cosBit, Span stageRange) { Guard.MustBeSizedAtLeast(input, 16, nameof(input)); @@ -14,6 +18,12 @@ internal class Av1Dct16Forward1dTransformer : IAv1Transformer1d TransformScalar(ref input[0], ref output[0], cosBit); } + /// + /// Applies the staged 16-point fixed-point forward DCT. + /// + /// A reference to the first input value. + /// A reference to the first output coefficient. + /// The cosine-table fixed-point precision. private static void TransformScalar(ref int input, ref int output, int cosBit) { Span temp0 = stackalloc int[16]; diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Dct32Forward1dTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Dct32Forward1dTransformer.cs index 544b5a2f0..aea1bc0d0 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Dct32Forward1dTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Dct32Forward1dTransformer.cs @@ -5,8 +5,12 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; +/// +/// Applies the 32-point AV1 forward discrete cosine transform to a one-dimensional residual vector. +/// internal class Av1Dct32Forward1dTransformer : IAv1Transformer1d { + /// public void Transform(Span input, Span output, int cosBit, Span stageRange) { Guard.MustBeSizedAtLeast(input, 32, nameof(input)); @@ -14,6 +18,12 @@ internal class Av1Dct32Forward1dTransformer : IAv1Transformer1d TransformScalar(ref input[0], ref output[0], cosBit); } + /// + /// Applies the staged 32-point fixed-point forward DCT. + /// + /// A reference to the first input value. + /// A reference to the first output coefficient. + /// The cosine-table fixed-point precision. private static void TransformScalar(ref int input, ref int output, int cosBit) { Span temp0 = stackalloc int[32]; diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Dct4Forward1dTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Dct4Forward1dTransformer.cs index a7ed5f0a5..24a3cc88f 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Dct4Forward1dTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Dct4Forward1dTransformer.cs @@ -5,8 +5,12 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; +/// +/// Applies the four-point AV1 forward discrete cosine transform to a one-dimensional residual vector. +/// internal class Av1Dct4Forward1dTransformer : IAv1Transformer1d { + /// public void Transform(Span input, Span output, int cosBit, Span stageRange) { Guard.MustBeSizedAtLeast(input, 4, nameof(input)); @@ -14,6 +18,12 @@ internal class Av1Dct4Forward1dTransformer : IAv1Transformer1d TransformScalar(ref input[0], ref output[0], cosBit); } + /// + /// Applies the staged four-point fixed-point forward DCT. + /// + /// A reference to the first input value. + /// A reference to the first output coefficient. + /// The cosine-table fixed-point precision. private static void TransformScalar(ref int input, ref int output, int cosBit) { Span cospi = Av1SinusConstants.CosinusPi(cosBit); @@ -49,6 +59,15 @@ internal class Av1Dct4Forward1dTransformer : IAv1Transformer1d output3 = step3; } + /// + /// Applies one rounded two-input fixed-point butterfly output. + /// + /// The first fixed-point weight. + /// The first input value. + /// The second fixed-point weight. + /// The second input value. + /// The number of fractional bits removed after multiplication. + /// The rounded butterfly output. internal static int HalfButterfly(int w0, int in0, int w1, int in1, int bit) { long result64 = (long)(w0 * in0) + (w1 * in1); diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Dct64Forward1dTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Dct64Forward1dTransformer.cs index 84c169056..16699a9da 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Dct64Forward1dTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Dct64Forward1dTransformer.cs @@ -5,8 +5,12 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; +/// +/// Applies the 64-point AV1 forward discrete cosine transform to a one-dimensional residual vector. +/// internal class Av1Dct64Forward1dTransformer : IAv1Transformer1d { + /// public void Transform(Span input, Span output, int cosBit, Span stageRange) { Guard.MustBeSizedAtLeast(input, 64, nameof(input)); @@ -14,6 +18,12 @@ internal class Av1Dct64Forward1dTransformer : IAv1Transformer1d TransformScalar(ref input[0], ref output[0], cosBit); } + /// + /// Applies the staged 64-point fixed-point forward DCT. + /// + /// A reference to the first input value. + /// A reference to the first output coefficient. + /// The cosine-table fixed-point precision. private static void TransformScalar(ref int input, ref int output, int cosBit) { Span temp0 = stackalloc int[64]; diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Dct8Forward1dTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Dct8Forward1dTransformer.cs index 8f5fc8926..7fa046f59 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Dct8Forward1dTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Dct8Forward1dTransformer.cs @@ -5,8 +5,12 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; +/// +/// Applies the eight-point AV1 forward discrete cosine transform to a one-dimensional residual vector. +/// internal class Av1Dct8Forward1dTransformer : IAv1Transformer1d { + /// public void Transform(Span input, Span output, int cosBit, Span stageRange) { Guard.MustBeSizedAtLeast(input, 8, nameof(input)); @@ -14,6 +18,12 @@ internal class Av1Dct8Forward1dTransformer : IAv1Transformer1d TransformScalar(ref input[0], ref output[0], cosBit); } + /// + /// Applies the staged eight-point fixed-point forward DCT. + /// + /// A reference to the first input value. + /// A reference to the first output coefficient. + /// The cosine-table fixed-point precision. private static void TransformScalar(ref int input, ref int output, int cosBit) { Span temp0 = stackalloc int[8]; diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1DctDct4Forward2dTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1DctDct4Forward2dTransformer.cs index 9442618d2..4fc72fe7d 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1DctDct4Forward2dTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1DctDct4Forward2dTransformer.cs @@ -6,12 +6,33 @@ using System.Runtime.Intrinsics; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; +/// +/// Applies the AV1 four-by-four forward two-dimensional DCT-DCT transform. +/// internal class Av1DctDct4Forward2dTransformer : Av1Forward2dTransformerBase { + /// + /// The fixed transform configuration for a four-by-four DCT-DCT block. + /// private readonly Av1Transform2dFlipConfiguration config = new(Av1TransformType.DctDct, Av1TransformSize.Size4x4); + + /// + /// The four-point one-dimensional DCT reused for both axes. + /// private readonly Av1Dct4Forward1dTransformer transformer = new(); + + /// + /// The transposed intermediate coefficient plane used by the scalar two-dimensional pipeline. + /// private readonly int[] temp = new int[Av1Constants.MaxTransformSize * Av1Constants.MaxTransformSize]; + /// + /// Applies the four-by-four DCT-DCT transform to a residual block. + /// + /// The spatial residual samples. + /// The destination transform coefficients. + /// The cosine-table fixed-point precision. + /// The number of input values between adjacent rows. public void Transform(Span input, Span output, int cosBit, int columnNumber) { /*if (Vector256.IsHardwareAccelerated) @@ -27,8 +48,13 @@ internal class Av1DctDct4Forward2dTransformer : Av1Forward2dTransformerBase } /// - /// SVT: fdct4x4_sse4_1 + /// Applies the vectorized four-by-four forward DCT-DCT kernel. /// + /// A reference to the first vector of residual samples. + /// A reference to the first vector of transform coefficients. + /// The cosine-table fixed-point precision. + /// The number of vectors between adjacent input rows. + /// Corresponds to fdct4x4_sse4_1 in the original WIP reference. private static void TransformVector(ref Vector128 input, ref Vector128 output, int cosBit, int columnNumber) { // We only use stage-2 bit; diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Forward2dTransformerBase.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Forward2dTransformerBase.cs index 1da6135fe..b32134e03 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Forward2dTransformerBase.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Forward2dTransformerBase.cs @@ -5,14 +5,35 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; +/// +/// Provides the separable row-and-column pipeline shared by AV1 forward two-dimensional transforms. +/// internal abstract class Av1Forward2dTransformerBase { + /// + /// The fixed-point representation of sqrt(2) at fractional bits. + /// internal const int NewSqrt2 = 5793; + + /// + /// The number of fractional bits used by . + /// internal const int NewSqrt2BitCount = 12; /// - /// SVT: av1_tranform_two_d_core_c + /// Applies the separable column and row stages, including normative flips, shifts, and rectangular scaling. /// + /// The column-transform implementation type. + /// The row-transform implementation type. + /// The column-transform implementation. + /// The row-transform implementation. + /// The spatial residual samples. + /// The number of input samples between rows. + /// The destination transform coefficients and temporary axis buffers. + /// The per-axis transform, flip, shift, and range configuration. + /// The transposed intermediate coefficient plane. + /// The source sample bit depth. + /// Corresponds to av1_tranform_two_d_core_c in the original WIP reference. protected static void Transform2dCore(TColumn transformFunctionColumn, TRow transformFunctionRow, Span input, uint inputStride, Span output, Av1Transform2dFlipConfiguration config, Span buf, int bitDepth) where TColumn : IAv1Transformer1d where TRow : IAv1Transformer1d @@ -119,6 +140,12 @@ internal abstract class Av1Forward2dTransformerBase } } + /// + /// Applies a signed fixed-point shift to a contiguous transform-stage vector. + /// + /// A reference to the first transform-stage value. + /// The number of values to update. + /// A positive rounded-right shift or a negative exact-left shift. private static void RoundShiftArray(ref int arr, int size, int bit) { if (bit == 0) @@ -148,8 +175,12 @@ internal abstract class Av1Forward2dTransformerBase } /// - /// SVT: get_rect_tx_log_ratio + /// Gets the signed base-two ratio between transform columns and rows. /// + /// The transform width. + /// The transform height. + /// Zero for square transforms, positive when wider, or negative when taller. + /// Corresponds to get_rect_tx_log_ratio in the original WIP reference. public static int GetRectangularRatio(int col, int row) { if (col == row) diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Identity16Forward1dTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Identity16Forward1dTransformer.cs index 7b822c76e..bf5a881ff 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Identity16Forward1dTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Identity16Forward1dTransformer.cs @@ -5,10 +5,14 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; +/// +/// Applies the 16-point AV1 forward identity transform to a one-dimensional residual vector. +/// internal class Av1Identity16Forward1dTransformer : IAv1Transformer1d { private const int TwiceNewSqrt2 = 2 * 5793; + /// public void Transform(Span input, Span output, int cosBit, Span stageRange) { Guard.MustBeSizedAtLeast(input, 16, nameof(input)); @@ -16,6 +20,11 @@ internal class Av1Identity16Forward1dTransformer : IAv1Transformer1d TransformScalar(ref input[0], ref output[0]); } + /// + /// Scales 16 residual values according to the AV1 forward identity-transform definition. + /// + /// A reference to the first input value. + /// A reference to the first output coefficient. private static void TransformScalar(ref int input, ref int output) { output = Av1Math.RoundShift((long)input * TwiceNewSqrt2, Av1Forward2dTransformerBase.NewSqrt2BitCount); diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Identity32Forward1dTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Identity32Forward1dTransformer.cs index dac3ba003..b6ab85bae 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Identity32Forward1dTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Identity32Forward1dTransformer.cs @@ -5,8 +5,12 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; +/// +/// Applies the 32-point AV1 forward identity transform to a one-dimensional residual vector. +/// internal class Av1Identity32Forward1dTransformer : IAv1Transformer1d { + /// public void Transform(Span input, Span output, int cosBit, Span stageRange) { Guard.MustBeSizedAtLeast(input, 32, nameof(input)); @@ -19,6 +23,11 @@ internal class Av1Identity32Forward1dTransformer : IAv1Transformer1d TransformScalar(ref Unsafe.Add(ref inputRef, 24), ref Unsafe.Add(ref outputRef, 24)); } + /// + /// Scales 32 residual values according to the AV1 forward identity-transform definition. + /// + /// A reference to the first input value. + /// A reference to the first output coefficient. private static void TransformScalar(ref int input, ref int output) { output = input << 2; diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Identity4Forward1dTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Identity4Forward1dTransformer.cs index d1721af14..e1bf57965 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Identity4Forward1dTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Identity4Forward1dTransformer.cs @@ -5,8 +5,12 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; +/// +/// Applies the four-point AV1 forward identity transform to a one-dimensional residual vector. +/// internal class Av1Identity4Forward1dTransformer : IAv1Transformer1d { + /// public void Transform(Span input, Span output, int cosBit, Span stageRange) { Guard.MustBeSizedAtLeast(input, 4, nameof(input)); @@ -14,6 +18,11 @@ internal class Av1Identity4Forward1dTransformer : IAv1Transformer1d TransformScalar(ref input[0], ref output[0]); } + /// + /// Scales four residual values according to the AV1 forward identity-transform definition. + /// + /// A reference to the first input value. + /// A reference to the first output coefficient. private static void TransformScalar(ref int input, ref int output) { output = Av1Math.RoundShift((long)input * Av1Forward2dTransformerBase.NewSqrt2, Av1Forward2dTransformerBase.NewSqrt2BitCount); diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Identity64Forward1dTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Identity64Forward1dTransformer.cs index de62fd3d9..3f5b61638 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Identity64Forward1dTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Identity64Forward1dTransformer.cs @@ -5,10 +5,14 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; +/// +/// Applies the 64-point AV1 forward identity transform to a one-dimensional residual vector. +/// internal class Av1Identity64Forward1dTransformer : IAv1Transformer1d { private const int QuadNewSqrt2 = 4 * 5793; + /// public void Transform(Span input, Span output, int cosBit, Span stageRange) { Guard.MustBeSizedAtLeast(input, 64, nameof(input)); @@ -21,6 +25,11 @@ internal class Av1Identity64Forward1dTransformer : IAv1Transformer1d TransformScalar(ref Unsafe.Add(ref inputRef, 48), ref Unsafe.Add(ref outputRef, 48)); } + /// + /// Scales 64 residual values according to the AV1 forward identity-transform definition. + /// + /// A reference to the first input value. + /// A reference to the first output coefficient. private static void TransformScalar(ref int input, ref int output) { output = Av1Math.RoundShift((long)input * QuadNewSqrt2, Av1Forward2dTransformerBase.NewSqrt2BitCount); diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Identity8Forward1dTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Identity8Forward1dTransformer.cs index 20df9d906..0b9d70347 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Identity8Forward1dTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Forward/Av1Identity8Forward1dTransformer.cs @@ -5,8 +5,12 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Forward; +/// +/// Applies the eight-point AV1 forward identity transform to a one-dimensional residual vector. +/// internal class Av1Identity8Forward1dTransformer : IAv1Transformer1d { + /// public void Transform(Span input, Span output, int cosBit, Span stageRange) { Guard.MustBeSizedAtLeast(input, 8, nameof(input)); @@ -14,6 +18,11 @@ internal class Av1Identity8Forward1dTransformer : IAv1Transformer1d TransformScalar(ref input[0], ref output[0]); } + /// + /// Scales eight residual values according to the AV1 forward identity-transform definition. + /// + /// A reference to the first input value. + /// A reference to the first output coefficient. private static void TransformScalar(ref int input, ref int output) { output = input << 1; diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/IAv1Transformer1d.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/IAv1Transformer1d.cs index c1357734e..ee9ecadf1 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/IAv1Transformer1d.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/IAv1Transformer1d.cs @@ -4,7 +4,7 @@ namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform; /// -/// Implementation of a specific forward 1-dimensional transform function. +/// Defines a one-dimensional AV1 forward or inverse transform function. /// internal interface IAv1Transformer1d { diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Adst16Inverse1dTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Adst16Inverse1dTransformer.cs index 4458dec2a..874c2cc6d 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Adst16Inverse1dTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Adst16Inverse1dTransformer.cs @@ -5,8 +5,12 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Inverse; +/// +/// Applies the 16-point AV1 inverse asymmetric discrete sine transform to a one-dimensional coefficient vector. +/// internal class Av1Adst16Inverse1dTransformer : IAv1Transformer1d { + /// public void Transform(Span input, Span output, int cosBit, Span stageRange) { Guard.MustBeSizedAtLeast(input, 16, nameof(input)); @@ -15,8 +19,13 @@ internal class Av1Adst16Inverse1dTransformer : IAv1Transformer1d } /// - /// SVT: svt_av1_iadst16_new + /// Applies the staged 16-point fixed-point inverse ADST. /// + /// A reference to the first input coefficient. + /// A reference to the first output value. + /// The cosine-table fixed-point precision. + /// The signed-bit range permitted after each transform stage. + /// Corresponds to svt_av1_iadst16_new in the original WIP reference. private static void TransformScalar(ref int input, ref int output, int cos_bit, Span stage_range) { Span cospi = Av1SinusConstants.CosinusPi(cos_bit); diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Adst32Inverse1dTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Adst32Inverse1dTransformer.cs index 9d3e27d3b..b9ee020d1 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Adst32Inverse1dTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Adst32Inverse1dTransformer.cs @@ -5,8 +5,12 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Inverse; +/// +/// Applies the 32-point AV1 inverse asymmetric discrete sine transform to a one-dimensional coefficient vector. +/// internal class Av1Adst32Inverse1dTransformer : IAv1Transformer1d { + /// public void Transform(Span input, Span output, int cosBit, Span stageRange) { Guard.MustBeSizedAtLeast(input, 32, nameof(input)); @@ -15,8 +19,13 @@ internal class Av1Adst32Inverse1dTransformer : IAv1Transformer1d } /// - /// SVT: svt_av1_iadst32_new + /// Applies the staged 32-point fixed-point inverse ADST. /// + /// A reference to the first input coefficient. + /// A reference to the first output value. + /// The cosine-table fixed-point precision. + /// The signed-bit range permitted after each transform stage. + /// Corresponds to svt_av1_iadst32_new in the original WIP reference. private static void TransformScalar(ref int input, ref int output, int cosBit, Span stageRange) { Span cospi = Av1SinusConstants.CosinusPi(cosBit); diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Adst4Inverse1dTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Adst4Inverse1dTransformer.cs index fc94ee6b3..81d66413e 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Adst4Inverse1dTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Adst4Inverse1dTransformer.cs @@ -5,8 +5,12 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Inverse; +/// +/// Applies the four-point AV1 inverse asymmetric discrete sine transform to a one-dimensional coefficient vector. +/// internal class Av1Adst4Inverse1dTransformer : IAv1Transformer1d { + /// public void Transform(Span input, Span output, int cosBit, Span stageRange) { Guard.MustBeSizedAtLeast(input, 4, nameof(input)); @@ -15,8 +19,13 @@ internal class Av1Adst4Inverse1dTransformer : IAv1Transformer1d } /// - /// SVT: svt_av1_iadst4_new + /// Applies the staged four-point fixed-point inverse ADST. /// + /// A reference to the first input coefficient. + /// A reference to the first output value. + /// The sine-table fixed-point precision. + /// The signed-bit range permitted after each transform stage. + /// Corresponds to svt_av1_iadst4_new in the original WIP reference. private static void TransformScalar(ref int input, ref int output, int cosBit, Span stageRange) { int bit = cosBit; diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Adst8Inverse1dTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Adst8Inverse1dTransformer.cs index 104cf979d..4c46bfffa 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Adst8Inverse1dTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Adst8Inverse1dTransformer.cs @@ -5,8 +5,12 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Inverse; +/// +/// Applies the eight-point AV1 inverse asymmetric discrete sine transform to a one-dimensional coefficient vector. +/// internal class Av1Adst8Inverse1dTransformer : IAv1Transformer1d { + /// public void Transform(Span input, Span output, int cosBit, Span stageRange) { Guard.MustBeSizedAtLeast(input, 8, nameof(input)); @@ -15,8 +19,13 @@ internal class Av1Adst8Inverse1dTransformer : IAv1Transformer1d } /// - /// SVT: svt_av1_iadst8_new + /// Applies the staged eight-point fixed-point inverse ADST. /// + /// A reference to the first input coefficient. + /// A reference to the first output value. + /// The cosine-table fixed-point precision. + /// The signed-bit range permitted after each transform stage. + /// Corresponds to svt_av1_iadst8_new in the original WIP reference. private static void TransformScalar(ref int input, ref int output, int cosBit, Span stageRange) { Span cospi = Av1SinusConstants.CosinusPi(cosBit); diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Dct16Inverse1dTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Dct16Inverse1dTransformer.cs index 028f32e4e..f6557b26b 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Dct16Inverse1dTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Dct16Inverse1dTransformer.cs @@ -5,8 +5,12 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Inverse; +/// +/// Applies the 16-point AV1 inverse discrete cosine transform to a one-dimensional coefficient vector. +/// internal class Av1Dct16Inverse1dTransformer : IAv1Transformer1d { + /// public void Transform(Span input, Span output, int cosBit, Span stageRange) { Guard.MustBeSizedAtLeast(input, 16, nameof(input)); @@ -15,8 +19,13 @@ internal class Av1Dct16Inverse1dTransformer : IAv1Transformer1d } /// - /// SVT: svt_av1_idct16_new + /// Applies the staged 16-point fixed-point inverse DCT. /// + /// A reference to the first input coefficient. + /// A reference to the first output value. + /// The cosine-table fixed-point precision. + /// The signed-bit range permitted after each transform stage. + /// Corresponds to svt_av1_idct16_new in the original WIP reference. private static void TransformScalar(ref int input, ref int output, int cosBit, Span stageRange) { Span cospi = Av1SinusConstants.CosinusPi(cosBit); @@ -177,6 +186,12 @@ internal class Av1Dct16Inverse1dTransformer : IAv1Transformer1d Unsafe.Add(ref output, 15) = ClampValue(temp1[0] - temp1[15], range); } + /// + /// Clamps one transform-stage value to a signed range of the specified bit width. + /// + /// The value to clamp. + /// The signed range width in bits. + /// The clamped value. internal static int ClampValue(int value, byte bit) { if (bit <= 0) @@ -189,6 +204,15 @@ internal class Av1Dct16Inverse1dTransformer : IAv1Transformer1d return (int)Av1Math.Clamp(value, min_value, max_value); } + /// + /// Applies one rounded two-input fixed-point butterfly output. + /// + /// The first fixed-point weight. + /// The first input value. + /// The second fixed-point weight. + /// The second input value. + /// The number of fractional bits removed after multiplication. + /// The rounded butterfly output. internal static int HalfButterfly(int w0, int in0, int w1, int in1, int bit) { long result64 = (long)(w0 * in0) + (w1 * in1); diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Dct32Inverse1dTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Dct32Inverse1dTransformer.cs index 9107e9eac..b5ac2419c 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Dct32Inverse1dTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Dct32Inverse1dTransformer.cs @@ -5,8 +5,12 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Inverse; +/// +/// Applies the 32-point AV1 inverse discrete cosine transform to a one-dimensional coefficient vector. +/// internal class Av1Dct32Inverse1dTransformer : IAv1Transformer1d { + /// public void Transform(Span input, Span output, int cosBit, Span stageRange) { Guard.MustBeSizedAtLeast(input, 32, nameof(input)); @@ -15,8 +19,13 @@ internal class Av1Dct32Inverse1dTransformer : IAv1Transformer1d } /// - /// SVT: svt_av1_idct32_new + /// Applies the staged 32-point fixed-point inverse DCT. /// + /// A reference to the first input coefficient. + /// A reference to the first output value. + /// The cosine-table fixed-point precision. + /// The signed-bit range permitted after each transform stage. + /// Corresponds to svt_av1_idct32_new in the original WIP reference. private static void TransformScalar(ref int input, ref int output, int cosBit, Span stageRange) { Span cospi = Av1SinusConstants.CosinusPi(cosBit); @@ -365,6 +374,12 @@ internal class Av1Dct32Inverse1dTransformer : IAv1Transformer1d Unsafe.Add(ref output, 31) = ClampValue(temp0[0] - temp0[31], range); } + /// + /// Clamps one transform-stage value to a signed range of the specified bit width. + /// + /// The value to clamp. + /// The signed range width in bits. + /// The clamped value. internal static int ClampValue(int value, byte bit) { if (bit <= 0) @@ -377,6 +392,15 @@ internal class Av1Dct32Inverse1dTransformer : IAv1Transformer1d return (int)Av1Math.Clamp(value, min_value, max_value); } + /// + /// Applies one rounded two-input fixed-point butterfly output. + /// + /// The first fixed-point weight. + /// The first input value. + /// The second fixed-point weight. + /// The second input value. + /// The number of fractional bits removed after multiplication. + /// The rounded butterfly output. internal static int HalfButterfly(int w0, int in0, int w1, int in1, int bit) { long result64 = (long)(w0 * in0) + (w1 * in1); diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Dct4Inverse1dTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Dct4Inverse1dTransformer.cs index 0c0cd25b6..3992f8330 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Dct4Inverse1dTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Dct4Inverse1dTransformer.cs @@ -5,8 +5,12 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Inverse; +/// +/// Applies the four-point AV1 inverse discrete cosine transform to a one-dimensional coefficient vector. +/// internal class Av1Dct4Inverse1dTransformer : IAv1Transformer1d { + /// public void Transform(Span input, Span output, int cosBit, Span stageRange) { Guard.MustBeSizedAtLeast(input, 4, nameof(input)); @@ -15,8 +19,13 @@ internal class Av1Dct4Inverse1dTransformer : IAv1Transformer1d } /// - /// SVT: svt_av1_idct4_new + /// Applies the staged four-point fixed-point inverse DCT. /// + /// A reference to the first input coefficient. + /// A reference to the first output value. + /// The cosine-table fixed-point precision. + /// The signed-bit range permitted after each transform stage. + /// Corresponds to svt_av1_idct4_new in the original WIP reference. private static void TransformScalar(ref int input, ref int output, int cosBit, Span stageRange) { Span cospi = Av1SinusConstants.CosinusPi(cosBit); @@ -53,6 +62,12 @@ internal class Av1Dct4Inverse1dTransformer : IAv1Transformer1d ClampBuffer4(ref output, stageRange[stage]); } + /// + /// Clamps one transform-stage value to a signed range of the specified bit width. + /// + /// The value to clamp. + /// The signed range width in bits. + /// The clamped value. internal static int ClampValue(int value, byte bit) { if (bit <= 0) @@ -65,6 +80,11 @@ internal class Av1Dct4Inverse1dTransformer : IAv1Transformer1d return (int)Av1Math.Clamp(value, min_value, max_value); } + /// + /// Clamps four contiguous transform-stage values to a signed range. + /// + /// A reference to the first value. + /// The signed range width in bits. internal static void ClampBuffer4(ref int buffer, byte bit) { if (bit <= 0) @@ -81,6 +101,11 @@ internal class Av1Dct4Inverse1dTransformer : IAv1Transformer1d Unsafe.Add(ref buffer, 3) = (int)Av1Math.Clamp(Unsafe.Add(ref buffer, 3), min_value, max_value); } + /// + /// Clamps eight contiguous transform-stage values to a signed range. + /// + /// A reference to the first value. + /// The signed range width in bits. internal static void ClampBuffer8(ref int buffer, byte bit) { if (bit <= 0) @@ -101,6 +126,11 @@ internal class Av1Dct4Inverse1dTransformer : IAv1Transformer1d Unsafe.Add(ref buffer, 7) = (int)Av1Math.Clamp(Unsafe.Add(ref buffer, 7), min_value, max_value); } + /// + /// Clamps 16 contiguous transform-stage values to a signed range. + /// + /// A reference to the first value. + /// The signed range width in bits. internal static void ClampBuffer16(ref int buffer, byte bit) { if (bit <= 0) @@ -129,6 +159,11 @@ internal class Av1Dct4Inverse1dTransformer : IAv1Transformer1d Unsafe.Add(ref buffer, 15) = (int)Av1Math.Clamp(Unsafe.Add(ref buffer, 15), min_value, max_value); } + /// + /// Clamps 32 contiguous transform-stage values to a signed range. + /// + /// A reference to the first value. + /// The signed range width in bits. internal static void ClampBuffer32(ref int buffer, byte bit) { if (bit <= 0) @@ -173,6 +208,15 @@ internal class Av1Dct4Inverse1dTransformer : IAv1Transformer1d Unsafe.Add(ref buffer, 31) = (int)Av1Math.Clamp(Unsafe.Add(ref buffer, 31), min_value, max_value); } + /// + /// Applies one rounded two-input fixed-point butterfly output. + /// + /// The first fixed-point weight. + /// The first input value. + /// The second fixed-point weight. + /// The second input value. + /// The number of fractional bits removed after multiplication. + /// The rounded butterfly output. internal static int HalfButterfly(int w0, int in0, int w1, int in1, int bit) { long result64 = (long)(w0 * in0) + (w1 * in1); diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Dct64Inverse1dTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Dct64Inverse1dTransformer.cs index c4f754ce3..53192920e 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Dct64Inverse1dTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Dct64Inverse1dTransformer.cs @@ -5,8 +5,12 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Inverse; +/// +/// Applies the 64-point AV1 inverse discrete cosine transform to a one-dimensional coefficient vector. +/// internal class Av1Dct64Inverse1dTransformer : IAv1Transformer1d { + /// public void Transform(Span input, Span output, int cosBit, Span stageRange) { Guard.MustBeSizedAtLeast(input, 64, nameof(input)); @@ -15,8 +19,13 @@ internal class Av1Dct64Inverse1dTransformer : IAv1Transformer1d } /// - /// SVT: svt_av1_idct64_new + /// Applies the staged 64-point fixed-point inverse DCT. /// + /// A reference to the first input coefficient. + /// A reference to the first output value. + /// The cosine-table fixed-point precision. + /// The signed-bit range permitted after each transform stage. + /// Corresponds to svt_av1_idct64_new in the original WIP reference. private static void TransformScalar(ref int input, ref int output, int cosBit, Span stageRange) { Span cospi = Av1SinusConstants.CosinusPi(cosBit); diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Dct8Inverse1dTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Dct8Inverse1dTransformer.cs index 133d0e9e5..cc4ec256c 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Dct8Inverse1dTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Dct8Inverse1dTransformer.cs @@ -5,8 +5,12 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Inverse; +/// +/// Applies the eight-point AV1 inverse discrete cosine transform to a one-dimensional coefficient vector. +/// internal class Av1Dct8Inverse1dTransformer : IAv1Transformer1d { + /// public void Transform(Span input, Span output, int cosBit, Span stageRange) { Guard.MustBeSizedAtLeast(input, 8, nameof(input)); @@ -15,8 +19,13 @@ internal class Av1Dct8Inverse1dTransformer : IAv1Transformer1d } /// - /// SVT: svt_av1_idct8_new + /// Applies the staged eight-point fixed-point inverse DCT. /// + /// A reference to the first input coefficient. + /// A reference to the first output value. + /// The cosine-table fixed-point precision. + /// The signed-bit range permitted after each transform stage. + /// Corresponds to svt_av1_idct8_new in the original WIP reference. private static void TransformScalar(ref int input, ref int output, int cosBit, Span stageRange) { Span cospi = Av1SinusConstants.CosinusPi(cosBit); @@ -92,6 +101,12 @@ internal class Av1Dct8Inverse1dTransformer : IAv1Transformer1d Unsafe.Add(ref output, 7) = ClampValue(temp1[0] - temp1[7], range); } + /// + /// Clamps one transform-stage value to a signed range of the specified bit width. + /// + /// The value to clamp. + /// The signed range width in bits. + /// The clamped value. internal static int ClampValue(int value, byte bit) { if (bit <= 0) @@ -104,6 +119,15 @@ internal class Av1Dct8Inverse1dTransformer : IAv1Transformer1d return (int)Av1Math.Clamp(value, min_value, max_value); } + /// + /// Applies one rounded two-input fixed-point butterfly output. + /// + /// The first fixed-point weight. + /// The first input value. + /// The second fixed-point weight. + /// The second input value. + /// The number of fractional bits removed after multiplication. + /// The rounded butterfly output. internal static int HalfButterfly(int w0, int in0, int w1, int in1, int bit) { long result64 = (long)(w0 * in0) + (w1 * in1); diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Identity16Inverse1dTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Identity16Inverse1dTransformer.cs index 07c0510ad..bd62ad27c 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Identity16Inverse1dTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Identity16Inverse1dTransformer.cs @@ -5,10 +5,14 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Inverse; +/// +/// Applies the 16-point AV1 inverse identity transform to a one-dimensional coefficient vector. +/// internal class Av1Identity16Inverse1dTransformer : IAv1Transformer1d { private const long Sqrt2Times2 = Av1Identity4Inverse1dTransformer.Sqrt2 >> 1; + /// public void Transform(Span input, Span output, int cosBit, Span stageRange) { Guard.MustBeSizedAtLeast(input, 16, nameof(input)); @@ -17,8 +21,11 @@ internal class Av1Identity16Inverse1dTransformer : IAv1Transformer1d } /// - /// SVT: svt_av1_iidentity16_c + /// Scales 16 coefficients according to the AV1 inverse identity-transform definition. /// + /// A reference to the first input coefficient. + /// A reference to the first output value. + /// Corresponds to svt_av1_iidentity16_c in the original WIP reference. private static void TransformScalar(ref int input, ref int output) { // Normal input should fit into 32-bit. Cast to 64-bit here to avoid diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Identity32Inverse1dTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Identity32Inverse1dTransformer.cs index 15c7515da..7583b55e5 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Identity32Inverse1dTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Identity32Inverse1dTransformer.cs @@ -5,8 +5,12 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Inverse; +/// +/// Applies the 32-point AV1 inverse identity transform to a one-dimensional coefficient vector. +/// internal class Av1Identity32Inverse1dTransformer : IAv1Transformer1d { + /// public void Transform(Span input, Span output, int cosBit, Span stageRange) { Guard.MustBeSizedAtLeast(input, 32, nameof(input)); @@ -20,8 +24,11 @@ internal class Av1Identity32Inverse1dTransformer : IAv1Transformer1d } /// - /// SVT: svt_av1_iidentity32_c + /// Scales 32 coefficients according to the AV1 inverse identity-transform definition. /// + /// A reference to the first input coefficient. + /// A reference to the first output value. + /// Corresponds to svt_av1_iidentity32_c in the original WIP reference. private static void TransformScalar(ref int input, ref int output) { output = input << 2; diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Identity4Inverse1dTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Identity4Inverse1dTransformer.cs index c99ca98d1..df54bef6d 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Identity4Inverse1dTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Identity4Inverse1dTransformer.cs @@ -5,6 +5,9 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Inverse; +/// +/// Applies the four-point AV1 inverse identity transform to a one-dimensional coefficient vector. +/// internal class Av1Identity4Inverse1dTransformer : IAv1Transformer1d { internal const int Sqrt2Bits = 12; @@ -12,6 +15,7 @@ internal class Av1Identity4Inverse1dTransformer : IAv1Transformer1d // 2^12 * sqrt(2) internal const long Sqrt2 = 5793; + /// public void Transform(Span input, Span output, int cosBit, Span stageRange) { Guard.MustBeSizedAtLeast(input, 4, nameof(input)); @@ -20,8 +24,11 @@ internal class Av1Identity4Inverse1dTransformer : IAv1Transformer1d } /// - /// SVT: svt_av1_iidentity4_c + /// Scales four coefficients according to the AV1 inverse identity-transform definition. /// + /// A reference to the first input coefficient. + /// A reference to the first output value. + /// Corresponds to svt_av1_iidentity4_c in the original WIP reference. private static void TransformScalar(ref int input, ref int output) { // Normal input should fit into 32-bit. Cast to 64-bit here to avoid diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Identity64Inverse1dTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Identity64Inverse1dTransformer.cs index 682decdc8..e7e4b8fdd 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Identity64Inverse1dTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Identity64Inverse1dTransformer.cs @@ -5,10 +5,14 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Inverse; +/// +/// Applies the 64-point AV1 inverse identity transform to a one-dimensional coefficient vector. +/// internal class Av1Identity64Inverse1dTransformer : IAv1Transformer1d { private const long Sqrt2Times4 = Av1Identity4Inverse1dTransformer.Sqrt2 >> 2; + /// public void Transform(Span input, Span output, int cosBit, Span stageRange) { Guard.MustBeSizedAtLeast(input, 64, nameof(input)); @@ -26,8 +30,11 @@ internal class Av1Identity64Inverse1dTransformer : IAv1Transformer1d } /// - /// SVT: svt_av1_iidentity64_c + /// Scales 64 coefficients according to the AV1 inverse identity-transform definition. /// + /// A reference to the first input coefficient. + /// A reference to the first output value. + /// Corresponds to svt_av1_iidentity64_c in the original WIP reference. private static void TransformScalar(ref int input, ref int output) { // Normal input should fit into 32-bit. Cast to 64-bit here to avoid diff --git a/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Identity8Inverse1dTransformer.cs b/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Identity8Inverse1dTransformer.cs index a311e3240..a9de4dc33 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Identity8Inverse1dTransformer.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Transform/Inverse/Av1Identity8Inverse1dTransformer.cs @@ -5,8 +5,12 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform.Inverse; +/// +/// Applies the eight-point AV1 inverse identity transform to a one-dimensional coefficient vector. +/// internal class Av1Identity8Inverse1dTransformer : IAv1Transformer1d { + /// public void Transform(Span input, Span output, int cosBit, Span stageRange) { Guard.MustBeSizedAtLeast(input, 8, nameof(input)); @@ -15,8 +19,11 @@ internal class Av1Identity8Inverse1dTransformer : IAv1Transformer1d } /// - /// SVT: svt_av1_iidentity8_c + /// Scales eight coefficients according to the AV1 inverse identity-transform definition. /// + /// A reference to the first input coefficient. + /// A reference to the first output value. + /// Corresponds to svt_av1_iidentity8_c in the original WIP reference. private static void TransformScalar(ref int input, ref int output) { output = input << 1;