Browse Source

Implement Coefficient syntax

pull/2633/head
Ynse Hoornenborg 2 years ago
parent
commit
30f8884391
  1. 26
      src/ImageSharp/Formats/Heif/Av1/Av1Constants.cs
  2. 2
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuFrameHeader.cs
  3. 2
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReader.cs
  4. 2
      src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuWriter.cs
  5. 27
      src/ImageSharp/Formats/Heif/Av1/Prediction/Av1PreditionModeExtensions.cs
  6. 249
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1DefaultDistributions.cs
  7. 10
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1Distribution.cs
  8. 356
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1NzMap.cs
  9. 28
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1SymbolDecoder.cs
  10. 528
      src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileDecoder.cs
  11. 2
      src/ImageSharp/Formats/Heif/Av1/Transform/Av1InverseQuantizer.cs
  12. 2
      src/ImageSharp/Formats/Heif/Av1/Transform/Av1ScanOrder.cs
  13. 8
      src/ImageSharp/Formats/Heif/Av1/Transform/Av1ScanOrderConstants.cs
  14. 11
      src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformClass.cs
  15. 37
      src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformSetType.cs
  16. 96
      src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformSizeExtensions.cs
  17. 42
      src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformTypeExtensions.cs
  18. 4
      tests/ImageSharp.Tests/Formats/Heif/Av1/SymbolTest.cs

26
src/ImageSharp/Formats/Heif/Av1/Av1Constants.cs

@ -140,4 +140,30 @@ internal static class Av1Constants
public const int MaxTransformCategories = 4;
public const int CoefficientContextCount = 6;
public const int BaseLevelsCount = 2;
public const int CoefficientBaseRange = 12;
public const int TransformPadHorizontalLog2 = 2;
public const int TransformPadHorizontal = 1 << TransformPadHorizontalLog2;
public const int TransformPadVertical = 6;
public const int TransformPadEnd = 16;
public const int CoefficientContextBits = 6;
public const int CoefficientContextMask = (1 << CoefficientContextBits) - 1;
public const int TransformPad2d = ((MaxTransformSize + TransformPadHorizontal) * (MaxTransformSize + TransformPadVertical)) + TransformPadEnd;
public const int MaxTransformSize = 1 << 6;
public const int TransformPadTop = 2;
public const int BaseRangeSizeMinus1 = 3;
public const int MaxBaseRange = 15;
}

2
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuFrameHeader.cs

@ -33,7 +33,7 @@ internal class ObuFrameHeader
public ObuFilmGrainParameters FilmGrainParameters { get; set; } = new ObuFilmGrainParameters();
public bool ReducedTransformSet { get; set; }
public bool UseReducedTransformSet { get; set; }
public ObuLoopFilterParameters LoopFilterParameters { get; set; } = new ObuLoopFilterParameters();

2
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuReader.cs

@ -1159,7 +1159,7 @@ internal class ObuReader
frameInfo.AllowWarpedMotion = reader.ReadBoolean();
}
frameInfo.ReducedTransformSet = reader.ReadBoolean();
frameInfo.UseReducedTransformSet = reader.ReadBoolean();
ReadGlobalMotionParameters(ref reader, sequenceHeader, frameInfo, isIntraFrame);
frameInfo.FilmGrainParameters = ReadFilmGrainFilterParameters(ref reader, sequenceHeader, frameInfo);
}

2
src/ImageSharp/Formats/Heif/Av1/OpenBitstreamUnit/ObuWriter.cs

@ -415,7 +415,7 @@ internal class ObuWriter
// Not applicable for INTRA frames.
// WriteFrameReferenceMode(ref writer, frameInfo.ReferenceMode, isIntraFrame);
// WriteSkipModeParameters(ref writer, sequenceHeader, frameInfo, isIntraFrame, frameInfo.ReferenceMode);
writer.WriteBoolean(frameInfo.ReducedTransformSet);
writer.WriteBoolean(frameInfo.UseReducedTransformSet);
// Not applicable for INTRA frames.
// WriteGlobalMotionParameters(ref writer, sequenceHeader, frameInfo, isIntraFrame);

27
src/ImageSharp/Formats/Heif/Av1/Prediction/Av1PreditionModeExtensions.cs

@ -0,0 +1,27 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats.Heif.Av1.Transform;
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Prediction;
internal static class Av1PreditionModeExtensions
{
private static readonly Av1TransformType[] IntraPreditionMode2TransformType = [
Av1TransformType.DctDct, // DC
Av1TransformType.AdstDct, // V
Av1TransformType.DctAdst, // H
Av1TransformType.DctDct, // D45
Av1TransformType.AdstAdst, // D135
Av1TransformType.AdstDct, // D117
Av1TransformType.DctAdst, // D153
Av1TransformType.DctAdst, // D207
Av1TransformType.AdstDct, // D63
Av1TransformType.AdstAdst, // SMOOTH
Av1TransformType.AdstDct, // SMOOTH_V
Av1TransformType.DctAdst, // SMOOTH_H
Av1TransformType.AdstAdst, // PAETH
];
public static Av1TransformType ToTransformType(this Av1PredictionMode mode) => IntraPreditionMode2TransformType[(int)mode];
}

249
src/ImageSharp/Formats/Heif/Av1/Tiling/Av1DefaultDistributions.cs

