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;