1160 lines
		
	
	
	
		
			42 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			1160 lines
		
	
	
	
		
			42 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using Ryujinx.Common.Memory;
 | |
| using Ryujinx.Graphics.Nvdec.Vp9.Dsp;
 | |
| using Ryujinx.Graphics.Nvdec.Vp9.Types;
 | |
| using Ryujinx.Graphics.Video;
 | |
| using System;
 | |
| using System.Diagnostics;
 | |
| using System.Runtime.CompilerServices;
 | |
| using Mv = Ryujinx.Graphics.Nvdec.Vp9.Types.Mv;
 | |
| using MvRef = Ryujinx.Graphics.Nvdec.Vp9.Types.MvRef;
 | |
| 
 | |
| namespace Ryujinx.Graphics.Nvdec.Vp9
 | |
| {
 | |
|     internal static class DecodeMv
 | |
|     {
 | |
|         private const int MvrefNeighbours = 8;
 | |
| 
 | |
|         private static PredictionMode ReadIntraMode(ref Reader r, ReadOnlySpan<byte> p)
 | |
|         {
 | |
|             return (PredictionMode)r.ReadTree(Luts.Vp9IntraModeTree, p);
 | |
|         }
 | |
| 
 | |
|         private static PredictionMode ReadIntraModeY(ref Vp9Common cm, ref MacroBlockD xd, ref Reader r, int sizeGroup)
 | |
|         {
 | |
|             PredictionMode yMode = ReadIntraMode(ref r, cm.Fc.Value.YModeProb[sizeGroup].ToSpan());
 | |
|             if (!xd.Counts.IsNull)
 | |
|             {
 | |
|                 ++xd.Counts.Value.YMode[sizeGroup][(int)yMode];
 | |
|             }
 | |
| 
 | |
|             return yMode;
 | |
|         }
 | |
| 
 | |
|         private static PredictionMode ReadIntraModeUv(ref Vp9Common cm, ref MacroBlockD xd, ref Reader r, byte yMode)
 | |
|         {
 | |
|             PredictionMode uvMode = ReadIntraMode(ref r, cm.Fc.Value.UvModeProb[yMode].ToSpan());
 | |
|             if (!xd.Counts.IsNull)
 | |
|             {
 | |
|                 ++xd.Counts.Value.UvMode[yMode][(int)uvMode];
 | |
|             }
 | |
| 
 | |
|             return uvMode;
 | |
|         }
 | |
| 
 | |
|         private static PredictionMode ReadInterMode(ref Vp9Common cm, ref MacroBlockD xd, ref Reader r, int ctx)
 | |
|         {
 | |
|             int mode = r.ReadTree(Luts.Vp9InterModeTree, cm.Fc.Value.InterModeProb[ctx].ToSpan());
 | |
|             if (!xd.Counts.IsNull)
 | |
|             {
 | |
|                 ++xd.Counts.Value.InterMode[ctx][mode];
 | |
|             }
 | |
| 
 | |
|             return PredictionMode.NearestMv + mode;
 | |
|         }
 | |
| 
 | |
|         private static int ReadSegmentId(ref Reader r, ref Array7<byte> segTreeProbs)
 | |
|         {
 | |
|             return r.ReadTree(Luts.Vp9SegmentTree, segTreeProbs.ToSpan());
 | |
|         }
 | |
| 
 | |
|         private static ReadOnlySpan<byte> GetTxProbs(ref Vp9EntropyProbs fc, TxSize maxTxSize, int ctx)
 | |
|         {
 | |
|             switch (maxTxSize)
 | |
|             {
 | |
|                 case TxSize.Tx8x8: return fc.Tx8x8Prob[ctx].ToSpan();
 | |
|                 case TxSize.Tx16x16: return fc.Tx16x16Prob[ctx].ToSpan();
 | |
|                 case TxSize.Tx32x32: return fc.Tx32x32Prob[ctx].ToSpan();
 | |
|                 default: Debug.Assert(false, "Invalid maxTxSize."); return ReadOnlySpan<byte>.Empty;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private static Span<uint> GetTxCounts(ref Vp9BackwardUpdates counts, TxSize maxTxSize, int ctx)
 | |
|         {
 | |
|             switch (maxTxSize)
 | |
|             {
 | |
|                 case TxSize.Tx8x8: return counts.Tx8x8[ctx].ToSpan();
 | |
|                 case TxSize.Tx16x16: return counts.Tx16x16[ctx].ToSpan();
 | |
|                 case TxSize.Tx32x32: return counts.Tx32x32[ctx].ToSpan();
 | |
|                 default: Debug.Assert(false, "Invalid maxTxSize."); return Span<uint>.Empty;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private static TxSize ReadSelectedTxSize(ref Vp9Common cm, ref MacroBlockD xd, TxSize maxTxSize, ref Reader r)
 | |
|         {
 | |
|             int ctx = xd.GetTxSizeContext();
 | |
|             ReadOnlySpan<byte> txProbs = GetTxProbs(ref cm.Fc.Value, maxTxSize, ctx);
 | |
|             TxSize txSize = (TxSize)r.Read(txProbs[0]);
 | |
|             if (txSize != TxSize.Tx4x4 && maxTxSize >= TxSize.Tx16x16)
 | |
|             {
 | |
|                 txSize += r.Read(txProbs[1]);
 | |
|                 if (txSize != TxSize.Tx8x8 && maxTxSize >= TxSize.Tx32x32)
 | |
|                 {
 | |
|                     txSize += r.Read(txProbs[2]);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if (!xd.Counts.IsNull)
 | |
|             {
 | |
|                 ++GetTxCounts(ref xd.Counts.Value, maxTxSize, ctx)[(int)txSize];
 | |
|             }
 | |
| 
 | |
|             return txSize;
 | |
|         }
 | |
| 
 | |
|         private static TxSize ReadTxSize(ref Vp9Common cm, ref MacroBlockD xd, bool allowSelect, ref Reader r)
 | |
|         {
 | |
|             TxMode txMode = cm.TxMode;
 | |
|             BlockSize bsize = xd.Mi[0].Value.SbType;
 | |
|             TxSize maxTxSize = Luts.MaxTxSizeLookup[(int)bsize];
 | |
|             if (allowSelect && txMode == TxMode.TxModeSelect && bsize >= BlockSize.Block8x8)
 | |
|             {
 | |
|                 return ReadSelectedTxSize(ref cm, ref xd, maxTxSize, ref r);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 return (TxSize)Math.Min((int)maxTxSize, (int)Luts.TxModeToBiggestTxSize[(int)txMode]);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private static int DecGetSegmentId(ref Vp9Common cm, ArrayPtr<byte> segmentIds, int miOffset, int xMis, int yMis)
 | |
|         {
 | |
|             int x, y, segmentId = int.MaxValue;
 | |
| 
 | |
|             for (y = 0; y < yMis; y++)
 | |
|             {
 | |
|                 for (x = 0; x < xMis; x++)
 | |
|                 {
 | |
|                     segmentId = Math.Min(segmentId, segmentIds[miOffset + y * cm.MiCols + x]);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             Debug.Assert(segmentId >= 0 && segmentId < Constants.MaxSegments);
 | |
|             return segmentId;
 | |
|         }
 | |
| 
 | |
|         private static void SetSegmentId(ref Vp9Common cm, int miOffset, int xMis, int yMis, int segmentId)
 | |
|         {
 | |
|             int x, y;
 | |
| 
 | |
|             Debug.Assert(segmentId >= 0 && segmentId < Constants.MaxSegments);
 | |
| 
 | |
|             for (y = 0; y < yMis; y++)
 | |
|             {
 | |
|                 for (x = 0; x < xMis; x++)
 | |
|                 {
 | |
|                     cm.CurrentFrameSegMap[miOffset + y * cm.MiCols + x] = (byte)segmentId;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private static void CopySegmentId(
 | |
|             ref Vp9Common cm,
 | |
|             ArrayPtr<byte> lastSegmentIds,
 | |
|             ArrayPtr<byte> currentSegmentIds,
 | |
|             int miOffset,
 | |
|             int xMis,
 | |
|             int yMis)
 | |
|         {
 | |
|             int x, y;
 | |
| 
 | |
|             for (y = 0; y < yMis; y++)
 | |
|             {
 | |
|                 for (x = 0; x < xMis; x++)
 | |
|                 {
 | |
|                     currentSegmentIds[miOffset + y * cm.MiCols + x] = (byte)(!lastSegmentIds.IsNull ? lastSegmentIds[miOffset + y * cm.MiCols + x] : 0);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private static int ReadIntraSegmentId(ref Vp9Common cm, int miOffset, int xMis, int yMis, ref Reader r)
 | |
|         {
 | |
|             ref Segmentation seg = ref cm.Seg;
 | |
|             int segmentId;
 | |
| 
 | |
|             if (!seg.Enabled)
 | |
|             {
 | |
|                 return 0;  // Default for disabled segmentation
 | |
|             }
 | |
| 
 | |
|             if (!seg.UpdateMap)
 | |
|             {
 | |
|                 CopySegmentId(ref cm, cm.LastFrameSegMap, cm.CurrentFrameSegMap, miOffset, xMis, yMis);
 | |
|                 return 0;
 | |
|             }
 | |
| 
 | |
|             segmentId = ReadSegmentId(ref r, ref cm.Fc.Value.SegTreeProb);
 | |
|             SetSegmentId(ref cm, miOffset, xMis, yMis, segmentId);
 | |
|             return segmentId;
 | |
|         }
 | |
| 
 | |
|         private static int ReadInterSegmentId(
 | |
|             ref Vp9Common cm,
 | |
|             ref MacroBlockD xd,
 | |
|             int miRow,
 | |
|             int miCol,
 | |
|             ref Reader r,
 | |
|             int xMis,
 | |
|             int yMis)
 | |
|         {
 | |
|             ref Segmentation seg = ref cm.Seg;
 | |
|             ref ModeInfo mi = ref xd.Mi[0].Value;
 | |
|             int predictedSegmentId, segmentId;
 | |
|             int miOffset = miRow * cm.MiCols + miCol;
 | |
| 
 | |
|             if (!seg.Enabled)
 | |
|             {
 | |
|                 return 0;  // Default for disabled segmentation
 | |
|             }
 | |
| 
 | |
|             predictedSegmentId = !cm.LastFrameSegMap.IsNull
 | |
|                 ? DecGetSegmentId(ref cm, cm.LastFrameSegMap, miOffset, xMis, yMis)
 | |
|                 : 0;
 | |
| 
 | |
|             if (!seg.UpdateMap)
 | |
|             {
 | |
|                 CopySegmentId(ref cm, cm.LastFrameSegMap, cm.CurrentFrameSegMap, miOffset, xMis, yMis);
 | |
|                 return predictedSegmentId;
 | |
|             }
 | |
| 
 | |
|             if (seg.TemporalUpdate)
 | |
|             {
 | |
|                 byte predProb = Segmentation.GetPredProbSegId(ref cm.Fc.Value.SegPredProb, ref xd);
 | |
|                 mi.SegIdPredicted = (sbyte)r.Read(predProb);
 | |
|                 segmentId = mi.SegIdPredicted != 0 ? predictedSegmentId : ReadSegmentId(ref r, ref cm.Fc.Value.SegTreeProb);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 segmentId = ReadSegmentId(ref r, ref cm.Fc.Value.SegTreeProb);
 | |
|             }
 | |
|             SetSegmentId(ref cm, miOffset, xMis, yMis, segmentId);
 | |
|             return segmentId;
 | |
|         }
 | |
| 
 | |
|         private static int ReadSkip(ref Vp9Common cm, ref MacroBlockD xd, int segmentId, ref Reader r)
 | |
|         {
 | |
|             if (cm.Seg.IsSegFeatureActive(segmentId, SegLvlFeatures.SegLvlSkip) != 0)
 | |
|             {
 | |
|                 return 1;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 int ctx = xd.GetSkipContext();
 | |
|                 int skip = r.Read(cm.Fc.Value.SkipProb[ctx]);
 | |
|                 if (!xd.Counts.IsNull)
 | |
|                 {
 | |
|                     ++xd.Counts.Value.Skip[ctx][skip];
 | |
|                 }
 | |
| 
 | |
|                 return skip;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private static int ReadMvComponent(ref Reader r, ref Vp9EntropyProbs fc, int mvcomp, bool usehp)
 | |
|         {
 | |
|             int mag, d, fr, hp;
 | |
|             bool sign = r.Read(fc.Sign[mvcomp]) != 0;
 | |
|             MvClassType mvClass = (MvClassType)r.ReadTree(Luts.Vp9MvClassTree, fc.Classes[mvcomp].ToSpan());
 | |
|             bool class0 = mvClass == MvClassType.MvClass0;
 | |
| 
 | |
|             // Integer part
 | |
|             if (class0)
 | |
|             {
 | |
|                 d = r.Read(fc.Class0[mvcomp][0]);
 | |
|                 mag = 0;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 int i;
 | |
|                 int n = (int)mvClass + Constants.Class0Bits - 1;  // Number of bits
 | |
| 
 | |
|                 d = 0;
 | |
|                 for (i = 0; i < n; ++i)
 | |
|                 {
 | |
|                     d |= r.Read(fc.Bits[mvcomp][i]) << i;
 | |
|                 }
 | |
| 
 | |
|                 mag = Constants.Class0Size << ((int)mvClass + 2);
 | |
|             }
 | |
| 
 | |
|             // Fractional part
 | |
|             fr = r.ReadTree(Luts.Vp9MvFPTree, class0 ? fc.Class0Fp[mvcomp][d].ToSpan() : fc.Fp[mvcomp].ToSpan());
 | |
| 
 | |
|             // High precision part (if hp is not used, the default value of the hp is 1)
 | |
|             hp = usehp ? r.Read(class0 ? fc.Class0Hp[mvcomp] : fc.Hp[mvcomp]) : 1;
 | |
| 
 | |
|             // Result
 | |
|             mag += ((d << 3) | (fr << 1) | hp) + 1;
 | |
|             return sign ? -mag : mag;
 | |
|         }
 | |
| 
 | |
|         private static void ReadMv(
 | |
|             ref Reader r,
 | |
|             ref Mv mv,
 | |
|             ref Mv refr,
 | |
|             ref Vp9EntropyProbs fc,
 | |
|             Ptr<Vp9BackwardUpdates> counts,
 | |
|             bool allowHP)
 | |
|         {
 | |
|             MvJointType jointType = (MvJointType)r.ReadTree(Luts.Vp9MvJointTree, fc.Joints.ToSpan());
 | |
|             bool useHP = allowHP && refr.UseMvHp();
 | |
|             Mv diff = new Mv();
 | |
| 
 | |
|             if (Mv.MvJointVertical(jointType))
 | |
|             {
 | |
|                 diff.Row = (short)ReadMvComponent(ref r, ref fc, 0, useHP);
 | |
|             }
 | |
| 
 | |
|             if (Mv.MvJointHorizontal(jointType))
 | |
|             {
 | |
|                 diff.Col = (short)ReadMvComponent(ref r, ref fc, 1, useHP);
 | |
|             }
 | |
| 
 | |
|             diff.IncMv(counts);
 | |
| 
 | |
|             mv.Row = (short)(refr.Row + diff.Row);
 | |
|             mv.Col = (short)(refr.Col + diff.Col);
 | |
|         }
 | |
| 
 | |
|         private static ReferenceMode ReadBlockReferenceMode(ref Vp9Common cm, ref MacroBlockD xd, ref Reader r)
 | |
|         {
 | |
|             if (cm.ReferenceMode == ReferenceMode.ReferenceModeSelect)
 | |
|             {
 | |
|                 int ctx = PredCommon.GetReferenceModeContext(ref cm, ref xd);
 | |
|                 ReferenceMode mode = (ReferenceMode)r.Read(cm.Fc.Value.CompInterProb[ctx]);
 | |
|                 if (!xd.Counts.IsNull)
 | |
|                 {
 | |
|                     ++xd.Counts.Value.CompInter[ctx][(int)mode];
 | |
|                 }
 | |
| 
 | |
|                 return mode;  // SingleReference or CompoundReference
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 return cm.ReferenceMode;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // Read the referncence frame
 | |
|         private static void ReadRefFrames(
 | |
|             ref Vp9Common cm,
 | |
|             ref MacroBlockD xd,
 | |
|             ref Reader r,
 | |
|             int segmentId,
 | |
|             ref Array2<sbyte> refFrame)
 | |
|         {
 | |
|             ref Vp9EntropyProbs fc = ref cm.Fc.Value;
 | |
| 
 | |
|             if (cm.Seg.IsSegFeatureActive(segmentId, SegLvlFeatures.SegLvlRefFrame) != 0)
 | |
|             {
 | |
|                 refFrame[0] = (sbyte)cm.Seg.GetSegData(segmentId, SegLvlFeatures.SegLvlRefFrame);
 | |
|                 refFrame[1] = Constants.None;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 ReferenceMode mode = ReadBlockReferenceMode(ref cm, ref xd, ref r);
 | |
|                 if (mode == ReferenceMode.CompoundReference)
 | |
|                 {
 | |
|                     int idx = cm.RefFrameSignBias[cm.CompFixedRef];
 | |
|                     int ctx = PredCommon.GetPredContextCompRefP(ref cm, ref xd);
 | |
|                     int bit = r.Read(fc.CompRefProb[ctx]);
 | |
|                     if (!xd.Counts.IsNull)
 | |
|                     {
 | |
|                         ++xd.Counts.Value.CompRef[ctx][bit];
 | |
|                     }
 | |
| 
 | |
|                     refFrame[idx] = cm.CompFixedRef;
 | |
|                     refFrame[idx == 0 ? 1 : 0] = cm.CompVarRef[bit];
 | |
|                 }
 | |
|                 else if (mode == ReferenceMode.SingleReference)
 | |
|                 {
 | |
|                     int ctx0 = PredCommon.GetPredContextSingleRefP1(ref xd);
 | |
|                     int bit0 = r.Read(fc.SingleRefProb[ctx0][0]);
 | |
|                     if (!xd.Counts.IsNull)
 | |
|                     {
 | |
|                         ++xd.Counts.Value.SingleRef[ctx0][0][bit0];
 | |
|                     }
 | |
| 
 | |
|                     if (bit0 != 0)
 | |
|                     {
 | |
|                         int ctx1 = PredCommon.GetPredContextSingleRefP2(ref xd);
 | |
|                         int bit1 = r.Read(fc.SingleRefProb[ctx1][1]);
 | |
|                         if (!xd.Counts.IsNull)
 | |
|                         {
 | |
|                             ++xd.Counts.Value.SingleRef[ctx1][1][bit1];
 | |
|                         }
 | |
| 
 | |
|                         refFrame[0] = (sbyte)(bit1 != 0 ? Constants.AltRefFrame : Constants.GoldenFrame);
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         refFrame[0] = Constants.LastFrame;
 | |
|                     }
 | |
| 
 | |
|                     refFrame[1] = Constants.None;
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     Debug.Assert(false, "Invalid prediction mode.");
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private static byte ReadSwitchableInterpFilter(ref Vp9Common cm, ref MacroBlockD xd, ref Reader r)
 | |
|         {
 | |
|             int ctx = xd.GetPredContextSwitchableInterp();
 | |
|             byte type = (byte)r.ReadTree(Luts.Vp9SwitchableInterpTree, cm.Fc.Value.SwitchableInterpProb[ctx].ToSpan());
 | |
|             if (!xd.Counts.IsNull)
 | |
|             {
 | |
|                 ++xd.Counts.Value.SwitchableInterp[ctx][type];
 | |
|             }
 | |
| 
 | |
|             return type;
 | |
|         }
 | |
| 
 | |
|         private static void ReadIntraBlockModeInfo(ref Vp9Common cm, ref MacroBlockD xd, ref ModeInfo mi, ref Reader r)
 | |
|         {
 | |
|             BlockSize bsize = mi.SbType;
 | |
|             int i;
 | |
| 
 | |
|             switch (bsize)
 | |
|             {
 | |
|                 case BlockSize.Block4x4:
 | |
|                     for (i = 0; i < 4; ++i)
 | |
|                     {
 | |
|                         mi.Bmi[i].Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
 | |
|                     }
 | |
| 
 | |
|                     mi.Mode = mi.Bmi[3].Mode;
 | |
|                     break;
 | |
|                 case BlockSize.Block4x8:
 | |
|                     mi.Bmi[0].Mode = mi.Bmi[2].Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
 | |
|                     mi.Bmi[1].Mode = mi.Bmi[3].Mode = mi.Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
 | |
|                     break;
 | |
|                 case BlockSize.Block8x4:
 | |
|                     mi.Bmi[0].Mode = mi.Bmi[1].Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
 | |
|                     mi.Bmi[2].Mode = mi.Bmi[3].Mode = mi.Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
 | |
|                     break;
 | |
|                 default: mi.Mode = ReadIntraModeY(ref cm, ref xd, ref r, Luts.SizeGroupLookup[(int)bsize]); break;
 | |
|             }
 | |
| 
 | |
|             mi.UvMode = ReadIntraModeUv(ref cm, ref xd, ref r, (byte)mi.Mode);
 | |
| 
 | |
|             // Initialize interp_filter here so we do not have to check for inter block
 | |
|             // modes in GetPredContextSwitchableInterp()
 | |
|             mi.InterpFilter = Constants.SwitchableFilters;
 | |
| 
 | |
|             mi.RefFrame[0] = Constants.IntraFrame;
 | |
|             mi.RefFrame[1] = Constants.None;
 | |
|         }
 | |
| 
 | |
|         private static bool IsMvValid(ref Mv mv)
 | |
|         {
 | |
|             return mv.Row > Constants.MvLow &&
 | |
|                    mv.Row < Constants.MvUpp &&
 | |
|                    mv.Col > Constants.MvLow &&
 | |
|                    mv.Col < Constants.MvUpp;
 | |
|         }
 | |
| 
 | |
|         private static void CopyMvPair(ref Array2<Mv> dst, ref Array2<Mv> src)
 | |
|         {
 | |
|             dst[0] = src[0];
 | |
|             dst[1] = src[1];
 | |
|         }
 | |
| 
 | |
|         private static void ZeroMvPair(ref Array2<Mv> dst)
 | |
|         {
 | |
|             dst[0] = new Mv();
 | |
|             dst[1] = new Mv();
 | |
|         }
 | |
| 
 | |
|         private static bool AssignMv(
 | |
|             ref Vp9Common cm,
 | |
|             ref MacroBlockD xd,
 | |
|             PredictionMode mode,
 | |
|             ref Array2<Mv> mv,
 | |
|             ref Array2<Mv> refMv,
 | |
|             ref Array2<Mv> nearNearestMv,
 | |
|             int isCompound,
 | |
|             bool allowHP,
 | |
|             ref Reader r)
 | |
|         {
 | |
|             int i;
 | |
|             bool ret = true;
 | |
| 
 | |
|             switch (mode)
 | |
|             {
 | |
|                 case PredictionMode.NewMv:
 | |
|                     {
 | |
|                         for (i = 0; i < 1 + isCompound; ++i)
 | |
|                         {
 | |
|                             ReadMv(ref r, ref mv[i], ref refMv[i], ref cm.Fc.Value, xd.Counts, allowHP);
 | |
|                             ret = ret && IsMvValid(ref mv[i]);
 | |
|                         }
 | |
|                         break;
 | |
|                     }
 | |
|                 case PredictionMode.NearMv:
 | |
|                 case PredictionMode.NearestMv:
 | |
|                     {
 | |
|                         CopyMvPair(ref mv, ref nearNearestMv);
 | |
|                         break;
 | |
|                     }
 | |
|                 case PredictionMode.ZeroMv:
 | |
|                     {
 | |
|                         ZeroMvPair(ref mv);
 | |
|                         break;
 | |
|                     }
 | |
|                 default: return false;
 | |
|             }
 | |
|             return ret;
 | |
|         }
 | |
| 
 | |
|         private static bool ReadIsInterBlock(ref Vp9Common cm, ref MacroBlockD xd, int segmentId, ref Reader r)
 | |
|         {
 | |
|             if (cm.Seg.IsSegFeatureActive(segmentId, SegLvlFeatures.SegLvlRefFrame) != 0)
 | |
|             {
 | |
|                 return cm.Seg.GetSegData(segmentId, SegLvlFeatures.SegLvlRefFrame) != Constants.IntraFrame;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 int ctx = xd.GetIntraInterContext();
 | |
|                 bool isInter = r.Read(cm.Fc.Value.IntraInterProb[ctx]) != 0;
 | |
|                 if (!xd.Counts.IsNull)
 | |
|                 {
 | |
|                     ++xd.Counts.Value.IntraInter[ctx][isInter ? 1 : 0];
 | |
|                 }
 | |
| 
 | |
|                 return isInter;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private static void DecFindBestRefMvs(bool allowHP, Span<Mv> mvlist, ref Mv bestMv, int refmvCount)
 | |
|         {
 | |
|             int i;
 | |
| 
 | |
|             // Make sure all the candidates are properly clamped etc
 | |
|             for (i = 0; i < refmvCount; ++i)
 | |
|             {
 | |
|                 mvlist[i].LowerMvPrecision(allowHP);
 | |
|                 bestMv = mvlist[i];
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private static bool AddMvRefListEb(Mv mv, ref int refMvCount, Span<Mv> mvRefList, bool earlyBreak)
 | |
|         {
 | |
|             if (refMvCount != 0)
 | |
|             {
 | |
|                 if (Unsafe.As<Mv, int>(ref mv) != Unsafe.As<Mv, int>(ref mvRefList[0]))
 | |
|                 {
 | |
|                     mvRefList[refMvCount] = mv;
 | |
|                     refMvCount++;
 | |
|                     return true;
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 mvRefList[refMvCount++] = mv;
 | |
|                 if (earlyBreak)
 | |
|                 {
 | |
|                     return true;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         // Performs mv sign inversion if indicated by the reference frame combination.
 | |
|         private static Mv ScaleMv(ref ModeInfo mi, int refr, sbyte thisRefFrame, ref Array4<sbyte> refSignBias)
 | |
|         {
 | |
|             Mv mv = mi.Mv[refr];
 | |
|             if (refSignBias[mi.RefFrame[refr]] != refSignBias[thisRefFrame])
 | |
|             {
 | |
|                 mv.Row *= -1;
 | |
|                 mv.Col *= -1;
 | |
|             }
 | |
|             return mv;
 | |
|         }
 | |
| 
 | |
|         private static bool IsDiffRefFrameAddMvEb(
 | |
|             ref ModeInfo mbmi,
 | |
|             sbyte refFrame,
 | |
|             ref Array4<sbyte> refSignBias,
 | |
|             ref int refmvCount,
 | |
|             Span<Mv> mvRefList,
 | |
|             bool earlyBreak)
 | |
|         {
 | |
|             if (mbmi.IsInterBlock())
 | |
|             {
 | |
|                 if (mbmi.RefFrame[0] != refFrame)
 | |
|                 {
 | |
|                     if (AddMvRefListEb(ScaleMv(ref mbmi, 0, refFrame, ref refSignBias), ref refmvCount, mvRefList, earlyBreak))
 | |
|                     {
 | |
|                         return true;
 | |
|                     }
 | |
|                 }
 | |
|                 if (mbmi.HasSecondRef() && mbmi.RefFrame[1] != refFrame && Unsafe.As<Mv, int>(ref mbmi.Mv[1]) != Unsafe.As<Mv, int>(ref mbmi.Mv[0]))
 | |
|                 {
 | |
|                     if (AddMvRefListEb(ScaleMv(ref mbmi, 1, refFrame, ref refSignBias), ref refmvCount, mvRefList, earlyBreak))
 | |
|                     {
 | |
|                         return true;
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|             }
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         // This function searches the neighborhood of a given MB/SB
 | |
|         // to try and find candidate reference vectors.
 | |
|         private static unsafe int DecFindMvRefs(
 | |
|             ref Vp9Common cm,
 | |
|             ref MacroBlockD xd,
 | |
|             PredictionMode mode,
 | |
|             sbyte refFrame,
 | |
|             Span<Position> mvRefSearch,
 | |
|             Span<Mv> mvRefList,
 | |
|             int miRow,
 | |
|             int miCol,
 | |
|             int block,
 | |
|             int isSub8X8)
 | |
|         {
 | |
|             ref Array4<sbyte> refSignBias = ref cm.RefFrameSignBias;
 | |
|             int i, refmvCount = 0;
 | |
|             bool differentRefFound = false;
 | |
|             Ptr<MvRef> prevFrameMvs = cm.UsePrevFrameMvs ? new Ptr<MvRef>(ref cm.PrevFrameMvs[miRow * cm.MiCols + miCol]) : Ptr<MvRef>.Null;
 | |
|             ref TileInfo tile = ref xd.Tile;
 | |
|             // If mode is nearestmv or newmv (uses nearestmv as a reference) then stop
 | |
|             // searching after the first mv is found.
 | |
|             bool earlyBreak = mode != PredictionMode.NearMv;
 | |
| 
 | |
|             // Blank the reference vector list
 | |
|             mvRefList.Slice(0, Constants.MaxMvRefCandidates).Fill(new Mv());
 | |
| 
 | |
|             i = 0;
 | |
|             if (isSub8X8 != 0)
 | |
|             {
 | |
|                 // If the size < 8x8 we get the mv from the bmi substructure for the
 | |
|                 // nearest two blocks.
 | |
|                 for (i = 0; i < 2; ++i)
 | |
|                 {
 | |
|                     ref Position mvRef = ref mvRefSearch[i];
 | |
|                     if (tile.IsInside(miCol, miRow, cm.MiRows, ref mvRef))
 | |
|                     {
 | |
|                         ref ModeInfo candidateMi = ref xd.Mi[mvRef.Col + mvRef.Row * xd.MiStride].Value;
 | |
|                         differentRefFound = true;
 | |
| 
 | |
|                         if (candidateMi.RefFrame[0] == refFrame)
 | |
|                         {
 | |
|                             if (AddMvRefListEb(candidateMi.GetSubBlockMv(0, mvRef.Col, block), ref refmvCount, mvRefList, earlyBreak))
 | |
|                             {
 | |
|                                 goto Done;
 | |
|                             }
 | |
|                         }
 | |
|                         else if (candidateMi.RefFrame[1] == refFrame)
 | |
|                         {
 | |
|                             if (AddMvRefListEb(candidateMi.GetSubBlockMv(1, mvRef.Col, block), ref refmvCount, mvRefList, earlyBreak))
 | |
|                             {
 | |
|                                 goto Done;
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             // Check the rest of the neighbors in much the same way
 | |
|             // as before except we don't need to keep track of sub blocks or
 | |
|             // mode counts.
 | |
|             for (; i < MvrefNeighbours; ++i)
 | |
|             {
 | |
|                 ref Position mvRef = ref mvRefSearch[i];
 | |
|                 if (tile.IsInside(miCol, miRow, cm.MiRows, ref mvRef))
 | |
|                 {
 | |
|                     ref ModeInfo candidate = ref xd.Mi[mvRef.Col + mvRef.Row * xd.MiStride].Value;
 | |
|                     differentRefFound = true;
 | |
| 
 | |
|                     if (candidate.RefFrame[0] == refFrame)
 | |
|                     {
 | |
|                         if (AddMvRefListEb(candidate.Mv[0], ref refmvCount, mvRefList, earlyBreak))
 | |
|                         {
 | |
|                             goto Done;
 | |
|                         }
 | |
|                     }
 | |
|                     else if (candidate.RefFrame[1] == refFrame)
 | |
|                     {
 | |
|                         if (AddMvRefListEb(candidate.Mv[1], ref refmvCount, mvRefList, earlyBreak))
 | |
|                         {
 | |
|                             goto Done;
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             // Check the last frame's mode and mv info.
 | |
|             if (!prevFrameMvs.IsNull)
 | |
|             {
 | |
|                 if (prevFrameMvs.Value.RefFrame[0] == refFrame)
 | |
|                 {
 | |
|                     if (AddMvRefListEb(prevFrameMvs.Value.Mv[0], ref refmvCount, mvRefList, earlyBreak))
 | |
|                     {
 | |
|                         goto Done;
 | |
|                     }
 | |
|                 }
 | |
|                 else if (prevFrameMvs.Value.RefFrame[1] == refFrame)
 | |
|                 {
 | |
|                     if (AddMvRefListEb(prevFrameMvs.Value.Mv[1], ref refmvCount, mvRefList, earlyBreak))
 | |
|                     {
 | |
|                         goto Done;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             // Since we couldn't find 2 mvs from the same reference frame
 | |
|             // go back through the neighbors and find motion vectors from
 | |
|             // different reference frames.
 | |
|             if (differentRefFound)
 | |
|             {
 | |
|                 for (i = 0; i < MvrefNeighbours; ++i)
 | |
|                 {
 | |
|                     ref Position mvRef = ref mvRefSearch[i];
 | |
|                     if (tile.IsInside(miCol, miRow, cm.MiRows, ref mvRef))
 | |
|                     {
 | |
|                         ref ModeInfo candidate = ref xd.Mi[mvRef.Col + mvRef.Row * xd.MiStride].Value;
 | |
| 
 | |
|                         // If the candidate is Intra we don't want to consider its mv.
 | |
|                         if (IsDiffRefFrameAddMvEb(ref candidate, refFrame, ref refSignBias, ref refmvCount, mvRefList, earlyBreak))
 | |
|                         {
 | |
|                             goto Done;
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             // Since we still don't have a candidate we'll try the last frame.
 | |
|             if (!prevFrameMvs.IsNull)
 | |
|             {
 | |
|                 if (prevFrameMvs.Value.RefFrame[0] != refFrame && prevFrameMvs.Value.RefFrame[0] > Constants.IntraFrame)
 | |
|                 {
 | |
|                     Mv mv = prevFrameMvs.Value.Mv[0];
 | |
|                     if (refSignBias[prevFrameMvs.Value.RefFrame[0]] != refSignBias[refFrame])
 | |
|                     {
 | |
|                         mv.Row *= -1;
 | |
|                         mv.Col *= -1;
 | |
|                     }
 | |
|                     if (AddMvRefListEb(mv, ref refmvCount, mvRefList, earlyBreak))
 | |
|                     {
 | |
|                         goto Done;
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 if (prevFrameMvs.Value.RefFrame[1] > Constants.IntraFrame &&
 | |
|                     prevFrameMvs.Value.RefFrame[1] != refFrame &&
 | |
|                     Unsafe.As<Mv, int>(ref prevFrameMvs.Value.Mv[1]) != Unsafe.As<Mv, int>(ref prevFrameMvs.Value.Mv[0]))
 | |
|                 {
 | |
|                     Mv mv = prevFrameMvs.Value.Mv[1];
 | |
|                     if (refSignBias[prevFrameMvs.Value.RefFrame[1]] != refSignBias[refFrame])
 | |
|                     {
 | |
|                         mv.Row *= -1;
 | |
|                         mv.Col *= -1;
 | |
|                     }
 | |
|                     if (AddMvRefListEb(mv, ref refmvCount, mvRefList, earlyBreak))
 | |
|                     {
 | |
|                         goto Done;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if (mode == PredictionMode.NearMv)
 | |
|             {
 | |
|                 refmvCount = Constants.MaxMvRefCandidates;
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 // We only care about the nearestmv for the remaining modes
 | |
|                 refmvCount = 1;
 | |
|             }
 | |
| 
 | |
|         Done:
 | |
|             // Clamp vectors
 | |
|             for (i = 0; i < refmvCount; ++i)
 | |
|             {
 | |
|                 mvRefList[i].ClampMvRef(ref xd);
 | |
|             }
 | |
| 
 | |
|             return refmvCount;
 | |
|         }
 | |
| 
 | |
|         private static void AppendSub8x8MvsForIdx(
 | |
|             ref Vp9Common cm,
 | |
|             ref MacroBlockD xd,
 | |
|             Span<Position> mvRefSearch,
 | |
|             PredictionMode bMode,
 | |
|             int block,
 | |
|             int refr,
 | |
|             int miRow,
 | |
|             int miCol,
 | |
|             ref Mv bestSub8x8)
 | |
|         {
 | |
|             Span<Mv> mvList = stackalloc Mv[Constants.MaxMvRefCandidates];
 | |
|             ref ModeInfo mi = ref xd.Mi[0].Value;
 | |
|             ref Array4<BModeInfo> bmi = ref mi.Bmi;
 | |
|             int n;
 | |
|             int refmvCount;
 | |
| 
 | |
|             Debug.Assert(Constants.MaxMvRefCandidates == 2);
 | |
| 
 | |
|             refmvCount = DecFindMvRefs(ref cm, ref xd, bMode, mi.RefFrame[refr], mvRefSearch, mvList, miRow, miCol, block, 1);
 | |
| 
 | |
|             switch (block)
 | |
|             {
 | |
|                 case 0: bestSub8x8 = mvList[refmvCount - 1]; break;
 | |
|                 case 1:
 | |
|                 case 2:
 | |
|                     if (bMode == PredictionMode.NearestMv)
 | |
|                     {
 | |
|                         bestSub8x8 = bmi[0].Mv[refr];
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         bestSub8x8 = new Mv();
 | |
|                         for (n = 0; n < refmvCount; ++n)
 | |
|                         {
 | |
|                             if (Unsafe.As<Mv, int>(ref bmi[0].Mv[refr]) != Unsafe.As<Mv, int>(ref mvList[n]))
 | |
|                             {
 | |
|                                 bestSub8x8 = mvList[n];
 | |
|                                 break;
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                     break;
 | |
|                 case 3:
 | |
|                     if (bMode == PredictionMode.NearestMv)
 | |
|                     {
 | |
|                         bestSub8x8 = bmi[2].Mv[refr];
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         Span<Mv> candidates = stackalloc Mv[2 + Constants.MaxMvRefCandidates];
 | |
|                         candidates[0] = bmi[1].Mv[refr];
 | |
|                         candidates[1] = bmi[0].Mv[refr];
 | |
|                         candidates[2] = mvList[0];
 | |
|                         candidates[3] = mvList[1];
 | |
|                         bestSub8x8 = new Mv();
 | |
|                         for (n = 0; n < 2 + Constants.MaxMvRefCandidates; ++n)
 | |
|                         {
 | |
|                             if (Unsafe.As<Mv, int>(ref bmi[2].Mv[refr]) != Unsafe.As<Mv, int>(ref candidates[n]))
 | |
|                             {
 | |
|                                 bestSub8x8 = candidates[n];
 | |
|                                 break;
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                     break;
 | |
|                 default: Debug.Assert(false, "Invalid block index."); break;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private static byte GetModeContext(ref Vp9Common cm, ref MacroBlockD xd, Span<Position> mvRefSearch, int miRow, int miCol)
 | |
|         {
 | |
|             int i;
 | |
|             int contextCounter = 0;
 | |
|             ref TileInfo tile = ref xd.Tile;
 | |
| 
 | |
|             // Get mode count from nearest 2 blocks
 | |
|             for (i = 0; i < 2; ++i)
 | |
|             {
 | |
|                 ref Position mvRef = ref mvRefSearch[i];
 | |
|                 if (tile.IsInside(miCol, miRow, cm.MiRows, ref mvRef))
 | |
|                 {
 | |
|                     ref ModeInfo candidate = ref xd.Mi[mvRef.Col + mvRef.Row * xd.MiStride].Value;
 | |
|                     // Keep counts for entropy encoding.
 | |
|                     contextCounter += Luts.Mode2Counter[(int)candidate.Mode];
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return (byte)Luts.CounterToContext[contextCounter];
 | |
|         }
 | |
| 
 | |
|         private static void ReadInterBlockModeInfo(
 | |
|             ref Vp9Common cm,
 | |
|             ref MacroBlockD xd,
 | |
|             ref ModeInfo mi,
 | |
|             int miRow,
 | |
|             int miCol,
 | |
|             ref Reader r)
 | |
|         {
 | |
|             BlockSize bsize = mi.SbType;
 | |
|             bool allowHP = cm.AllowHighPrecisionMv;
 | |
|             Array2<Mv> bestRefMvs = new Array2<Mv>();
 | |
|             int refr, isCompound;
 | |
|             byte interModeCtx;
 | |
|             Span<Position> mvRefSearch = Luts.MvRefBlocks[(int)bsize];
 | |
| 
 | |
|             ReadRefFrames(ref cm, ref xd, ref r, mi.SegmentId, ref mi.RefFrame);
 | |
|             isCompound = mi.HasSecondRef() ? 1 : 0;
 | |
|             interModeCtx = GetModeContext(ref cm, ref xd, mvRefSearch, miRow, miCol);
 | |
| 
 | |
|             if (cm.Seg.IsSegFeatureActive(mi.SegmentId, SegLvlFeatures.SegLvlSkip) != 0)
 | |
|             {
 | |
|                 mi.Mode = PredictionMode.ZeroMv;
 | |
|                 if (bsize < BlockSize.Block8x8)
 | |
|                 {
 | |
|                     xd.ErrorInfo.Value.InternalError(CodecErr.CodecUnsupBitstream, "Invalid usage of segement feature on small blocks");
 | |
|                     return;
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 if (bsize >= BlockSize.Block8x8)
 | |
|                 {
 | |
|                     mi.Mode = ReadInterMode(ref cm, ref xd, ref r, interModeCtx);
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     // Sub 8x8 blocks use the nearestmv as a ref_mv if the bMode is NewMv.
 | |
|                     // Setting mode to NearestMv forces the search to stop after the nearestmv
 | |
|                     // has been found. After bModes have been read, mode will be overwritten
 | |
|                     // by the last bMode.
 | |
|                     mi.Mode = PredictionMode.NearestMv;
 | |
|                 }
 | |
| 
 | |
|                 if (mi.Mode != PredictionMode.ZeroMv)
 | |
|                 {
 | |
|                     Span<Mv> tmpMvs = stackalloc Mv[Constants.MaxMvRefCandidates];
 | |
| 
 | |
|                     for (refr = 0; refr < 1 + isCompound; ++refr)
 | |
|                     {
 | |
|                         sbyte frame = mi.RefFrame[refr];
 | |
|                         int refmvCount;
 | |
| 
 | |
|                         refmvCount = DecFindMvRefs(ref cm, ref xd, mi.Mode, frame, mvRefSearch, tmpMvs, miRow, miCol, -1, 0);
 | |
| 
 | |
|                         DecFindBestRefMvs(allowHP, tmpMvs, ref bestRefMvs[refr], refmvCount);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             mi.InterpFilter = (cm.InterpFilter == Constants.Switchable) ? ReadSwitchableInterpFilter(ref cm, ref xd, ref r) : cm.InterpFilter;
 | |
| 
 | |
|             if (bsize < BlockSize.Block8x8)
 | |
|             {
 | |
|                 int num4X4W = 1 << xd.BmodeBlocksWl;
 | |
|                 int num4X4H = 1 << xd.BmodeBlocksHl;
 | |
|                 int idx, idy;
 | |
|                 PredictionMode bMode = 0;
 | |
|                 Array2<Mv> bestSub8x8 = new Array2<Mv>();
 | |
|                 const uint invalidMv = 0x80008000;
 | |
|                 // Initialize the 2nd element as even though it won't be used meaningfully
 | |
|                 // if isCompound is false.
 | |
|                 Unsafe.As<Mv, uint>(ref bestSub8x8[1]) = invalidMv;
 | |
|                 for (idy = 0; idy < 2; idy += num4X4H)
 | |
|                 {
 | |
|                     for (idx = 0; idx < 2; idx += num4X4W)
 | |
|                     {
 | |
|                         int j = idy * 2 + idx;
 | |
|                         bMode = ReadInterMode(ref cm, ref xd, ref r, interModeCtx);
 | |
| 
 | |
|                         if (bMode == PredictionMode.NearestMv || bMode == PredictionMode.NearMv)
 | |
|                         {
 | |
|                             for (refr = 0; refr < 1 + isCompound; ++refr)
 | |
|                             {
 | |
|                                 AppendSub8x8MvsForIdx(ref cm, ref xd, mvRefSearch, bMode, j, refr, miRow, miCol, ref bestSub8x8[refr]);
 | |
|                             }
 | |
|                         }
 | |
| 
 | |
|                         if (!AssignMv(ref cm, ref xd, bMode, ref mi.Bmi[j].Mv, ref bestRefMvs, ref bestSub8x8, isCompound, allowHP, ref r))
 | |
|                         {
 | |
|                             xd.Corrupted |= true;
 | |
|                             break;
 | |
|                         }
 | |
| 
 | |
|                         if (num4X4H == 2)
 | |
|                         {
 | |
|                             mi.Bmi[j + 2] = mi.Bmi[j];
 | |
|                         }
 | |
| 
 | |
|                         if (num4X4W == 2)
 | |
|                         {
 | |
|                             mi.Bmi[j + 1] = mi.Bmi[j];
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 mi.Mode = bMode;
 | |
| 
 | |
|                 CopyMvPair(ref mi.Mv, ref mi.Bmi[3].Mv);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 xd.Corrupted |= !AssignMv(ref cm, ref xd, mi.Mode, ref mi.Mv, ref bestRefMvs, ref bestRefMvs, isCompound, allowHP, ref r);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private static void ReadInterFrameModeInfo(
 | |
|             ref Vp9Common cm,
 | |
|             ref MacroBlockD xd,
 | |
|             int miRow,
 | |
|             int miCol,
 | |
|             ref Reader r,
 | |
|             int xMis,
 | |
|             int yMis)
 | |
|         {
 | |
|             ref ModeInfo mi = ref xd.Mi[0].Value;
 | |
|             bool interBlock;
 | |
| 
 | |
|             mi.SegmentId = (sbyte)ReadInterSegmentId(ref cm, ref xd, miRow, miCol, ref r, xMis, yMis);
 | |
|             mi.Skip = (sbyte)ReadSkip(ref cm, ref xd, mi.SegmentId, ref r);
 | |
|             interBlock = ReadIsInterBlock(ref cm, ref xd, mi.SegmentId, ref r);
 | |
|             mi.TxSize = ReadTxSize(ref cm, ref xd, mi.Skip == 0 || !interBlock, ref r);
 | |
| 
 | |
|             if (interBlock)
 | |
|             {
 | |
|                 ReadInterBlockModeInfo(ref cm, ref xd, ref mi, miRow, miCol, ref r);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 ReadIntraBlockModeInfo(ref cm, ref xd, ref mi, ref r);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private static PredictionMode LeftBlockMode(Ptr<ModeInfo> curMi, Ptr<ModeInfo> leftMi, int b)
 | |
|         {
 | |
|             if (b == 0 || b == 2)
 | |
|             {
 | |
|                 if (leftMi.IsNull || leftMi.Value.IsInterBlock())
 | |
|                 {
 | |
|                     return PredictionMode.DcPred;
 | |
|                 }
 | |
| 
 | |
|                 return leftMi.Value.GetYMode(b + 1);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 Debug.Assert(b == 1 || b == 3);
 | |
|                 return curMi.Value.Bmi[b - 1].Mode;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private static PredictionMode AboveBlockMode(Ptr<ModeInfo> curMi, Ptr<ModeInfo> aboveMi, int b)
 | |
|         {
 | |
|             if (b == 0 || b == 1)
 | |
|             {
 | |
|                 if (aboveMi.IsNull || aboveMi.Value.IsInterBlock())
 | |
|                 {
 | |
|                     return PredictionMode.DcPred;
 | |
|                 }
 | |
| 
 | |
|                 return aboveMi.Value.GetYMode(b + 2);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 Debug.Assert(b == 2 || b == 3);
 | |
|                 return curMi.Value.Bmi[b - 2].Mode;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private static ReadOnlySpan<byte> GetYModeProbs(
 | |
|             ref Vp9EntropyProbs fc,
 | |
|             Ptr<ModeInfo> mi,
 | |
|             Ptr<ModeInfo> aboveMi,
 | |
|             Ptr<ModeInfo> leftMi,
 | |
|             int block)
 | |
|         {
 | |
|             PredictionMode above = AboveBlockMode(mi, aboveMi, block);
 | |
|             PredictionMode left = LeftBlockMode(mi, leftMi, block);
 | |
|             return fc.KfYModeProb[(int)above][(int)left].ToSpan();
 | |
|         }
 | |
| 
 | |
|         private static void ReadIntraFrameModeInfo(
 | |
|             ref Vp9Common cm,
 | |
|             ref MacroBlockD xd,
 | |
|             int miRow,
 | |
|             int miCol,
 | |
|             ref Reader r,
 | |
|             int xMis,
 | |
|             int yMis)
 | |
|         {
 | |
|             Ptr<ModeInfo> mi = xd.Mi[0];
 | |
|             Ptr<ModeInfo> aboveMi = xd.AboveMi;
 | |
|             Ptr<ModeInfo> leftMi = xd.LeftMi;
 | |
|             BlockSize bsize = mi.Value.SbType;
 | |
|             int i;
 | |
|             int miOffset = miRow * cm.MiCols + miCol;
 | |
| 
 | |
|             mi.Value.SegmentId = (sbyte)ReadIntraSegmentId(ref cm, miOffset, xMis, yMis, ref r);
 | |
|             mi.Value.Skip = (sbyte)ReadSkip(ref cm, ref xd, mi.Value.SegmentId, ref r);
 | |
|             mi.Value.TxSize = ReadTxSize(ref cm, ref xd, true, ref r);
 | |
|             mi.Value.RefFrame[0] = Constants.IntraFrame;
 | |
|             mi.Value.RefFrame[1] = Constants.None;
 | |
| 
 | |
|             switch (bsize)
 | |
|             {
 | |
|                 case BlockSize.Block4x4:
 | |
|                     for (i = 0; i < 4; ++i)
 | |
|                     {
 | |
|                         mi.Value.Bmi[i].Mode =
 | |
|                             ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, i));
 | |
|                     }
 | |
| 
 | |
|                     mi.Value.Mode = mi.Value.Bmi[3].Mode;
 | |
|                     break;
 | |
|                 case BlockSize.Block4x8:
 | |
|                     mi.Value.Bmi[0].Mode = mi.Value.Bmi[2].Mode =
 | |
|                         ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 0));
 | |
|                     mi.Value.Bmi[1].Mode = mi.Value.Bmi[3].Mode = mi.Value.Mode =
 | |
|                         ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 1));
 | |
|                     break;
 | |
|                 case BlockSize.Block8x4:
 | |
|                     mi.Value.Bmi[0].Mode = mi.Value.Bmi[1].Mode =
 | |
|                         ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 0));
 | |
|                     mi.Value.Bmi[2].Mode = mi.Value.Bmi[3].Mode = mi.Value.Mode =
 | |
|                         ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 2));
 | |
|                     break;
 | |
|                 default:
 | |
|                     mi.Value.Mode = ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 0));
 | |
|                     break;
 | |
|             }
 | |
| 
 | |
|             mi.Value.UvMode = ReadIntraMode(ref r, cm.Fc.Value.KfUvModeProb[(int)mi.Value.Mode].ToSpan());
 | |
|         }
 | |
| 
 | |
|         private static void CopyRefFramePair(ref Array2<sbyte> dst, ref Array2<sbyte> src)
 | |
|         {
 | |
|             dst[0] = src[0];
 | |
|             dst[1] = src[1];
 | |
|         }
 | |
| 
 | |
|         public static void ReadModeInfo(
 | |
|             ref TileWorkerData twd,
 | |
|             ref Vp9Common cm,
 | |
|             int miRow,
 | |
|             int miCol,
 | |
|             int xMis,
 | |
|             int yMis)
 | |
|         {
 | |
|             ref Reader r = ref twd.BitReader;
 | |
|             ref MacroBlockD xd = ref twd.Xd;
 | |
|             ref ModeInfo mi = ref xd.Mi[0].Value;
 | |
|             ArrayPtr<MvRef> frameMvs = cm.CurFrameMvs.Slice(miRow * cm.MiCols + miCol);
 | |
|             int w, h;
 | |
| 
 | |
|             if (cm.FrameIsIntraOnly())
 | |
|             {
 | |
|                 ReadIntraFrameModeInfo(ref cm, ref xd, miRow, miCol, ref r, xMis, yMis);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 ReadInterFrameModeInfo(ref cm, ref xd, miRow, miCol, ref r, xMis, yMis);
 | |
| 
 | |
|                 for (h = 0; h < yMis; ++h)
 | |
|                 {
 | |
|                     for (w = 0; w < xMis; ++w)
 | |
|                     {
 | |
|                         ref MvRef mv = ref frameMvs[w];
 | |
|                         CopyRefFramePair(ref mv.RefFrame, ref mi.RefFrame);
 | |
|                         CopyMvPair(ref mv.Mv, ref mi.Mv);
 | |
|                     }
 | |
|                     frameMvs = frameMvs.Slice(cm.MiCols);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | 
