Browse Source

Initial implementation of Mode Info block writing

pull/2633/head
Ynse Hoornenborg 2 years ago
parent
commit
e2286243a6
  1. 6
      src/ImageSharp/Formats/Heif/Av1/Av1BlockSizeExtensions.cs
  2. 4
      src/ImageSharp/Formats/Heif/Av1/Entropy/Av1DefaultDistributions.cs
  3. 10
      src/ImageSharp/Formats/Heif/Av1/Entropy/Av1SymbolDecoder.cs
  4. 84
      src/ImageSharp/Formats/Heif/Av1/Entropy/Av1SymbolEncoder.cs
  5. 2
      src/ImageSharp/Formats/Heif/Av1/Entropy/Av1SymbolWriter.cs
  6. 1
      src/ImageSharp/Formats/Heif/Av1/Prediction/Av1PredictionMode.cs
  7. 4
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1EncoderBlockModeInfo.cs
  8. 2
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1EncoderBlockStruct.cs
  9. 13
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1EncoderPredictionUnit.cs
  10. 42
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1MacroBlockD.cs
  11. 9
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1ModeInfo.cs
  12. 2
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1NeighborArrayUnit.cs
  13. 6
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1PartitionContext.cs
  14. 45
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1PictureControlSet.cs
  15. 526
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileWriter.cs

6
src/ImageSharp/Formats/Heif/Av1/Av1BlockSizeExtensions.cs

@ -65,6 +65,12 @@ internal static class Av1BlockSizeExtensions
public static int Get4x4HighCount(this Av1BlockSize blockSize) => SizeHigh[(int)blockSize];
/// <summary>
/// Gets the <see cref="Av1BlockSize"/> given by the Log2 of the width and height.
/// </summary>
/// <param name="widthLog2">Log2 of the width value.</param>
/// <param name="heightLog2">Log2 of the height value.</param>
/// <returns>The <see cref="Av1BlockSize"/>.</returns>
public static Av1BlockSize FromWidthAndHeight(uint widthLog2, uint heightLog2) => HeightWidthToSize[heightLog2][widthLog2];
/// <summary>

4
src/ImageSharp/Formats/Heif/Av1/Entropy/Av1DefaultDistributions.cs

@ -2003,9 +2003,9 @@ internal static class Av1DefaultDistributions
]
];
public static Av1Distribution ChromeForLumaSign => new(1418, 2123, 13340, 18405, 26972, 28343, 32294);
public static Av1Distribution ChromaFromLumaSign => new(1418, 2123, 13340, 18405, 26972, 28343, 32294);
public static Av1Distribution[] ChromeForLumaAlpha =>
public static Av1Distribution[] ChromaFromLumaAlpha =>
[
new(7637, 20719, 31401, 32481, 32657, 32688, 32692, 32696, 32700, 32704, 32708, 32712, 32716, 32720, 32724),
new(14365, 23603, 28135, 31168, 32167, 32395, 32487, 32573, 32620, 32647, 32668, 32672, 32676, 32680, 32684),

10
src/ImageSharp/Formats/Heif/Av1/Entropy/Av1SymbolDecoder.cs

@ -41,8 +41,8 @@ internal ref struct Av1SymbolDecoder
private readonly Av1Distribution[][][] coefficientsBaseRange;
private readonly Av1Distribution[][] transformBlockSkip;
private readonly Av1Distribution[][][] endOfBlockExtra;
private readonly Av1Distribution chromeForLumaSign = Av1DefaultDistributions.ChromeForLumaSign;
private readonly Av1Distribution[] chromeForLumaAlpha = Av1DefaultDistributions.ChromeForLumaAlpha;
private readonly Av1Distribution chromaFromLumaSign = Av1DefaultDistributions.ChromaFromLumaSign;
private readonly Av1Distribution[] chromaFromLumaAlpha = Av1DefaultDistributions.ChromaFromLumaAlpha;
private readonly Av1Distribution[][][] intraExtendedTransform = Av1DefaultDistributions.IntraExtendedTransform;
private readonly Configuration configuration;
private Av1SymbolReader reader;
@ -248,21 +248,21 @@ internal ref struct Av1SymbolDecoder
public int ReadChromFromLumaSign()
{
ref Av1SymbolReader r = ref this.reader;
return r.ReadSymbol(this.chromeForLumaSign);
return r.ReadSymbol(this.chromaFromLumaSign);
}
public int ReadChromaFromLumaAlphaU(int jointSignPlus1)
{
ref Av1SymbolReader r = ref this.reader;
int context = jointSignPlus1 - 3;
return r.ReadSymbol(this.chromeForLumaAlpha[context]);
return r.ReadSymbol(this.chromaFromLumaAlpha[context]);
}
public int ReadChromaFromLumaAlphaV(int jointSignPlus1)
{
ref Av1SymbolReader r = ref this.reader;
int context = AlphaVContexts[jointSignPlus1];
return r.ReadSymbol(this.chromeForLumaAlpha[context]);
return r.ReadSymbol(this.chromaFromLumaAlpha[context]);
}
/// <summary>

84
src/ImageSharp/Formats/Heif/Av1/Entropy/Av1SymbolEncoder.cs

@ -22,18 +22,25 @@ internal class Av1SymbolEncoder : IDisposable
private readonly Av1Distribution tileIntraBlockCopy = Av1DefaultDistributions.IntraBlockCopy;
private readonly Av1Distribution[] tilePartitionTypes = Av1DefaultDistributions.PartitionTypes;
private readonly Av1Distribution[][] keyFrameYMode = Av1DefaultDistributions.KeyFrameYMode;
private readonly Av1Distribution[][] uvMode = Av1DefaultDistributions.UvMode;
private readonly Av1Distribution[][] transformBlockSkip;
private readonly Av1Distribution[][][] endOfBlockFlag;
private readonly Av1Distribution[][][] coefficientsBaseRange;
private readonly Av1Distribution[][][] coefficientsBase;
private readonly Av1Distribution[][][] coefficientsBaseEndOfBlock;
private readonly Av1Distribution[] filterIntra = Av1DefaultDistributions.FilterIntra;
private readonly Av1Distribution filterIntraMode = Av1DefaultDistributions.FilterIntraMode;
private readonly Av1Distribution deltaQuantizerAbsolute = Av1DefaultDistributions.DeltaQuantizerAbsolute;
private readonly Av1Distribution[][] dcSign;
private readonly Av1Distribution[][][] endOfBlockExtra;
private readonly Av1Distribution[][][] intraExtendedTransform = Av1DefaultDistributions.IntraExtendedTransform;
private readonly Av1Distribution[] segmentId = Av1DefaultDistributions.SegmentId;
private readonly Av1Distribution[] angleDelta = Av1DefaultDistributions.AngleDelta;
private readonly Av1Distribution[] skip = Av1DefaultDistributions.Skip;
private readonly Av1Distribution[] skipMode = Av1DefaultDistributions.SkipMode;
private readonly Av1Distribution chromaFromLumaSign = Av1DefaultDistributions.ChromaFromLumaSign;
private readonly Av1Distribution[] chromaFromLumaAlpha = Av1DefaultDistributions.ChromaFromLumaAlpha;
private bool isDisposed;
private readonly Configuration configuration;
private Av1SymbolWriter writer;
@ -332,9 +339,86 @@ internal class Av1SymbolEncoder : IDisposable
w.WriteSymbol(skip, this.skipMode[context]);
}
internal void WriteFilterIntra(Av1FilterIntraMode filterIntraMode, Av1BlockSize blockSize)
{
ref Av1SymbolWriter w = ref this.writer;
w.WriteSymbol(filterIntraMode != Av1FilterIntraMode.AllFilterIntraModes, this.filterIntra[(int)blockSize]);
}
internal void WriteFilterIntraMode(Av1FilterIntraMode filterIntraMode)
{
ref Av1SymbolWriter w = ref this.writer;
w.WriteSymbol((int)filterIntraMode, this.filterIntraMode);
}
internal void WriteDeltaQIndex(int deltaQindex)
{
ref Av1SymbolWriter w = ref this.writer;
bool sign = deltaQindex < 0;
int abs = Math.Abs(deltaQindex);
bool smallval = abs < Av1Constants.DeltaQuantizerSmall;
w.WriteSymbol(Math.Min(abs, Av1Constants.DeltaQuantizerSmall), this.deltaQuantizerAbsolute);
if (!smallval)
{
int rem_bits = Av1Math.MostSignificantBit((uint)(abs - 1)) - 1;
int threshold = (1 << rem_bits) + 1;
w.WriteLiteral((uint)(rem_bits - 1), 3);
w.WriteLiteral((uint)(abs - threshold), rem_bits);
}
if (abs > 0)
{
w.WriteLiteral(sign);
}
}
internal void WriteLumaMode(Av1PredictionMode lumaMode, byte topContext, byte leftContext)
{
ref Av1SymbolWriter w = ref this.writer;
w.WriteSymbol((int)lumaMode, this.keyFrameYMode[topContext][leftContext]);
}
internal void WriteAngleDelta(int angleDelta, Av1PredictionMode context)
{
ref Av1SymbolWriter w = ref this.writer;
w.WriteSymbol(angleDelta, this.angleDelta[context - Av1PredictionMode.Vertical]);
}
internal void WriteCdefStrength(int cdefStrength, int bitCount)
{
ref Av1SymbolWriter w = ref this.writer;
w.WriteLiteral((uint)cdefStrength, bitCount);
}
internal void WriteChromaMode(Av1PredictionMode chromaMode, bool isChromaFromLumaAllowed, Av1PredictionMode lumaMode)
{
ref Av1SymbolWriter w = ref this.writer;
int cflAllowed = isChromaFromLumaAllowed ? 1 : 0;
w.WriteSymbol((int)chromaMode, this.uvMode[cflAllowed][(int)lumaMode]);
}
internal void WriteChromaFromLumaAlphas(int chromaFromLumaIndex, int joinedSign)
{
ref Av1SymbolWriter w = ref this.writer;
w.WriteSymbol(joinedSign, this.chromaFromLumaSign);
// Magnitudes are only signaled for nonzero codes.
int signU = ((joinedSign + 1) * 11) >> 5;
if (signU != 0)
{
int contextU = chromaFromLumaIndex - 2;
int indexU = chromaFromLumaIndex >> Av1Constants.ChromaFromLumaAlphabetSizeLog2;
w.WriteSymbol(indexU, this.chromaFromLumaAlpha[contextU]);
}
int signV = (joinedSign + 1) - (3 * signU);
if (signV != 0)
{
int contextV = (signV * 3) - signU - 3;
int indexV = chromaFromLumaIndex & ((1 << Av1Constants.ChromaFromLumaAlphabetSizeLog2) - 1);
w.WriteSymbol(indexV, this.chromaFromLumaAlpha[contextV]);
}
}
}