@ -1,6 +1,8 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System;
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Symbol;
internal static class Av1DefaultDistributions
@ -179,4 +181,251 @@ internal static class Av1DefaultDistributions
[new(12986, 15180), new(12986, 15180), new(24302, 25602)],
[new(5782, 11475), new(5782, 11475), new(16803, 22759)],
];
private static Av1Distribution[][][] EndOfBlockFlagMulti16 =>
[
[
[new(840, 1039, 1980, 4895), new(370, 671, 1883, 4471)],
[new(3247, 4950, 9688, 14563), new(1904, 3354, 7763, 14647)]
],
[
[new(2125, 2551, 5165, 8946), new(513, 765, 1859, 6339)],
[new(7637, 9498, 14259, 19108), new(2497, 4096, 8866, 16993)]
],
[
[new(4016, 4897, 8881, 14968), new(716, 1105, 2646, 10056)],
[new(11139, 13270, 18241, 23566), new(3192, 5032, 10297, 19755)]
],
[
[new(6708, 8958, 14746, 22133), new(1222, 2074, 4783, 15410)],
[new(19575, 21766, 26044, 29709), new(7297, 10767, 19273, 28194)]
]
];
private static Av1Distribution[][][] EndOfBlockFlagMulti32 =>
[
[
[new(400, 520, 977, 2102, 6542), new(210, 405, 1315, 3326, 7537)],
[new(2636, 4273, 7588, 11794, 20401), new(1786, 3179, 6902, 11357, 19054)]
],
[
[new(989, 1249, 2019, 4151, 10785), new(313, 441, 1099, 2917, 8562)],
[new(8394, 10352, 13932, 18855, 26014), new(2578, 4124, 8181, 13670, 24234)]
],
[
[new(2515, 3003, 4452, 8162, 16041), new(574, 821, 1836, 5089, 13128)],
[new(13468, 16303, 20361, 25105, 29281), new(3542, 5502, 10415, 16760, 25644)]
],
[
[new(4617, 5709, 8446, 13584, 23135), new(1156, 1702, 3675, 9274, 20539)],
[new(22086, 24282, 27010, 29770, 31743), new(7699, 10897, 20891, 26926, 31628)]
]
];
private static Av1Distribution[][][] EndOfBlockFlagMulti64 =>
[
[
[new(329, 498, 1101, 1784, 3265, 7758), new(335, 730, 1459, 5494, 8755, 12997)],
[new(3505, 5304, 10086, 13814, 17684, 23370), new(1563, 2700, 4876, 10911, 14706, 22480)],
],
[
[new(1260, 1446, 2253, 3712, 6652, 13369), new(401, 605, 1029, 2563, 5845, 12626)],
[new(8609, 10612, 14624, 18714, 22614, 29024), new(1923, 3127, 5867, 9703, 14277, 27100)]
],
[
[new(2374, 2772, 4583, 7276, 12288, 19706), new(497, 810, 1315, 3000, 7004, 15641)],
[new(15050, 17126, 21410, 24886, 28156, 30726), new(4034, 6290, 10235, 14982, 21214, 28491)]
],
[
[new(6307, 7541, 12060, 16358, 22553, 27865), new(1289, 2320, 3971, 7926, 14153, 24291)],
[new(24212, 25708, 28268, 30035, 31307, 32049), new(8726, 12378, 19409, 26450, 30038, 32462)]
]
];
private static Av1Distribution[][][] EndOfBlockFlagMulti128 =>
[
[
[new(219, 482, 1140, 2091, 3680, 6028, 12586), new(371, 699, 1254, 4830, 9479, 12562, 17497)],
[new(5245, 7456, 12880, 15852, 20033, 23932, 27608), new(2054, 3472, 5869, 14232, 18242, 20590, 26752)]
],
[
[new(685, 933, 1488, 2714, 4766, 8562, 19254), new(217, 352, 618, 2303, 5261, 9969, 17472)],
[new(8045, 11200, 15497, 19595, 23948, 27408, 30938), new(2310, 4160, 7471, 14997, 17931, 20768, 30240)]
],
[
[new(1366, 1738, 2527, 5016, 9355, 15797, 24643), new(354, 558, 944, 2760, 7287, 14037, 21779)],
[new(13627, 16246, 20173, 24429, 27948, 30415, 31863), new(6275, 9889, 14769, 23164, 27988, 30493, 32272)]
],
[
[new(3472, 4885, 7489, 12481, 18517, 24536, 29635), new(886, 1731, 3271, 8469, 15569, 22126, 28383)],
[new(24313, 26062, 28385, 30107, 31217, 31898, 32345), new(9165, 13282, 21150, 30286, 31894, 32571, 32712)]
]
];
private static Av1Distribution[][][] EndOfBlockFlagMulti256 =>
[
[
[
new(310, 584, 1887, 3589, 6168, 8611, 11352, 15652),
new(998, 1850, 2998, 5604, 17341, 19888, 22899, 25583),
],
[
new(2520, 3240, 5952, 8870, 12577, 17558, 19954, 24168),
new(2203, 4130, 7435, 10739, 20652, 23681, 25609, 27261)
],
],
[
[
new(1448, 2109, 4151, 6263, 9329, 13260, 17944, 23300),
new(399, 1019, 1749, 3038, 10444, 15546, 22739, 27294)
],
[
new(6402, 8148, 12623, 15072, 18728, 22847, 26447, 29377),
new(1674, 3252, 5734, 10159, 22397, 23802, 24821, 30940)
]
],
[
[
new(3089, 3920, 6038, 9460, 14266, 19881, 25766, 29176),
new(1084, 2358, 3488, 5122, 11483, 18103, 26023, 29799)
],
[
new(11514, 13794, 17480, 20754, 24361, 27378, 29492, 31277),
new(6571, 9610, 15516, 21826, 29092, 30829, 31842, 32708)
]
],
[
[
new(5348, 7113, 11820, 15924, 22106, 26777, 30334, 31757),
new(2453, 4474, 6307, 8777, 16474, 22975, 29000, 31547)
],
[
new(23110, 24597, 27140, 28894, 30167, 30927, 31392, 32094),
new(9998, 17661, 25178, 28097, 31308, 32038, 32403, 32695)
]
]
];
private static Av1Distribution[][][] EndOfBlockFlagMulti512 =>
[
[
[
new(641, 983, 3707, 5430, 10234, 14958, 18788, 23412, 26061),
new(3277, 6554, 9830, 13107, 16384, 19661, 22938, 26214, 29491)
],
[
new(5095, 6446, 9996, 13354, 16017, 17986, 20919, 26129, 29140),
new(3277, 6554, 9830, 13107, 16384, 19661, 22938, 26214, 29491)
]
],
[
[
new(1230, 2278, 5035, 7776, 11871, 15346, 19590, 24584, 28749),
new(3277, 6554, 9830, 13107, 16384, 19661, 22938, 26214, 29491)
],
[
new(7265, 9979, 15819, 19250, 21780, 23846, 26478, 28396, 31811),
new(3277, 6554, 9830, 13107, 16384, 19661, 22938, 26214, 29491)
]
],
[
[
new(2624, 3936, 6480, 9686, 13979, 17726, 23267, 28410, 31078),
new(3277, 6554, 9830, 13107, 16384, 19661, 22938, 26214, 29491)
],
[
new(12015, 14769, 19588, 22052, 24222, 25812, 27300, 29219, 32114),
new(3277, 6554, 9830, 13107, 16384, 19661, 22938, 26214, 29491)
]
],
[
[
new(5927, 7809, 10923, 14597, 19439, 24135, 28456, 31142, 32060),
new(3277, 6554, 9830, 13107, 16384, 19661, 22938, 26214, 29491)
],
[
new(21093, 23043, 25742, 27658, 29097, 29716, 30073, 30820, 31956),
new(3277, 6554, 9830, 13107, 16384, 19661, 22938, 26214, 29491)
]
]
];
private static Av1Distribution[][][] EndOfBlockFlagMulti1024 =>
[
[
[
new(393, 421, 751, 1623, 3160, 6352, 13345, 18047, 22571, 25830),
new(2979, 5958, 8937, 11916, 14895, 17873, 20852, 23831, 26810, 29789)
],
[
new(1865, 1988, 2930, 4242, 10533, 16538, 21354, 27255, 28546, 31784),
new(2979, 5958, 8937, 11916, 14895, 17873, 20852, 23831, 26810, 29789)
]
],
[
[
new(696, 948, 3145, 5702, 9706, 13217, 17851, 21856, 25692, 28034),
new(2979, 5958, 8937, 11916, 14895, 17873, 20852, 23831, 26810, 29789)
],
[
new(2672, 3591, 9330, 17084, 22725, 24284, 26527, 28027, 28377, 30876),
new(2979, 5958, 8937, 11916, 14895, 17873, 20852, 23831, 26810, 29789)
]
],
[
[
new(2784, 3831, 7041, 10521, 14847, 18844, 23155, 26682, 29229, 31045),
new(2979, 5958, 8937, 11916, 14895, 17873, 20852, 23831, 26810, 29789)
],
[
new(9577, 12466, 17739, 20750, 22061, 23215, 24601, 25483, 25843, 32056),
new(2979, 5958, 8937, 11916, 14895, 17873, 20852, 23831, 26810, 29789)
]
],
[
[
new(6698, 8334, 11961, 15762, 20186, 23862, 27434, 29326, 31082, 32050),
new(2979, 5958, 8937, 11916, 14895, 17873, 20852, 23831, 26810, 29789)
],
[
new(20569, 22426, 25569, 26859, 28053, 28913, 29486, 29724, 29807, 32570),
new(2979, 5958, 8937, 11916, 14895, 17873, 20852, 23831, 26810, 29789)
]
]
];
public static Av1Distribution[][][] GetEndOfBlockFlag(int baseQIndex)
{
int qContext = GetQContext(baseQIndex);
return
[
EndOfBlockFlagMulti16[qContext],
EndOfBlockFlagMulti32[qContext],
EndOfBlockFlagMulti64[qContext],
EndOfBlockFlagMulti128[qContext],
EndOfBlockFlagMulti256[qContext],
EndOfBlockFlagMulti512[qContext],
EndOfBlockFlagMulti1024[qContext],
];
}
private static int GetQContext(int q)
{
if (q <= 20)
{
return 0;
}
if (q <= 60)
{
return 1;
}
if (q <= 120)
{
return 2;
}
return 3;
}
}

