mirror of https://github.com/SixLabors/ImageSharp
16 changed files with 1902 additions and 22 deletions
@ -0,0 +1,505 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Prediction; |
|||
|
|||
internal class Av1BottomRightTopLeftConstants |
|||
{ |
|||
// Tables to store if the top-right reference pixels are available. The flags
|
|||
// are represented with bits, packed into 8-bit integers. E.g., for the 32x32
|
|||
// blocks in a 128x128 superblock, the index of the "o" block is 10 (in raster
|
|||
// order), so its flag is stored at the 3rd bit of the 2nd entry in the table,
|
|||
// i.e. (table[10 / 8] >> (10 % 8)) & 1.
|
|||
// . . . .
|
|||
// . . . .
|
|||
// . . o .
|
|||
// . . . .
|
|||
private static readonly byte[] HasTopRight4x4 = [ |
|||
255, 255, 255, 255, 85, 85, 85, 85, 119, 119, 119, 119, 85, 85, 85, 85, 127, 127, 127, 127, 85, 85, |
|||
85, 85, 119, 119, 119, 119, 85, 85, 85, 85, 255, 127, 255, 127, 85, 85, 85, 85, 119, 119, 119, 119, |
|||
85, 85, 85, 85, 127, 127, 127, 127, 85, 85, 85, 85, 119, 119, 119, 119, 85, 85, 85, 85, 255, 255, |
|||
255, 127, 85, 85, 85, 85, 119, 119, 119, 119, 85, 85, 85, 85, 127, 127, 127, 127, 85, 85, 85, 85, |
|||
119, 119, 119, 119, 85, 85, 85, 85, 255, 127, 255, 127, 85, 85, 85, 85, 119, 119, 119, 119, 85, 85, |
|||
85, 85, 127, 127, 127, 127, 85, 85, 85, 85, 119, 119, 119, 119, 85, 85, 85, 85, |
|||
]; |
|||
|
|||
private static readonly byte[] HasTopRight4x8 = [ |
|||
255, 255, 255, 255, 119, 119, 119, 119, 127, 127, 127, 127, 119, 119, 119, 119, 255, 127, 255, 127, 119, 119, |
|||
119, 119, 127, 127, 127, 127, 119, 119, 119, 119, 255, 255, 255, 127, 119, 119, 119, 119, 127, 127, 127, 127, |
|||
119, 119, 119, 119, 255, 127, 255, 127, 119, 119, 119, 119, 127, 127, 127, 127, 119, 119, 119, 119, |
|||
]; |
|||
|
|||
private static readonly byte[] HasTopRight8x4 = [ |
|||
255, 255, 0, 0, 85, 85, 0, 0, 119, 119, 0, 0, 85, 85, 0, 0, 127, 127, 0, 0, 85, 85, |
|||
0, 0, 119, 119, 0, 0, 85, 85, 0, 0, 255, 127, 0, 0, 85, 85, 0, 0, 119, 119, 0, 0, |
|||
85, 85, 0, 0, 127, 127, 0, 0, 85, 85, 0, 0, 119, 119, 0, 0, 85, 85, 0, 0, |
|||
]; |
|||
|
|||
private static readonly byte[] HasTopRight8x8 = [ |
|||
255, 255, 85, 85, 119, 119, 85, 85, 127, 127, 85, 85, 119, 119, 85, 85, |
|||
255, 127, 85, 85, 119, 119, 85, 85, 127, 127, 85, 85, 119, 119, 85, 85, |
|||
]; |
|||
|
|||
private static readonly byte[] HasTopRight8x16 = [ |
|||
255, |
|||
255, |
|||
119, |
|||
119, |
|||
127, |
|||
127, |
|||
119, |
|||
119, |
|||
255, |
|||
127, |
|||
119, |
|||
119, |
|||
127, |
|||
127, |
|||
119, |
|||
119, |
|||
]; |
|||
|
|||
private static readonly byte[] HasTopRight16x8 = [ |
|||
255, |
|||
0, |
|||
85, |
|||
0, |
|||
119, |
|||
0, |
|||
85, |
|||
0, |
|||
127, |
|||
0, |
|||
85, |
|||
0, |
|||
119, |
|||
0, |
|||
85, |
|||
0, |
|||
]; |
|||
|
|||
private static readonly byte[] HasTopRight16x16 = [ |
|||
255, |
|||
85, |
|||
119, |
|||
85, |
|||
127, |
|||
85, |
|||
119, |
|||
85, |
|||
]; |
|||
|
|||
private static readonly byte[] HasTopRight16x32 = [255, 119, 127, 119]; |
|||
private static readonly byte[] HasTopRight32x16 = [15, 5, 7, 5]; |
|||
private static readonly byte[] HasTopRight32x32 = [95, 87]; |
|||
private static readonly byte[] HasTopRight32x64 = [127]; |
|||
private static readonly byte[] HasTopRight64x32 = [19]; |
|||
private static readonly byte[] HasTopRight64x64 = [7]; |
|||
private static readonly byte[] HasTopRight64x128 = [3]; |
|||
private static readonly byte[] HasTopRight128x64 = [1]; |
|||
private static readonly byte[] HasTopRight128x128 = [1]; |
|||
private static readonly byte[] HasTopRight4x16 = [ |
|||
255, 255, 255, 255, 127, 127, 127, 127, 255, 127, 255, 127, 127, 127, 127, 127, |
|||
255, 255, 255, 127, 127, 127, 127, 127, 255, 127, 255, 127, 127, 127, 127, 127, |
|||
]; |
|||
|
|||
private static readonly byte[] HasTopRight16x4 = [ |
|||
255, 0, 0, 0, 85, 0, 0, 0, 119, 0, 0, 0, 85, 0, 0, 0, 127, 0, 0, 0, 85, 0, 0, 0, 119, 0, 0, 0, 85, 0, 0, 0, |
|||
]; |
|||
|
|||
private static readonly byte[] HasTopRight8x32 = [ |
|||
255, |
|||
255, |
|||
127, |
|||
127, |
|||
255, |
|||
127, |
|||
127, |
|||
127, |
|||
]; |
|||
|
|||
private static readonly byte[] HasTopRight32x8 = [ |
|||
15, |
|||
0, |
|||
5, |
|||
0, |
|||
7, |
|||
0, |
|||
5, |
|||
0, |
|||
]; |
|||
|
|||
private static readonly byte[] HasTopRight16x64 = [255, 127]; |
|||
private static readonly byte[] HasTopRight64x16 = [3, 1]; |
|||
|
|||
private static readonly byte[][] HasTopRightTables = [ |
|||
|
|||
// 4X4
|
|||
HasTopRight4x4, |
|||
|
|||
// 4X8, 8X4, 8X8
|
|||
HasTopRight4x8, |
|||
HasTopRight8x4, |
|||
HasTopRight8x8, |
|||
|
|||
// 8X16, 16X8, 16X16
|
|||
HasTopRight8x16, |
|||
HasTopRight16x8, |
|||
HasTopRight16x16, |
|||
|
|||
// 16X32, 32X16, 32X32
|
|||
HasTopRight16x32, |
|||
HasTopRight32x16, |
|||
HasTopRight32x32, |
|||
|
|||
// 32X64, 64X32, 64X64
|
|||
HasTopRight32x64, |
|||
HasTopRight64x32, |
|||
HasTopRight64x64, |
|||
|
|||
// 64x128, 128x64, 128x128
|
|||
HasTopRight64x128, |
|||
HasTopRight128x64, |
|||
HasTopRight128x128, |
|||
|
|||
// 4x16, 16x4, 8x32
|
|||
HasTopRight4x16, |
|||
HasTopRight16x4, |
|||
HasTopRight8x32, |
|||
|
|||
// 32x8, 16x64, 64x16
|
|||
HasTopRight32x8, |
|||
HasTopRight16x64, |
|||
HasTopRight64x16 |
|||
]; |
|||
|
|||
private static readonly byte[] HasTopRightVertical8x8 = [ |
|||
255, 255, 0, 0, 119, 119, 0, 0, 127, 127, 0, 0, 119, 119, 0, 0, |
|||
255, 127, 0, 0, 119, 119, 0, 0, 127, 127, 0, 0, 119, 119, 0, 0, |
|||
]; |
|||
|
|||
private static readonly byte[] HasTopRightVertical16x16 = [ |
|||
255, |
|||
0, |
|||
119, |
|||
0, |
|||
127, |
|||
0, |
|||
119, |
|||
0, |
|||
]; |
|||
|
|||
private static readonly byte[] HasTopRightVertical32x32 = [15, 7]; |
|||
private static readonly byte[] HasTopRightVertical64x64 = [3]; |
|||
|
|||
// The _vert_* tables are like the ordinary tables above, but describe the
|
|||
// order we visit square blocks when doing a PARTITION_VERT_A or
|
|||
// PARTITION_VERT_B. This is the same order as normal except for on the last
|
|||
// split where we go vertically (TL, BL, TR, BR). We treat the rectangular block
|
|||
// as a pair of squares, which means that these tables work correctly for both
|
|||
// mixed vertical partition types.
|
|||
//
|
|||
// There are tables for each of the square sizes. Vertical rectangles (like
|
|||
// BLOCK_16X32) use their respective "non-vert" table
|
|||
private static readonly byte[]?[] HasTopRightVerticalTables = [ |
|||
|
|||
// 4X4
|
|||
null, |
|||
|
|||
// 4X8, 8X4, 8X8
|
|||
HasTopRight4x8, |
|||
null, |
|||
HasTopRightVertical8x8, |
|||
|
|||
// 8X16, 16X8, 16X16
|
|||
HasTopRight8x16, |
|||
null, |
|||
HasTopRightVertical16x16, |
|||
|
|||
// 16X32, 32X16, 32X32
|
|||
HasTopRight16x32, |
|||
null, |
|||
HasTopRightVertical32x32, |
|||
|
|||
// 32X64, 64X32, 64X64
|
|||
HasTopRight32x64, |
|||
null, |
|||
HasTopRightVertical64x64, |
|||
|
|||
// 64x128, 128x64, 128x128
|
|||
HasTopRight64x128, |
|||
null, |
|||
HasTopRight128x128 |
|||
]; |
|||
|
|||
// Similar to the has_tr_* tables, but store if the bottom-left reference
|
|||
// pixels are available.
|
|||
private static readonly byte[] HasBottomLeft4x4 = [ |
|||
84, 85, 85, 85, 16, 17, 17, 17, 84, 85, 85, 85, 0, 1, 1, 1, 84, 85, 85, 85, 16, 17, 17, 17, 84, 85, |
|||
85, 85, 0, 0, 1, 0, 84, 85, 85, 85, 16, 17, 17, 17, 84, 85, 85, 85, 0, 1, 1, 1, 84, 85, 85, 85, |
|||
16, 17, 17, 17, 84, 85, 85, 85, 0, 0, 0, 0, 84, 85, 85, 85, 16, 17, 17, 17, 84, 85, 85, 85, 0, 1, |
|||
1, 1, 84, 85, 85, 85, 16, 17, 17, 17, 84, 85, 85, 85, 0, 0, 1, 0, 84, 85, 85, 85, 16, 17, 17, 17, |
|||
84, 85, 85, 85, 0, 1, 1, 1, 84, 85, 85, 85, 16, 17, 17, 17, 84, 85, 85, 85, 0, 0, 0, 0, |
|||
]; |
|||
|
|||
private static readonly byte[] HasBottomLeft4x8 = [ |
|||
16, 17, 17, 17, 0, 1, 1, 1, 16, 17, 17, 17, 0, 0, 1, 0, 16, 17, 17, 17, 0, 1, 1, 1, 16, 17, 17, 17, 0, 0, 0, 0, |
|||
16, 17, 17, 17, 0, 1, 1, 1, 16, 17, 17, 17, 0, 0, 1, 0, 16, 17, 17, 17, 0, 1, 1, 1, 16, 17, 17, 17, 0, 0, 0, 0, |
|||
]; |
|||
|
|||
private static readonly byte[] HasBottomLeft8x4 = [ |
|||
254, 255, 84, 85, 254, 255, 16, 17, 254, 255, 84, 85, 254, 255, 0, 1, 254, 255, 84, 85, 254, 255, |
|||
16, 17, 254, 255, 84, 85, 254, 255, 0, 0, 254, 255, 84, 85, 254, 255, 16, 17, 254, 255, 84, 85, |
|||
254, 255, 0, 1, 254, 255, 84, 85, 254, 255, 16, 17, 254, 255, 84, 85, 254, 255, 0, 0, |
|||
]; |
|||
|
|||
private static readonly byte[] HasBottomLeft8x8 = [ |
|||
84, 85, 16, 17, 84, 85, 0, 1, 84, 85, 16, 17, 84, 85, 0, 0, |
|||
84, 85, 16, 17, 84, 85, 0, 1, 84, 85, 16, 17, 84, 85, 0, 0, |
|||
]; |
|||
|
|||
private static readonly byte[] HasBottomLeft8x16 = [ |
|||
16, |
|||
17, |
|||
0, |
|||
1, |
|||
16, |
|||
17, |
|||
0, |
|||
0, |
|||
16, |
|||
17, |
|||
0, |
|||
1, |
|||
16, |
|||
17, |
|||
0, |
|||
0, |
|||
]; |
|||
|
|||
private static readonly byte[] HasBottomLeft16x8 = [ |
|||
254, |
|||
84, |
|||
254, |
|||
16, |
|||
254, |
|||
84, |
|||
254, |
|||
0, |
|||
254, |
|||
84, |
|||
254, |
|||
16, |
|||
254, |
|||
84, |
|||
254, |
|||
0, |
|||
]; |
|||
|
|||
private static readonly byte[] HasBottomLeft16x16 = [ |
|||
84, |
|||
16, |
|||
84, |
|||
0, |
|||
84, |
|||
16, |
|||
84, |
|||
0, |
|||
]; |
|||
|
|||
private static readonly byte[] HasBottomLeft16x32 = [16, 0, 16, 0]; |
|||
private static readonly byte[] HasBottomLeft32x16 = [78, 14, 78, 14]; |
|||
private static readonly byte[] HasBottomLeft32x32 = [4, 4]; |
|||
private static readonly byte[] HasBottomLeft32x64 = [0]; |
|||
private static readonly byte[] HasBottomLeft64x32 = [34]; |
|||
private static readonly byte[] HasBottomLeft64x64 = [0]; |
|||
private static readonly byte[] HasBottomLeft64x128 = [0]; |
|||
private static readonly byte[] HasBottomLeft128x64 = [0]; |
|||
private static readonly byte[] HasBottomLeft128x128 = [0]; |
|||
private static readonly byte[] HasBottomLeft4x16 = [ |
|||
0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, |
|||
]; |
|||
|
|||
private static readonly byte[] HasBottomLeft16x4 = [ |
|||
254, 254, 254, 84, 254, 254, 254, 16, 254, 254, 254, 84, 254, 254, 254, 0, |
|||
254, 254, 254, 84, 254, 254, 254, 16, 254, 254, 254, 84, 254, 254, 254, 0, |
|||
]; |
|||
|
|||
private static readonly byte[] HasBottomLeft8x32 = [ |
|||
0, |
|||
1, |
|||
0, |
|||
0, |
|||
0, |
|||
1, |
|||
0, |
|||
0, |
|||
]; |
|||
|
|||
private static readonly byte[] HasBottomLeft32x8 = [ |
|||
238, |
|||
78, |
|||
238, |
|||
14, |
|||
238, |
|||
78, |
|||
238, |
|||
14, |
|||
]; |
|||
|
|||
private static readonly byte[] HasBottomLeft16x64 = [0, 0]; |
|||
private static readonly byte[] HasBottomLeft64x16 = [42, 42]; |
|||
|
|||
private static readonly byte[][] HasBottomLeftTables = [ |
|||
|
|||
// 4X4
|
|||
HasBottomLeft4x4, |
|||
|
|||
// 4X8, 8X4, 8X8
|
|||
HasBottomLeft4x8, |
|||
HasBottomLeft8x4, |
|||
HasBottomLeft8x8, |
|||
|
|||
// 8X16, 16X8, 16X16
|
|||
HasBottomLeft8x16, |
|||
HasBottomLeft16x8, |
|||
HasBottomLeft16x16, |
|||
|
|||
// 16X32, 32X16, 32X32
|
|||
HasBottomLeft16x32, |
|||
HasBottomLeft32x16, |
|||
HasBottomLeft32x32, |
|||
|
|||
// 32X64, 64X32, 64X64
|
|||
HasBottomLeft32x64, |
|||
HasBottomLeft64x32, |
|||
HasBottomLeft64x64, |
|||
|
|||
// 64x128, 128x64, 128x128
|
|||
HasBottomLeft64x128, |
|||
HasBottomLeft128x64, |
|||
HasBottomLeft128x128, |
|||
|
|||
// 4x16, 16x4, 8x32
|
|||
HasBottomLeft4x16, |
|||
HasBottomLeft16x4, |
|||
HasBottomLeft8x32, |
|||
|
|||
// 32x8, 16x64, 64x16
|
|||
HasBottomLeft32x8, |
|||
HasBottomLeft16x64, |
|||
HasBottomLeft64x16 |
|||
]; |
|||
|
|||
private static readonly byte[] HasBottomLeftVertical8x8 = [ |
|||
254, 255, 16, 17, 254, 255, 0, 1, 254, 255, 16, 17, 254, 255, 0, 0, |
|||
254, 255, 16, 17, 254, 255, 0, 1, 254, 255, 16, 17, 254, 255, 0, 0, |
|||
]; |
|||
|
|||
private static readonly byte[] HasBottomLeftVertical16x16 = [ |
|||
254, |
|||
16, |
|||
254, |
|||
0, |
|||
254, |
|||
16, |
|||
254, |
|||
0, |
|||
]; |
|||
|
|||
private static readonly byte[] HasBottomLeftVertical32x32 = [14, 14]; |
|||
private static readonly byte[] HasBottomLeftVertical64x64 = [2]; |
|||
|
|||
// The _vert_* tables are like the ordinary tables above, but describe the
|
|||
// order we visit square blocks when doing a PARTITION_VERT_A or
|
|||
// PARTITION_VERT_B. This is the same order as normal except for on the last
|
|||
// split where we go vertically (TL, BL, TR, BR). We treat the rectangular block
|
|||
// as a pair of squares, which means that these tables work correctly for both
|
|||
// mixed vertical partition types.
|
|||
//
|
|||
// There are tables for each of the square sizes. Vertical rectangles (like
|
|||
// BLOCK_16X32) use their respective "non-vert" table
|
|||
private static readonly byte[]?[] HasBottomLeftVerticalTables = [ |
|||
|
|||
// 4X4
|
|||
null, |
|||
|
|||
// 4X8, 8X4, 8X8
|
|||
HasBottomLeft4x8, |
|||
null, |
|||
HasBottomLeftVertical8x8, |
|||
|
|||
// 8X16, 16X8, 16X16
|
|||
HasBottomLeft8x16, |
|||
null, |
|||
HasBottomLeftVertical16x16, |
|||
|
|||
// 16X32, 32X16, 32X32
|
|||
HasBottomLeft16x32, |
|||
null, |
|||
HasBottomLeftVertical32x32, |
|||
|
|||
// 32X64, 64X32, 64X64
|
|||
HasBottomLeft32x64, |
|||
null, |
|||
HasBottomLeftVertical64x64, |
|||
|
|||
// 64x128, 128x64, 128x128
|
|||
HasBottomLeft64x128, |
|||
null, |
|||
HasBottomLeft128x128]; |
|||
|
|||
public static bool HasTopRight(Av1PartitionType partitionType, Av1BlockSize blockSize, int blockIndex) |
|||
{ |
|||
int index1 = blockIndex / 8; |
|||
int index2 = blockIndex % 8; |
|||
Span<byte> hasBottomLeftTable = GetHasTopRightTable(partitionType, blockSize); |
|||
return ((hasBottomLeftTable[index1] >> index2) & 1) > 0; |
|||
} |
|||
|
|||
public static bool HasBottomLeft(Av1PartitionType partitionType, Av1BlockSize blockSize, int blockIndex) |
|||
{ |
|||
int index1 = blockIndex / 8; |
|||
int index2 = blockIndex % 8; |
|||
Span<byte> hasBottomLeftTable = GetHasBottomLeftTable(partitionType, blockSize); |
|||
return ((hasBottomLeftTable[index1] >> index2) & 1) > 0; |
|||
} |
|||
|
|||
private static Span<byte> GetHasTopRightTable(Av1PartitionType partition, Av1BlockSize blockSize) |
|||
{ |
|||
byte[]? ret; |
|||
|
|||
// If this is a mixed vertical partition, look up block size in vertical order.
|
|||
if (partition is Av1PartitionType.VerticalA or Av1PartitionType.VerticalB) |
|||
{ |
|||
DebugGuard.MustBeLessThan((int)blockSize, (int)Av1BlockSize.SizeS, nameof(blockSize)); |
|||
ret = HasTopRightVerticalTables[(int)blockSize]; |
|||
} |
|||
else |
|||
{ |
|||
ret = HasTopRightTables[(int)blockSize]; |
|||
} |
|||
|
|||
DebugGuard.NotNull(ret, nameof(ret)); |
|||
return ret; |
|||
} |
|||
|
|||
private static Span<byte> GetHasBottomLeftTable(Av1PartitionType partition, Av1BlockSize blockSize) |
|||
{ |
|||
byte[]? ret; |
|||
|
|||
// If this is a mixed vertical partition, look up block size in vertical order.
|
|||
if (partition is Av1PartitionType.VerticalA or Av1PartitionType.VerticalB) |
|||
{ |
|||
DebugGuard.MustBeLessThan((int)blockSize, (int)Av1BlockSize.SizeS, nameof(blockSize)); |
|||
ret = HasBottomLeftVerticalTables[(int)blockSize]; |
|||
} |
|||
else |
|||
{ |
|||
ret = HasBottomLeftTables[(int)blockSize]; |
|||
} |
|||
|
|||
DebugGuard.NotNull(ret, nameof(ret)); |
|||
return ret; |
|||
} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Prediction; |
|||
|
|||
[Flags] |
|||
internal enum Av1NeighborNeed |
|||
{ |
|||
Nothing = 0, |
|||
Left = 2, |
|||
Above = 4, |
|||
AboveRight = 8, |
|||
AboveLeft = 16, |
|||
BottomLeft = 32, |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using SixLabors.ImageSharp.Formats.Heif.Av1.Tiling; |
|||
using SixLabors.ImageSharp.Formats.Heif.Av1.Transform; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Prediction; |
|||
|
|||
internal class Av1PredictorFactory |
|||
{ |
|||
internal static void DcPredictor(bool v1, bool v2, Av1TransformSize transformSize, ref byte destination, nuint destinationStride, Span<byte> aboveRow, Span<byte> leftColumn) => throw new NotImplementedException(); |
|||
|
|||
internal static void DirectionalPredictor(ref byte destination, nuint destinationStride, Av1TransformSize transformSize, Span<byte> aboveRow, Span<byte> leftColumn, bool upsampleAbove, bool upsampleLeft, int angle) => throw new NotImplementedException(); |
|||
|
|||
internal static void FilterIntraPredictor(ref byte destination, nuint destinationStride, Av1TransformSize transformSize, Span<byte> aboveRow, Span<byte> leftColumn, Av1FilterIntraMode filterIntraMode) => throw new NotImplementedException(); |
|||
|
|||
internal static void GeneralPredictor(Av1PredictionMode mode, Av1TransformSize transformSize, ref byte destination, nuint destinationStride, Span<byte> aboveRow, Span<byte> leftColumn) => throw new NotImplementedException(); |
|||
} |
|||
@ -0,0 +1,120 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
using System.Runtime.CompilerServices; |
|||
using SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit; |
|||
using SixLabors.ImageSharp.Formats.Heif.Av1.Transform; |
|||
using SixLabors.ImageSharp.Memory; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Prediction.ChromaFromLuma; |
|||
|
|||
internal class Av1ChromaFromLumaContext |
|||
{ |
|||
private const int BufferLine = 32; |
|||
|
|||
private int bufferHeight; |
|||
private int bufferWidth; |
|||
private readonly bool subX; |
|||
private readonly bool subY; |
|||
|
|||
public Av1ChromaFromLumaContext(Configuration configuration, ObuColorConfig colorConfig) |
|||
{ |
|||
this.subX = colorConfig.SubSamplingX; |
|||
this.subY = colorConfig.SubSamplingY; |
|||
this.Q3Buffer = configuration.MemoryAllocator.Allocate2D<short>(new Size(32, 32), AllocationOptions.Clean); |
|||
} |
|||
|
|||
public Buffer2D<short> Q3Buffer { get; private set; } |
|||
|
|||
public bool AreParametersComputed { get; private set; } |
|||
|
|||
public void ComputeParameters(Av1TransformSize transformSize) |
|||
{ |
|||
Guard.IsFalse(this.AreParametersComputed, nameof(this.AreParametersComputed), "Do not call cfl_compute_parameters multiple time on the same values."); |
|||
this.Pad(transformSize.GetWidth(), transformSize.GetHeight()); |
|||
SubtractAverage(ref this.Q3Buffer[0, 0], transformSize); |
|||
this.AreParametersComputed = true; |
|||
} |
|||
|
|||
private void Pad(int width, int height) |
|||
{ |
|||
int diff_width = width - this.bufferWidth; |
|||
int diff_height = height - this.bufferHeight; |
|||
|
|||
if (diff_width > 0) |
|||
{ |
|||
int min_height = height - diff_height; |
|||
ref short recon_buf_q3 = ref this.Q3Buffer[width - diff_width, 0]; |
|||
for (int j = 0; j < min_height; j++) |
|||
{ |
|||
short last_pixel = Unsafe.Subtract(ref recon_buf_q3, 1); |
|||
Guard.IsTrue(Unsafe.IsAddressLessThan(ref Unsafe.Add(ref recon_buf_q3, diff_width), ref this.Q3Buffer[BufferLine, BufferLine]), nameof(recon_buf_q3), "Shall stay within bounds."); |
|||
for (int i = 0; i < diff_width; i++) |
|||
{ |
|||
Unsafe.Add(ref recon_buf_q3, i) = last_pixel; |
|||
} |
|||
|
|||
recon_buf_q3 += BufferLine; |
|||
} |
|||
|
|||
this.bufferWidth = width; |
|||
} |
|||
|
|||
if (diff_height > 0) |
|||
{ |
|||
ref short recon_buf_q3 = ref this.Q3Buffer[0, height - diff_height]; |
|||
for (int j = 0; j < diff_height; j++) |
|||
{ |
|||
ref short last_row_q3 = ref Unsafe.Subtract(ref recon_buf_q3, BufferLine); |
|||
Guard.IsTrue(Unsafe.IsAddressLessThan(ref Unsafe.Add(ref recon_buf_q3, diff_width), ref this.Q3Buffer[BufferLine, BufferLine]), nameof(recon_buf_q3), "Shall stay within bounds."); |
|||
for (int i = 0; i < width; i++) |
|||
{ |
|||
Unsafe.Add(ref recon_buf_q3, i) = Unsafe.Add(ref last_row_q3, i); |
|||
} |
|||
|
|||
recon_buf_q3 += BufferLine; |
|||
} |
|||
|
|||
this.bufferHeight = height; |
|||
} |
|||
} |
|||
|
|||
/************************************************************************************************ |
|||
* svt_subtract_average_c |
|||
* Calculate the DC value by averaging over all sample. Subtract DC value to get AC values In C |
|||
************************************************************************************************/ |
|||
private static void SubtractAverage(ref short pred_buf_q3, Av1TransformSize transformSize) |
|||
{ |
|||
int width = transformSize.GetWidth(); |
|||
int height = transformSize.GetHeight(); |
|||
int roundOffset = (width * height) >> 1; |
|||
int pelCountLog2 = transformSize.GetBlockWidthLog2() + transformSize.GetBlockHeightLog2(); |
|||
int sum_q3 = 0; |
|||
ref short pred_buf = ref pred_buf_q3; |
|||
for (int j = 0; j < height; j++) |
|||
{ |
|||
// assert(pred_buf_q3 + tx_width <= cfl->pred_buf_q3 + CFL_BUF_SQUARE);
|
|||
for (int i = 0; i < width; i++) |
|||
{ |
|||
sum_q3 += Unsafe.Add(ref pred_buf, i); |
|||
} |
|||
|
|||
pred_buf += BufferLine; |
|||
} |
|||
|
|||
int avg_q3 = (sum_q3 + roundOffset) >> pelCountLog2; |
|||
|
|||
// Loss is never more than 1/2 (in Q3)
|
|||
// assert(abs((avg_q3 * (1 << num_pel_log2)) - sum_q3) <= 1 << num_pel_log2 >>
|
|||
// 1);
|
|||
for (int j = 0; j < height; j++) |
|||
{ |
|||
for (int i = 0; i < width; i++) |
|||
{ |
|||
Unsafe.Add(ref pred_buf_q3, i) -= (short)avg_q3; |
|||
} |
|||
|
|||
pred_buf_q3 += BufferLine; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Six Labors Split License.
|
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Prediction.ChromaFromLuma; |
|||
|
|||
internal static class Av1ChromaFromLumaMath |
|||
{ |
|||
private const int Signs = 3; |
|||
private const int AlphabetSizeLog2 = 4; |
|||
|
|||
public const int SignZero = 0; |
|||
public const int SignNegative = 1; |
|||
public const int SignPositive = 2; |
|||
|
|||
public static int SignU(int jointSign) => ((jointSign + 1) * 11) >> 5; |
|||
|
|||
public static int SignV(int jointSign) => (jointSign + 1) - (Signs * SignU(jointSign)); |
|||
|
|||
public static int IndexU(int index) => index >> AlphabetSizeLog2; |
|||
|
|||
public static int IndexV(int index) => index & (AlphabetSizeLog2 - 1); |
|||
|
|||
public static int ContextU(int jointSign) => jointSign + 1 - Signs; |
|||
|
|||
public static int ContextV(int jointSign) => (SignV(jointSign) * Signs) + SignU(jointSign) - Signs; |
|||
} |
|||
File diff suppressed because it is too large
Loading…
Reference in new issue