2
src/ImageSharp/Formats/Heif/Av1/Entropy/Av1SymbolWriter.cs

@ -38,6 +38,8 @@ internal class Av1SymbolWriter : IDisposable
distribution.Update(symbol);
}
public void WriteLiteral(bool value) => this.WriteLiteral(value ? 1u : 0u, 1);
public void WriteLiteral(uint value, int bitCount)
{
const uint p = 0x4000U; // (0x7FFFFFU - (128 << 15) + 128) >> 8;

1
src/ImageSharp/Formats/Heif/Av1/Prediction/Av1PredictionMode.cs

@ -23,5 +23,6 @@ internal enum Av1PredictionMode
IntraModeStart = DC,
IntraModeEnd = Paeth + 1,
IntraModes = Paeth,
UvIntraModes = UvChromaFromLuma + 1,
IntraInvalid = 25,
}

4
src/ImageSharp/Formats/Heif/Av1/Tiling/Av1EncoderBlockModeInfo.cs

@ -24,4 +24,8 @@ internal class Av1EncoderBlockModeInfo
public int SegmentId { get; }
public int TransformDepth { get; internal set; }
public Av1PredictionMode Mode { get; internal set; }
public Av1PredictionMode UvMode { get; internal set; }
}

2
src/ImageSharp/Formats/Heif/Av1/Tiling/Av1EncoderBlockStruct.cs

@ -18,4 +18,6 @@ internal class Av1EncoderBlockStruct
public Av1FilterIntraMode FilterIntraMode { get; set; }
public required int[] PaletteSize { get; internal set; }
public required Av1EncoderPredictionUnit[] PredictionUnits { get; internal set; }
}

13
src/ImageSharp/Formats/Heif/Av1/Tiling/Av1EncoderPredictionUnit.cs

@ -0,0 +1,13 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Tiling;
internal class Av1EncoderPredictionUnit
{
public required byte[] AngleDelta { get; set; }
public int ChromaFromLumaIndex { get; internal set; }
public int ChromaFromLumaSigns { get; internal set; }
}

42
src/ImageSharp/Formats/Heif/Av1/Tiling/Av1MacroBlockD.cs

@ -5,15 +5,51 @@ namespace SixLabors.ImageSharp.Formats.Heif.Av1.Tiling;
internal class Av1MacroBlockD
{
public required Av1BlockModeInfo ModeInfo { get; internal set; }
private Av1ModeInfo[] modeInfo = [];
public required Span<Av1ModeInfo> ModeInfo
{
get => this.modeInfo;
internal set
{
this.modeInfo = new Av1ModeInfo[value.Length];
value.CopyTo(this.modeInfo);
}
}
public required Av1TileInfo Tile { get; internal set; }
public bool IsUpAvailable { get; }
public bool IsUpAvailable { get; internal set; }
public bool IsLeftAvailable { get; }
public bool IsLeftAvailable { get; internal set; }
public Av1MacroBlockModeInfo? AboveMacroBlock { get; internal set; }
public Av1MacroBlockModeInfo? LeftMacroBlock { get; internal set; }
public int ModeInfoStride { get; internal set; }
/// <summary>
/// Gets or sets the number of macro blocks until the top edge.
/// </summary>
public int ToTopEdge { get; internal set; }
/// <summary>
/// Gets or sets the number of macro blocks until the bottom edge.
/// </summary>
public int ToBottomEdge { get; internal set; }
/// <summary>
/// Gets or sets the number of macro blocks until the left edge.
/// </summary>
public int ToLeftEdge { get; internal set; }
/// <summary>
/// Gets or sets the number of macro blocks until the right edge.
/// </summary>
public int ToRightEdge { get; internal set; }
public Size N8Size { get; internal set; }
public bool IsSecondRectangle { get; internal set; }
}

