mirror of https://github.com/SixLabors/ImageSharp
14 changed files with 850 additions and 24 deletions
@ -0,0 +1,81 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Six Labors Split License.
|
||||
|
|
||||
|
using SixLabors.ImageSharp.Formats.Heif.Av1.Tiling; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Pipeline; |
||||
|
|
||||
|
/// <content>
|
||||
|
/// Defines the sample-storage operations used by single-tile intra encoding.
|
||||
|
/// </content>
|
||||
|
internal sealed partial class Av1IntraTileWriter |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Defines type-specific superblock encoding without coupling tile traversal to sample storage width.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TSample">The native unsigned sample storage type.</typeparam>
|
||||
|
private interface ITileEncodingOperator<TSample> |
||||
|
where TSample : unmanaged |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Encodes and reconstructs one superblock.
|
||||
|
/// </summary>
|
||||
|
/// <param name="source">The coded source frame.</param>
|
||||
|
/// <param name="reconstruction">The reconstructed frame updated by the block transforms.</param>
|
||||
|
/// <param name="picture">The frame coding and mode-information state.</param>
|
||||
|
/// <param name="superblock">The reusable partition and final-block decisions.</param>
|
||||
|
/// <param name="coefficientBuffer">The frame-owned quantized coefficient and transform state.</param>
|
||||
|
/// <param name="blockWorkspace">The reusable block arithmetic workspace.</param>
|
||||
|
public static abstract void EncodeSuperblock( |
||||
|
Av1EncoderFrame<TSample> source, |
||||
|
Av1EncoderFrame<TSample> reconstruction, |
||||
|
Av1PictureControlSet picture, |
||||
|
Av1Superblock superblock, |
||||
|
Av1EncoderCoefficientBuffer coefficientBuffer, |
||||
|
Av1EncoderBlockWorkspace blockWorkspace); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Encodes tiles stored as eight-bit samples.
|
||||
|
/// </summary>
|
||||
|
private readonly struct ByteOperator : ITileEncodingOperator<byte> |
||||
|
{ |
||||
|
/// <inheritdoc/>
|
||||
|
public static void EncodeSuperblock( |
||||
|
Av1EncoderFrame<byte> source, |
||||
|
Av1EncoderFrame<byte> reconstruction, |
||||
|
Av1PictureControlSet picture, |
||||
|
Av1Superblock superblock, |
||||
|
Av1EncoderCoefficientBuffer coefficientBuffer, |
||||
|
Av1EncoderBlockWorkspace blockWorkspace) |
||||
|
=> Av1IntraSuperblockEncoder.Encode( |
||||
|
source, |
||||
|
reconstruction, |
||||
|
picture, |
||||
|
superblock, |
||||
|
coefficientBuffer, |
||||
|
blockWorkspace); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Encodes tiles stored as high-bit-depth samples.
|
||||
|
/// </summary>
|
||||
|
private readonly struct UInt16Operator : ITileEncodingOperator<ushort> |
||||
|
{ |
||||
|
/// <inheritdoc/>
|
||||
|
public static void EncodeSuperblock( |
||||
|
Av1EncoderFrame<ushort> source, |
||||
|
Av1EncoderFrame<ushort> reconstruction, |
||||
|
Av1PictureControlSet picture, |
||||
|
Av1Superblock superblock, |
||||
|
Av1EncoderCoefficientBuffer coefficientBuffer, |
||||
|
Av1EncoderBlockWorkspace blockWorkspace) |
||||
|
=> Av1IntraSuperblockEncoder.Encode( |
||||
|
source, |
||||
|
reconstruction, |
||||
|
picture, |
||||
|
superblock, |
||||
|
coefficientBuffer, |
||||
|
blockWorkspace); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,176 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Six Labors Split License.
|
||||
|
|
||||
|
using System.Buffers; |
||||
|
using SixLabors.ImageSharp.Formats.Heif.Av1.Entropy; |
||||
|
using SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit; |
||||
|
using SixLabors.ImageSharp.Formats.Heif.Av1.Tiling; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Pipeline; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Encodes and owns one range-coded all-intra tile payload.
|
||||
|
/// </summary>
|
||||
|
internal sealed partial class Av1IntraTileWriter : IAv1TileWriter, IDisposable |
||||
|
{ |
||||
|
private IMemoryOwner<byte>? tileData; |
||||
|
private readonly int tileDataLength; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="Av1IntraTileWriter"/> class for eight-bit samples.
|
||||
|
/// </summary>
|
||||
|
/// <param name="configuration">The configuration providing tile output memory.</param>
|
||||
|
/// <param name="source">The coded source frame.</param>
|
||||
|
/// <param name="reconstruction">The reconstructed frame updated during encoding.</param>
|
||||
|
/// <param name="picture">The frame coding and mode-information state.</param>
|
||||
|
/// <param name="coefficientBuffer">The frame-owned quantized coefficient and transform state.</param>
|
||||
|
/// <param name="superblockWorkspace">The reusable partition and final-block decision workspace.</param>
|
||||
|
/// <param name="blockWorkspace">The reusable block arithmetic workspace.</param>
|
||||
|
/// <param name="initialSize">The estimated encoded tile size in bytes.</param>
|
||||
|
public Av1IntraTileWriter( |
||||
|
Configuration configuration, |
||||
|
Av1EncoderFrame<byte> source, |
||||
|
Av1EncoderFrame<byte> reconstruction, |
||||
|
Av1PictureControlSet picture, |
||||
|
Av1EncoderCoefficientBuffer coefficientBuffer, |
||||
|
Av1EncoderSuperblockWorkspace superblockWorkspace, |
||||
|
Av1EncoderBlockWorkspace blockWorkspace, |
||||
|
int initialSize) |
||||
|
{ |
||||
|
this.tileData = Encode<byte, ByteOperator>( |
||||
|
configuration, |
||||
|
source, |
||||
|
reconstruction, |
||||
|
picture, |
||||
|
coefficientBuffer, |
||||
|
superblockWorkspace, |
||||
|
blockWorkspace, |
||||
|
initialSize, |
||||
|
out this.tileDataLength); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="Av1IntraTileWriter"/> class for high-bit-depth samples.
|
||||
|
/// </summary>
|
||||
|
/// <param name="configuration">The configuration providing tile output memory.</param>
|
||||
|
/// <param name="source">The coded source frame.</param>
|
||||
|
/// <param name="reconstruction">The reconstructed frame updated during encoding.</param>
|
||||
|
/// <param name="picture">The frame coding and mode-information state.</param>
|
||||
|
/// <param name="coefficientBuffer">The frame-owned quantized coefficient and transform state.</param>
|
||||
|
/// <param name="superblockWorkspace">The reusable partition and final-block decision workspace.</param>
|
||||
|
/// <param name="blockWorkspace">The reusable block arithmetic workspace.</param>
|
||||
|
/// <param name="initialSize">The estimated encoded tile size in bytes.</param>
|
||||
|
public Av1IntraTileWriter( |
||||
|
Configuration configuration, |
||||
|
Av1EncoderFrame<ushort> source, |
||||
|
Av1EncoderFrame<ushort> reconstruction, |
||||
|
Av1PictureControlSet picture, |
||||
|
Av1EncoderCoefficientBuffer coefficientBuffer, |
||||
|
Av1EncoderSuperblockWorkspace superblockWorkspace, |
||||
|
Av1EncoderBlockWorkspace blockWorkspace, |
||||
|
int initialSize) |
||||
|
{ |
||||
|
this.tileData = Encode<ushort, UInt16Operator>( |
||||
|
configuration, |
||||
|
source, |
||||
|
reconstruction, |
||||
|
picture, |
||||
|
coefficientBuffer, |
||||
|
superblockWorkspace, |
||||
|
blockWorkspace, |
||||
|
initialSize, |
||||
|
out this.tileDataLength); |
||||
|
} |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public ReadOnlySpan<byte> GetTileData(int tileNum) |
||||
|
{ |
||||
|
ObjectDisposedException.ThrowIf(this.tileData is null, this); |
||||
|
return this.tileData.Memory.Span[..this.tileDataLength]; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Returns the detached range-coded tile allocation to the configured allocator.
|
||||
|
/// </summary>
|
||||
|
public void Dispose() |
||||
|
{ |
||||
|
this.tileData?.Dispose(); |
||||
|
this.tileData = null; |
||||
|
} |
||||
|
|
||||
|
private static IMemoryOwner<byte> Encode<TSample, TOperator>( |
||||
|
Configuration configuration, |
||||
|
Av1EncoderFrame<TSample> source, |
||||
|
Av1EncoderFrame<TSample> reconstruction, |
||||
|
Av1PictureControlSet picture, |
||||
|
Av1EncoderCoefficientBuffer coefficientBuffer, |
||||
|
Av1EncoderSuperblockWorkspace superblockWorkspace, |
||||
|
Av1EncoderBlockWorkspace blockWorkspace, |
||||
|
int initialSize, |
||||
|
out int tileDataLength) |
||||
|
where TSample : unmanaged |
||||
|
where TOperator : struct, ITileEncodingOperator<TSample> |
||||
|
{ |
||||
|
ObuFrameHeader frameHeader = picture.Parent.FrameHeader; |
||||
|
ObuSequenceHeader sequenceHeader = picture.Sequence.SequenceHeader; |
||||
|
const ushort TileIndex = 0; |
||||
|
Av1TileInfo tile = new(0, 0, frameHeader); |
||||
|
Av1Superblock superblock = new() |
||||
|
{ |
||||
|
Workspace = superblockWorkspace, |
||||
|
TileInfo = tile |
||||
|
}; |
||||
|
|
||||
|
Point firstModeInfoPosition = new(tile.ModeInfoColumnStart, tile.ModeInfoRowStart); |
||||
|
Av1TileWriter.Av1EntropyCodingContext entropyContext = new() |
||||
|
{ |
||||
|
MacroBlock = new Av1MacroBlockD { Tile = tile }, |
||||
|
MacroBlockModeInfo = picture.GetMacroBlockModeInfo(firstModeInfoPosition) |
||||
|
}; |
||||
|
|
||||
|
using Av1SymbolEncoder writer = new( |
||||
|
configuration, |
||||
|
initialSize, |
||||
|
frameHeader.QuantizationParameters.BaseQIndex, |
||||
|
updateCdf: !frameHeader.DisableCdfUpdate); |
||||
|
|
||||
|
int superblockModeInfoSize = sequenceHeader.SuperblockModeInfoSize; |
||||
|
int superblockShift = sequenceHeader.SuperblockSizeLog2 - Av1Constants.ModeInfoSizeLog2; |
||||
|
for (int modeInfoRow = tile.ModeInfoRowStart; |
||||
|
modeInfoRow < tile.ModeInfoRowEnd; |
||||
|
modeInfoRow += superblockModeInfoSize) |
||||
|
{ |
||||
|
for (int modeInfoColumn = tile.ModeInfoColumnStart; |
||||
|
modeInfoColumn < tile.ModeInfoColumnEnd; |
||||
|
modeInfoColumn += superblockModeInfoSize) |
||||
|
{ |
||||
|
int superblockRow = modeInfoRow >> superblockShift; |
||||
|
int superblockColumn = modeInfoColumn >> superblockShift; |
||||
|
superblock.Index = (superblockRow * coefficientBuffer.SuperblockColumnCount) + superblockColumn; |
||||
|
entropyContext.SuperblockOrigin = new Point( |
||||
|
modeInfoColumn << Av1Constants.ModeInfoSizeLog2, |
||||
|
modeInfoRow << Av1Constants.ModeInfoSizeLog2); |
||||
|
|
||||
|
// Analyze immediately before entropy coding so the reusable decision workspace and reconstructed
|
||||
|
// neighbors remain synchronized without a second superblock-sized decision allocation.
|
||||
|
TOperator.EncodeSuperblock( |
||||
|
source, |
||||
|
reconstruction, |
||||
|
picture, |
||||
|
superblock, |
||||
|
coefficientBuffer, |
||||
|
blockWorkspace); |
||||
|
|
||||
|
Av1TileWriter.WriteSuperblock( |
||||
|
picture, |
||||
|
entropyContext, |
||||
|
writer, |
||||
|
superblock, |
||||
|
coefficientBuffer, |
||||
|
TileIndex); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return writer.Exit(out tileDataLength); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,200 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Six Labors Split License.
|
||||
|
|
||||
|
using System.Buffers; |
||||
|
using System.Runtime.CompilerServices; |
||||
|
using SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit; |
||||
|
using SixLabors.ImageSharp.Memory; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Tiling; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Owns mode information, segmentation data, and tile-neighbor contexts for one encoded AV1 picture.
|
||||
|
/// </summary>
|
||||
|
internal sealed class Av1EncoderPictureBuffer : IDisposable |
||||
|
{ |
||||
|
private readonly Av1EncoderModeInfoBuffer modeInfo; |
||||
|
private readonly IMemoryOwner<byte> stateStorage; |
||||
|
private readonly ByteMemoryManager<Av1PartitionContext> partitionContextMemory; |
||||
|
private readonly Av1NeighborArrayUnit<Av1PartitionContext>[] partitionContexts; |
||||
|
private readonly Av1NeighborArrayUnit<byte>[] lumaCoefficientContexts; |
||||
|
private readonly Av1NeighborArrayUnit<byte>[] blueCoefficientContexts; |
||||
|
private readonly Av1NeighborArrayUnit<byte>[] redCoefficientContexts; |
||||
|
private readonly Av1NeighborArrayUnit<byte>[] transformContexts; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="Av1EncoderPictureBuffer"/> class.
|
||||
|
/// </summary>
|
||||
|
/// <param name="configuration">The configuration providing picture-lifetime memory.</param>
|
||||
|
/// <param name="sequenceHeader">The sequence header defining superblock and chroma geometry.</param>
|
||||
|
/// <param name="frameHeader">The frame header defining dimensions and tiles.</param>
|
||||
|
/// <param name="width">The visible luma width.</param>
|
||||
|
/// <param name="height">The visible luma height.</param>
|
||||
|
public Av1EncoderPictureBuffer( |
||||
|
Configuration configuration, |
||||
|
ObuSequenceHeader sequenceHeader, |
||||
|
ObuFrameHeader frameHeader, |
||||
|
int width, |
||||
|
int height) |
||||
|
{ |
||||
|
const int ContextAlignmentLog2 = Av1Constants.MaxSuperBlockSizeLog2 - Av1Constants.ModeInfoSizeLog2; |
||||
|
this.modeInfo = new Av1EncoderModeInfoBuffer( |
||||
|
configuration, |
||||
|
width, |
||||
|
height, |
||||
|
disallow4x4AllFrames: true); |
||||
|
|
||||
|
int alignedModeInfoRowCount = Av1Math.AlignPowerOf2(this.modeInfo.ModeInfoRowCount, ContextAlignmentLog2); |
||||
|
int lumaLeftLength = alignedModeInfoRowCount; |
||||
|
int lumaTopLength = this.modeInfo.ModeInfoStride; |
||||
|
ObuColorConfig colorConfig = sequenceHeader.ColorConfig; |
||||
|
int chromaLeftLength = colorConfig.IsMonochrome |
||||
|
? 0 |
||||
|
: lumaLeftLength >> (colorConfig.SubSamplingY ? 1 : 0); |
||||
|
|
||||
|
int chromaTopLength = colorConfig.IsMonochrome |
||||
|
? 0 |
||||
|
: lumaTopLength >> (colorConfig.SubSamplingX ? 1 : 0); |
||||
|
|
||||
|
int tileCount = frameHeader.TilesInfo.TileColumnCount * frameHeader.TilesInfo.TileRowCount; |
||||
|
int lumaContextLength = checked(lumaLeftLength + lumaTopLength); |
||||
|
int chromaContextLength = checked(chromaLeftLength + chromaTopLength); |
||||
|
int byteContextLengthPerTile = checked((2 * lumaContextLength) + (2 * chromaContextLength)); |
||||
|
int partitionContextLength = checked(tileCount * lumaContextLength); |
||||
|
int segmentationLength = checked(this.modeInfo.ModeInfoColumnCount * this.modeInfo.ModeInfoRowCount); |
||||
|
int partitionContextSize = Unsafe.SizeOf<Av1PartitionContext>(); |
||||
|
int partitionStorageOffset = checked( |
||||
|
((segmentationLength + partitionContextSize - 1) / partitionContextSize) * partitionContextSize); |
||||
|
|
||||
|
int partitionStorageLength = checked( |
||||
|
partitionContextLength * Unsafe.SizeOf<Av1PartitionContext>()); |
||||
|
|
||||
|
int byteContextStorageOffset = checked(partitionStorageOffset + partitionStorageLength); |
||||
|
int stateStorageLength = checked(byteContextStorageOffset + (tileCount * byteContextLengthPerTile)); |
||||
|
|
||||
|
// Segmentation and every tile edge share one clean picture lifetime. The partition region begins at its
|
||||
|
// native alignment, while typed views keep the entropy writer independent from the packed byte owner.
|
||||
|
this.stateStorage = configuration.MemoryAllocator.Allocate<byte>( |
||||
|
stateStorageLength, |
||||
|
AllocationOptions.Clean); |
||||
|
|
||||
|
Memory<byte> stateStorage = this.stateStorage.Memory[..stateStorageLength]; |
||||
|
this.partitionContextMemory = new ByteMemoryManager<Av1PartitionContext>( |
||||
|
stateStorage.Slice(partitionStorageOffset, partitionStorageLength)); |
||||
|
|
||||
|
Memory<Av1PartitionContext> partitionStorage = this.partitionContextMemory.Memory; |
||||
|
Memory<byte> byteContextStorage = stateStorage[byteContextStorageOffset..]; |
||||
|
this.partitionContexts = new Av1NeighborArrayUnit<Av1PartitionContext>[tileCount]; |
||||
|
this.lumaCoefficientContexts = new Av1NeighborArrayUnit<byte>[tileCount]; |
||||
|
this.blueCoefficientContexts = new Av1NeighborArrayUnit<byte>[tileCount]; |
||||
|
this.redCoefficientContexts = new Av1NeighborArrayUnit<byte>[tileCount]; |
||||
|
this.transformContexts = new Av1NeighborArrayUnit<byte>[tileCount]; |
||||
|
int[][] cdefPreset = new int[tileCount][]; |
||||
|
int[] previousQIndex = new int[tileCount]; |
||||
|
for (int tileIndex = 0; tileIndex < tileCount; tileIndex++) |
||||
|
{ |
||||
|
this.partitionContexts[tileIndex] = new Av1NeighborArrayUnit<Av1PartitionContext>( |
||||
|
partitionStorage.Slice(tileIndex * lumaContextLength, lumaContextLength), |
||||
|
lumaLeftLength, |
||||
|
lumaTopLength) |
||||
|
{ |
||||
|
GranularityNormalLog2 = Av1Constants.ModeInfoSizeLog2 |
||||
|
}; |
||||
|
|
||||
|
int byteContextOffset = tileIndex * byteContextLengthPerTile; |
||||
|
this.lumaCoefficientContexts[tileIndex] = new Av1NeighborArrayUnit<byte>( |
||||
|
byteContextStorage.Slice(byteContextOffset, lumaContextLength), |
||||
|
lumaLeftLength, |
||||
|
lumaTopLength) |
||||
|
{ |
||||
|
GranularityNormalLog2 = Av1Constants.ModeInfoSizeLog2 |
||||
|
}; |
||||
|
|
||||
|
byteContextOffset += lumaContextLength; |
||||
|
this.blueCoefficientContexts[tileIndex] = new Av1NeighborArrayUnit<byte>( |
||||
|
byteContextStorage.Slice(byteContextOffset, chromaContextLength), |
||||
|
chromaLeftLength, |
||||
|
chromaTopLength) |
||||
|
{ |
||||
|
GranularityNormalLog2 = Av1Constants.ModeInfoSizeLog2 |
||||
|
}; |
||||
|
|
||||
|
byteContextOffset += chromaContextLength; |
||||
|
this.redCoefficientContexts[tileIndex] = new Av1NeighborArrayUnit<byte>( |
||||
|
byteContextStorage.Slice(byteContextOffset, chromaContextLength), |
||||
|
chromaLeftLength, |
||||
|
chromaTopLength) |
||||
|
{ |
||||
|
GranularityNormalLog2 = Av1Constants.ModeInfoSizeLog2 |
||||
|
}; |
||||
|
|
||||
|
byteContextOffset += chromaContextLength; |
||||
|
this.transformContexts[tileIndex] = new Av1NeighborArrayUnit<byte>( |
||||
|
byteContextStorage.Slice(byteContextOffset, lumaContextLength), |
||||
|
lumaLeftLength, |
||||
|
lumaTopLength) |
||||
|
{ |
||||
|
GranularityNormalLog2 = Av1Constants.ModeInfoSizeLog2 |
||||
|
}; |
||||
|
|
||||
|
cdefPreset[tileIndex] = [-1, -1, -1, -1]; |
||||
|
previousQIndex[tileIndex] = frameHeader.QuantizationParameters.BaseQIndex; |
||||
|
} |
||||
|
|
||||
|
this.Picture = new Av1PictureControlSet |
||||
|
{ |
||||
|
PartitionContexts = this.partitionContexts, |
||||
|
LuminanceDcSignLevelCoefficientNeighbors = this.lumaCoefficientContexts, |
||||
|
CbDcSignLevelCoefficientNeighbors = this.blueCoefficientContexts, |
||||
|
CrDcSignLevelCoefficientNeighbors = this.redCoefficientContexts, |
||||
|
TransformFunctionContexts = this.transformContexts, |
||||
|
Sequence = new Av1SequenceControlSet { SequenceHeader = sequenceHeader }, |
||||
|
Parent = new Av1PictureParentControlSet |
||||
|
{ |
||||
|
Common = new Av1EncoderCommon |
||||
|
{ |
||||
|
ModeInfoColumnCount = this.modeInfo.ModeInfoColumnCount, |
||||
|
ModeInfoRowCount = this.modeInfo.ModeInfoRowCount, |
||||
|
ModeInfoStride = this.modeInfo.ModeInfoStride, |
||||
|
FrameSize = frameHeader.FrameSize, |
||||
|
TilesInfo = frameHeader.TilesInfo |
||||
|
}, |
||||
|
FrameHeader = frameHeader, |
||||
|
PreviousQIndex = previousQIndex |
||||
|
}, |
||||
|
SegmentationNeighborMap = stateStorage[..segmentationLength], |
||||
|
ModeInfoGrid = this.modeInfo.Grid, |
||||
|
ModeInfoAllocation = this.modeInfo.Allocation, |
||||
|
ModeInfoStride = this.modeInfo.ModeInfoStride, |
||||
|
Disallow4x4AllFrames = this.modeInfo.Disallow4x4AllFrames, |
||||
|
CdefPreset = cdefPreset |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the non-owning picture state consumed by superblock analysis and tile writing.
|
||||
|
/// </summary>
|
||||
|
public Av1PictureControlSet Picture { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Returns every picture-lifetime allocation to the configured allocator.
|
||||
|
/// </summary>
|
||||
|
public void Dispose() |
||||
|
{ |
||||
|
foreach (Av1NeighborArrayUnit<Av1PartitionContext> context in this.partitionContexts) |
||||
|
{ |
||||
|
context.Dispose(); |
||||
|
} |
||||
|
|
||||
|
for (int tileIndex = 0; tileIndex < this.lumaCoefficientContexts.Length; tileIndex++) |
||||
|
{ |
||||
|
this.lumaCoefficientContexts[tileIndex].Dispose(); |
||||
|
this.blueCoefficientContexts[tileIndex].Dispose(); |
||||
|
this.redCoefficientContexts[tileIndex].Dispose(); |
||||
|
this.transformContexts[tileIndex].Dispose(); |
||||
|
} |
||||
|
|
||||
|
this.stateStorage.Dispose(); |
||||
|
this.modeInfo.Dispose(); |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue