diff --git a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1SymbolDecoder.cs b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1SymbolDecoder.cs index d33b5f6599..a80b62e3d7 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1SymbolDecoder.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1SymbolDecoder.cs @@ -197,48 +197,346 @@ internal ref struct Av1SymbolDecoder return r.ReadSymbol(this.endOfBlockExtra[(int)transformSizeContext][(int)planeType][endOfBlockContext]) > 0; } - public int ReadCoefficientsBaseRange(Av1TransformSize transformSizeContext, Av1PlaneType planeType, int baseRangeContext) + public int ReadChromFromLumaSign() + { + ref Av1SymbolReader r = ref this.reader; + return r.ReadSymbol(this.chromeForLumaSign); + } + + public int ReadChromaFromLumaAlphaU(int jointSignPlus1) + { + ref Av1SymbolReader r = ref this.reader; + int context = jointSignPlus1 - 3; + return r.ReadSymbol(this.chromeForLumaAlpha[context]); + } + + public int ReadChromaFromLumaAlphaV(int jointSignPlus1) + { + ref Av1SymbolReader r = ref this.reader; + int context = AlphaVContexts[jointSignPlus1]; + return r.ReadSymbol(this.chromeForLumaAlpha[context]); + } + + public void ReadCoefficientsEndOfBlock(Av1TransformClass transformClass, int endOfBlock, int height, Span scan, int bwl, Span levels, Av1TransformSize transformSizeContext, Av1PlaneType planeType) + { + int i = endOfBlock - 1; + int pos = scan[i]; + int coefficientContext = GetLowerLevelContextEndOfBlock(bwl, height, i); + int level = this.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 = this.ReadCoefficientsBaseRange(transformSizeContext, planeType, baseRangeContext); + level += coefficinetBaseRange; + if (coefficinetBaseRange < Av1Constants.BaseRangeSizeMinus1) + { + break; + } + } + } + + levels[GetPaddedIndex(pos, bwl)] = level; + } + + public void ReadCoefficientsReverse2d(Av1TransformSize transformSize, int startSi, int endSi, Span scan, int bwl, Span levels, Av1TransformSize transformSizeContext, Av1PlaneType planeType) + { + for (int c = endSi; c >= startSi; --c) + { + int pos = scan[c]; + int coefficientContext = GetLowerLevelsContext2d(levels, pos, bwl, transformSize); + int level = this.ReadCoefficientsBase(coefficientContext, transformSizeContext, planeType); + if (level > Av1Constants.BaseLevelsCount) + { + int baseRangeContext = GetBaseRangeContext2d(levels, pos, bwl); + for (int idx = 0; idx < Av1Constants.CoefficientBaseRange; idx += Av1Constants.BaseRangeSizeMinus1) + { + int k = this.ReadCoefficientsBaseRange(transformSizeContext, planeType, baseRangeContext); + level += k; + if (k < Av1Constants.BaseRangeSizeMinus1) + { + break; + } + } + } + + levels[GetPaddedIndex(pos, bwl)] = level; + } + } + + public void ReadCoefficientsReverse(Av1TransformSize transformSize, Av1TransformClass transformClass, int startSi, int endSi, Span scan, int bwl, Span levels, Av1TransformSize transformSizeContext, Av1PlaneType planeType) + { + for (int c = endSi; c >= startSi; --c) + { + int pos = scan[c]; + int coefficientContext = GetLowerLevelsContext(levels, pos, bwl, transformSize, transformClass); + int level = this.ReadCoefficientsBase(coefficientContext, 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 = this.ReadCoefficientsBaseRange(transformSizeContext, planeType, baseRangeContext); + level += k; + if (k < Av1Constants.BaseRangeSizeMinus1) + { + break; + } + } + } + + levels[GetPaddedIndex(pos, bwl)] = level; + } + } + + public int ReadCoefficientsDc(Span coefficientBuffer, int endOfBlock, Span scan, int bwl, Span levels, int dcSignContext, Av1PlaneType planeType) + { + int maxScanLine = 0; + int culLevel = 0; + int dcValue = 0; + coefficientBuffer[0] = endOfBlock; + for (int c = 0; c < endOfBlock; c++) + { + int sign = 0; + int level = levels[GetPaddedIndex(scan[c], bwl)]; + if (level != 0) + { + maxScanLine = Math.Max(maxScanLine, scan[c]); + if (c == 0) + { + sign = this.ReadDcSign(planeType, dcSignContext); + } + else + { + sign = this.ReadLiteral(1); + } + + if (level >= Av1Constants.CoefficientBaseRange + Av1Constants.BaseLevelsCount + 1) + { + level += this.ReadGolomb(); + } + + 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); + + return culLevel; + } + + private int ReadCoefficientsBaseRange(Av1TransformSize transformSizeContext, Av1PlaneType planeType, int baseRangeContext) { ref Av1SymbolReader r = ref this.reader; return r.ReadSymbol(this.coefficientsBaseRange[(int)transformSizeContext][(int)planeType][baseRangeContext]); } - public int ReadDcSign(Av1PlaneType planeType, int dcSignContext) + private int ReadDcSign(Av1PlaneType planeType, int dcSignContext) { ref Av1SymbolReader r = ref this.reader; return r.ReadSymbol(this.dcSign[(int)planeType][dcSignContext]); } - public int ReadBaseEndOfBlock(Av1TransformSize transformSizeContext, Av1PlaneType planeType, int coefficientContext) + private int ReadBaseEndOfBlock(Av1TransformSize transformSizeContext, Av1PlaneType planeType, int coefficientContext) { ref Av1SymbolReader r = ref this.reader; return r.ReadSymbol(this.baseEndOfBlock[(int)transformSizeContext][(int)planeType][coefficientContext]); } - public int ReadCoefficientsBase(int coefficientContext, Av1TransformSize transformSizeContext, Av1PlaneType planeType) + private int ReadCoefficientsBase(int coefficientContext, Av1TransformSize transformSizeContext, Av1PlaneType planeType) { ref Av1SymbolReader r = ref this.reader; return r.ReadSymbol(this.coefficientsBase[(int)transformSizeContext][(int)planeType][coefficientContext]); } - public int ReadChromFromLumaSign() + private static int GetBaseRangeContextEndOfBlock(int pos, int bwl, Av1TransformClass transformClass) { - ref Av1SymbolReader r = ref this.reader; - return r.ReadSymbol(this.chromeForLumaSign); + 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; } - public int ReadChromaFromLumaAlphaU(int jointSignPlus1) + private static int GetLowerLevelContextEndOfBlock(int bwl, int height, int scanIndex) { - ref Av1SymbolReader r = ref this.reader; - int context = jointSignPlus1 - 3; - return r.ReadSymbol(this.chromeForLumaAlpha[context]); + if (scanIndex == 0) + { + return 0; + } + + if (scanIndex <= (height << bwl) >> 3) + { + return 1; + } + + if (scanIndex <= (height << bwl) >> 2) + { + return 2; + } + + return 3; } - public int ReadChromaFromLumaAlphaV(int jointSignPlus1) + private static int GetBaseRangeContext2d(Span levels, int c, int bwl) { - ref Av1SymbolReader r = ref this.reader; - int context = AlphaVContexts[jointSignPlus1]; - return r.ReadSymbol(this.chromeForLumaAlpha[context]); + 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 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 int GetBaseRangeContext(Span 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 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 GetPaddedIndex(int scanIndex, int bwl) + => scanIndex + ((scanIndex >> bwl) << Av1Constants.TransformPadHorizontalLog2); + + private int ReadGolomb() + { + int x = 1; + int length = 0; + int i = 0; + + while (i == 0) + { + i = this.ReadLiteral(1); + ++length; + if (length > 20) + { + // SVT_LOG("Invalid length in read_golomb"); + break; + } + } + + for (i = 0; i < length - 1; ++i) + { + x <<= 1; + x += this.ReadLiteral(1); + } + + return x - 1; + } + + private static void SetDcSign(ref int culLevel, int dcValue) + { + if (dcValue < 0) + { + culLevel |= 1 << Av1Constants.CoefficientContextBitCount; + } + else if (dcValue > 0) + { + culLevel += 2 << Av1Constants.CoefficientContextBitCount; + } } internal static Av1Distribution GetSplitOrHorizontalDistribution(Av1Distribution[] inputs, Av1BlockSize blockSize, int context) diff --git a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileReader.cs b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileReader.cs index d4355fc016..934355e708 100644 --- a/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileReader.cs +++ b/src/ImageSharp/Formats/Heif/Av1/Tiling/Av1TileReader.cs @@ -566,7 +566,6 @@ internal class Av1TileReader : IAv1TileReader 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 levels = levelsBuffer.AsSpan()[(Av1Constants.TransformPadTop * (width + Av1Constants.TransformPadHorizontal))..]; @@ -574,7 +573,6 @@ internal class Av1TileReader : IAv1TileReader bool allZero = reader.ReadTransformBlockSkip(transformSizeContext, transformBlockContext.SkipContext); int bwl = transformSize.GetBlockWidthLog2(); int endOfBlock; - int maxScanLine = 0; if (allZero) { if (plane == 0) @@ -623,314 +621,28 @@ internal class Av1TileReader : IAv1TileReader 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.ReadCoefficientsBaseRange(transformSizeContext, planeType, baseRangeContext); - level += coefficinetBaseRange; - if (coefficinetBaseRange < Av1Constants.BaseRangeSizeMinus1) - { - break; - } - } - } - - levels[GetPaddedIndex(pos, bwl)] = level; - + reader.ReadCoefficientsEndOfBlock(transformClass, endOfBlock, height, scan, bwl, levels, transformSizeContext, planeType); 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); + reader.ReadCoefficientsReverse2d(transformSize, 1, endOfBlock - 1 - 1, scan, bwl, levels, transformSizeContext, planeType); + reader.ReadCoefficientsReverse(transformSize, transformClass, 0, 0, scan, bwl, levels, transformSizeContext, planeType); } else { - ReadCoefficientsReverse(ref reader, transformSize, transformInfo.Type, 0, endOfBlock - 1 - 1, scan, bwl, levels, transformSizeContext, planeType); + reader.ReadCoefficientsReverse(transformSize, transformClass, 0, endOfBlock - 1 - 1, scan, bwl, levels, transformSizeContext, planeType); } } DebugGuard.MustBeGreaterThan(scan.Length, 0, nameof(scan)); - coefficientBuffer[0] = 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); - + culLevel = reader.ReadCoefficientsDc(coefficientBuffer, endOfBlock, scan, bwl, levels, transformBlockContext.DcSignContext, planeType); 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 scan, int bwl, Span levels, Av1TransformSize transformSizeContext, Av1PlaneType planeType) - { - for (int c = endSi; c >= startSi; --c) - { - int pos = scan[c]; - int coefficientContext = GetLowerLevelsContext2d(levels, pos, bwl, transformSize); - int level = reader.ReadCoefficientsBase(coefficientContext, 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.ReadCoefficientsBaseRange(transformSizeContext, planeType, baseRangeContext); - level += k; - if (k < Av1Constants.BaseRangeSizeMinus1) - { - break; - } - } - } - - levels[GetPaddedIndex(pos, bwl)] = level; - } - } - - private static int GetBaseRangeContext2d(Span 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 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 scan, int bwl, Span levels, Av1TransformSize transformSizeContext, Av1PlaneType planeType) - { - Av1TransformClass transformClass = transformType.ToClass(); - for (int c = endSi; c >= startSi; --c) - { - int pos = scan[c]; - int coefficientContext = GetLowerLevelsContext(levels, pos, bwl, transformSize, transformClass); - int level = reader.ReadCoefficientsBase(coefficientContext, 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.ReadCoefficientsBaseRange(transformSizeContext, planeType, baseRangeContext); - level += k; - if (k < Av1Constants.BaseRangeSizeMinus1) - { - break; - } - } - } - - levels[GetPaddedIndex(pos, bwl)] = level; - } - } - - private static int GetBaseRangeContext(Span 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 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.CoefficientContextBitCount; - } - else if (dcValue > 0) - { - culLevel += 2 << Av1Constants.CoefficientContextBitCount; - } - } - - 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;