9
src/ImageSharp/Formats/Heif/Av1/Tiling/Av1ModeInfo.cs

@ -0,0 +1,9 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Tiling;
internal class Av1ModeInfo
{
public required Av1MacroBlockModeInfo MacroBlockModeInfo { get; internal set; }
}

2
src/ImageSharp/Formats/Heif/Av1/Tiling/Av1NeighborArrayUnit.cs

@ -165,4 +165,6 @@ internal class Av1NeighborArrayUnit<T>
}
}
}
internal void UnitModeWrite(Span<byte> dcSignSpan, Point blockOrigin, Size blockSize, Av1NeighborArrayUnit<Av1PartitionContext>.UnitMask unitMask) => throw new NotImplementedException();
}

6
src/ImageSharp/Formats/Heif/Av1/Tiling/Av1PartitionContext.cs

@ -19,6 +19,12 @@ internal struct Av1PartitionContext : IMinMaxValue<Av1PartitionContext>
// Mask to extract ModeInfo offset within max ModeInfoBlock
public const int Mask = (1 << (7 - 2)) - 1;
public Av1PartitionContext(byte above, byte left)
{
this.Above = above;
this.Left = left;
}
public static Av1PartitionContext MaxValue => throw new NotImplementedException();
public static Av1PartitionContext MinValue => throw new NotImplementedException();

45
src/ImageSharp/Formats/Heif/Av1/Tiling/Av1PictureControlSet.cs

@ -1,6 +1,8 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System;
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Tiling;
internal class Av1PictureControlSet
@ -21,7 +23,48 @@ internal class Av1PictureControlSet
public required byte[] SegmentationNeighborMap { get; internal set; }
public required Av1BlockModeInfo[] ModeInfoGrid { get; internal set; }
public Av1ModeInfo[][] ModeInfoGrid { get; } = [];
public required Av1ModeInfo[] Mip { get; internal set; }
public int ModeInfoStride { get; internal set; }
// true if 4x4 blocks are disallowed for all frames, and NSQ is disabled (since granularity is
// needed for 8x8 NSQ blocks). Used to compute the offset for mip.
public bool Disallow4x4AllFrames { get; internal set; }
public required int[][] CdefPreset { get; internal set; }
public Span<Av1ModeInfo> GetFromModeInfoGrid(Point position)
=> this.ModeInfoGrid[(position.Y * this.ModeInfoStride) + position.X];
public void SetModeInfoGridRow(Point position, Span<Av1ModeInfo> span)
=> this.SetModeInfoGridRow((position.Y * this.ModeInfoStride) + position.X, span);
public void SetModeInfoGridRow(int offset, Span<Av1ModeInfo> span)
{
this.ModeInfoGrid[offset] = new Av1ModeInfo[span.Length];
span.CopyTo(this.ModeInfoGrid[offset]);
}
/// <summary>
/// SVT: get_mbmi
/// </summary>
internal Av1MacroBlockModeInfo GetMacroBlockModeInfo(Point blockOrigin)
{
int modeInfoStride = this.ModeInfoStride;
int offset = (blockOrigin.Y * modeInfoStride) + blockOrigin.X;
// Reset the mi_grid (needs to be done here in case it was changed for NSQ blocks during MD - svt_aom_init_xd())
// mip offset may be different from grid offset when 4x4 blocks are disallowed
int disallow4x4 = this.Disallow4x4AllFrames ? 1 : 0;
int mipOffset = ((blockOrigin.Y >> disallow4x4) * (modeInfoStride >> disallow4x4)) + (blockOrigin.X >> disallow4x4);
this.SetModeInfoGridRow(offset, ((Span<Av1ModeInfo>)this.Mip)[mipOffset..]);
// use idx 0 as that's the first MacroBlockModeInfo in the block.
Av1ModeInfo modeInfo = this.ModeInfoGrid[offset][0];
return modeInfo.MacroBlockModeInfo;
}
/// <summary>
/// SVT: svt_av1_update_segmentation_map

526
src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileWriter.cs