10
src/ImageSharp/Formats/Heif/Av1/Tiling/Av1Distribution.cs

@ -54,11 +54,21 @@ internal class Av1Distribution
{
}
public Av1Distribution(uint p0, uint p1, uint p2, uint p3, uint p4, uint p5, uint p6, uint p7)
: this([p0, p1, p2, p3, p4, p5, p6, p7, 0], 2)
{
}
public Av1Distribution(uint p0, uint p1, uint p2, uint p3, uint p4, uint p5, uint p6, uint p7, uint p8)
: this([p0, p1, p2, p3, p4, p5, p6, p7, p8, 0], 2)
{
}
public Av1Distribution(uint p0, uint p1, uint p2, uint p3, uint p4, uint p5, uint p6, uint p7, uint p8, uint p9)
: this([p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, 0], 2)
{
}
public Av1Distribution(uint p0, uint p1, uint p2, uint p3, uint p4, uint p5, uint p6, uint p7, uint p8, uint p9, uint p10, uint p11)
: this([p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, 0], 2)
{

356
src/ImageSharp/Formats/Heif/Av1/Tiling/Av1NzMap.cs

@ -0,0 +1,356 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats.Heif.Av1.Transform;
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Symbol;
internal static class Av1NzMap
{
private static readonly int[] ClipMax3 = [
0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
];
// SIG_COEF_CONTEXTS_2D = 26
private const int NzMapContext0 = 26;
private const int NzMapContext5 = NzMapContext0 + 5;
private const int NzMapContext10 = NzMapContext0 + 10;
private static readonly int[] NzMapContextOffset1d = [
NzMapContext0, NzMapContext5, NzMapContext10, NzMapContext10, NzMapContext10, NzMapContext10, NzMapContext10,
NzMapContext10, NzMapContext10, NzMapContext10, NzMapContext10, NzMapContext10, NzMapContext10, NzMapContext10,
NzMapContext10, NzMapContext10, NzMapContext10, NzMapContext10, NzMapContext10, NzMapContext10, NzMapContext10,
NzMapContext10, NzMapContext10, NzMapContext10, NzMapContext10, NzMapContext10, NzMapContext10, NzMapContext10,
NzMapContext10, NzMapContext10, NzMapContext10, NzMapContext10,
];
// The ctx offset table when TX is TX_CLASS_2D.
// TX col and row indices are clamped to 4
private static readonly int[] NzMapContextOffset4x4 = [0, 1, 6, 6, 1, 6, 6, 21, 6, 6, 21, 21, 6, 21, 21, 21];
private static readonly int[] NzMapContextOffset8x8 = [
0, 1, 6, 6, 21, 21, 21, 21, 1, 6, 6, 21, 21, 21, 21, 21, 6, 6, 21, 21, 21, 21,
21, 21, 6, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
];
private static readonly int[] NzMapContextOffset16x16 = [
0, 1, 6, 6, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 1, 6, 6, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 6, 6, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 6, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
];
private static readonly int[] NzMapContextOffset32x32 = [
0, 1, 6, 6, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 1, 6, 6, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 6, 6, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 6, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21,
];
private static readonly int[] NzMapContextOffset8x4 = [
0, 16, 6, 6, 21, 21, 21, 21, 16, 16, 6, 21, 21, 21, 21, 21,
16, 16, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21,
];
private static readonly int[] NzMapContextOffset16x8 = [
0, 16, 6, 6, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 6, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
];
private static readonly int[] NzMapContextOffset16x32 = [
0, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 6, 6, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 6, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
];
private static readonly int[] NzMapContextOffset32x16 = [
0, 16, 6, 6, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 16, 16, 6, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
];
private static readonly int[] NzMapContextOffset32x64 = [
0, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 6, 6, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 6, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21,
];
private static readonly int[] NzMapContextOffset64x32 = [
0, 16, 6, 6, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 16, 16, 6, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16,
16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21,
];
private static readonly int[] NzMapContextOffset4x16 = [
0, 11, 11, 11, 11, 11, 11, 11, 6, 6, 21, 21, 6, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
];
private static readonly int[] NzMapContextOffset16x4 = [
0, 16, 6, 6, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 6, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
];
private static readonly int[] NzMapContextOffset8x32 = [
0, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 6, 6, 21, 21, 21, 21, 21, 21, 6, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
];
private static readonly int[] NzMapContextOffset32x8 = [
0, 16, 6, 6, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 16, 16, 6, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 16, 16, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
];
private static readonly int[][] NzMapContextOffset = [
NzMapContextOffset4x4, // TX_4x4
NzMapContextOffset8x8, // TX_8x8
NzMapContextOffset16x16, // TX_16x16
NzMapContextOffset32x32, // TX_32x32
NzMapContextOffset32x32, // TX_32x32
NzMapContextOffset4x16, // TX_4x8
NzMapContextOffset8x4, // TX_8x4
NzMapContextOffset8x32, // TX_8x16
NzMapContextOffset16x8, // TX_16x8
NzMapContextOffset16x32, // TX_16x32
NzMapContextOffset32x16, // TX_32x16
NzMapContextOffset32x64, // TX_32x64
NzMapContextOffset64x32, // TX_64x32
NzMapContextOffset4x16, // TX_4x16
NzMapContextOffset16x4, // TX_16x4
NzMapContextOffset8x32, // TX_8x32
NzMapContextOffset32x8, // TX_32x8
NzMapContextOffset16x32, // TX_16x64
NzMapContextOffset64x32, // TX_64x16
];
public static int GetNzMagnitude(Span<int> levels, int bwl, Av1TransformClass transformClass)
{
int mag;
// Note: AOMMIN(level, 3) is useless for decoder since level < 3.
mag = ClipMax3[levels[1]]; // { 0, 1 }
mag += ClipMax3[levels[(1 << bwl) + Av1Constants.TransformPadHorizontal]]; // { 1, 0 }
switch (transformClass)
{
case Av1TransformClass.Class2D:
mag += ClipMax3[levels[(1 << bwl) + Av1Constants.TransformPadHorizontal + 1]]; // { 1, 1 }
mag += ClipMax3[levels[2]]; // { 0, 2 }
mag += ClipMax3[levels[(2 << bwl) + (2 << Av1Constants.TransformPadHorizontalLog2)]]; // { 2, 0 }
break;
case Av1TransformClass.ClassVertical:
mag += ClipMax3[levels[(2 << bwl) + (2 << Av1Constants.TransformPadHorizontalLog2)]]; // { 2, 0 }
mag += ClipMax3[levels[(3 << bwl) + (3 << Av1Constants.TransformPadHorizontalLog2)]]; // { 3, 0 }
mag += ClipMax3[levels[(4 << bwl) + (4 << Av1Constants.TransformPadHorizontalLog2)]]; // { 4, 0 }
break;
case Av1TransformClass.ClassHorizontal:
mag += ClipMax3[levels[2]]; // { 0, 2 }
mag += ClipMax3[levels[3]]; // { 0, 3 }
mag += ClipMax3[levels[4]]; // { 0, 4 }
break;
}
return mag;
}
public static int GetNzMapContextFromStats(int stats, int pos, int bwl, Av1TransformSize transformSize, Av1TransformClass transformClass)
{
// tx_class == 0(TX_CLASS_2D)
if (((int)transformClass | pos) == 0)
{
return 0;
}
int ctx = (stats + 1) >> 1;
ctx = Math.Min(ctx, 4);
switch (transformClass)
{
case Av1TransformClass.Class2D:
// This is the algorithm to generate eb_av1_nz_map_ctx_offset[][]
// const int width = tx_size_wide[tx_size];
// const int height = tx_size_high[tx_size];
// if (width < height) {
// if (row < 2) return 11 + ctx;
// } else if (width > height) {
// if (col < 2) return 16 + ctx;
// }
// if (row + col < 2) return ctx + 1;
// if (row + col < 4) return 5 + ctx + 1;
// return 21 + ctx;
return ctx + NzMapContextOffset[(int)transformSize][pos];
case Av1TransformClass.ClassHorizontal:
int row = pos >> bwl;
int col = pos - (row << bwl);
return ctx + NzMapContextOffset1d[col];
case Av1TransformClass.ClassVertical:
int row2 = pos >> bwl;
return ctx + NzMapContextOffset1d[row2];
default:
break;
}
return 0;
}
public static int GetNzMapContext(Av1TransformSize transformSize, int pos) => NzMapContextOffset[(int)transformSize][pos];
}

28
src/ImageSharp/Formats/Heif/Av1/Tiling/Av1SymbolDecoder.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Drawing;
using SixLabors.ImageSharp.Formats.Heif.Av1.Prediction;
using SixLabors.ImageSharp.Formats.Heif.Av1.Transform;
@ -23,9 +22,14 @@ internal ref struct Av1SymbolDecoder
private readonly Av1Distribution filterIntraMode = Av1DefaultDistributions.FilterIntraMode;
private readonly Av1Distribution[] filterIntra = Av1DefaultDistributions.FilterIntra;
private readonly Av1Distribution[][] transformSize = Av1DefaultDistributions.TransformSize;
private readonly Av1Distribution[][][] endOfBlockFlag;
private Av1SymbolReader reader;
public Av1SymbolDecoder(Span<byte> tileData) => this.reader = new Av1SymbolReader(tileData);
public Av1SymbolDecoder(Span<byte> tileData, int qIndex)
{
this.reader = new Av1SymbolReader(tileData);
this.endOfBlockFlag = Av1DefaultDistributions.GetEndOfBlockFlag(qIndex);
}
public int ReadLiteral(int bitCount)
{
@ -176,6 +180,26 @@ internal ref struct Av1SymbolDecoder
return transformSize;
}
public int ReadEndOfBlockFlag(Av1PlaneType planeType, Av1TransformClass transformClass, Av1TransformSize transformSize)
{
int endOfBlockContext = transformClass == Av1TransformClass.Class2D ? 0 : 1;
int endOfBlockMultiSize = transformSize.GetLog2Minus4();
ref Av1SymbolReader r = ref this.reader;
return r.ReadSymbol(this.endOfBlockFlag[endOfBlockMultiSize][(int)planeType][endOfBlockContext]) + 1;
}
public bool ReadTransformBlockSkip(Av1TransformSize transformSizeContext, int skipContext) => throw new NotImplementedException();
public bool ReadEndOfBlockExtra(Av1TransformSize transformSizeContext, Av1PlaneType planeType, int endOfBlockContext) => throw new NotImplementedException();
public int ReadBaseRange(Av1TransformSize transformSizeContext, Av1PlaneType planeType, int baseRangeContext) => throw new NotImplementedException();
public int ReadDcSign(Av1PlaneType planeType, int dcSignContext) => throw new NotImplementedException();
public int ReadBaseEndOfBlock(Av1TransformSize transformSizeContext, Av1PlaneType planeType, int coefficientContext) => throw new NotImplementedException();
public int ReadBase(int coeff_ctx, Av1TransformSize transformSizeContext, Av1PlaneType planeType) => throw new NotImplementedException();
private static uint GetElementProbability(Av1Distribution probability, Av1PartitionType element)
=> probability[(int)element - 1] - probability[(int)element];
}

