diff --git a/src/ImageSharp/Formats/Heif/Av1/Av1Constants.cs b/src/ImageSharp/Formats/Heif/Av1/Av1Constants.cs index 2cb64a545b..fb8203ae70 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Av1Constants.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Av1Constants.cs @@ -168,4 +168,9 @@ internal static class Av1Constants public const int BaseRangeSizeMinus1 = 3; public const int MaxBaseRange = 15; + + /// + /// Log2 of number of values for ChromaFromLuma Alpha U and ChromaFromLuma Alpha V. + /// + public const int ChromaFromLumaAlphabetSizeLog2 = 4; } diff --git a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1DefaultDistributions.cs b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1DefaultDistributions.cs index 3991b55f5f..afda5388eb 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1DefaultDistributions.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1DefaultDistributions.cs @@ -1994,6 +1994,18 @@ internal static class Av1DefaultDistributions ] ]; + public static Av1Distribution ChromeForLumaSign => new(1418, 2123, 13340, 18405, 26972, 28343, 32294); + + public static Av1Distribution[] ChromeForLumaAlpha => + [ + new(7637, 20719, 31401, 32481, 32657, 32688, 32692, 32696, 32700, 32704, 32708, 32712, 32716, 32720, 32724), + new(14365, 23603, 28135, 31168, 32167, 32395, 32487, 32573, 32620, 32647, 32668, 32672, 32676, 32680, 32684), + new(11532, 22380, 28445, 31360, 32349, 32523, 32584, 32649, 32673, 32677, 32681, 32685, 32689, 32693, 32697), + new(26990, 31402, 32282, 32571, 32692, 32696, 32700, 32704, 32708, 32712, 32716, 32720, 32724, 32728, 32732), + new(17248, 26058, 28904, 30608, 31305, 31877, 32126, 32321, 32394, 32464, 32516, 32560, 32576, 32593, 32622), + new(14738, 21678, 25779, 27901, 29024, 30302, 30980, 31843, 32144, 32413, 32520, 32594, 32622, 32656, 32660) + ]; + public static Av1Distribution[][][] GetEndOfBlockFlag(int baseQIndex) { int qContext = GetQContext(baseQIndex); diff --git a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1Distribution.cs b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1Distribution.cs index 241b6ec4e1..9e4a6d3edd 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1Distribution.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1Distribution.cs @@ -79,6 +79,11 @@ internal class Av1Distribution { } + 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, uint p12, uint p13, uint p14) + : this([p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, 0], 2) + { + } + private Av1Distribution(uint[] props, int speed) { // this.probabilities = props; diff --git a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1SymbolDecoder.cs b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1SymbolDecoder.cs index 01226aef26..dde2e72e48 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1SymbolDecoder.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1SymbolDecoder.cs @@ -29,6 +29,8 @@ internal ref struct Av1SymbolDecoder private readonly Av1Distribution[][][] coefficientsBaseRange; private readonly Av1Distribution[][] transformBlockSkip; private readonly Av1Distribution[][][] endOfBlockExtra; + private readonly Av1Distribution chromeForLumaSign = Av1DefaultDistributions.ChromeForLumaSign; + private readonly Av1Distribution[] chromeForLumaAlpha = Av1DefaultDistributions.ChromeForLumaAlpha; private Av1SymbolReader reader; public Av1SymbolDecoder(Span tileData, int qIndex) @@ -236,6 +238,26 @@ internal ref struct Av1SymbolDecoder return r.ReadSymbol(this.coefficientsBase[(int)transformSizeContext][(int)planeType][coefficientContext]); } + public int ReadChromFromLumaSign() + { + ref Av1SymbolReader r = ref this.reader; + return r.ReadSymbol(this.chromeForLumaSign); + } + + public int ReadChromaFromLumaAlphaU(int jointSign) + { + ref Av1SymbolReader r = ref this.reader; + int context = jointSign + 1 - 3; + return r.ReadSymbol(this.chromeForLumaAlpha[context]); + } + + public int ReadChromaFromLumaAlphaV(int jointSign) + { + ref Av1SymbolReader r = ref this.reader; + int context = (((jointSign + 1) % 3) * 3) + ((jointSign + 1) / 3) - 3; + return r.ReadSymbol(this.chromeForLumaAlpha[context]); + } + private static uint GetElementProbability(Av1Distribution probability, Av1PartitionType element) => probability[(int)element - 1] - probability[(int)element]; } diff --git a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileDecoder.cs b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileDecoder.cs index 830f3c6454..49f2cbd050 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileDecoder.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileDecoder.cs @@ -1449,7 +1449,7 @@ internal class Av1TileDecoder : IAv1TileDecoder partitionInfo.ModeInfo.UvMode = reader.ReadIntraModeUv(partitionInfo.ModeInfo.YMode, this.IsChromaForLumaAllowed(partitionInfo)); if (partitionInfo.ModeInfo.UvMode == Av1PredictionMode.UvChromaFromLuma) { - this.ReadChromaFromLumaAlphas(ref reader, partitionInfo); + ReadChromaFromLumaAlphas(ref reader, partitionInfo.ModeInfo); } // 5.11.43.Intra angle info chroma syntax. @@ -1523,10 +1523,23 @@ internal class Av1TileDecoder : IAv1TileDecoder /// /// 5.11.45. Read CFL alphas syntax. /// - private void ReadChromaFromLumaAlphas(ref Av1SymbolDecoder reader, Av1PartitionInfo partitionInfo) => + private static void ReadChromaFromLumaAlphas(ref Av1SymbolDecoder reader, Av1BlockModeInfo modeInfo) + { + int jointSign = reader.ReadChromFromLumaSign(); + int index = 0; + if (jointSign + 1 != 0) + { + index = reader.ReadChromaFromLumaAlphaU(jointSign) << Av1Constants.ChromaFromLumaAlphabetSizeLog2; + } - // TODO: Implement. - throw new NotImplementedException(); + if ((jointSign + 1) % 3 != 0) + { + index += reader.ReadChromaFromLumaAlphaV(jointSign); + } + + modeInfo.ChromaFromLumaAlphaSign = jointSign; + modeInfo.ChromaFromLumaAlphaIndex = index; + } /// /// 5.11.42. and 5.11.43.