@ -12,6 +12,37 @@ namespace SixLabors.ImageSharp.Formats.Heif.Av1.Tiling;
internal partial class Av1TileWriter
{
// Generates 5 bit field in which each bit set to 1 represents
// a BlockSize partition 11111 means we split 128x128, 64x64, 32x32, 16x16
// and 8x8. 10000 means we just split the 128x128 to 64x64
private static readonly Av1PartitionContext[] PartitionContextLookup =
[
new(31, 31), // 4X4 - {0b11111, 0b11111}
new(31, 30), // 4X8 - {0b11111, 0b11110}
new(30, 31), // 8X4 - {0b11110, 0b11111}
new(30, 30), // 8X8 - {0b11110, 0b11110}
new(30, 28), // 8X16 - {0b11110, 0b11100}
new(28, 30), // 16X8 - {0b11100, 0b11110}
new(28, 28), // 16X16 - {0b11100, 0b11100}
new(28, 24), // 16X32 - {0b11100, 0b11000}
new(24, 28), // 32X16 - {0b11000, 0b11100}
new(24, 24), // 32X32 - {0b11000, 0b11000}
new(24, 16), // 32X64 - {0b11000, 0b10000}
new(16, 24), // 64X32 - {0b10000, 0b11000}
new(16, 16), // 64X64 - {0b10000, 0b10000}
new(16, 0), // 64X128- {0b10000, 0b00000}
new(0, 16), // 128X64- {0b00000, 0b10000}
new(0, 0), // 128X128-{0b00000, 0b00000}
new(31, 28), // 4X16 - {0b11111, 0b11100}
new(28, 31), // 16X4 - {0b11100, 0b11111}
new(30, 24), // 8X32 - {0b11110, 0b11000}
new(24, 30), // 32X8 - {0b11000, 0b11110}
new(28, 16), // 16X64 - {0b11100, 0b10000}
new(16, 28), // 64X16 - {0b10000, 0b11100}
];
private static readonly byte[] IntraModeContextLookup = [0, 1, 2, 3, 4, 4, 4, 4, 3, 0, 1, 2, 0];
/// <summary>
/// SVT: svt_aom_write_sb
/// </summary>
@ -24,11 +55,11 @@ internal partial class Av1TileWriter
ushort tileIndex)
{
Av1SequenceControlSet scs = pcs.Sequence;
Av1NeighborArrayUnit<Av1PartitionContext> partition_context_na = pcs.PartitionContexts[tileIndex];
Av1NeighborArrayUnit<Av1PartitionContext> partitionContextNeighbors = pcs.PartitionContexts[tileIndex];
// CU Varaiables
int blk_index = 0;
uint final_blk_index = 0;
int blockIndex = 0;
uint finalBlockIndex = 0;
ec_ctx.CodedAreaSuperblock = 0;
ec_ctx.CodedAreaSuperblockUv = 0;
@ -37,8 +68,8 @@ internal partial class Av1TileWriter
do
{
bool code_blk_cond = true; // Code cu only if it is inside the picture
Av1EncoderBlockStruct blk_ptr = superblock.FinalBlocks[final_blk_index];
Av1BlockGeometry blk_geom = Av1BlockGeometryFactory.GetBlockGeometryByModeDecisionScanIndex(blk_index);
Av1EncoderBlockStruct blk_ptr = superblock.FinalBlocks[finalBlockIndex];
Av1BlockGeometry blk_geom = Av1BlockGeometryFactory.GetBlockGeometryByModeDecisionScanIndex(blockIndex);
Av1BlockSize bsize = blk_geom.BlockSize;
Point blockOrigin = blk_geom.Origin;
@ -98,17 +129,16 @@ internal partial class Av1TileWriter
// Code Split Flag
EncodePartition(
pcs,
ec_ctx,
writer,
ref writer,
bsize,
superblock.CodingUnitPartitionTypes[blk_index],
superblock.CodingUnitPartitionTypes[blockIndex],
blockOrigin,
partition_context_na);
partitionContextNeighbors);
}
// assert(blk_geom.Shape == PART_N);
Guard.IsTrue(Av1Math.Implies(bsize == Av1BlockSize.Block4x4, superblock.CodingUnitPartitionTypes[blk_index] == Av1PartitionType.None), nameof(bsize), string.Empty);
switch (superblock.CodingUnitPartitionTypes[blk_index])
Guard.IsTrue(Av1Math.Implies(bsize == Av1BlockSize.Block4x4, superblock.CodingUnitPartitionTypes[blockIndex] == Av1PartitionType.None), nameof(bsize), string.Empty);
switch (superblock.CodingUnitPartitionTypes[blockIndex])
{
case Av1PartitionType.None:
WriteModesBlock(pcs, ec_ctx, ref writer, superblock, blk_ptr, tileIndex, frameBuffer);
@ -119,8 +149,8 @@ internal partial class Av1TileWriter
if (mi_row + hbs < cm.ModeInfoRowCount)
{
final_blk_index++;
blk_ptr = superblock.FinalBlocks[final_blk_index];
finalBlockIndex++;
blk_ptr = superblock.FinalBlocks[finalBlockIndex];
WriteModesBlock(pcs, ec_ctx, ref writer, superblock, blk_ptr, tileIndex, frameBuffer);
}
@ -130,8 +160,8 @@ internal partial class Av1TileWriter
WriteModesBlock(pcs, ec_ctx, ref writer, superblock, blk_ptr, tileIndex, frameBuffer);
if (mi_col + hbs < cm.ModeInfoColumnCount)
{
final_blk_index++;
blk_ptr = superblock.FinalBlocks[final_blk_index];
finalBlockIndex++;
blk_ptr = superblock.FinalBlocks[finalBlockIndex];
WriteModesBlock(pcs, ec_ctx, ref writer, superblock, blk_ptr, tileIndex, frameBuffer);
}
@ -141,48 +171,48 @@ internal partial class Av1TileWriter
case Av1PartitionType.HorizontalA:
WriteModesBlock(pcs, ec_ctx, ref writer, superblock, blk_ptr, tileIndex, frameBuffer);
final_blk_index++;
blk_ptr = superblock.FinalBlocks[final_blk_index];
finalBlockIndex++;
blk_ptr = superblock.FinalBlocks[finalBlockIndex];
WriteModesBlock(pcs, ec_ctx, ref writer, superblock, blk_ptr, tileIndex, frameBuffer);
final_blk_index++;
blk_ptr = superblock.FinalBlocks[final_blk_index];
finalBlockIndex++;
blk_ptr = superblock.FinalBlocks[finalBlockIndex];
WriteModesBlock(pcs, ec_ctx, ref writer, superblock, blk_ptr, tileIndex, frameBuffer);
break;
case Av1PartitionType.HorizontalB:
WriteModesBlock(pcs, ec_ctx, ref writer, superblock, blk_ptr, tileIndex, frameBuffer);
final_blk_index++;
blk_ptr = superblock.FinalBlocks[final_blk_index];
finalBlockIndex++;
blk_ptr = superblock.FinalBlocks[finalBlockIndex];
WriteModesBlock(pcs, ec_ctx, ref writer, superblock, blk_ptr, tileIndex, frameBuffer);
final_blk_index++;
blk_ptr = superblock.FinalBlocks[final_blk_index];
finalBlockIndex++;
blk_ptr = superblock.FinalBlocks[finalBlockIndex];
WriteModesBlock(pcs, ec_ctx, ref writer, superblock, blk_ptr, tileIndex, frameBuffer);
break;
case Av1PartitionType.VerticalA:
WriteModesBlock(pcs, ec_ctx, ref writer, superblock, blk_ptr, tileIndex, frameBuffer);
final_blk_index++;
blk_ptr = superblock.FinalBlocks[final_blk_index];
finalBlockIndex++;
blk_ptr = superblock.FinalBlocks[finalBlockIndex];
WriteModesBlock(pcs, ec_ctx, ref writer, superblock, blk_ptr, tileIndex, frameBuffer);
final_blk_index++;
blk_ptr = superblock.FinalBlocks[final_blk_index];
finalBlockIndex++;
blk_ptr = superblock.FinalBlocks[finalBlockIndex];
WriteModesBlock(pcs, ec_ctx, ref writer, superblock, blk_ptr, tileIndex, frameBuffer);
break;
case Av1PartitionType.VerticalB:
WriteModesBlock(pcs, ec_ctx, ref writer, superblock, blk_ptr, tileIndex, frameBuffer);
final_blk_index++;
blk_ptr = superblock.FinalBlocks[final_blk_index];
finalBlockIndex++;
blk_ptr = superblock.FinalBlocks[finalBlockIndex];
WriteModesBlock(pcs, ec_ctx, ref writer, superblock, blk_ptr, tileIndex, frameBuffer);
final_blk_index++;
blk_ptr = superblock.FinalBlocks[final_blk_index];
finalBlockIndex++;
blk_ptr = superblock.FinalBlocks[finalBlockIndex];
WriteModesBlock(pcs, ec_ctx, ref writer, superblock, blk_ptr, tileIndex, frameBuffer);
break;
@ -200,8 +230,8 @@ internal partial class Av1TileWriter
if (i > 0)
{
final_blk_index++;
blk_ptr = superblock.FinalBlocks[final_blk_index];
finalBlockIndex++;
blk_ptr = superblock.FinalBlocks[finalBlockIndex];
}
WriteModesBlock(pcs, ec_ctx, ref writer, superblock, blk_ptr, tileIndex, frameBuffer);
@ -222,8 +252,8 @@ internal partial class Av1TileWriter
if (i > 0)
{
final_blk_index++;
blk_ptr = superblock.FinalBlocks[final_blk_index];
finalBlockIndex++;
blk_ptr = superblock.FinalBlocks[finalBlockIndex];
}
WriteModesBlock(pcs, ec_ctx, ref writer, superblock, blk_ptr, tileIndex, frameBuffer);
@ -232,26 +262,24 @@ internal partial class Av1TileWriter
break;
}
if (superblock.CodingUnitPartitionTypes[blk_index] != Av1PartitionType.Split)
if (superblock.CodingUnitPartitionTypes[blockIndex] != Av1PartitionType.Split)
{
final_blk_index++;
blk_index += blk_geom.NextDepthOffset;
finalBlockIndex++;
blockIndex += blk_geom.NextDepthOffset;
}
else
{
blk_index += blk_geom.Depth1Offset;
blockIndex += blk_geom.Depth1Offset;
}
}
else
{
blk_index += blk_geom.Depth1Offset;
blockIndex += blk_geom.Depth1Offset;
}
}
while (blk_index < scs.MaxBlockCount);
while (blockIndex < scs.MaxBlockCount);
}
private static void EncodePartition(Av1PictureControlSet pcs, Av1EntropyCodingContext ec_ctx, Av1SymbolEncoder writer, Av1BlockSize bsize, object value, Point blockOrigin, Av1NeighborArrayUnit<Av1PartitionContext> partition_context_na) => throw new NotImplementedException();
/// <summary>
/// SVT: encode_partition_av1
/// </summary>
@ -332,15 +360,14 @@ internal partial class Av1TileWriter
{
Av1SequenceControlSet scs = pcs.Sequence;
ObuFrameHeader frm_hdr = pcs.Parent.FrameHeader;
/*
Av1NeighborArrayUnit<byte> luma_dc_sign_level_coeff_na = pcs.LuminanceDcSignLevelCoefficientNeighbors[tile_idx];
Av1NeighborArrayUnit<byte> cr_dc_sign_level_coeff_na = pcs.CrDcSignLevelCoefficientNeighbors[tile_idx];
Av1NeighborArrayUnit<byte> cb_dc_sign_level_coeff_na = pcs.CbDcSignLevelCoefficientNeighbors[tile_idx];
Av1NeighborArrayUnit<byte> txfm_context_array = pcs.TransformFunctionContexts[tile_idx];
Av1BlockGeometry blockGeometry = GetBlockGeometryMds(blk_ptr.ModeDecisionScanIndex);
Av1BlockGeometry blockGeometry = Av1BlockGeometryFactory.GetBlockGeometryByModeDecisionScanIndex(blk_ptr.ModeDecisionScanIndex);
Point blockOrigin = Point.Add(entropyCodingContext.SuperblockOrigin, (Size)blockGeometry.Origin);
Av1BlockSize blockSize = blockGeometry.BlockSize;
Av1MacroBlockModeInfo macroBlockModeInfo = GetMacroBlockModeInfo(pcs, blockOrigin);
Av1MacroBlockModeInfo macroBlockModeInfo = pcs.GetMacroBlockModeInfo(blockOrigin);
bool skipWritingCoefficients = macroBlockModeInfo.Block.Skip;
entropyCodingContext.MacroBlockModeInfo = macroBlockModeInfo;
@ -359,7 +386,7 @@ internal partial class Av1TileWriter
if (blk_ptr.MacroBlock.IsUpAvailable)
{
blk_ptr.MacroBlock.AboveMacroBlock = blk_ptr.MacroBlock.ModeInfo[-mi_stride].mbmi;
blk_ptr.MacroBlock.AboveMacroBlock = blk_ptr.MacroBlock.ModeInfo[-mi_stride].MacroBlockModeInfo;
}
else
{
@ -368,25 +395,21 @@ internal partial class Av1TileWriter
if (blk_ptr.MacroBlock.IsLeftAvailable)
{
blk_ptr.MacroBlock.LeftMacroBlock = blk_ptr.MacroBlock.ModeInfo[-1].mbmi;
blk_ptr.MacroBlock.LeftMacroBlock = blk_ptr.MacroBlock.ModeInfo[-1].MacroBlockModeInfo;
}
else
{
blk_ptr.MacroBlock.LeftMacroBlock = null;
}
blk_ptr.MacroBlock.tile_ctx = frame_context;
int bw = blockSize.GetWidth();
int bh = blockSize.GetHeight();
set_mi_row_col(
// Not required, part of Av1SymbolEncoder.
// blk_ptr.MacroBlock.tile_ctx = frame_context;
SetModeInfoRowAndColumn(
pcs,
blk_ptr.MacroBlock,
blk_ptr.MacroBlock.Tile,
mi_row,
bh,
mi_col,
bw,
modeInfoPosition,
blockSize,
mi_stride,
pcs.Parent.Common.ModeInfoRowCount,
pcs.Parent.Common.ModeInfoColumnCount);
@ -394,7 +417,6 @@ internal partial class Av1TileWriter
// if (pcs.slice_type == I_SLICE)
// We implement only INTRA frames.
{
// const int32_t skip = write_skip(cm, xd, mbmi->segment_id, mi, w)
if (pcs.Parent.FrameHeader.SegmentationParameters.Enabled && pcs.Parent.FrameHeader.SegmentationParameters.SegmentIdPrecedesSkip)
{
@ -413,7 +435,6 @@ internal partial class Av1TileWriter
pcs,
ref writer,
tile_idx,
blk_ptr.MacroBlock,
skipWritingCoefficients,
blockOrigin << Av1Constants.ModeInfoSizeLog2);
@ -434,8 +455,8 @@ internal partial class Av1TileWriter
}
Av1PredictionMode intra_luma_mode = macroBlockModeInfo.Block.Mode;
uint intra_chroma_mode = macroBlockModeInfo.Block.UvMode;
if (svt_aom_allow_intrabc(pcs.Parent.FrameHeader, pcs.Parent.SliceType))
Av1PredictionMode intra_chroma_mode = macroBlockModeInfo.Block.UvMode;
if (IsIntraBlockCopyAllowed(pcs.Parent.FrameHeader/*, pcs.Parent.SliceType*/))
{
WriteIntraBlockCopyInfo(ref writer, macroBlockModeInfo, blk_ptr);
}
@ -460,10 +481,10 @@ internal partial class Av1TileWriter
}
}
if (!macroBlockModeInfo.Block.UseIntraBlockCopy && svt_aom_allow_palette(frm_hdr.AllowScreenContentTools, blockGeometry.BlockSize))
if (!macroBlockModeInfo.Block.UseIntraBlockCopy && IsPaletteAllowed(frm_hdr.AllowScreenContentTools, blockGeometry.BlockSize))
{
WritePaletteModeInfo(
pcs.Parent,
scs,
ref writer,
macroBlockModeInfo,
blk_ptr,
@ -472,10 +493,9 @@ internal partial class Av1TileWriter
}
if (!macroBlockModeInfo.Block.UseIntraBlockCopy &&
svt_aom_filter_intra_allowed(
scs.SequenceHeader.FilterIntraLevel, blockSize, blk_ptr.PaletteSize[0], intra_luma_mode))
IsFilterIntraAllowed(scs.SequenceHeader.FilterIntraLevel > 0, blockSize, blk_ptr.PaletteSize[0], intra_luma_mode))
{
writer.WriteSkip(blk_ptr.FilterIntraMode != Av1FilterIntraMode.AllFilterIntraModes, blockSize);
writer.WriteFilterIntra(blk_ptr.FilterIntraMode, blockSize);
if (blk_ptr.FilterIntraMode != Av1FilterIntraMode.AllFilterIntraModes)
{
writer.WriteFilterIntraMode(blk_ptr.FilterIntraMode);
@ -484,13 +504,16 @@ internal partial class Av1TileWriter
if (!macroBlockModeInfo.Block.UseIntraBlockCopy)
{
assert(blk_ptr.PaletteSize[1] == 0);
TOKENEXTRA tok = entropyCodingContext.tok;
Guard.IsTrue(blk_ptr.PaletteSize[1] == 0, nameof(blk_ptr), "Palette of chroma plane shall be empty.");
// TOKENEXTRA tok = entropyCodingContext.tok;
for (int plane = 0; plane < 2; ++plane)
{
int palette_size_plane = blk_ptr.PaletteSize[plane];
if (palette_size_plane > 0)
{
throw new NotImplementedException("Tokenizing palette not implemented.");
/*
Av1TransformSize tx_size =
blockGeometry.TransformSize[macroBlockModeInfo.Block.TransformDepth]; // inherit tx_size from 1st transform block;
svt_av1_tokenize_color_map(
@ -503,12 +526,13 @@ internal partial class Av1TileWriter
PALETTE_MAP,
0); // NO CDF update in entropy, the update will take place in arithmetic encode
assert(macroBlockModeInfo.Block.UseIntraBlockCopy);
assert(svt_aom_allow_palette(pcs.Parent.FrameHeader.AllowScreenContentTools, blockGeometry.BlockSize));
assert(IsPaletteAllowed(pcs.Parent.FrameHeader.AllowScreenContentTools, blockGeometry.BlockSize));
svt_aom_get_block_dimensions(blockGeometry.BlockSize, plane, blk_ptr.MacroBlock, null, null, out int rowCount, out int columnCount);
pack_map_tokens(ref writer, ref entropyCodingContext.tok, palette_size_plane, rowCount * columnCount);
// advance the pointer
entropyCodingContext.tok = tok;
*/
}
}
}
@ -546,16 +570,374 @@ internal partial class Av1TileWriter
}
// Update the neighbors
ec_update_neighbors(pcs, entropyCodingContext, blockOrigin, blk_ptr, tile_idx, blockSize, coeff_ptr);
UpdateNeighbors(pcs, entropyCodingContext, blockOrigin, blk_ptr, tile_idx, blockSize);
if (svt_av1_allow_palette(pcs.Parent.PaletteLevel, blockGeometry.BlockSize))
if (IsPaletteAllowed(pcs.Parent.PaletteLevel, blockGeometry.BlockSize))
{
/*
// free ENCDEC palette info buffer
assert(blk_ptr.palette_info.color_idx_map != null && "free palette:Null");
EB_FREE(blk_ptr.palette_info.color_idx_map);
blk_ptr.palette_info.color_idx_map = null;
EB_FREE(blk_ptr.palette_info);
EB_FREE(blk_ptr.palette_info);*/
}
}
private static void EncodeIntraChromaMode(
ref Av1SymbolEncoder writer,
Av1MacroBlockModeInfo macroBlockModeInfo,
Av1EncoderBlockStruct blk_ptr,
Av1BlockSize blockSize,
Av1PredictionMode lumaMode,
Av1PredictionMode chromaMode,
bool isChromaFromLumaAllowed)
{
writer.WriteChromaMode(chromaMode, isChromaFromLumaAllowed, lumaMode);
if (chromaMode == Av1PredictionMode.UvChromaFromLuma)
{
writer.WriteChromaFromLumaAlphas(
blk_ptr.PredictionUnits[0].ChromaFromLumaIndex,
blk_ptr.PredictionUnits[0].ChromaFromLumaSigns);
}
if (blockSize >= Av1BlockSize.Block8x8 && macroBlockModeInfo.Block.UvMode.IsDirectional())
{
writer.WriteAngleDelta(blk_ptr.PredictionUnits[0].AngleDelta[(int)Av1PlaneType.Uv] + Av1Constants.MaxAngleDelta, chromaMode);
}
}
/// <summary>
/// Get the contexts (left and top) for writing the intra luma mode for key frames.
/// Intended to be used for key frame only.
/// </summary>
/// <remarks>SVT: svt_aom_get_kf_y_mode_ctx</remarks>
private static void GetYModeContext(Av1MacroBlockD xd, out byte above_ctx, out byte left_ctx)
{
Av1PredictionMode intraLumaLeftMode = Av1PredictionMode.DC;
Av1PredictionMode intraLumaTopMode = Av1PredictionMode.DC;
if (xd.IsLeftAvailable)
{
// When called for key frame, neighbouring mode should be intra
// assert(!is_inter_block(&xd->mi[-1]->mbmi.block_mi) || is_intrabc_block(&xd->mi[-1]->mbmi.block_mi));
intraLumaLeftMode = xd.ModeInfo[-1].MacroBlockModeInfo.Block.Mode;
}
if (xd.IsUpAvailable)
{
// When called for key frame, neighbouring mode should be intra
// assert(!is_inter_block(&xd->mi[-xd->mi_stride]->mbmi.block_mi) ||
// is_intrabc_block(&xd->mi[-xd->mi_stride]->mbmi.block_mi));
intraLumaTopMode = xd.ModeInfo[-xd.ModeInfoStride].MacroBlockModeInfo.Block.Mode;
}
above_ctx = IntraModeContextLookup[(int)intraLumaTopMode];
left_ctx = IntraModeContextLookup[(int)intraLumaLeftMode];
}
/// <summary>
/// SVT: encode_intra_luma_mode_kf_av1
/// </summary>
private static void EncodeIntraLumaMode(
ref Av1SymbolEncoder writer,
Av1MacroBlockModeInfo macroBlockModeInfo,
Av1EncoderBlockStruct blk_ptr,
Av1BlockSize blockSize,
Av1PredictionMode lumaMode)
{
GetYModeContext(blk_ptr.MacroBlock, out byte topContext, out byte leftContext);
writer.WriteLumaMode(lumaMode, topContext, leftContext);
if (blockSize >= Av1BlockSize.Block8x8 && macroBlockModeInfo.Block.Mode.IsDirectional())
{
writer.WriteAngleDelta(blk_ptr.PredictionUnits[0].AngleDelta[(int)Av1PlaneType.Y] + Av1Constants.MaxAngleDelta, lumaMode);
}
}
private static void WritePaletteModeInfo(
Av1SequenceControlSet scs,
ref Av1SymbolEncoder writer,
Av1MacroBlockModeInfo macroBlockModeInfo,
Av1EncoderBlockStruct blk_ptr,
Av1BlockSize blockSize,
Point point)
{/*
Av1PredictionMode intra_luma_mode = macroBlockModeInfo.Mode;
Av1PredictionMode intra_chroma_mode = macroBlockModeInfo.ModeUv;
Av1PaletteModeInfo pmi = blk_ptr.PaletteInfo.pmi;
int bsize_ctx = svt_aom_get_palette_bsize_ctx(bsize);
Guard.MustBeGreaterThanOrEqualTo(bsize_ctx, 0, nameof(bsize_ctx));
if (intra_luma_mode == Av1PredictionMode.DC)
{
int n = blk_ptr.PaletteSize[0];
int palette_y_mode_ctx = svt_aom_get_palette_mode_ctx(blk_ptr->av1xd);
writer.WriteYMode(n > 0, bsize_ctx, palette_y_mode_ctx);
if (n > 0)
{
writer.WriteYSize(n - PALETTE_MIN_SIZE, bsize_ctx);
write_palette_colors_y(blk_ptr.MacroBlock, pmi, scs.StaticConfig.EncoderBitDepth, ref writer, n);
}
}
bool uv_dc_pred = intra_chroma_mode == Av1PredictionMode.DC && is_chroma_reference(point, blockSize, 1, 1);
if (uv_dc_pred)
{
// assert(blk_ptr->palette_size[1] == 0); //remove when chroma is on
bool palette_uv_mode_ctx = blk_ptr.PaletteSize[0] > 0;
writer.WriteUvMode(false, palette_uv_mode_ctx);
}*/
throw new NotImplementedException("Palette mode encoding not implemented.");
}
/// <summary>
/// SVT: svt_aom_filter_intra_allowed
/// </summary>
private static bool IsFilterIntraAllowed(
bool enableFilterIntra,
Av1BlockSize blockSize,
int paletteSize,
Av1PredictionMode mode)
=> mode == Av1PredictionMode.DC && paletteSize == 0 && IsFilterIntraAllowedBlockSize(enableFilterIntra, blockSize);
/// <summary>
/// SVT: svt_aom_filter_intra_allowed_bsize
/// </summary>
private static bool IsFilterIntraAllowedBlockSize(bool enableFilterIntra, Av1BlockSize blockSize)
{
if (!enableFilterIntra)
{
return false;
}
return blockSize.GetWidth() <= 32 && blockSize.GetHeight() <= 32;
}
/// <summary>
/// SVT: write_intrabc_info
/// </summary>
private static void WriteIntraBlockCopyInfo(
ref Av1SymbolEncoder writer,
Av1MacroBlockModeInfo macroBlockModeInfo,
Av1EncoderBlockStruct block)
{
bool use_intrabc = macroBlockModeInfo.Block.UseIntraBlockCopy;
writer.WriteUseIntraBlockCopy(use_intrabc);
if (use_intrabc)
{
throw new NotImplementedException("Intra block code encoding not implemented.");
/*
//assert(mbmi->mode == DC_PRED);
//assert(mbmi->uv_mode == UV_DC_PRED);
//assert(mbmi->motion_mode == SIMPLE_TRANSLATION);
IntMv dv_ref = block->predmv[0]; // mbmi_ext->ref_mv_stack[INTRA_FRAME][0].this_mv;
MV mv;
mv = macroBlockModeInfo.Block.mv[INTRA_FRAME].as_mv;
svt_av1_encode_dv(w, &mv, &dv_ref.as_mv, &ec_ctx->ndvc);*/
}
}
/// <summary>
/// SVT: svt_aom_allow_intrabc
/// </summary>
private static bool IsIntraBlockCopyAllowed(ObuFrameHeader frameHeader)
=> frameHeader.AllowScreenContentTools && frameHeader.AllowIntraBlockCopy;
/// <summary>
/// SVT: ec_update_neighbors
/// </summary>
private static void UpdateNeighbors(
Av1PictureControlSet pcs,
Av1EntropyCodingContext entropyCodingContext,
Point blockOrigin,
Av1EncoderBlockStruct blk_ptr,
ushort tile_idx,
Av1BlockSize blockSize)
{
Av1NeighborArrayUnit<Av1PartitionContext> partition_context_na = pcs.PartitionContexts[tile_idx];
Av1NeighborArrayUnit<byte> luma_dc_sign_level_coeff_na = pcs.LuminanceDcSignLevelCoefficientNeighbors[tile_idx];
Av1NeighborArrayUnit<byte> cr_dc_sign_level_coeff_na = pcs.CrDcSignLevelCoefficientNeighbors[tile_idx];
Av1NeighborArrayUnit<byte> cb_dc_sign_level_coeff_na = pcs.CbDcSignLevelCoefficientNeighbors[tile_idx];
Av1BlockGeometry blk_geom = Av1BlockGeometryFactory.GetBlockGeometryByModeDecisionScanIndex(blk_ptr.ModeDecisionScanIndex);
Av1MacroBlockModeInfo mbmi = pcs.GetMacroBlockModeInfo(blockOrigin);
bool skip_coeff = mbmi.Block.Skip;
// Update the Leaf Depth Neighbor Array
Av1PartitionContext partition = new(
PartitionContextLookup[(int)blockSize].Above,
PartitionContextLookup[(int)blockSize].Left);
Size size = new(blk_geom.BlockWidth, blk_geom.BlockHeight);
Span<Av1PartitionContext> partitionSpan = new(ref partition);
partition_context_na.UnitModeWrite(
partitionSpan,
blockOrigin,
size,
Av1NeighborArrayUnit<Av1PartitionContext>.UnitMask.Left | Av1NeighborArrayUnit<Av1PartitionContext>.UnitMask.Top);
if (skip_coeff)
{
byte dcSignLevelCoefficient = 0;
Span<byte> dcSignSpan = new(ref dcSignLevelCoefficient);
luma_dc_sign_level_coeff_na.UnitModeWrite(
dcSignSpan,
blockOrigin,
size,
Av1NeighborArrayUnit<Av1PartitionContext>.UnitMask.Left | Av1NeighborArrayUnit<Av1PartitionContext>.UnitMask.Top);
if (blk_geom.HasUv)
{
cb_dc_sign_level_coeff_na.UnitModeWrite(
dcSignSpan,
((blockOrigin >> 3) << 3) >> 1,
size,
Av1NeighborArrayUnit<Av1PartitionContext>.UnitMask.Left | Av1NeighborArrayUnit<Av1PartitionContext>.UnitMask.Top);
cr_dc_sign_level_coeff_na.UnitModeWrite(
dcSignSpan,
((blockOrigin >> 3) << 3) >> 1,
size,
Av1NeighborArrayUnit<Av1PartitionContext>.UnitMask.Left | Av1NeighborArrayUnit<Av1PartitionContext>.UnitMask.Top);
entropyCodingContext.CodedAreaSuperblockUv += blk_geom.BlockWidthUv * blk_geom.BlockHeightUv;
}
entropyCodingContext.CodedAreaSuperblock += blk_geom.BlockWidth * blk_geom.BlockHeight;
}
}
/// <summary>
/// SVT: svt_av1_allow_palette
/// </summary>
private static bool IsPaletteAllowed(int allowPalette, Av1BlockSize blockSize)
{
Guard.MustBeLessThan((int)blockSize, (int)Av1BlockSize.AllSizes, nameof(blockSize));
return allowPalette != 0 &&
blockSize.GetWidth() <= 64 &&
blockSize.GetHeight() <= 64 &&
blockSize >= Av1BlockSize.Block8x8;
}
/// <summary>
/// SVT: svt_aom_allow_palette
/// </summary>
private static bool IsPaletteAllowed(bool allowScreenContentTools, Av1BlockSize blockSize)
=> allowScreenContentTools &&
blockSize.GetWidth() <= 64 &&
blockSize.GetHeight() <= 64 &&
blockSize >= Av1BlockSize.Block8x8;
/// <summary>
/// SVT: write_cdef
/// </summary>
private static void WriteCdef(
Av1SequenceControlSet scs,
Av1PictureControlSet pcs,
ref Av1SymbolEncoder writer,
int tileIndex,
bool skip,
Point modeInfoPosition)
{
Av1EncoderCommon cm = pcs.Parent.Common;
ObuFrameHeader frameHeader = pcs.Parent.FrameHeader;
if (frameHeader.CodedLossless || frameHeader.AllowIntraBlockCopy)
{
// Initialize to indicate no CDEF for safety.
frameHeader.CdefParameters.BitCount = 0;
frameHeader.CdefParameters.YStrength[0] = 0;
frameHeader.CdefParameters.UvStrength[0] = 0;
// pcs.Parent.nb_cdef_strengths = 1;
return;
}
// int m = ~((1 << (6 - Av1Constants.ModeInfoSizeLog2)) - 1);
// cm->mi_grid_visible[(mi_row & m) * cm->mi_stride + (mi_col & m)];
Av1ModeInfo mi = pcs.GetFromModeInfoGrid(modeInfoPosition)[0];
// Initialise when at top left part of the superblock
if ((modeInfoPosition.Y & (scs.SequenceHeader.SuperblockModeInfoSize - 1)) == 0 &&
(modeInfoPosition.X & (scs.SequenceHeader.SuperblockModeInfoSize - 1)) == 0)
{
// Top left?
pcs.CdefPreset[tileIndex][0] = -1;
pcs.CdefPreset[tileIndex][1] = -1;
pcs.CdefPreset[tileIndex][2] = -1;
pcs.CdefPreset[tileIndex][3] = -1;
}
// Emit CDEF param at first non-skip coding block
int mask = 1 << (6 - Av1Constants.ModeInfoSizeLog2);
int index = scs.SequenceHeader.Use128x128Superblock ? Math.Max(1, modeInfoPosition.X & mask) + (2 * Math.Max(1, modeInfoPosition.Y & mask)) : 0;
if (pcs.CdefPreset[tileIndex][index] == -1 && !skip)
{
writer.WriteCdefStrength(mi.MacroBlockModeInfo.CdefStrength, frameHeader.CdefParameters.BitCount);
pcs.CdefPreset[tileIndex][index] = mi.MacroBlockModeInfo.CdefStrength;
}
}
/// <summary>
/// SVT: set_mi_row_col
/// </summary>
private static void SetModeInfoRowAndColumn(
Av1PictureControlSet pcs,
Av1MacroBlockD macroBlock,
Av1TileInfo tile,
Point modeInfoPosition,
Av1BlockSize blockSize,
int modeInfoStride,
int modeInfoRowCount,
int modeInfoColumnCount)
{
macroBlock.ToTopEdge = -((modeInfoPosition.Y << Av1Constants.ModeInfoSizeLog2) << 3);
macroBlock.ToBottomEdge = ((modeInfoRowCount - blockSize.GetHeight() - modeInfoPosition.Y) << Av1Constants.ModeInfoSizeLog2) << 3;
macroBlock.ToLeftEdge = -((modeInfoPosition.X << Av1Constants.ModeInfoSizeLog2) << 3);
macroBlock.ToRightEdge = ((modeInfoColumnCount - blockSize.GetWidth() - modeInfoPosition.X) << Av1Constants.ModeInfoSizeLog2) << 3;
macroBlock.ModeInfoStride = modeInfoStride;
// Are edges available for intra prediction?
macroBlock.IsUpAvailable = modeInfoPosition.Y > tile.ModeInfoRowStart;
macroBlock.IsLeftAvailable = modeInfoPosition.X > tile.ModeInfoColumnStart;
macroBlock.ModeInfo = pcs.GetFromModeInfoGrid(modeInfoPosition);
if (macroBlock.IsUpAvailable)
{
macroBlock.AboveMacroBlock = macroBlock.ModeInfo[-modeInfoStride].MacroBlockModeInfo;
}
else
{
macroBlock.AboveMacroBlock = null;
}
if (macroBlock.IsLeftAvailable)
{
macroBlock.LeftMacroBlock = macroBlock.ModeInfo[-1].MacroBlockModeInfo;
}
else
{
macroBlock.LeftMacroBlock = null;
}
macroBlock.N8Size = new Size(blockSize.GetWidth(), blockSize.GetHeight());
macroBlock.IsSecondRectangle = false;
if (macroBlock.N8Size.Width < macroBlock.N8Size.Height)
{
// Only mark is_sec_rect as 1 for the last block.
// For PARTITION_VERT_4, it would be (0, 0, 0, 1);
// For other partitions, it would be (0, 1).
if (((modeInfoPosition.X + macroBlock.N8Size.Width) & (macroBlock.N8Size.Height - 1)) == 0)
{
macroBlock.IsSecondRectangle = true;
}
}
if (macroBlock.N8Size.Width > macroBlock.N8Size.Height)
{
if ((modeInfoPosition.Y & (macroBlock.N8Size.Width - 1)) > 0)
{
macroBlock.IsSecondRectangle = true;
}
}
}
/// <summary>

Loading…
Cancel
Save