DecodeMv.cs 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160
  1. using Ryujinx.Common.Memory;
  2. using Ryujinx.Graphics.Nvdec.Vp9.Dsp;
  3. using Ryujinx.Graphics.Nvdec.Vp9.Types;
  4. using Ryujinx.Graphics.Video;
  5. using System;
  6. using System.Diagnostics;
  7. using System.Runtime.CompilerServices;
  8. using Mv = Ryujinx.Graphics.Nvdec.Vp9.Types.Mv;
  9. using MvRef = Ryujinx.Graphics.Nvdec.Vp9.Types.MvRef;
  10. namespace Ryujinx.Graphics.Nvdec.Vp9
  11. {
  12. internal static class DecodeMv
  13. {
  14. private const int MvrefNeighbours = 8;
  15. private static PredictionMode ReadIntraMode(ref Reader r, ReadOnlySpan<byte> p)
  16. {
  17. return (PredictionMode)r.ReadTree(Luts.Vp9IntraModeTree, p);
  18. }
  19. private static PredictionMode ReadIntraModeY(ref Vp9Common cm, ref MacroBlockD xd, ref Reader r, int sizeGroup)
  20. {
  21. PredictionMode yMode = ReadIntraMode(ref r, cm.Fc.Value.YModeProb[sizeGroup].ToSpan());
  22. if (!xd.Counts.IsNull)
  23. {
  24. ++xd.Counts.Value.YMode[sizeGroup][(int)yMode];
  25. }
  26. return yMode;
  27. }
  28. private static PredictionMode ReadIntraModeUv(ref Vp9Common cm, ref MacroBlockD xd, ref Reader r, byte yMode)
  29. {
  30. PredictionMode uvMode = ReadIntraMode(ref r, cm.Fc.Value.UvModeProb[yMode].ToSpan());
  31. if (!xd.Counts.IsNull)
  32. {
  33. ++xd.Counts.Value.UvMode[yMode][(int)uvMode];
  34. }
  35. return uvMode;
  36. }
  37. private static PredictionMode ReadInterMode(ref Vp9Common cm, ref MacroBlockD xd, ref Reader r, int ctx)
  38. {
  39. int mode = r.ReadTree(Luts.Vp9InterModeTree, cm.Fc.Value.InterModeProb[ctx].ToSpan());
  40. if (!xd.Counts.IsNull)
  41. {
  42. ++xd.Counts.Value.InterMode[ctx][mode];
  43. }
  44. return PredictionMode.NearestMv + mode;
  45. }
  46. private static int ReadSegmentId(ref Reader r, ref Array7<byte> segTreeProbs)
  47. {
  48. return r.ReadTree(Luts.Vp9SegmentTree, segTreeProbs.ToSpan());
  49. }
  50. private static ReadOnlySpan<byte> GetTxProbs(ref Vp9EntropyProbs fc, TxSize maxTxSize, int ctx)
  51. {
  52. switch (maxTxSize)
  53. {
  54. case TxSize.Tx8x8: return fc.Tx8x8Prob[ctx].ToSpan();
  55. case TxSize.Tx16x16: return fc.Tx16x16Prob[ctx].ToSpan();
  56. case TxSize.Tx32x32: return fc.Tx32x32Prob[ctx].ToSpan();
  57. default: Debug.Assert(false, "Invalid maxTxSize."); return ReadOnlySpan<byte>.Empty;
  58. }
  59. }
  60. private static Span<uint> GetTxCounts(ref Vp9BackwardUpdates counts, TxSize maxTxSize, int ctx)
  61. {
  62. switch (maxTxSize)
  63. {
  64. case TxSize.Tx8x8: return counts.Tx8x8[ctx].ToSpan();
  65. case TxSize.Tx16x16: return counts.Tx16x16[ctx].ToSpan();
  66. case TxSize.Tx32x32: return counts.Tx32x32[ctx].ToSpan();
  67. default: Debug.Assert(false, "Invalid maxTxSize."); return Span<uint>.Empty;
  68. }
  69. }
  70. private static TxSize ReadSelectedTxSize(ref Vp9Common cm, ref MacroBlockD xd, TxSize maxTxSize, ref Reader r)
  71. {
  72. int ctx = xd.GetTxSizeContext();
  73. ReadOnlySpan<byte> txProbs = GetTxProbs(ref cm.Fc.Value, maxTxSize, ctx);
  74. TxSize txSize = (TxSize)r.Read(txProbs[0]);
  75. if (txSize != TxSize.Tx4x4 && maxTxSize >= TxSize.Tx16x16)
  76. {
  77. txSize += r.Read(txProbs[1]);
  78. if (txSize != TxSize.Tx8x8 && maxTxSize >= TxSize.Tx32x32)
  79. {
  80. txSize += r.Read(txProbs[2]);
  81. }
  82. }
  83. if (!xd.Counts.IsNull)
  84. {
  85. ++GetTxCounts(ref xd.Counts.Value, maxTxSize, ctx)[(int)txSize];
  86. }
  87. return txSize;
  88. }
  89. private static TxSize ReadTxSize(ref Vp9Common cm, ref MacroBlockD xd, bool allowSelect, ref Reader r)
  90. {
  91. TxMode txMode = cm.TxMode;
  92. BlockSize bsize = xd.Mi[0].Value.SbType;
  93. TxSize maxTxSize = Luts.MaxTxSizeLookup[(int)bsize];
  94. if (allowSelect && txMode == TxMode.TxModeSelect && bsize >= BlockSize.Block8x8)
  95. {
  96. return ReadSelectedTxSize(ref cm, ref xd, maxTxSize, ref r);
  97. }
  98. else
  99. {
  100. return (TxSize)Math.Min((int)maxTxSize, (int)Luts.TxModeToBiggestTxSize[(int)txMode]);
  101. }
  102. }
  103. private static int DecGetSegmentId(ref Vp9Common cm, ArrayPtr<byte> segmentIds, int miOffset, int xMis, int yMis)
  104. {
  105. int x, y, segmentId = int.MaxValue;
  106. for (y = 0; y < yMis; y++)
  107. {
  108. for (x = 0; x < xMis; x++)
  109. {
  110. segmentId = Math.Min(segmentId, segmentIds[miOffset + y * cm.MiCols + x]);
  111. }
  112. }
  113. Debug.Assert(segmentId >= 0 && segmentId < Constants.MaxSegments);
  114. return segmentId;
  115. }
  116. private static void SetSegmentId(ref Vp9Common cm, int miOffset, int xMis, int yMis, int segmentId)
  117. {
  118. int x, y;
  119. Debug.Assert(segmentId >= 0 && segmentId < Constants.MaxSegments);
  120. for (y = 0; y < yMis; y++)
  121. {
  122. for (x = 0; x < xMis; x++)
  123. {
  124. cm.CurrentFrameSegMap[miOffset + y * cm.MiCols + x] = (byte)segmentId;
  125. }
  126. }
  127. }
  128. private static void CopySegmentId(
  129. ref Vp9Common cm,
  130. ArrayPtr<byte> lastSegmentIds,
  131. ArrayPtr<byte> currentSegmentIds,
  132. int miOffset,
  133. int xMis,
  134. int yMis)
  135. {
  136. int x, y;
  137. for (y = 0; y < yMis; y++)
  138. {
  139. for (x = 0; x < xMis; x++)
  140. {
  141. currentSegmentIds[miOffset + y * cm.MiCols + x] = (byte)(!lastSegmentIds.IsNull ? lastSegmentIds[miOffset + y * cm.MiCols + x] : 0);
  142. }
  143. }
  144. }
  145. private static int ReadIntraSegmentId(ref Vp9Common cm, int miOffset, int xMis, int yMis, ref Reader r)
  146. {
  147. ref Segmentation seg = ref cm.Seg;
  148. int segmentId;
  149. if (!seg.Enabled)
  150. {
  151. return 0; // Default for disabled segmentation
  152. }
  153. if (!seg.UpdateMap)
  154. {
  155. CopySegmentId(ref cm, cm.LastFrameSegMap, cm.CurrentFrameSegMap, miOffset, xMis, yMis);
  156. return 0;
  157. }
  158. segmentId = ReadSegmentId(ref r, ref cm.Fc.Value.SegTreeProb);
  159. SetSegmentId(ref cm, miOffset, xMis, yMis, segmentId);
  160. return segmentId;
  161. }
  162. private static int ReadInterSegmentId(
  163. ref Vp9Common cm,
  164. ref MacroBlockD xd,
  165. int miRow,
  166. int miCol,
  167. ref Reader r,
  168. int xMis,
  169. int yMis)
  170. {
  171. ref Segmentation seg = ref cm.Seg;
  172. ref ModeInfo mi = ref xd.Mi[0].Value;
  173. int predictedSegmentId, segmentId;
  174. int miOffset = miRow * cm.MiCols + miCol;
  175. if (!seg.Enabled)
  176. {
  177. return 0; // Default for disabled segmentation
  178. }
  179. predictedSegmentId = !cm.LastFrameSegMap.IsNull
  180. ? DecGetSegmentId(ref cm, cm.LastFrameSegMap, miOffset, xMis, yMis)
  181. : 0;
  182. if (!seg.UpdateMap)
  183. {
  184. CopySegmentId(ref cm, cm.LastFrameSegMap, cm.CurrentFrameSegMap, miOffset, xMis, yMis);
  185. return predictedSegmentId;
  186. }
  187. if (seg.TemporalUpdate)
  188. {
  189. byte predProb = Segmentation.GetPredProbSegId(ref cm.Fc.Value.SegPredProb, ref xd);
  190. mi.SegIdPredicted = (sbyte)r.Read(predProb);
  191. segmentId = mi.SegIdPredicted != 0 ? predictedSegmentId : ReadSegmentId(ref r, ref cm.Fc.Value.SegTreeProb);
  192. }
  193. else
  194. {
  195. segmentId = ReadSegmentId(ref r, ref cm.Fc.Value.SegTreeProb);
  196. }
  197. SetSegmentId(ref cm, miOffset, xMis, yMis, segmentId);
  198. return segmentId;
  199. }
  200. private static int ReadSkip(ref Vp9Common cm, ref MacroBlockD xd, int segmentId, ref Reader r)
  201. {
  202. if (cm.Seg.IsSegFeatureActive(segmentId, SegLvlFeatures.SegLvlSkip) != 0)
  203. {
  204. return 1;
  205. }
  206. else
  207. {
  208. int ctx = xd.GetSkipContext();
  209. int skip = r.Read(cm.Fc.Value.SkipProb[ctx]);
  210. if (!xd.Counts.IsNull)
  211. {
  212. ++xd.Counts.Value.Skip[ctx][skip];
  213. }
  214. return skip;
  215. }
  216. }
  217. private static int ReadMvComponent(ref Reader r, ref Vp9EntropyProbs fc, int mvcomp, bool usehp)
  218. {
  219. int mag, d, fr, hp;
  220. bool sign = r.Read(fc.Sign[mvcomp]) != 0;
  221. MvClassType mvClass = (MvClassType)r.ReadTree(Luts.Vp9MvClassTree, fc.Classes[mvcomp].ToSpan());
  222. bool class0 = mvClass == MvClassType.MvClass0;
  223. // Integer part
  224. if (class0)
  225. {
  226. d = r.Read(fc.Class0[mvcomp][0]);
  227. mag = 0;
  228. }
  229. else
  230. {
  231. int i;
  232. int n = (int)mvClass + Constants.Class0Bits - 1; // Number of bits
  233. d = 0;
  234. for (i = 0; i < n; ++i)
  235. {
  236. d |= r.Read(fc.Bits[mvcomp][i]) << i;
  237. }
  238. mag = Constants.Class0Size << ((int)mvClass + 2);
  239. }
  240. // Fractional part
  241. fr = r.ReadTree(Luts.Vp9MvFPTree, class0 ? fc.Class0Fp[mvcomp][d].ToSpan() : fc.Fp[mvcomp].ToSpan());
  242. // High precision part (if hp is not used, the default value of the hp is 1)
  243. hp = usehp ? r.Read(class0 ? fc.Class0Hp[mvcomp] : fc.Hp[mvcomp]) : 1;
  244. // Result
  245. mag += ((d << 3) | (fr << 1) | hp) + 1;
  246. return sign ? -mag : mag;
  247. }
  248. private static void ReadMv(
  249. ref Reader r,
  250. ref Mv mv,
  251. ref Mv refr,
  252. ref Vp9EntropyProbs fc,
  253. Ptr<Vp9BackwardUpdates> counts,
  254. bool allowHP)
  255. {
  256. MvJointType jointType = (MvJointType)r.ReadTree(Luts.Vp9MvJointTree, fc.Joints.ToSpan());
  257. bool useHP = allowHP && refr.UseMvHp();
  258. Mv diff = new Mv();
  259. if (Mv.MvJointVertical(jointType))
  260. {
  261. diff.Row = (short)ReadMvComponent(ref r, ref fc, 0, useHP);
  262. }
  263. if (Mv.MvJointHorizontal(jointType))
  264. {
  265. diff.Col = (short)ReadMvComponent(ref r, ref fc, 1, useHP);
  266. }
  267. diff.IncMv(counts);
  268. mv.Row = (short)(refr.Row + diff.Row);
  269. mv.Col = (short)(refr.Col + diff.Col);
  270. }
  271. private static ReferenceMode ReadBlockReferenceMode(ref Vp9Common cm, ref MacroBlockD xd, ref Reader r)
  272. {
  273. if (cm.ReferenceMode == ReferenceMode.ReferenceModeSelect)
  274. {
  275. int ctx = PredCommon.GetReferenceModeContext(ref cm, ref xd);
  276. ReferenceMode mode = (ReferenceMode)r.Read(cm.Fc.Value.CompInterProb[ctx]);
  277. if (!xd.Counts.IsNull)
  278. {
  279. ++xd.Counts.Value.CompInter[ctx][(int)mode];
  280. }
  281. return mode; // SingleReference or CompoundReference
  282. }
  283. else
  284. {
  285. return cm.ReferenceMode;
  286. }
  287. }
  288. // Read the referncence frame
  289. private static void ReadRefFrames(
  290. ref Vp9Common cm,
  291. ref MacroBlockD xd,
  292. ref Reader r,
  293. int segmentId,
  294. ref Array2<sbyte> refFrame)
  295. {
  296. ref Vp9EntropyProbs fc = ref cm.Fc.Value;
  297. if (cm.Seg.IsSegFeatureActive(segmentId, SegLvlFeatures.SegLvlRefFrame) != 0)
  298. {
  299. refFrame[0] = (sbyte)cm.Seg.GetSegData(segmentId, SegLvlFeatures.SegLvlRefFrame);
  300. refFrame[1] = Constants.None;
  301. }
  302. else
  303. {
  304. ReferenceMode mode = ReadBlockReferenceMode(ref cm, ref xd, ref r);
  305. if (mode == ReferenceMode.CompoundReference)
  306. {
  307. int idx = cm.RefFrameSignBias[cm.CompFixedRef];
  308. int ctx = PredCommon.GetPredContextCompRefP(ref cm, ref xd);
  309. int bit = r.Read(fc.CompRefProb[ctx]);
  310. if (!xd.Counts.IsNull)
  311. {
  312. ++xd.Counts.Value.CompRef[ctx][bit];
  313. }
  314. refFrame[idx] = cm.CompFixedRef;
  315. refFrame[idx == 0 ? 1 : 0] = cm.CompVarRef[bit];
  316. }
  317. else if (mode == ReferenceMode.SingleReference)
  318. {
  319. int ctx0 = PredCommon.GetPredContextSingleRefP1(ref xd);
  320. int bit0 = r.Read(fc.SingleRefProb[ctx0][0]);
  321. if (!xd.Counts.IsNull)
  322. {
  323. ++xd.Counts.Value.SingleRef[ctx0][0][bit0];
  324. }
  325. if (bit0 != 0)
  326. {
  327. int ctx1 = PredCommon.GetPredContextSingleRefP2(ref xd);
  328. int bit1 = r.Read(fc.SingleRefProb[ctx1][1]);
  329. if (!xd.Counts.IsNull)
  330. {
  331. ++xd.Counts.Value.SingleRef[ctx1][1][bit1];
  332. }
  333. refFrame[0] = (sbyte)(bit1 != 0 ? Constants.AltRefFrame : Constants.GoldenFrame);
  334. }
  335. else
  336. {
  337. refFrame[0] = Constants.LastFrame;
  338. }
  339. refFrame[1] = Constants.None;
  340. }
  341. else
  342. {
  343. Debug.Assert(false, "Invalid prediction mode.");
  344. }
  345. }
  346. }
  347. private static byte ReadSwitchableInterpFilter(ref Vp9Common cm, ref MacroBlockD xd, ref Reader r)
  348. {
  349. int ctx = xd.GetPredContextSwitchableInterp();
  350. byte type = (byte)r.ReadTree(Luts.Vp9SwitchableInterpTree, cm.Fc.Value.SwitchableInterpProb[ctx].ToSpan());
  351. if (!xd.Counts.IsNull)
  352. {
  353. ++xd.Counts.Value.SwitchableInterp[ctx][type];
  354. }
  355. return type;
  356. }
  357. private static void ReadIntraBlockModeInfo(ref Vp9Common cm, ref MacroBlockD xd, ref ModeInfo mi, ref Reader r)
  358. {
  359. BlockSize bsize = mi.SbType;
  360. int i;
  361. switch (bsize)
  362. {
  363. case BlockSize.Block4x4:
  364. for (i = 0; i < 4; ++i)
  365. {
  366. mi.Bmi[i].Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
  367. }
  368. mi.Mode = mi.Bmi[3].Mode;
  369. break;
  370. case BlockSize.Block4x8:
  371. mi.Bmi[0].Mode = mi.Bmi[2].Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
  372. mi.Bmi[1].Mode = mi.Bmi[3].Mode = mi.Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
  373. break;
  374. case BlockSize.Block8x4:
  375. mi.Bmi[0].Mode = mi.Bmi[1].Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
  376. mi.Bmi[2].Mode = mi.Bmi[3].Mode = mi.Mode = ReadIntraModeY(ref cm, ref xd, ref r, 0);
  377. break;
  378. default: mi.Mode = ReadIntraModeY(ref cm, ref xd, ref r, Luts.SizeGroupLookup[(int)bsize]); break;
  379. }
  380. mi.UvMode = ReadIntraModeUv(ref cm, ref xd, ref r, (byte)mi.Mode);
  381. // Initialize interp_filter here so we do not have to check for inter block
  382. // modes in GetPredContextSwitchableInterp()
  383. mi.InterpFilter = Constants.SwitchableFilters;
  384. mi.RefFrame[0] = Constants.IntraFrame;
  385. mi.RefFrame[1] = Constants.None;
  386. }
  387. private static bool IsMvValid(ref Mv mv)
  388. {
  389. return mv.Row > Constants.MvLow &&
  390. mv.Row < Constants.MvUpp &&
  391. mv.Col > Constants.MvLow &&
  392. mv.Col < Constants.MvUpp;
  393. }
  394. private static void CopyMvPair(ref Array2<Mv> dst, ref Array2<Mv> src)
  395. {
  396. dst[0] = src[0];
  397. dst[1] = src[1];
  398. }
  399. private static void ZeroMvPair(ref Array2<Mv> dst)
  400. {
  401. dst[0] = new Mv();
  402. dst[1] = new Mv();
  403. }
  404. private static bool AssignMv(
  405. ref Vp9Common cm,
  406. ref MacroBlockD xd,
  407. PredictionMode mode,
  408. ref Array2<Mv> mv,
  409. ref Array2<Mv> refMv,
  410. ref Array2<Mv> nearNearestMv,
  411. int isCompound,
  412. bool allowHP,
  413. ref Reader r)
  414. {
  415. int i;
  416. bool ret = true;
  417. switch (mode)
  418. {
  419. case PredictionMode.NewMv:
  420. {
  421. for (i = 0; i < 1 + isCompound; ++i)
  422. {
  423. ReadMv(ref r, ref mv[i], ref refMv[i], ref cm.Fc.Value, xd.Counts, allowHP);
  424. ret = ret && IsMvValid(ref mv[i]);
  425. }
  426. break;
  427. }
  428. case PredictionMode.NearMv:
  429. case PredictionMode.NearestMv:
  430. {
  431. CopyMvPair(ref mv, ref nearNearestMv);
  432. break;
  433. }
  434. case PredictionMode.ZeroMv:
  435. {
  436. ZeroMvPair(ref mv);
  437. break;
  438. }
  439. default: return false;
  440. }
  441. return ret;
  442. }
  443. private static bool ReadIsInterBlock(ref Vp9Common cm, ref MacroBlockD xd, int segmentId, ref Reader r)
  444. {
  445. if (cm.Seg.IsSegFeatureActive(segmentId, SegLvlFeatures.SegLvlRefFrame) != 0)
  446. {
  447. return cm.Seg.GetSegData(segmentId, SegLvlFeatures.SegLvlRefFrame) != Constants.IntraFrame;
  448. }
  449. else
  450. {
  451. int ctx = xd.GetIntraInterContext();
  452. bool isInter = r.Read(cm.Fc.Value.IntraInterProb[ctx]) != 0;
  453. if (!xd.Counts.IsNull)
  454. {
  455. ++xd.Counts.Value.IntraInter[ctx][isInter ? 1 : 0];
  456. }
  457. return isInter;
  458. }
  459. }
  460. private static void DecFindBestRefMvs(bool allowHP, Span<Mv> mvlist, ref Mv bestMv, int refmvCount)
  461. {
  462. int i;
  463. // Make sure all the candidates are properly clamped etc
  464. for (i = 0; i < refmvCount; ++i)
  465. {
  466. mvlist[i].LowerMvPrecision(allowHP);
  467. bestMv = mvlist[i];
  468. }
  469. }
  470. private static bool AddMvRefListEb(Mv mv, ref int refMvCount, Span<Mv> mvRefList, bool earlyBreak)
  471. {
  472. if (refMvCount != 0)
  473. {
  474. if (Unsafe.As<Mv, int>(ref mv) != Unsafe.As<Mv, int>(ref mvRefList[0]))
  475. {
  476. mvRefList[refMvCount] = mv;
  477. refMvCount++;
  478. return true;
  479. }
  480. }
  481. else
  482. {
  483. mvRefList[refMvCount++] = mv;
  484. if (earlyBreak)
  485. {
  486. return true;
  487. }
  488. }
  489. return false;
  490. }
  491. // Performs mv sign inversion if indicated by the reference frame combination.
  492. private static Mv ScaleMv(ref ModeInfo mi, int refr, sbyte thisRefFrame, ref Array4<sbyte> refSignBias)
  493. {
  494. Mv mv = mi.Mv[refr];
  495. if (refSignBias[mi.RefFrame[refr]] != refSignBias[thisRefFrame])
  496. {
  497. mv.Row *= -1;
  498. mv.Col *= -1;
  499. }
  500. return mv;
  501. }
  502. private static bool IsDiffRefFrameAddMvEb(
  503. ref ModeInfo mbmi,
  504. sbyte refFrame,
  505. ref Array4<sbyte> refSignBias,
  506. ref int refmvCount,
  507. Span<Mv> mvRefList,
  508. bool earlyBreak)
  509. {
  510. if (mbmi.IsInterBlock())
  511. {
  512. if (mbmi.RefFrame[0] != refFrame)
  513. {
  514. if (AddMvRefListEb(ScaleMv(ref mbmi, 0, refFrame, ref refSignBias), ref refmvCount, mvRefList, earlyBreak))
  515. {
  516. return true;
  517. }
  518. }
  519. if (mbmi.HasSecondRef() && mbmi.RefFrame[1] != refFrame && Unsafe.As<Mv, int>(ref mbmi.Mv[1]) != Unsafe.As<Mv, int>(ref mbmi.Mv[0]))
  520. {
  521. if (AddMvRefListEb(ScaleMv(ref mbmi, 1, refFrame, ref refSignBias), ref refmvCount, mvRefList, earlyBreak))
  522. {
  523. return true;
  524. }
  525. }
  526. }
  527. return false;
  528. }
  529. // This function searches the neighborhood of a given MB/SB
  530. // to try and find candidate reference vectors.
  531. private static unsafe int DecFindMvRefs(
  532. ref Vp9Common cm,
  533. ref MacroBlockD xd,
  534. PredictionMode mode,
  535. sbyte refFrame,
  536. Span<Position> mvRefSearch,
  537. Span<Mv> mvRefList,
  538. int miRow,
  539. int miCol,
  540. int block,
  541. int isSub8X8)
  542. {
  543. ref Array4<sbyte> refSignBias = ref cm.RefFrameSignBias;
  544. int i, refmvCount = 0;
  545. bool differentRefFound = false;
  546. Ptr<MvRef> prevFrameMvs = cm.UsePrevFrameMvs ? new Ptr<MvRef>(ref cm.PrevFrameMvs[miRow * cm.MiCols + miCol]) : Ptr<MvRef>.Null;
  547. ref TileInfo tile = ref xd.Tile;
  548. // If mode is nearestmv or newmv (uses nearestmv as a reference) then stop
  549. // searching after the first mv is found.
  550. bool earlyBreak = mode != PredictionMode.NearMv;
  551. // Blank the reference vector list
  552. mvRefList.Slice(0, Constants.MaxMvRefCandidates).Fill(new Mv());
  553. i = 0;
  554. if (isSub8X8 != 0)
  555. {
  556. // If the size < 8x8 we get the mv from the bmi substructure for the
  557. // nearest two blocks.
  558. for (i = 0; i < 2; ++i)
  559. {
  560. ref Position mvRef = ref mvRefSearch[i];
  561. if (tile.IsInside(miCol, miRow, cm.MiRows, ref mvRef))
  562. {
  563. ref ModeInfo candidateMi = ref xd.Mi[mvRef.Col + mvRef.Row * xd.MiStride].Value;
  564. differentRefFound = true;
  565. if (candidateMi.RefFrame[0] == refFrame)
  566. {
  567. if (AddMvRefListEb(candidateMi.GetSubBlockMv(0, mvRef.Col, block), ref refmvCount, mvRefList, earlyBreak))
  568. {
  569. goto Done;
  570. }
  571. }
  572. else if (candidateMi.RefFrame[1] == refFrame)
  573. {
  574. if (AddMvRefListEb(candidateMi.GetSubBlockMv(1, mvRef.Col, block), ref refmvCount, mvRefList, earlyBreak))
  575. {
  576. goto Done;
  577. }
  578. }
  579. }
  580. }
  581. }
  582. // Check the rest of the neighbors in much the same way
  583. // as before except we don't need to keep track of sub blocks or
  584. // mode counts.
  585. for (; i < MvrefNeighbours; ++i)
  586. {
  587. ref Position mvRef = ref mvRefSearch[i];
  588. if (tile.IsInside(miCol, miRow, cm.MiRows, ref mvRef))
  589. {
  590. ref ModeInfo candidate = ref xd.Mi[mvRef.Col + mvRef.Row * xd.MiStride].Value;
  591. differentRefFound = true;
  592. if (candidate.RefFrame[0] == refFrame)
  593. {
  594. if (AddMvRefListEb(candidate.Mv[0], ref refmvCount, mvRefList, earlyBreak))
  595. {
  596. goto Done;
  597. }
  598. }
  599. else if (candidate.RefFrame[1] == refFrame)
  600. {
  601. if (AddMvRefListEb(candidate.Mv[1], ref refmvCount, mvRefList, earlyBreak))
  602. {
  603. goto Done;
  604. }
  605. }
  606. }
  607. }
  608. // Check the last frame's mode and mv info.
  609. if (!prevFrameMvs.IsNull)
  610. {
  611. if (prevFrameMvs.Value.RefFrame[0] == refFrame)
  612. {
  613. if (AddMvRefListEb(prevFrameMvs.Value.Mv[0], ref refmvCount, mvRefList, earlyBreak))
  614. {
  615. goto Done;
  616. }
  617. }
  618. else if (prevFrameMvs.Value.RefFrame[1] == refFrame)
  619. {
  620. if (AddMvRefListEb(prevFrameMvs.Value.Mv[1], ref refmvCount, mvRefList, earlyBreak))
  621. {
  622. goto Done;
  623. }
  624. }
  625. }
  626. // Since we couldn't find 2 mvs from the same reference frame
  627. // go back through the neighbors and find motion vectors from
  628. // different reference frames.
  629. if (differentRefFound)
  630. {
  631. for (i = 0; i < MvrefNeighbours; ++i)
  632. {
  633. ref Position mvRef = ref mvRefSearch[i];
  634. if (tile.IsInside(miCol, miRow, cm.MiRows, ref mvRef))
  635. {
  636. ref ModeInfo candidate = ref xd.Mi[mvRef.Col + mvRef.Row * xd.MiStride].Value;
  637. // If the candidate is Intra we don't want to consider its mv.
  638. if (IsDiffRefFrameAddMvEb(ref candidate, refFrame, ref refSignBias, ref refmvCount, mvRefList, earlyBreak))
  639. {
  640. goto Done;
  641. }
  642. }
  643. }
  644. }
  645. // Since we still don't have a candidate we'll try the last frame.
  646. if (!prevFrameMvs.IsNull)
  647. {
  648. if (prevFrameMvs.Value.RefFrame[0] != refFrame && prevFrameMvs.Value.RefFrame[0] > Constants.IntraFrame)
  649. {
  650. Mv mv = prevFrameMvs.Value.Mv[0];
  651. if (refSignBias[prevFrameMvs.Value.RefFrame[0]] != refSignBias[refFrame])
  652. {
  653. mv.Row *= -1;
  654. mv.Col *= -1;
  655. }
  656. if (AddMvRefListEb(mv, ref refmvCount, mvRefList, earlyBreak))
  657. {
  658. goto Done;
  659. }
  660. }
  661. if (prevFrameMvs.Value.RefFrame[1] > Constants.IntraFrame &&
  662. prevFrameMvs.Value.RefFrame[1] != refFrame &&
  663. Unsafe.As<Mv, int>(ref prevFrameMvs.Value.Mv[1]) != Unsafe.As<Mv, int>(ref prevFrameMvs.Value.Mv[0]))
  664. {
  665. Mv mv = prevFrameMvs.Value.Mv[1];
  666. if (refSignBias[prevFrameMvs.Value.RefFrame[1]] != refSignBias[refFrame])
  667. {
  668. mv.Row *= -1;
  669. mv.Col *= -1;
  670. }
  671. if (AddMvRefListEb(mv, ref refmvCount, mvRefList, earlyBreak))
  672. {
  673. goto Done;
  674. }
  675. }
  676. }
  677. if (mode == PredictionMode.NearMv)
  678. {
  679. refmvCount = Constants.MaxMvRefCandidates;
  680. }
  681. else
  682. {
  683. // We only care about the nearestmv for the remaining modes
  684. refmvCount = 1;
  685. }
  686. Done:
  687. // Clamp vectors
  688. for (i = 0; i < refmvCount; ++i)
  689. {
  690. mvRefList[i].ClampMvRef(ref xd);
  691. }
  692. return refmvCount;
  693. }
  694. private static void AppendSub8x8MvsForIdx(
  695. ref Vp9Common cm,
  696. ref MacroBlockD xd,
  697. Span<Position> mvRefSearch,
  698. PredictionMode bMode,
  699. int block,
  700. int refr,
  701. int miRow,
  702. int miCol,
  703. ref Mv bestSub8x8)
  704. {
  705. Span<Mv> mvList = stackalloc Mv[Constants.MaxMvRefCandidates];
  706. ref ModeInfo mi = ref xd.Mi[0].Value;
  707. ref Array4<BModeInfo> bmi = ref mi.Bmi;
  708. int n;
  709. int refmvCount;
  710. Debug.Assert(Constants.MaxMvRefCandidates == 2);
  711. refmvCount = DecFindMvRefs(ref cm, ref xd, bMode, mi.RefFrame[refr], mvRefSearch, mvList, miRow, miCol, block, 1);
  712. switch (block)
  713. {
  714. case 0: bestSub8x8 = mvList[refmvCount - 1]; break;
  715. case 1:
  716. case 2:
  717. if (bMode == PredictionMode.NearestMv)
  718. {
  719. bestSub8x8 = bmi[0].Mv[refr];
  720. }
  721. else
  722. {
  723. bestSub8x8 = new Mv();
  724. for (n = 0; n < refmvCount; ++n)
  725. {
  726. if (Unsafe.As<Mv, int>(ref bmi[0].Mv[refr]) != Unsafe.As<Mv, int>(ref mvList[n]))
  727. {
  728. bestSub8x8 = mvList[n];
  729. break;
  730. }
  731. }
  732. }
  733. break;
  734. case 3:
  735. if (bMode == PredictionMode.NearestMv)
  736. {
  737. bestSub8x8 = bmi[2].Mv[refr];
  738. }
  739. else
  740. {
  741. Span<Mv> candidates = stackalloc Mv[2 + Constants.MaxMvRefCandidates];
  742. candidates[0] = bmi[1].Mv[refr];
  743. candidates[1] = bmi[0].Mv[refr];
  744. candidates[2] = mvList[0];
  745. candidates[3] = mvList[1];
  746. bestSub8x8 = new Mv();
  747. for (n = 0; n < 2 + Constants.MaxMvRefCandidates; ++n)
  748. {
  749. if (Unsafe.As<Mv, int>(ref bmi[2].Mv[refr]) != Unsafe.As<Mv, int>(ref candidates[n]))
  750. {
  751. bestSub8x8 = candidates[n];
  752. break;
  753. }
  754. }
  755. }
  756. break;
  757. default: Debug.Assert(false, "Invalid block index."); break;
  758. }
  759. }
  760. private static byte GetModeContext(ref Vp9Common cm, ref MacroBlockD xd, Span<Position> mvRefSearch, int miRow, int miCol)
  761. {
  762. int i;
  763. int contextCounter = 0;
  764. ref TileInfo tile = ref xd.Tile;
  765. // Get mode count from nearest 2 blocks
  766. for (i = 0; i < 2; ++i)
  767. {
  768. ref Position mvRef = ref mvRefSearch[i];
  769. if (tile.IsInside(miCol, miRow, cm.MiRows, ref mvRef))
  770. {
  771. ref ModeInfo candidate = ref xd.Mi[mvRef.Col + mvRef.Row * xd.MiStride].Value;
  772. // Keep counts for entropy encoding.
  773. contextCounter += Luts.Mode2Counter[(int)candidate.Mode];
  774. }
  775. }
  776. return (byte)Luts.CounterToContext[contextCounter];
  777. }
  778. private static void ReadInterBlockModeInfo(
  779. ref Vp9Common cm,
  780. ref MacroBlockD xd,
  781. ref ModeInfo mi,
  782. int miRow,
  783. int miCol,
  784. ref Reader r)
  785. {
  786. BlockSize bsize = mi.SbType;
  787. bool allowHP = cm.AllowHighPrecisionMv;
  788. Array2<Mv> bestRefMvs = new Array2<Mv>();
  789. int refr, isCompound;
  790. byte interModeCtx;
  791. Span<Position> mvRefSearch = Luts.MvRefBlocks[(int)bsize];
  792. ReadRefFrames(ref cm, ref xd, ref r, mi.SegmentId, ref mi.RefFrame);
  793. isCompound = mi.HasSecondRef() ? 1 : 0;
  794. interModeCtx = GetModeContext(ref cm, ref xd, mvRefSearch, miRow, miCol);
  795. if (cm.Seg.IsSegFeatureActive(mi.SegmentId, SegLvlFeatures.SegLvlSkip) != 0)
  796. {
  797. mi.Mode = PredictionMode.ZeroMv;
  798. if (bsize < BlockSize.Block8x8)
  799. {
  800. xd.ErrorInfo.Value.InternalError(CodecErr.CodecUnsupBitstream, "Invalid usage of segement feature on small blocks");
  801. return;
  802. }
  803. }
  804. else
  805. {
  806. if (bsize >= BlockSize.Block8x8)
  807. {
  808. mi.Mode = ReadInterMode(ref cm, ref xd, ref r, interModeCtx);
  809. }
  810. else
  811. {
  812. // Sub 8x8 blocks use the nearestmv as a ref_mv if the bMode is NewMv.
  813. // Setting mode to NearestMv forces the search to stop after the nearestmv
  814. // has been found. After bModes have been read, mode will be overwritten
  815. // by the last bMode.
  816. mi.Mode = PredictionMode.NearestMv;
  817. }
  818. if (mi.Mode != PredictionMode.ZeroMv)
  819. {
  820. Span<Mv> tmpMvs = stackalloc Mv[Constants.MaxMvRefCandidates];
  821. for (refr = 0; refr < 1 + isCompound; ++refr)
  822. {
  823. sbyte frame = mi.RefFrame[refr];
  824. int refmvCount;
  825. refmvCount = DecFindMvRefs(ref cm, ref xd, mi.Mode, frame, mvRefSearch, tmpMvs, miRow, miCol, -1, 0);
  826. DecFindBestRefMvs(allowHP, tmpMvs, ref bestRefMvs[refr], refmvCount);
  827. }
  828. }
  829. }
  830. mi.InterpFilter = (cm.InterpFilter == Constants.Switchable) ? ReadSwitchableInterpFilter(ref cm, ref xd, ref r) : cm.InterpFilter;
  831. if (bsize < BlockSize.Block8x8)
  832. {
  833. int num4X4W = 1 << xd.BmodeBlocksWl;
  834. int num4X4H = 1 << xd.BmodeBlocksHl;
  835. int idx, idy;
  836. PredictionMode bMode = 0;
  837. Array2<Mv> bestSub8x8 = new Array2<Mv>();
  838. const uint invalidMv = 0x80008000;
  839. // Initialize the 2nd element as even though it won't be used meaningfully
  840. // if isCompound is false.
  841. Unsafe.As<Mv, uint>(ref bestSub8x8[1]) = invalidMv;
  842. for (idy = 0; idy < 2; idy += num4X4H)
  843. {
  844. for (idx = 0; idx < 2; idx += num4X4W)
  845. {
  846. int j = idy * 2 + idx;
  847. bMode = ReadInterMode(ref cm, ref xd, ref r, interModeCtx);
  848. if (bMode == PredictionMode.NearestMv || bMode == PredictionMode.NearMv)
  849. {
  850. for (refr = 0; refr < 1 + isCompound; ++refr)
  851. {
  852. AppendSub8x8MvsForIdx(ref cm, ref xd, mvRefSearch, bMode, j, refr, miRow, miCol, ref bestSub8x8[refr]);
  853. }
  854. }
  855. if (!AssignMv(ref cm, ref xd, bMode, ref mi.Bmi[j].Mv, ref bestRefMvs, ref bestSub8x8, isCompound, allowHP, ref r))
  856. {
  857. xd.Corrupted |= true;
  858. break;
  859. }
  860. if (num4X4H == 2)
  861. {
  862. mi.Bmi[j + 2] = mi.Bmi[j];
  863. }
  864. if (num4X4W == 2)
  865. {
  866. mi.Bmi[j + 1] = mi.Bmi[j];
  867. }
  868. }
  869. }
  870. mi.Mode = bMode;
  871. CopyMvPair(ref mi.Mv, ref mi.Bmi[3].Mv);
  872. }
  873. else
  874. {
  875. xd.Corrupted |= !AssignMv(ref cm, ref xd, mi.Mode, ref mi.Mv, ref bestRefMvs, ref bestRefMvs, isCompound, allowHP, ref r);
  876. }
  877. }
  878. private static void ReadInterFrameModeInfo(
  879. ref Vp9Common cm,
  880. ref MacroBlockD xd,
  881. int miRow,
  882. int miCol,
  883. ref Reader r,
  884. int xMis,
  885. int yMis)
  886. {
  887. ref ModeInfo mi = ref xd.Mi[0].Value;
  888. bool interBlock;
  889. mi.SegmentId = (sbyte)ReadInterSegmentId(ref cm, ref xd, miRow, miCol, ref r, xMis, yMis);
  890. mi.Skip = (sbyte)ReadSkip(ref cm, ref xd, mi.SegmentId, ref r);
  891. interBlock = ReadIsInterBlock(ref cm, ref xd, mi.SegmentId, ref r);
  892. mi.TxSize = ReadTxSize(ref cm, ref xd, mi.Skip == 0 || !interBlock, ref r);
  893. if (interBlock)
  894. {
  895. ReadInterBlockModeInfo(ref cm, ref xd, ref mi, miRow, miCol, ref r);
  896. }
  897. else
  898. {
  899. ReadIntraBlockModeInfo(ref cm, ref xd, ref mi, ref r);
  900. }
  901. }
  902. private static PredictionMode LeftBlockMode(Ptr<ModeInfo> curMi, Ptr<ModeInfo> leftMi, int b)
  903. {
  904. if (b == 0 || b == 2)
  905. {
  906. if (leftMi.IsNull || leftMi.Value.IsInterBlock())
  907. {
  908. return PredictionMode.DcPred;
  909. }
  910. return leftMi.Value.GetYMode(b + 1);
  911. }
  912. else
  913. {
  914. Debug.Assert(b == 1 || b == 3);
  915. return curMi.Value.Bmi[b - 1].Mode;
  916. }
  917. }
  918. private static PredictionMode AboveBlockMode(Ptr<ModeInfo> curMi, Ptr<ModeInfo> aboveMi, int b)
  919. {
  920. if (b == 0 || b == 1)
  921. {
  922. if (aboveMi.IsNull || aboveMi.Value.IsInterBlock())
  923. {
  924. return PredictionMode.DcPred;
  925. }
  926. return aboveMi.Value.GetYMode(b + 2);
  927. }
  928. else
  929. {
  930. Debug.Assert(b == 2 || b == 3);
  931. return curMi.Value.Bmi[b - 2].Mode;
  932. }
  933. }
  934. private static ReadOnlySpan<byte> GetYModeProbs(
  935. ref Vp9EntropyProbs fc,
  936. Ptr<ModeInfo> mi,
  937. Ptr<ModeInfo> aboveMi,
  938. Ptr<ModeInfo> leftMi,
  939. int block)
  940. {
  941. PredictionMode above = AboveBlockMode(mi, aboveMi, block);
  942. PredictionMode left = LeftBlockMode(mi, leftMi, block);
  943. return fc.KfYModeProb[(int)above][(int)left].ToSpan();
  944. }
  945. private static void ReadIntraFrameModeInfo(
  946. ref Vp9Common cm,
  947. ref MacroBlockD xd,
  948. int miRow,
  949. int miCol,
  950. ref Reader r,
  951. int xMis,
  952. int yMis)
  953. {
  954. Ptr<ModeInfo> mi = xd.Mi[0];
  955. Ptr<ModeInfo> aboveMi = xd.AboveMi;
  956. Ptr<ModeInfo> leftMi = xd.LeftMi;
  957. BlockSize bsize = mi.Value.SbType;
  958. int i;
  959. int miOffset = miRow * cm.MiCols + miCol;
  960. mi.Value.SegmentId = (sbyte)ReadIntraSegmentId(ref cm, miOffset, xMis, yMis, ref r);
  961. mi.Value.Skip = (sbyte)ReadSkip(ref cm, ref xd, mi.Value.SegmentId, ref r);
  962. mi.Value.TxSize = ReadTxSize(ref cm, ref xd, true, ref r);
  963. mi.Value.RefFrame[0] = Constants.IntraFrame;
  964. mi.Value.RefFrame[1] = Constants.None;
  965. switch (bsize)
  966. {
  967. case BlockSize.Block4x4:
  968. for (i = 0; i < 4; ++i)
  969. {
  970. mi.Value.Bmi[i].Mode =
  971. ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, i));
  972. }
  973. mi.Value.Mode = mi.Value.Bmi[3].Mode;
  974. break;
  975. case BlockSize.Block4x8:
  976. mi.Value.Bmi[0].Mode = mi.Value.Bmi[2].Mode =
  977. ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 0));
  978. mi.Value.Bmi[1].Mode = mi.Value.Bmi[3].Mode = mi.Value.Mode =
  979. ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 1));
  980. break;
  981. case BlockSize.Block8x4:
  982. mi.Value.Bmi[0].Mode = mi.Value.Bmi[1].Mode =
  983. ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 0));
  984. mi.Value.Bmi[2].Mode = mi.Value.Bmi[3].Mode = mi.Value.Mode =
  985. ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 2));
  986. break;
  987. default:
  988. mi.Value.Mode = ReadIntraMode(ref r, GetYModeProbs(ref cm.Fc.Value, mi, aboveMi, leftMi, 0));
  989. break;
  990. }
  991. mi.Value.UvMode = ReadIntraMode(ref r, cm.Fc.Value.KfUvModeProb[(int)mi.Value.Mode].ToSpan());
  992. }
  993. private static void CopyRefFramePair(ref Array2<sbyte> dst, ref Array2<sbyte> src)
  994. {
  995. dst[0] = src[0];
  996. dst[1] = src[1];
  997. }
  998. public static void ReadModeInfo(
  999. ref TileWorkerData twd,
  1000. ref Vp9Common cm,
  1001. int miRow,
  1002. int miCol,
  1003. int xMis,
  1004. int yMis)
  1005. {
  1006. ref Reader r = ref twd.BitReader;
  1007. ref MacroBlockD xd = ref twd.Xd;
  1008. ref ModeInfo mi = ref xd.Mi[0].Value;
  1009. ArrayPtr<MvRef> frameMvs = cm.CurFrameMvs.Slice(miRow * cm.MiCols + miCol);
  1010. int w, h;
  1011. if (cm.FrameIsIntraOnly())
  1012. {
  1013. ReadIntraFrameModeInfo(ref cm, ref xd, miRow, miCol, ref r, xMis, yMis);
  1014. }
  1015. else
  1016. {
  1017. ReadInterFrameModeInfo(ref cm, ref xd, miRow, miCol, ref r, xMis, yMis);
  1018. for (h = 0; h < yMis; ++h)
  1019. {
  1020. for (w = 0; w < xMis; ++w)
  1021. {
  1022. ref MvRef mv = ref frameMvs[w];
  1023. CopyRefFramePair(ref mv.RefFrame, ref mi.RefFrame);
  1024. CopyMvPair(ref mv.Mv, ref mi.Mv);
  1025. }
  1026. frameMvs = frameMvs.Slice(cm.MiCols);
  1027. }
  1028. }
  1029. }
  1030. }
  1031. }