528
src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileDecoder.cs

@ -1,6 +1,8 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System;
using System.Formats.Asn1;
using SixLabors.ImageSharp.Formats.Heif.Av1;
using SixLabors.ImageSharp.Formats.Heif.Av1.OpenBitstreamUnit;
using SixLabors.ImageSharp.Formats.Heif.Av1.Prediction;
@ -21,16 +23,15 @@ internal class Av1TileDecoder : IAv1TileDecoder
private static readonly int[][] SkipContexts = [
[1, 2, 2, 2, 3], [1, 4, 4, 4, 5], [1, 4, 4, 4, 5], [1, 4, 4, 4, 5], [1, 4, 4, 4, 6]];
private static readonly int[] EndOfBlockGroupStart = [0, 1, 2, 3, 5, 9, 17, 33, 65, 129, 257, 513];
private static readonly int[] EndOfBlockOffsetBits = [0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
private bool[][][] blockDecoded = [];
private int[][] referenceSgrXqd = [];
private int[][][] referenceLrWiener = [];
private Av1ParseAboveNeighbor4x4Context aboveNeighborContext;
private Av1ParseLeftNeighbor4x4Context leftNeighborContext;
private readonly Av1ParseAboveNeighbor4x4Context aboveNeighborContext;
private readonly Av1ParseLeftNeighbor4x4Context leftNeighborContext;
private int currentQuantizerIndex;
private int[][] aboveLevelContext = [];
private int[][] aboveDcContext = [];
private int[][] leftLevelContext = [];
private int[][] leftDcContext = [];
private int[][] segmentIds = [];
private int deltaLoopFilterResolution = -1;
private bool readDeltas;
@ -76,7 +77,7 @@ internal class Av1TileDecoder : IAv1TileDecoder
public void DecodeTile(Span<byte> tileData, int tileNum)
{
Av1SymbolDecoder reader = new(tileData);
Av1SymbolDecoder reader = new(tileData, this.FrameInfo.QuantizationParameters.BaseQIndex);
int tileColumnIndex = tileNum % this.FrameInfo.TilesInfo.TileColumnCount;
int tileRowIndex = tileNum / this.FrameInfo.TilesInfo.TileColumnCount;
@ -521,6 +522,9 @@ internal class Av1TileDecoder : IAv1TileDecoder
/// <summary>
/// 5.11.35. Transform block syntax.
/// </summary>
/// <remarks>
/// The implementation is taken from SVT-AV1 library, which deviates from the code flow in the specification.
/// </remarks>
private int TransformBlock(
ref Av1SymbolDecoder reader,
Av1PartitionInfo partitionInfo,
@ -561,7 +565,486 @@ internal class Av1TileDecoder : IAv1TileDecoder
/// <summary>
/// 5.11.39. Coefficients syntax.
/// </summary>
private int ParseCoefficients(ref Av1SymbolDecoder reader, Av1PartitionInfo partitionInfo, int startY, int startX, int blockRow, int blockColumn, int plane, Av1TransformBlockContext transformBlockContext, Av1TransformSize transformSize, int coefficientIndex, Av1TransformInfo transformInfo) => throw new NotImplementedException();
/// <remarks>
/// The implementation is taken from SVT-AV1 library, which deviates from the code flow in the specification.
/// </remarks>
private int ParseCoefficients(ref Av1SymbolDecoder reader, Av1PartitionInfo partitionInfo, int blockRow, int blockColumn, int aboveOffset, int leftOffset, int plane, Av1TransformBlockContext transformBlockContext, Av1TransformSize transformSize, int coefficientIndex, Av1TransformInfo transformInfo)
{
Span<int> coefficientBuffer = this.FrameBuffer.GetCoefficients(plane);
int width = transformSize.GetWidth();
int height = transformSize.GetHeight();
Av1TransformSize transformSizeContext = (Av1TransformSize)(((int)transformSize.GetSquareSize() + ((int)transformSize.GetSquareUpSize() + 1)) >> 1);
Av1PlaneType planeType = (Av1PlaneType)Math.Min(plane, 1);
int culLevel = 0;
int dcValue = 0;
int[] levelsBuffer = new int[Av1Constants.TransformPad2d];
Span<int> levels = levelsBuffer.AsSpan()[(Av1Constants.TransformPadTop * (width + Av1Constants.TransformPadHorizontal))..];
bool allZero = reader.ReadTransformBlockSkip(transformSizeContext, transformBlockContext.SkipContext);
int bwl = transformSize.GetBlockWidthLog2();
int endOfBlock;
int maxScanLine = 0;
if (allZero)
{
if (plane == 0)
{
transformInfo.Type = Av1TransformType.DctDct;
transformInfo.CodeBlockFlag = false;
}
this.UpdateCoefficientContext(plane, partitionInfo, transformSize, blockRow, blockColumn, aboveOffset, leftOffset, culLevel);
return 0;
}
int endOfBlockExtra = 0;
int endOfBlockPoint = 0;
transformInfo.Type = this.ComputeTransformType(planeType, partitionInfo, transformSize, transformInfo);
Av1TransformClass transformClass = transformInfo.Type.ToClass();
Av1ScanOrder scanOrder = Av1ScanOrderConstants.GetScanOrder(transformSize, transformInfo.Type);
Span<short> scan = scanOrder.Scan;
endOfBlockPoint = reader.ReadEndOfBlockFlag(planeType, transformClass, transformSize);
int endOfBlockShift = EndOfBlockOffsetBits[endOfBlockPoint];
if (endOfBlockShift > 0)
{
int endOfBlockContext = endOfBlockPoint;
bool bit = reader.ReadEndOfBlockExtra(transformSizeContext, planeType, endOfBlockContext);
if (bit)
{
endOfBlockExtra += 1 << (endOfBlockShift - 1);
}
else
{
for (int j = 1; j < endOfBlockShift; j++)
{
if (reader.ReadLiteral(1) != 0)
{
endOfBlockExtra += 1 << (endOfBlockShift - 1 - j);
}
}
}
}
endOfBlock = RecordEndOfBlockPosition(endOfBlockPoint, endOfBlockExtra);
if (endOfBlock > 1)
{
Array.Fill(levelsBuffer, 0, 0, ((width + Av1Constants.TransformPadHorizontal) * (height + Av1Constants.TransformPadVertical)) + Av1Constants.TransformPadEnd);
}
int i = endOfBlock - 1;
int pos = scan[i];
int coefficientContext = GetLowerLevelContextEndOfBlock(bwl, height, i);
int level = reader.ReadBaseEndOfBlock(transformSizeContext, planeType, coefficientContext);
if (level > Av1Constants.BaseLevelsCount)
{
int baseRangeContext = GetBaseRangeContextEndOfBlock(pos, bwl, transformClass);
for (int idx = 0; idx < Av1Constants.CoefficientBaseRange / Av1Constants.BaseRangeSizeMinus1; idx++)
{
int coefficinetBaseRange = reader.ReadBaseRange(transformSizeContext, planeType, baseRangeContext);
level += coefficinetBaseRange;
if (coefficinetBaseRange < Av1Constants.BaseRangeSizeMinus1)
{
break;
}
}
}
levels[GetPaddedIndex(pos, bwl)] = level;
if (endOfBlock > 1)
{
if (transformClass == Av1TransformClass.Class2D)
{
ReadCoefficientsReverse2d(ref reader, transformSize, 1, endOfBlock - 1 - 1, scan, bwl, levels, transformSizeContext, planeType);
ReadCoefficientsReverse(ref reader, transformSize, transformInfo.Type, 0, 0, scan, bwl, levels, transformSizeContext, planeType);
}
else
{
ReadCoefficientsReverse(ref reader, transformSize, transformInfo.Type, 0, endOfBlock - 1 - 1, scan, bwl, levels, transformSizeContext, planeType);
}
}
coefficientBuffer[this.coefficientIndex[plane]] = endOfBlock;
for (int c = 0; c < endOfBlock; c++)
{
int sign = 0;
level = levels[GetPaddedIndex(scan[c], bwl)];
if (level != 0)
{
maxScanLine = Math.Max(maxScanLine, scan[c]);
if (c == 0)
{
sign = reader.ReadDcSign(planeType, transformBlockContext.DcSignContext);
}
else
{
sign = reader.ReadLiteral(1);
}
if (level >= Av1Constants.CoefficientBaseRange + Av1Constants.BaseLevelsCount + 1)
{
level += ReadGolomb(ref reader);
}
if (c == 0)
{
dcValue = sign != 0 ? -level : level;
}
level &= 0xfffff;
culLevel += level;
}
coefficientBuffer[c + 1] = sign != 0 ? -level : level;
}
culLevel = Math.Min(Av1Constants.CoefficientContextMask, culLevel);
SetDcSign(ref culLevel, dcValue);
this.UpdateCoefficientContext(plane, partitionInfo, transformSize, blockRow, blockColumn, aboveOffset, leftOffset, culLevel);
transformInfo.CodeBlockFlag = true;
return endOfBlock;
}
private static void ReadCoefficientsReverse2d(ref Av1SymbolDecoder reader, Av1TransformSize transformSize, int startSi, int endSi, Span<short> scan, int bwl, Span<int> levels, Av1TransformSize transformSizeContext, Av1PlaneType planeType)
{
for (int c = endSi; c >= startSi; --c)
{
int pos = scan[c];
int coeff_ctx = GetLowerLevelsContext2d(levels, pos, bwl, transformSize);
int level = reader.ReadBase(pos, transformSizeContext, planeType);
if (level > Av1Constants.BaseLevelsCount)
{
int baseRangeContext = GetBaseRangeContext2d(levels, pos, bwl);
for (int idx = 0; idx < Av1Constants.CoefficientBaseRange; idx += Av1Constants.BaseRangeSizeMinus1)
{
int k = reader.ReadBaseRange(transformSizeContext, planeType, baseRangeContext);
level += k;
if (k < Av1Constants.BaseRangeSizeMinus1)
{
break;
}
}
}
levels[GetPaddedIndex(pos, bwl)] = level;
}
}
private static int GetBaseRangeContext2d(Span<int> levels, int c, int bwl)
{
DebugGuard.MustBeGreaterThan(c, 0, nameof(c));
int row = c >> bwl;
int col = c - (row << bwl);
int stride = (1 << bwl) + Av1Constants.TransformPadHorizontal;
int pos = (row * stride) + col;
int mag =
Math.Min(levels[pos + 1], Av1Constants.MaxBaseRange) +
Math.Min(levels[pos + stride], Av1Constants.MaxBaseRange) +
Math.Min(levels[pos + 1 + stride], Av1Constants.MaxBaseRange);
mag = Math.Min((mag + 1) >> 1, 6);
if ((row | col) < 2)
{
return mag + 7;
}
return mag + 14;
}
private static int GetLowerLevelsContext2d(Span<int> levels, int pos, int bwl, Av1TransformSize transformSize)
{
DebugGuard.MustBeGreaterThan(pos, 0, nameof(pos));
int mag;
levels = levels[GetPaddedIndex(pos, bwl)..];
mag = Math.Min(levels[1], 3); // { 0, 1 }
mag += Math.Min(levels[(1 << bwl) + Av1Constants.TransformPadHorizontal], 3); // { 1, 0 }
mag += Math.Min(levels[(1 << bwl) + Av1Constants.TransformPadHorizontal + 1], 3); // { 1, 1 }
mag += Math.Min(levels[2], 3); // { 0, 2 }
mag += Math.Min(levels[(2 << bwl) + (2 << Av1Constants.TransformPadHorizontalLog2)], 3); // { 2, 0 }
int ctx = Math.Min((mag + 1) >> 1, 4);
return ctx + Av1NzMap.GetNzMapContext(transformSize, pos);
}
private static void ReadCoefficientsReverse(ref Av1SymbolDecoder reader, Av1TransformSize transformSize, Av1TransformType transformType, int startSi, int endSi, Span<short> scan, int bwl, Span<int> levels, Av1TransformSize transformSizeContext, Av1PlaneType planeType)
{
Av1TransformClass transformClass = transformType.ToClass();
for (int c = endSi; c >= startSi; --c)
{
int pos = scan[c];
int coeff_ctx = GetLowerLevelsContext(levels, pos, bwl, transformSize, transformClass);
int level = reader.ReadBase(coeff_ctx, transformSizeContext, planeType);
if (level > Av1Constants.BaseLevelsCount)
{
int baseRangeContext = GetBaseRangeContext(levels, pos, bwl, transformClass);
for (int idx = 0; idx < Av1Constants.CoefficientBaseRange; idx += Av1Constants.BaseRangeSizeMinus1)
{
int k = reader.ReadBaseRange(transformSizeContext, planeType, baseRangeContext);
level += k;
if (k < Av1Constants.BaseRangeSizeMinus1)
{
break;
}
}
}
levels[GetPaddedIndex(pos, bwl)] = level;
}
}
private static int GetBaseRangeContext(Span<int> levels, int c, int bwl, Av1TransformClass transformClass)
{
int row = c >> bwl;
int col = c - (row << bwl);
int stride = (1 << bwl) + Av1Constants.TransformPadHorizontal;
int pos = (row * stride) + col;
int mag = levels[pos + 1];
mag += levels[pos + stride];
switch (transformClass)
{
case Av1TransformClass.Class2D:
mag += levels[pos + stride + 1];
mag = Math.Min((mag + 1) >> 1, 6);
if (c == 0)
{
return mag;
}
if ((row < 2) && (col < 2))
{
return mag + 7;
}
break;
case Av1TransformClass.ClassHorizontal:
mag += levels[pos + 2];
mag = Math.Min((mag + 1) >> 1, 6);
if (c == 0)
{
return mag;
}
if (col == 0)
{
return mag + 7;
}
break;
case Av1TransformClass.ClassVertical:
mag += levels[pos + (stride << 1)];
mag = Math.Min((mag + 1) >> 1, 6);
if (c == 0)
{
return mag;
}
if (row == 0)
{
return mag + 7;
}
break;
default:
break;
}
return mag + 14;
}
private static int GetLowerLevelsContext(Span<int> levels, int pos, int bwl, Av1TransformSize transformSize, Av1TransformClass transformClass)
{
int stats = Av1NzMap.GetNzMagnitude(levels[GetPaddedIndex(pos, bwl)..], bwl, transformClass);
return Av1NzMap.GetNzMapContextFromStats(stats, pos, bwl, transformSize, transformClass);
}
private static int ReadGolomb(ref Av1SymbolDecoder reader)
{
int x = 1;
int length = 0;
int i = 0;
while (i == 0)
{
i = reader.ReadLiteral(1);
++length;
if (length > 20)
{
// SVT_LOG("Invalid length in read_golomb");
break;
}
}
for (i = 0; i < length - 1; ++i)
{
x <<= 1;
x += reader.ReadLiteral(1);
}
return x - 1;
}
private static void SetDcSign(ref int culLevel, int dcValue)
{
if (dcValue < 0)
{
culLevel |= 1 << Av1Constants.CoefficientContextBits;
}
else if (dcValue > 0)
{
culLevel += 2 << Av1Constants.CoefficientContextBits;
}
}
private static int GetPaddedIndex(int scanIndex, int bwl)
=> scanIndex + ((scanIndex >> bwl) << Av1Constants.TransformPadHorizontalLog2);
private static int GetBaseRangeContextEndOfBlock(int pos, int bwl, Av1TransformClass transformClass)
{
int row = pos >> bwl;
int col = pos - (row << bwl);
if (pos == 0)
{
return 0;
}
if ((transformClass == Av1TransformClass.Class2D && row < 2 && col < 2) ||
(transformClass == Av1TransformClass.ClassHorizontal && col == 0) ||
(transformClass == Av1TransformClass.ClassVertical && row == 0))
{
return 7;
}
return 14;
}
private static int GetLowerLevelContextEndOfBlock(int bwl, int height, int scanIndex)
{
if (scanIndex == 0)
{
return 0;
}
if (scanIndex <= (height << bwl) >> 3)
{
return 1;
}
if (scanIndex <= (height << bwl) >> 2)
{
return 2;
}
return 3;
}
private void UpdateCoefficientContext(int plane, Av1PartitionInfo partitionInfo, Av1TransformSize transformSize, int blockRow, int blockColumn, int aboveOffset, int leftOffset, int culLevel)
{
bool subX = this.SequenceHeader.ColorConfig.SubSamplingX;
bool subY = this.SequenceHeader.ColorConfig.SubSamplingY;
int[] aboveContexts = this.aboveNeighborContext.GetContext(plane);
int[] leftContexts = this.leftNeighborContext.GetContext(plane);
int transformSizeWide = transformSize.Get4x4WideCount();
int transformSizeHigh = transformSize.Get4x4HighCount();
if (partitionInfo.ModeBlockToRightEdge < 0)
{
Av1BlockSize planeBlockSize = partitionInfo.ModeInfo.BlockSize.GetSubsampled(subX, subY);
int blocksWide = partitionInfo.GetMaxBlockWide(planeBlockSize, subX);
int aboveContextCount = Math.Min(transformSizeWide, blocksWide - aboveOffset);
Array.Fill(aboveContexts, culLevel, 0, aboveContextCount);
Array.Fill(aboveContexts, 0, aboveContextCount, transformSizeWide - aboveContextCount);
}
else
{
Array.Fill(aboveContexts, culLevel, 0, transformSizeWide);
}
if (partitionInfo.ModeBlockToBottomEdge < 0)
{
Av1BlockSize planeBlockSize = partitionInfo.ModeInfo.BlockSize.GetSubsampled(subX, subY);
int blocksHigh = partitionInfo.GetMaxBlockHigh(planeBlockSize, subY);
int leftContextCount = Math.Min(transformSizeHigh, blocksHigh - leftOffset);
Array.Fill(leftContexts, culLevel, 0, leftContextCount);
Array.Fill(leftContexts, 0, leftContextCount, transformSizeWide - leftContextCount);
}
else
{
Array.Fill(leftContexts, culLevel, 0, transformSizeHigh);
}
}
private static int RecordEndOfBlockPosition(int endOfBlockPoint, int endOfBlockExtra)
{
int endOfBlock = EndOfBlockGroupStart[endOfBlockPoint];
if (endOfBlock > 2)
{
endOfBlock += endOfBlockExtra;
}
return endOfBlock;
}
private Av1TransformType ComputeTransformType(Av1PlaneType planeType, Av1PartitionInfo partitionInfo, Av1TransformSize transformSize, Av1TransformInfo transformInfo)
{
Av1TransformType transformType = Av1TransformType.DctDct;
if (this.FrameInfo.LosslessArray[partitionInfo.ModeInfo.SegmentId] || transformSize.GetSquareUpSize() > Av1TransformSize.Size32x32)
{
transformType = Av1TransformType.DctDct;
}
else
{
if (planeType == Av1PlaneType.Y)
{
transformType = transformInfo.Type;
}
else
{
// In intra mode, uv planes don't share the same prediction mode as y
// plane, so the tx_type should not be shared
transformType = ConvertIntraModeToTransformType(partitionInfo.ModeInfo, Av1PlaneType.Uv);
}
}
Av1TransformSetType transformSetType = GetExtendedTransformSetType(transformSize, this.FrameInfo.UseReducedTransformSet);
if (!transformType.IsExtendedSetUsed(transformSetType))
{
transformType = Av1TransformType.DctDct;
}
return transformType;
}
private static Av1TransformSetType GetExtendedTransformSetType(Av1TransformSize transformSize, bool useReducedSet)
{
Av1TransformSize squareUpSize = transformSize.GetSquareUpSize();
if (squareUpSize >= Av1TransformSize.Size32x32)
{
return Av1TransformSetType.DctOnly;
}
if (useReducedSet)
{
return Av1TransformSetType.Dtt4Identity;
}
Av1TransformSize squareSize = transformSize.GetSquareSize();
return squareSize == Av1TransformSize.Size16x16 ? Av1TransformSetType.Dtt4Identity : Av1TransformSetType.Dtt4Identity1dDct;
}
private static Av1TransformType ConvertIntraModeToTransformType(Av1BlockModeInfo modeInfo, Av1PlaneType planeType)
{
Av1PredictionMode mode = (planeType == Av1PlaneType.Y) ? modeInfo.YMode : modeInfo.UvMode;
if (mode == Av1PredictionMode.UvChromaFromLuma)
{
mode = Av1PredictionMode.DC;
}
return mode.ToTransformType();
}
private Av1TransformBlockContext GetTransformBlockContext(Av1TransformSize transformSize, int plane, Av1BlockSize planeBlockSize, int transformBlockUnitHighCount, int transformBlockUnitWideCount, int startY, int startX)
{
@ -583,7 +1066,7 @@ internal class Av1TileDecoder : IAv1TileDecoder
if (plane == 0)
{
if (planeBlockSize == transformSize.GetBlockSize())
if (planeBlockSize == transformSize.ToBlockSize())
{
transformBlockContext.SkipContext = 0;
}
@ -617,7 +1100,7 @@ internal class Av1TileDecoder : IAv1TileDecoder
else
{
int contextBase = GetEntropyContext(transformSize, aboveContext, leftContext);
int contextOffset = planeBlockSize.GetPelsLog2Count() > transformSize.GetBlockSize().GetPelsLog2Count() ? 10 : 7;
int contextOffset = planeBlockSize.GetPelsLog2Count() > transformSize.ToBlockSize().GetPelsLog2Count() ? 10 : 7;
transformBlockContext.SkipContext = contextBase + contextOffset;
}
@ -771,30 +1254,9 @@ internal class Av1TileDecoder : IAv1TileDecoder
/// <summary>
/// Page 65, below 5.11.5. Decode block syntax.
/// </summary>
private void ResetBlockContext(int rowIndex, int columnIndex, Av1BlockSize blockSize)
private static void ResetBlockContext(int rowIndex, int columnIndex, Av1BlockSize blockSize)
{
int block4x4Width = blockSize.Get4x4WideCount();
int block4x4Height = blockSize.Get4x4HighCount();
bool subsamplingX = this.SequenceHeader.ColorConfig.SubSamplingX;
bool subsamplingY = this.SequenceHeader.ColorConfig.SubSamplingY;
int endPlane = this.HasChroma(rowIndex, columnIndex, blockSize) ? 3 : 1;
this.aboveLevelContext = new int[3][];
this.aboveDcContext = new int[3][];
this.leftLevelContext = new int[3][];
this.leftDcContext = new int[3][];
for (int plane = 0; plane < endPlane; plane++)
{
int subX = plane > 0 && subsamplingX ? 1 : 0;
int subY = plane > 0 && subsamplingY ? 1 : 0;
this.aboveLevelContext[plane] = new int[(columnIndex + block4x4Width) >> subX];
this.aboveDcContext[plane] = new int[(columnIndex + block4x4Width) >> subX];
this.leftLevelContext[plane] = new int[(rowIndex + block4x4Height) >> subY];
this.leftDcContext[plane] = new int[(rowIndex + block4x4Height) >> subY];
Array.Fill(this.aboveLevelContext[plane], 0);
Array.Fill(this.aboveDcContext[plane], 0);
Array.Fill(this.leftLevelContext[plane], 0);
Array.Fill(this.leftDcContext[plane], 0);
}
// TODO: Do we still need this method.
}
/// <summary>

2
src/ImageSharp/Formats/Heif/Av1/Transform/Av1InverseQuantizer.cs

@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Formats.Heif.Av1.Quantization;
internal class Av1InverseQuantizer
{
public static int InverseQuantize(ObuSequenceHeader sequenceHeader, ObuFrameHeader frameHeader, ObuPartitionInfo part, Av1BlockModeInfo mode, int[] level, int[] qCoefficients, Av1TransformMode txType, Av1TransformSize txSize, Av1Plane plane)
public static int InverseQuantize(ObuSequenceHeader sequenceHeader, ObuFrameHeader frameHeader, ObuPartitionInfo part, Av1BlockModeInfo mode, int[] level, int[] qCoefficients, Av1TransformType txType, Av1TransformSize txSize, Av1Plane plane)
{
Av1ScanOrder scanOrder = Av1ScanOrderConstants.GetScanOrder(txSize, txType);
short[] scanIndices = scanOrder.Scan;

2
src/ImageSharp/Formats/Heif/Av1/Transform/Av1ScanOrder.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform;

8
src/ImageSharp/Formats/Heif/Av1/Transform/Av1ScanOrderConstants.cs

@ -1,8 +1,6 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats.Heif.Av1.Quantization;
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform;
internal static class Av1ScanOrderConstants
@ -70,6 +68,6 @@ internal static class Av1ScanOrderConstants
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,
44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63];
public static Av1ScanOrder GetScanOrder(Av1TransformSize txSize, Av1TransformMode txMode)
=> ScanOrders[(int)txSize][(int)txMode];
public static Av1ScanOrder GetScanOrder(Av1TransformSize transformSize, Av1TransformType transformType)
=> ScanOrders[(int)transformSize][(int)transformType];
}

11
src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformClass.cs

@ -0,0 +1,11 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform;
internal enum Av1TransformClass
{
Class2D = 0,
ClassHorizontal = 1,
ClassVertical = 2,
}

37
src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformSetType.cs

@ -0,0 +1,37 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform;
internal enum Av1TransformSetType
{
/// <summary>
/// DCT only.
/// </summary>
DctOnly,
/// <summary>
/// DCT + Identity only
/// </summary>
DctIdentity,
/// <summary>
/// Discrete Trig transforms w/o flip (4) + Identity (1)
/// </summary>
Dtt4Identity,
/// <summary>
/// Discrete Trig transforms w/o flip (4) + Identity (1) + 1D Hor/vert DCT (2)
/// </summary>
Dtt4Identity1dDct,
/// <summary>
/// Discrete Trig transforms w/ flip (9) + Identity (1) + 1D Hor/Ver DCT (2)
/// </summary>
Dtt9Identity1dDct,
/// <summary>
/// Discrete Trig transforms w/ flip (9) + Identity (1) + 1D Hor/Ver (6)
/// </summary>
All16
}

96
src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformSizeExtensions.cs

@ -59,6 +59,82 @@ internal static class Av1TransformSizeExtensions
Av1BlockSize.Block64x16, // TX_64X16
];
private static readonly Av1TransformSize[] SquareMap = [
Av1TransformSize.Size4x4, // TX_4X4
Av1TransformSize.Size8x8, // TX_8X8
Av1TransformSize.Size16x16, // TX_16X16
Av1TransformSize.Size32x32, // TX_32X32
Av1TransformSize.Size64x64, // TX_64X64
Av1TransformSize.Size4x4, // TX_4X8
Av1TransformSize.Size4x4, // TX_8X4
Av1TransformSize.Size8x8, // TX_8X16
Av1TransformSize.Size8x8, // TX_16X8
Av1TransformSize.Size16x16, // TX_16X32
Av1TransformSize.Size16x16, // TX_32X16
Av1TransformSize.Size32x32, // TX_32X64
Av1TransformSize.Size32x32, // TX_64X32
Av1TransformSize.Size4x4, // TX_4X16
Av1TransformSize.Size4x4, // TX_16X4
Av1TransformSize.Size8x8, // TX_8X32
Av1TransformSize.Size8x8, // TX_32X8
Av1TransformSize.Size16x16, // TX_16X64
Av1TransformSize.Size16x16, // TX_64X16
];
private static readonly Av1TransformSize[] SquareUpMap = [
Av1TransformSize.Size4x4, // TX_4X4
Av1TransformSize.Size8x8, // TX_8X8
Av1TransformSize.Size16x16, // TX_16X16
Av1TransformSize.Size32x32, // TX_32X32
Av1TransformSize.Size64x64, // TX_64X64
Av1TransformSize.Size8x8, // TX_4X8
Av1TransformSize.Size8x8, // TX_8X4
Av1TransformSize.Size16x16, // TX_8X16
Av1TransformSize.Size16x16, // TX_16X8
Av1TransformSize.Size32x32, // TX_16X32
Av1TransformSize.Size32x32, // TX_32X16
Av1TransformSize.Size64x64, // TX_32X64
Av1TransformSize.Size64x64, // TX_64X32
Av1TransformSize.Size16x16, // TX_4X16
Av1TransformSize.Size16x16, // TX_16X4
Av1TransformSize.Size32x32, // TX_8X32
Av1TransformSize.Size32x32, // TX_32X8
Av1TransformSize.Size64x64, // TX_16X64
Av1TransformSize.Size64x64, // TX_64X16
];
private static readonly int[] Log2Minus4 = [
0, // TX_4X4
2, // TX_8X8
4, // TX_16X16
6, // TX_32X32
6, // TX_64X64
1, // TX_4X8
1, // TX_8X4
3, // TX_8X16
3, // TX_16X8
5, // TX_16X32
5, // TX_32X16
6, // TX_32X64
6, // TX_64X32
2, // TX_4X16
2, // TX_16X4
4, // TX_8X32
4, // TX_32X8
5, // TX_16X64
5, // TX_64X16
];
// Transform block width in log2
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
private static readonly int[] BlockHeightLog2 = [
2, 3, 4, 5, 6, 3, 2, 4, 3, 5, 4, 6, 5, 4, 2, 5, 3, 6, 4,
];
public static int GetScale(this Av1TransformSize size)
{
int pels = Size2d[(int)size];
@ -79,5 +155,23 @@ internal static class Av1TransformSizeExtensions
public static Av1TransformSize GetSubSize(this Av1TransformSize size) => SubTransformSize[(int)size];
public static Av1BlockSize GetBlockSize(this Av1TransformSize transformSize) => (Av1BlockSize)BlockSize[(int)transformSize];
public static Av1TransformSize GetSquareSize(this Av1TransformSize size) => SquareMap[(int)size];
public static Av1TransformSize GetSquareUpSize(this Av1TransformSize size) => SquareUpMap[(int)size];
public static Av1BlockSize ToBlockSize(this Av1TransformSize transformSize) => BlockSize[(int)transformSize];
public static int GetLog2Minus4(this Av1TransformSize size) => Log2Minus4[(int)size];
public static Av1TransformSize GetAdjusted(this Av1TransformSize size) => size switch
{
Av1TransformSize.Size64x64 or Av1TransformSize.Size64x32 or Av1TransformSize.Size32x64 => Av1TransformSize.Size32x32,
Av1TransformSize.Size64x16 => Av1TransformSize.Size32x16,
Av1TransformSize.Size16x64 => Av1TransformSize.Size16x32,
_ => size
};
public static int GetBlockWidthLog2(this Av1TransformSize size) => BlockWidthLog2[(int)GetAdjusted(size)];
public static int GetBlockHeightLog2(this Av1TransformSize size) => BlockHeightLog2[(int)GetAdjusted(size)];
}

42
src/ImageSharp/Formats/Heif/Av1/Transform/Av1TransformTypeExtensions.cs

@ -0,0 +1,42 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System;
namespace SixLabors.ImageSharp.Formats.Heif.Av1.Transform;
internal static class Av1TransformTypeExtensions
{
private static readonly Av1TransformClass[] Type2Class = [
Av1TransformClass.Class2D, // DCT_DCT
Av1TransformClass.Class2D, // ADST_DCT
Av1TransformClass.Class2D, // DCT_ADST
Av1TransformClass.Class2D, // ADST_ADST
Av1TransformClass.Class2D, // FLIPADST_DCT
Av1TransformClass.Class2D, // DCT_FLIPADST
Av1TransformClass.Class2D, // FLIPADST_FLIPADST
Av1TransformClass.Class2D, // ADST_FLIPADST
Av1TransformClass.Class2D, // FLIPADST_ADST
Av1TransformClass.Class2D, // IDTX
Av1TransformClass.ClassVertical, // V_DCT
Av1TransformClass.ClassHorizontal, // H_DCT
Av1TransformClass.ClassVertical, // V_ADST
Av1TransformClass.ClassHorizontal, // H_ADST
Av1TransformClass.ClassVertical, // V_FLIPADST
Av1TransformClass.ClassHorizontal, // H_FLIPADST
];
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],
[true, true, true, true, false, false, false, false, false, true, false, false, false, false, false, false],
[true, true, true, true, false, false, false, false, false, true, true, true, false, false, false, false],
[true, true, true, true, true, true, true, true, true, true, true, true, false, false, false, false],
[true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true],
];
public static Av1TransformClass ToClass(this Av1TransformType transformType) => Type2Class[(int)transformType];
public static bool IsExtendedSetUsed(this Av1TransformType transformType, Av1TransformSetType setType)
=> ExtendedTransformUsed[(int)setType][(int)transformType];
}

4
tests/ImageSharp.Tests/Formats/Heif/Av1/SymbolTest.cs

@ -206,7 +206,7 @@ public class SymbolTest
using IMemoryOwner<byte> encoded = encoder.Exit();
Av1SymbolDecoder decoder = new(encoded.GetSpan());
Av1SymbolDecoder decoder = new(encoded.GetSpan(), 0);
Av1SymbolReader reader = new(encoded.GetSpan());
for (int i = 0; i < values.Length; i++)
{
@ -234,7 +234,7 @@ public class SymbolTest
using IMemoryOwner<byte> encoded = encoder.Exit();
Av1SymbolDecoder decoder = new(encoded.GetSpan());
Av1SymbolDecoder decoder = new(encoded.GetSpan(), 0);
Av1SymbolReader reader = new(encoded.GetSpan());
for (int i = 0; i < values.Length; i++)
{

Loading…
Cancel
Save