DecodeFrame.cs 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185
  1. using Ryujinx.Common.Memory;
  2. using System;
  3. using System.Buffers.Binary;
  4. using System.Diagnostics;
  5. using System.Runtime.CompilerServices;
  6. using System.Runtime.InteropServices;
  7. using Ryujinx.Graphics.Nvdec.Vp9.Common;
  8. using Ryujinx.Graphics.Nvdec.Vp9.Dsp;
  9. using Ryujinx.Graphics.Nvdec.Vp9.Types;
  10. using Ryujinx.Graphics.Video;
  11. using Mv = Ryujinx.Graphics.Nvdec.Vp9.Types.Mv;
  12. namespace Ryujinx.Graphics.Nvdec.Vp9
  13. {
  14. static class DecodeFrame
  15. {
  16. private static bool ReadIsValid(ArrayPtr<byte> start, int len)
  17. {
  18. return len != 0 && len <= start.Length;
  19. }
  20. private static void InverseTransformBlockInter(ref MacroBlockD xd, int plane, TxSize txSize, Span<byte> dst, int stride, int eob)
  21. {
  22. ref MacroBlockDPlane pd = ref xd.Plane[plane];
  23. ArrayPtr<int> dqcoeff = pd.DqCoeff;
  24. Debug.Assert(eob > 0);
  25. if (xd.CurBuf.HighBd)
  26. {
  27. Span<ushort> dst16 = MemoryMarshal.Cast<byte, ushort>(dst);
  28. if (xd.Lossless)
  29. {
  30. Idct.HighbdIwht4x4Add(dqcoeff.ToSpan(), dst16, stride, eob, xd.Bd);
  31. }
  32. else
  33. {
  34. switch (txSize)
  35. {
  36. case TxSize.Tx4x4:
  37. Idct.HighbdIdct4x4Add(dqcoeff.ToSpan(), dst16, stride, eob, xd.Bd);
  38. break;
  39. case TxSize.Tx8x8:
  40. Idct.HighbdIdct8x8Add(dqcoeff.ToSpan(), dst16, stride, eob, xd.Bd);
  41. break;
  42. case TxSize.Tx16x16:
  43. Idct.HighbdIdct16x16Add(dqcoeff.ToSpan(), dst16, stride, eob, xd.Bd);
  44. break;
  45. case TxSize.Tx32x32:
  46. Idct.HighbdIdct32x32Add(dqcoeff.ToSpan(), dst16, stride, eob, xd.Bd);
  47. break;
  48. default: Debug.Assert(false, "Invalid transform size"); break;
  49. }
  50. }
  51. }
  52. else
  53. {
  54. if (xd.Lossless)
  55. {
  56. Idct.Iwht4x4Add(dqcoeff.ToSpan(), dst, stride, eob);
  57. }
  58. else
  59. {
  60. switch (txSize)
  61. {
  62. case TxSize.Tx4x4: Idct.Idct4x4Add(dqcoeff.ToSpan(), dst, stride, eob); break;
  63. case TxSize.Tx8x8: Idct.Idct8x8Add(dqcoeff.ToSpan(), dst, stride, eob); break;
  64. case TxSize.Tx16x16: Idct.Idct16x16Add(dqcoeff.ToSpan(), dst, stride, eob); break;
  65. case TxSize.Tx32x32: Idct.Idct32x32Add(dqcoeff.ToSpan(), dst, stride, eob); break;
  66. default: Debug.Assert(false, "Invalid transform size"); return;
  67. }
  68. }
  69. }
  70. if (eob == 1)
  71. {
  72. dqcoeff.ToSpan()[0] = 0;
  73. }
  74. else
  75. {
  76. if (txSize <= TxSize.Tx16x16 && eob <= 10)
  77. {
  78. dqcoeff.ToSpan().Slice(0, 4 * (4 << (int)txSize)).Fill(0);
  79. }
  80. else if (txSize == TxSize.Tx32x32 && eob <= 34)
  81. {
  82. dqcoeff.ToSpan().Slice(0, 256).Fill(0);
  83. }
  84. else
  85. {
  86. dqcoeff.ToSpan().Slice(0, 16 << ((int)txSize << 1)).Fill(0);
  87. }
  88. }
  89. }
  90. private static void InverseTransformBlockIntra(
  91. ref MacroBlockD xd,
  92. int plane,
  93. TxType txType,
  94. TxSize txSize,
  95. Span<byte> dst,
  96. int stride,
  97. int eob)
  98. {
  99. ref MacroBlockDPlane pd = ref xd.Plane[plane];
  100. ArrayPtr<int> dqcoeff = pd.DqCoeff;
  101. Debug.Assert(eob > 0);
  102. if (xd.CurBuf.HighBd)
  103. {
  104. Span<ushort> dst16 = MemoryMarshal.Cast<byte, ushort>(dst);
  105. if (xd.Lossless)
  106. {
  107. Idct.HighbdIwht4x4Add(dqcoeff.ToSpan(), dst16, stride, eob, xd.Bd);
  108. }
  109. else
  110. {
  111. switch (txSize)
  112. {
  113. case TxSize.Tx4x4:
  114. Idct.HighbdIht4x4Add(txType, dqcoeff.ToSpan(), dst16, stride, eob, xd.Bd);
  115. break;
  116. case TxSize.Tx8x8:
  117. Idct.HighbdIht8x8Add(txType, dqcoeff.ToSpan(), dst16, stride, eob, xd.Bd);
  118. break;
  119. case TxSize.Tx16x16:
  120. Idct.HighbdIht16x16Add(txType, dqcoeff.ToSpan(), dst16, stride, eob, xd.Bd);
  121. break;
  122. case TxSize.Tx32x32:
  123. Idct.HighbdIdct32x32Add(dqcoeff.ToSpan(), dst16, stride, eob, xd.Bd);
  124. break;
  125. default: Debug.Assert(false, "Invalid transform size"); break;
  126. }
  127. }
  128. }
  129. else
  130. {
  131. if (xd.Lossless)
  132. {
  133. Idct.Iwht4x4Add(dqcoeff.ToSpan(), dst, stride, eob);
  134. }
  135. else
  136. {
  137. switch (txSize)
  138. {
  139. case TxSize.Tx4x4: Idct.Iht4x4Add(txType, dqcoeff.ToSpan(), dst, stride, eob); break;
  140. case TxSize.Tx8x8: Idct.Iht8x8Add(txType, dqcoeff.ToSpan(), dst, stride, eob); break;
  141. case TxSize.Tx16x16: Idct.Iht16x16Add(txType, dqcoeff.ToSpan(), dst, stride, eob); break;
  142. case TxSize.Tx32x32: Idct.Idct32x32Add(dqcoeff.ToSpan(), dst, stride, eob); break;
  143. default: Debug.Assert(false, "Invalid transform size"); return;
  144. }
  145. }
  146. }
  147. if (eob == 1)
  148. {
  149. dqcoeff.ToSpan()[0] = 0;
  150. }
  151. else
  152. {
  153. if (txType == TxType.DctDct && txSize <= TxSize.Tx16x16 && eob <= 10)
  154. {
  155. dqcoeff.ToSpan().Slice(0, 4 * (4 << (int)txSize)).Fill(0);
  156. }
  157. else if (txSize == TxSize.Tx32x32 && eob <= 34)
  158. {
  159. dqcoeff.ToSpan().Slice(0, 256).Fill(0);
  160. }
  161. else
  162. {
  163. dqcoeff.ToSpan().Slice(0, 16 << ((int)txSize << 1)).Fill(0);
  164. }
  165. }
  166. }
  167. private static unsafe void PredictAndReconstructIntraBlock(
  168. ref TileWorkerData twd,
  169. ref ModeInfo mi,
  170. int plane,
  171. int row,
  172. int col,
  173. TxSize txSize)
  174. {
  175. ref MacroBlockD xd = ref twd.Xd;
  176. ref MacroBlockDPlane pd = ref xd.Plane[plane];
  177. PredictionMode mode = (plane == 0) ? mi.Mode : mi.UvMode;
  178. int dstOffset = 4 * row * pd.Dst.Stride + 4 * col;
  179. byte* dst = &pd.Dst.Buf.ToPointer()[dstOffset];
  180. Span<byte> dstSpan = pd.Dst.Buf.ToSpan().Slice(dstOffset);
  181. if (mi.SbType < BlockSize.Block8x8)
  182. {
  183. if (plane == 0)
  184. {
  185. mode = xd.Mi[0].Value.Bmi[(row << 1) + col].Mode;
  186. }
  187. }
  188. ReconIntra.PredictIntraBlock(ref xd, pd.N4Wl, txSize, mode, dst, pd.Dst.Stride, dst, pd.Dst.Stride, col, row, plane);
  189. if (mi.Skip == 0)
  190. {
  191. TxType txType =
  192. (plane != 0 || xd.Lossless) ? TxType.DctDct : ReconIntra.IntraModeToTxTypeLookup[(int)mode];
  193. var sc = (plane != 0 || xd.Lossless)
  194. ? Luts.Vp9DefaultScanOrders[(int)txSize]
  195. : Luts.Vp9ScanOrders[(int)txSize][(int)txType];
  196. int eob = Detokenize.DecodeBlockTokens(ref twd, plane, sc, col, row, txSize, mi.SegmentId);
  197. if (eob > 0)
  198. {
  199. InverseTransformBlockIntra(ref xd, plane, txType, txSize, dstSpan, pd.Dst.Stride, eob);
  200. }
  201. }
  202. }
  203. private static int ReconstructInterBlock(
  204. ref TileWorkerData twd,
  205. ref ModeInfo mi,
  206. int plane,
  207. int row,
  208. int col,
  209. TxSize txSize)
  210. {
  211. ref MacroBlockD xd = ref twd.Xd;
  212. ref MacroBlockDPlane pd = ref xd.Plane[plane];
  213. var sc = Luts.Vp9DefaultScanOrders[(int)txSize];
  214. int eob = Detokenize.DecodeBlockTokens(ref twd, plane, sc, col, row, txSize, mi.SegmentId);
  215. Span<byte> dst = pd.Dst.Buf.ToSpan().Slice(4 * row * pd.Dst.Stride + 4 * col);
  216. if (eob > 0)
  217. {
  218. InverseTransformBlockInter(ref xd, plane, txSize, dst, pd.Dst.Stride, eob);
  219. }
  220. return eob;
  221. }
  222. private static unsafe void BuildMcBorder(
  223. byte* src,
  224. int srcStride,
  225. byte* dst,
  226. int dstStride,
  227. int x,
  228. int y,
  229. int bW,
  230. int bH,
  231. int w,
  232. int h)
  233. {
  234. // Get a pointer to the start of the real data for this row.
  235. byte* refRow = src - x - y * srcStride;
  236. if (y >= h)
  237. {
  238. refRow += (h - 1) * srcStride;
  239. }
  240. else if (y > 0)
  241. {
  242. refRow += y * srcStride;
  243. }
  244. do
  245. {
  246. int right = 0, copy;
  247. int left = x < 0 ? -x : 0;
  248. if (left > bW)
  249. {
  250. left = bW;
  251. }
  252. if (x + bW > w)
  253. {
  254. right = x + bW - w;
  255. }
  256. if (right > bW)
  257. {
  258. right = bW;
  259. }
  260. copy = bW - left - right;
  261. if (left != 0)
  262. {
  263. MemoryUtil.Fill(dst, refRow[0], left);
  264. }
  265. if (copy != 0)
  266. {
  267. MemoryUtil.Copy(dst + left, refRow + x + left, copy);
  268. }
  269. if (right != 0)
  270. {
  271. MemoryUtil.Fill(dst + left + copy, refRow[w - 1], right);
  272. }
  273. dst += dstStride;
  274. ++y;
  275. if (y > 0 && y < h)
  276. {
  277. refRow += srcStride;
  278. }
  279. } while (--bH != 0);
  280. }
  281. private static unsafe void HighBuildMcBorder(
  282. byte* src8,
  283. int srcStride,
  284. ushort* dst,
  285. int dstStride,
  286. int x,
  287. int y,
  288. int bW,
  289. int bH,
  290. int w,
  291. int h)
  292. {
  293. // Get a pointer to the start of the real data for this row.
  294. ushort* src = (ushort*)src8;
  295. ushort* refRow = src - x - y * srcStride;
  296. if (y >= h)
  297. {
  298. refRow += (h - 1) * srcStride;
  299. }
  300. else if (y > 0)
  301. {
  302. refRow += y * srcStride;
  303. }
  304. do
  305. {
  306. int right = 0, copy;
  307. int left = x < 0 ? -x : 0;
  308. if (left > bW)
  309. {
  310. left = bW;
  311. }
  312. if (x + bW > w)
  313. {
  314. right = x + bW - w;
  315. }
  316. if (right > bW)
  317. {
  318. right = bW;
  319. }
  320. copy = bW - left - right;
  321. if (left != 0)
  322. {
  323. MemoryUtil.Fill(dst, refRow[0], left);
  324. }
  325. if (copy != 0)
  326. {
  327. MemoryUtil.Copy(dst + left, refRow + x + left, copy);
  328. }
  329. if (right != 0)
  330. {
  331. MemoryUtil.Fill(dst + left + copy, refRow[w - 1], right);
  332. }
  333. dst += dstStride;
  334. ++y;
  335. if (y > 0 && y < h)
  336. {
  337. refRow += srcStride;
  338. }
  339. } while (--bH != 0);
  340. }
  341. [SkipLocalsInit]
  342. private static unsafe void ExtendAndPredict(
  343. byte* bufPtr1,
  344. int preBufStride,
  345. int x0,
  346. int y0,
  347. int bW,
  348. int bH,
  349. int frameWidth,
  350. int frameHeight,
  351. int borderOffset,
  352. byte* dst,
  353. int dstBufStride,
  354. int subpelX,
  355. int subpelY,
  356. Array8<short>[] kernel,
  357. ref ScaleFactors sf,
  358. ref MacroBlockD xd,
  359. int w,
  360. int h,
  361. int refr,
  362. int xs,
  363. int ys)
  364. {
  365. ushort* mcBufHigh = stackalloc ushort[80 * 2 * 80 * 2];
  366. if (xd.CurBuf.HighBd)
  367. {
  368. HighBuildMcBorder(bufPtr1, preBufStride, mcBufHigh, bW, x0, y0, bW, bH, frameWidth, frameHeight);
  369. ReconInter.HighbdInterPredictor(
  370. mcBufHigh + borderOffset,
  371. bW,
  372. (ushort*)dst,
  373. dstBufStride,
  374. subpelX,
  375. subpelY,
  376. ref sf,
  377. w,
  378. h,
  379. refr,
  380. kernel,
  381. xs,
  382. ys,
  383. xd.Bd);
  384. }
  385. else
  386. {
  387. BuildMcBorder(bufPtr1, preBufStride, (byte*)mcBufHigh, bW, x0, y0, bW, bH, frameWidth, frameHeight);
  388. ReconInter.InterPredictor(
  389. (byte*)mcBufHigh + borderOffset,
  390. bW,
  391. dst,
  392. dstBufStride,
  393. subpelX,
  394. subpelY,
  395. ref sf,
  396. w,
  397. h,
  398. refr,
  399. kernel,
  400. xs,
  401. ys);
  402. }
  403. }
  404. private static unsafe void DecBuildInterPredictors(
  405. ref MacroBlockD xd,
  406. int plane,
  407. int bw,
  408. int bh,
  409. int x,
  410. int y,
  411. int w,
  412. int h,
  413. int miX,
  414. int miY,
  415. Array8<short>[] kernel,
  416. ref ScaleFactors sf,
  417. ref Buf2D preBuf,
  418. ref Buf2D dstBuf,
  419. ref Mv mv,
  420. ref Surface refFrameBuf,
  421. bool isScaled,
  422. int refr)
  423. {
  424. ref MacroBlockDPlane pd = ref xd.Plane[plane];
  425. byte* dst = dstBuf.Buf.ToPointer() + dstBuf.Stride * y + x;
  426. Mv32 scaledMv;
  427. int xs, ys, x0, y0, x0_16, y0_16, frameWidth, frameHeight, bufStride, subpelX, subpelY;
  428. byte* refFrame;
  429. byte* bufPtr;
  430. // Get reference frame pointer, width and height.
  431. if (plane == 0)
  432. {
  433. frameWidth = refFrameBuf.Width;
  434. frameHeight = refFrameBuf.Height;
  435. refFrame = refFrameBuf.YBuffer.ToPointer();
  436. }
  437. else
  438. {
  439. frameWidth = refFrameBuf.UvWidth;
  440. frameHeight = refFrameBuf.UvHeight;
  441. refFrame = plane == 1 ? refFrameBuf.UBuffer.ToPointer() : refFrameBuf.VBuffer.ToPointer();
  442. }
  443. if (isScaled)
  444. {
  445. Mv mvQ4 = ReconInter.ClampMvToUmvBorderSb(ref xd, ref mv, bw, bh, pd.SubsamplingX, pd.SubsamplingY);
  446. // Co-ordinate of containing block to pixel precision.
  447. int xStart = (-xd.MbToLeftEdge >> (3 + pd.SubsamplingX));
  448. int yStart = (-xd.MbToTopEdge >> (3 + pd.SubsamplingY));
  449. // Co-ordinate of the block to 1/16th pixel precision.
  450. x0_16 = (xStart + x) << Filter.SubpelBits;
  451. y0_16 = (yStart + y) << Filter.SubpelBits;
  452. // Co-ordinate of current block in reference frame
  453. // to 1/16th pixel precision.
  454. x0_16 = sf.ScaleValueX(x0_16);
  455. y0_16 = sf.ScaleValueY(y0_16);
  456. // Map the top left corner of the block into the reference frame.
  457. x0 = sf.ScaleValueX(xStart + x);
  458. y0 = sf.ScaleValueY(yStart + y);
  459. // Scale the MV and incorporate the sub-pixel offset of the block
  460. // in the reference frame.
  461. scaledMv = sf.ScaleMv(ref mvQ4, miX + x, miY + y);
  462. xs = sf.XStepQ4;
  463. ys = sf.YStepQ4;
  464. }
  465. else
  466. {
  467. // Co-ordinate of containing block to pixel precision.
  468. x0 = (-xd.MbToLeftEdge >> (3 + pd.SubsamplingX)) + x;
  469. y0 = (-xd.MbToTopEdge >> (3 + pd.SubsamplingY)) + y;
  470. // Co-ordinate of the block to 1/16th pixel precision.
  471. x0_16 = x0 << Filter.SubpelBits;
  472. y0_16 = y0 << Filter.SubpelBits;
  473. scaledMv.Row = mv.Row * (1 << (1 - pd.SubsamplingY));
  474. scaledMv.Col = mv.Col * (1 << (1 - pd.SubsamplingX));
  475. xs = ys = 16;
  476. }
  477. subpelX = scaledMv.Col & Filter.SubpelMask;
  478. subpelY = scaledMv.Row & Filter.SubpelMask;
  479. // Calculate the top left corner of the best matching block in the
  480. // reference frame.
  481. x0 += scaledMv.Col >> Filter.SubpelBits;
  482. y0 += scaledMv.Row >> Filter.SubpelBits;
  483. x0_16 += scaledMv.Col;
  484. y0_16 += scaledMv.Row;
  485. // Get reference block pointer.
  486. bufPtr = refFrame + y0 * preBuf.Stride + x0;
  487. bufStride = preBuf.Stride;
  488. // Do border extension if there is motion or the
  489. // width/height is not a multiple of 8 pixels.
  490. if (isScaled || scaledMv.Col != 0 || scaledMv.Row != 0 || (frameWidth & 0x7) != 0 || (frameHeight & 0x7) != 0)
  491. {
  492. int y1 = ((y0_16 + (h - 1) * ys) >> Filter.SubpelBits) + 1;
  493. // Get reference block bottom right horizontal coordinate.
  494. int x1 = ((x0_16 + (w - 1) * xs) >> Filter.SubpelBits) + 1;
  495. int xPad = 0, yPad = 0;
  496. if (subpelX != 0 || (sf.XStepQ4 != Filter.SubpelShifts))
  497. {
  498. x0 -= Constants.Vp9InterpExtend - 1;
  499. x1 += Constants.Vp9InterpExtend;
  500. xPad = 1;
  501. }
  502. if (subpelY != 0 || (sf.YStepQ4 != Filter.SubpelShifts))
  503. {
  504. y0 -= Constants.Vp9InterpExtend - 1;
  505. y1 += Constants.Vp9InterpExtend;
  506. yPad = 1;
  507. }
  508. // Skip border extension if block is inside the frame.
  509. if (x0 < 0 || x0 > frameWidth - 1 || x1 < 0 || x1 > frameWidth - 1 ||
  510. y0 < 0 || y0 > frameHeight - 1 || y1 < 0 || y1 > frameHeight - 1)
  511. {
  512. // Extend the border.
  513. byte* bufPtr1 = refFrame + y0 * bufStride + x0;
  514. int bW = x1 - x0 + 1;
  515. int bH = y1 - y0 + 1;
  516. int borderOffset = yPad * 3 * bW + xPad * 3;
  517. ExtendAndPredict(
  518. bufPtr1,
  519. bufStride,
  520. x0,
  521. y0,
  522. bW,
  523. bH,
  524. frameWidth,
  525. frameHeight,
  526. borderOffset,
  527. dst,
  528. dstBuf.Stride,
  529. subpelX,
  530. subpelY,
  531. kernel,
  532. ref sf,
  533. ref xd,
  534. w,
  535. h,
  536. refr,
  537. xs,
  538. ys);
  539. return;
  540. }
  541. }
  542. if (xd.CurBuf.HighBd)
  543. {
  544. ReconInter.HighbdInterPredictor(
  545. (ushort*)bufPtr,
  546. bufStride,
  547. (ushort*)dst,
  548. dstBuf.Stride,
  549. subpelX,
  550. subpelY,
  551. ref sf,
  552. w,
  553. h,
  554. refr,
  555. kernel,
  556. xs,
  557. ys,
  558. xd.Bd);
  559. }
  560. else
  561. {
  562. ReconInter.InterPredictor(
  563. bufPtr,
  564. bufStride,
  565. dst,
  566. dstBuf.Stride,
  567. subpelX,
  568. subpelY,
  569. ref sf,
  570. w,
  571. h,
  572. refr,
  573. kernel,
  574. xs,
  575. ys);
  576. }
  577. }
  578. private static void DecBuildInterPredictorsSb(ref Vp9Common cm, ref MacroBlockD xd, int miRow, int miCol)
  579. {
  580. int plane;
  581. int miX = miCol * Constants.MiSize;
  582. int miY = miRow * Constants.MiSize;
  583. ref ModeInfo mi = ref xd.Mi[0].Value;
  584. Array8<short>[] kernel = Luts.Vp9FilterKernels[mi.InterpFilter];
  585. BlockSize sbType = mi.SbType;
  586. int isCompound = mi.HasSecondRef() ? 1 : 0;
  587. int refr;
  588. bool isScaled;
  589. for (refr = 0; refr < 1 + isCompound; ++refr)
  590. {
  591. int frame = mi.RefFrame[refr];
  592. ref RefBuffer refBuf = ref cm.FrameRefs[frame - Constants.LastFrame];
  593. ref ScaleFactors sf = ref refBuf.Sf;
  594. ref Surface refFrameBuf = ref refBuf.Buf;
  595. if (!sf.IsValidScale())
  596. {
  597. xd.ErrorInfo.Value.InternalError(CodecErr.CodecUnsupBitstream, "Reference frame has invalid dimensions");
  598. }
  599. isScaled = sf.IsScaled();
  600. ReconInter.SetupPrePlanes(ref xd, refr, ref refFrameBuf, miRow, miCol, isScaled ? new Ptr<ScaleFactors>(ref sf) : Ptr<ScaleFactors>.Null);
  601. xd.BlockRefs[refr] = new Ptr<RefBuffer>(ref refBuf);
  602. if (sbType < BlockSize.Block8x8)
  603. {
  604. for (plane = 0; plane < Constants.MaxMbPlane; ++plane)
  605. {
  606. ref MacroBlockDPlane pd = ref xd.Plane[plane];
  607. ref Buf2D dstBuf = ref pd.Dst;
  608. int num4x4W = pd.N4W;
  609. int num4x4H = pd.N4H;
  610. int n4Wx4 = 4 * num4x4W;
  611. int n4Hx4 = 4 * num4x4H;
  612. ref Buf2D preBuf = ref pd.Pre[refr];
  613. int i = 0, x, y;
  614. for (y = 0; y < num4x4H; ++y)
  615. {
  616. for (x = 0; x < num4x4W; ++x)
  617. {
  618. Mv mv = ReconInter.AverageSplitMvs(ref pd, ref mi, refr, i++);
  619. DecBuildInterPredictors(
  620. ref xd,
  621. plane,
  622. n4Wx4,
  623. n4Hx4,
  624. 4 * x,
  625. 4 * y,
  626. 4,
  627. 4,
  628. miX,
  629. miY,
  630. kernel,
  631. ref sf,
  632. ref preBuf,
  633. ref dstBuf,
  634. ref mv,
  635. ref refFrameBuf,
  636. isScaled,
  637. refr);
  638. }
  639. }
  640. }
  641. }
  642. else
  643. {
  644. Mv mv = mi.Mv[refr];
  645. for (plane = 0; plane < Constants.MaxMbPlane; ++plane)
  646. {
  647. ref MacroBlockDPlane pd = ref xd.Plane[plane];
  648. ref Buf2D dstBuf = ref pd.Dst;
  649. int num4x4W = pd.N4W;
  650. int num4x4H = pd.N4H;
  651. int n4Wx4 = 4 * num4x4W;
  652. int n4Hx4 = 4 * num4x4H;
  653. ref Buf2D preBuf = ref pd.Pre[refr];
  654. DecBuildInterPredictors(
  655. ref xd,
  656. plane,
  657. n4Wx4,
  658. n4Hx4,
  659. 0,
  660. 0,
  661. n4Wx4,
  662. n4Hx4,
  663. miX,
  664. miY,
  665. kernel,
  666. ref sf,
  667. ref preBuf,
  668. ref dstBuf,
  669. ref mv,
  670. ref refFrameBuf,
  671. isScaled,
  672. refr);
  673. }
  674. }
  675. }
  676. }
  677. private static unsafe void DecResetSkipContext(ref MacroBlockD xd)
  678. {
  679. int i;
  680. for (i = 0; i < Constants.MaxMbPlane; i++)
  681. {
  682. ref MacroBlockDPlane pd = ref xd.Plane[i];
  683. MemoryUtil.Fill(pd.AboveContext.ToPointer(), (sbyte)0, pd.N4W);
  684. MemoryUtil.Fill(pd.LeftContext.ToPointer(), (sbyte)0, pd.N4H);
  685. }
  686. }
  687. private static void SetPlaneN4(ref MacroBlockD xd, int bw, int bh, int bwl, int bhl)
  688. {
  689. int i;
  690. for (i = 0; i < Constants.MaxMbPlane; i++)
  691. {
  692. xd.Plane[i].N4W = (ushort)((bw << 1) >> xd.Plane[i].SubsamplingX);
  693. xd.Plane[i].N4H = (ushort)((bh << 1) >> xd.Plane[i].SubsamplingY);
  694. xd.Plane[i].N4Wl = (byte)(bwl - xd.Plane[i].SubsamplingX);
  695. xd.Plane[i].N4Hl = (byte)(bhl - xd.Plane[i].SubsamplingY);
  696. }
  697. }
  698. private static ref ModeInfo SetOffsets(
  699. ref Vp9Common cm,
  700. ref MacroBlockD xd,
  701. BlockSize bsize,
  702. int miRow,
  703. int miCol,
  704. int bw,
  705. int bh,
  706. int xMis,
  707. int yMis,
  708. int bwl,
  709. int bhl)
  710. {
  711. int offset = miRow * cm.MiStride + miCol;
  712. int x, y;
  713. ref TileInfo tile = ref xd.Tile;
  714. xd.Mi = cm.MiGridVisible.Slice(offset);
  715. xd.Mi[0] = new Ptr<ModeInfo>(ref cm.Mi[offset]);
  716. xd.Mi[0].Value.SbType = bsize;
  717. for (y = 0; y < yMis; ++y)
  718. {
  719. for (x = y == 0 ? 1 : 0; x < xMis; ++x)
  720. {
  721. xd.Mi[y * cm.MiStride + x] = xd.Mi[0];
  722. }
  723. }
  724. SetPlaneN4(ref xd, bw, bh, bwl, bhl);
  725. xd.SetSkipContext(miRow, miCol);
  726. // Distance of Mb to the various image edges. These are specified to 8th pel
  727. // as they are always compared to values that are in 1/8th pel units
  728. xd.SetMiRowCol(ref tile, miRow, bh, miCol, bw, cm.MiRows, cm.MiCols);
  729. ReconInter.SetupDstPlanes(ref xd.Plane, ref xd.CurBuf, miRow, miCol);
  730. return ref xd.Mi[0].Value;
  731. }
  732. private static void DecodeBlock(
  733. ref TileWorkerData twd,
  734. ref Vp9Common cm,
  735. int miRow,
  736. int miCol,
  737. BlockSize bsize,
  738. int bwl,
  739. int bhl)
  740. {
  741. bool less8x8 = bsize < BlockSize.Block8x8;
  742. int bw = 1 << (bwl - 1);
  743. int bh = 1 << (bhl - 1);
  744. int xMis = Math.Min(bw, cm.MiCols - miCol);
  745. int yMis = Math.Min(bh, cm.MiRows - miRow);
  746. ref Reader r = ref twd.BitReader;
  747. ref MacroBlockD xd = ref twd.Xd;
  748. ref ModeInfo mi = ref SetOffsets(ref cm, ref xd, bsize, miRow, miCol, bw, bh, xMis, yMis, bwl, bhl);
  749. if (bsize >= BlockSize.Block8x8 && (cm.SubsamplingX != 0 || cm.SubsamplingY != 0))
  750. {
  751. BlockSize uvSubsize = Luts.SsSizeLookup[(int)bsize][cm.SubsamplingX][cm.SubsamplingY];
  752. if (uvSubsize == BlockSize.BlockInvalid)
  753. {
  754. xd.ErrorInfo.Value.InternalError(CodecErr.CodecCorruptFrame, "Invalid block size.");
  755. }
  756. }
  757. DecodeMv.ReadModeInfo(ref twd, ref cm, miRow, miCol, xMis, yMis);
  758. if (mi.Skip != 0)
  759. {
  760. DecResetSkipContext(ref xd);
  761. }
  762. if (!mi.IsInterBlock())
  763. {
  764. int plane;
  765. for (plane = 0; plane < Constants.MaxMbPlane; ++plane)
  766. {
  767. ref MacroBlockDPlane pd = ref xd.Plane[plane];
  768. TxSize txSize = plane != 0 ? mi.GetUvTxSize(ref pd) : mi.TxSize;
  769. int num4x4W = pd.N4W;
  770. int num4x4H = pd.N4H;
  771. int step = 1 << (int)txSize;
  772. int row, col;
  773. int maxBlocksWide = num4x4W + (xd.MbToRightEdge >= 0 ? 0 : xd.MbToRightEdge >> (5 + pd.SubsamplingX));
  774. int maxBlocksHigh = num4x4H + (xd.MbToBottomEdge >= 0 ? 0 : xd.MbToBottomEdge >> (5 + pd.SubsamplingY));
  775. xd.MaxBlocksWide = (uint)(xd.MbToRightEdge >= 0 ? 0 : maxBlocksWide);
  776. xd.MaxBlocksHigh = (uint)(xd.MbToBottomEdge >= 0 ? 0 : maxBlocksHigh);
  777. for (row = 0; row < maxBlocksHigh; row += step)
  778. {
  779. for (col = 0; col < maxBlocksWide; col += step)
  780. {
  781. PredictAndReconstructIntraBlock(ref twd, ref mi, plane, row, col, txSize);
  782. }
  783. }
  784. }
  785. }
  786. else
  787. {
  788. // Prediction
  789. DecBuildInterPredictorsSb(ref cm, ref xd, miRow, miCol);
  790. // Reconstruction
  791. if (mi.Skip == 0)
  792. {
  793. int eobtotal = 0;
  794. int plane;
  795. for (plane = 0; plane < Constants.MaxMbPlane; ++plane)
  796. {
  797. ref MacroBlockDPlane pd = ref xd.Plane[plane];
  798. TxSize txSize = plane != 0 ? mi.GetUvTxSize(ref pd) : mi.TxSize;
  799. int num4x4W = pd.N4W;
  800. int num4x4H = pd.N4H;
  801. int step = 1 << (int)txSize;
  802. int row, col;
  803. int maxBlocksWide = num4x4W + (xd.MbToRightEdge >= 0 ? 0 : xd.MbToRightEdge >> (5 + pd.SubsamplingX));
  804. int maxBlocksHigh = num4x4H + (xd.MbToBottomEdge >= 0 ? 0 : xd.MbToBottomEdge >> (5 + pd.SubsamplingY));
  805. xd.MaxBlocksWide = (uint)(xd.MbToRightEdge >= 0 ? 0 : maxBlocksWide);
  806. xd.MaxBlocksHigh = (uint)(xd.MbToBottomEdge >= 0 ? 0 : maxBlocksHigh);
  807. for (row = 0; row < maxBlocksHigh; row += step)
  808. {
  809. for (col = 0; col < maxBlocksWide; col += step)
  810. {
  811. eobtotal += ReconstructInterBlock(ref twd, ref mi, plane, row, col, txSize);
  812. }
  813. }
  814. }
  815. if (!less8x8 && eobtotal == 0)
  816. {
  817. mi.Skip = 1; // Skip loopfilter
  818. }
  819. }
  820. }
  821. xd.Corrupted |= r.HasError();
  822. if (cm.Lf.FilterLevel != 0)
  823. {
  824. LoopFilter.BuildMask(ref cm, ref mi, miRow, miCol, bw, bh);
  825. }
  826. }
  827. private static int DecPartitionPlaneContext(ref TileWorkerData twd, int miRow, int miCol, int bsl)
  828. {
  829. ref sbyte aboveCtx = ref twd.Xd.AboveSegContext[miCol];
  830. ref sbyte leftCtx = ref twd.Xd.LeftSegContext[miRow & Constants.MiMask];
  831. int above = (aboveCtx >> bsl) & 1, left = (leftCtx >> bsl) & 1;
  832. return (left * 2 + above) + bsl * Constants.PartitionPloffset;
  833. }
  834. private static void DecUpdatePartitionContext(
  835. ref TileWorkerData twd,
  836. int miRow,
  837. int miCol,
  838. BlockSize subsize,
  839. int bw)
  840. {
  841. Span<sbyte> aboveCtx = twd.Xd.AboveSegContext.Slice(miCol).ToSpan();
  842. Span<sbyte> leftCtx = MemoryMarshal.CreateSpan(ref twd.Xd.LeftSegContext[miRow & Constants.MiMask], 8 - (miRow & Constants.MiMask));
  843. // Update the partition context at the end notes. Set partition bits
  844. // of block sizes larger than the current one to be one, and partition
  845. // bits of smaller block sizes to be zero.
  846. aboveCtx.Slice(0, bw).Fill(Luts.PartitionContextLookup[(int)subsize].Above);
  847. leftCtx.Slice(0, bw).Fill(Luts.PartitionContextLookup[(int)subsize].Left);
  848. }
  849. private static PartitionType ReadPartition(
  850. ref TileWorkerData twd,
  851. int miRow,
  852. int miCol,
  853. int hasRows,
  854. int hasCols,
  855. int bsl)
  856. {
  857. int ctx = DecPartitionPlaneContext(ref twd, miRow, miCol, bsl);
  858. ReadOnlySpan<byte> probs = MemoryMarshal.CreateReadOnlySpan(ref twd.Xd.PartitionProbs[ctx][0], 3);
  859. PartitionType p;
  860. ref Reader r = ref twd.BitReader;
  861. if (hasRows != 0 && hasCols != 0)
  862. {
  863. p = (PartitionType)r.ReadTree(Luts.Vp9PartitionTree, probs);
  864. }
  865. else if (hasRows == 0 && hasCols != 0)
  866. {
  867. p = r.Read(probs[1]) != 0 ? PartitionType.PartitionSplit : PartitionType.PartitionHorz;
  868. }
  869. else if (hasRows != 0 && hasCols == 0)
  870. {
  871. p = r.Read(probs[2]) != 0 ? PartitionType.PartitionSplit : PartitionType.PartitionVert;
  872. }
  873. else
  874. {
  875. p = PartitionType.PartitionSplit;
  876. }
  877. if (!twd.Xd.Counts.IsNull)
  878. {
  879. ++twd.Xd.Counts.Value.Partition[ctx][(int)p];
  880. }
  881. return p;
  882. }
  883. private static void DecodePartition(
  884. ref TileWorkerData twd,
  885. ref Vp9Common cm,
  886. int miRow,
  887. int miCol,
  888. BlockSize bsize,
  889. int n4x4L2)
  890. {
  891. int n8x8L2 = n4x4L2 - 1;
  892. int num8x8Wh = 1 << n8x8L2;
  893. int hbs = num8x8Wh >> 1;
  894. PartitionType partition;
  895. BlockSize subsize;
  896. bool hasRows = (miRow + hbs) < cm.MiRows;
  897. bool hasCols = (miCol + hbs) < cm.MiCols;
  898. ref MacroBlockD xd = ref twd.Xd;
  899. if (miRow >= cm.MiRows || miCol >= cm.MiCols)
  900. {
  901. return;
  902. }
  903. partition = ReadPartition(ref twd, miRow, miCol, hasRows ? 1 : 0, hasCols ? 1 : 0, n8x8L2);
  904. subsize = Luts.SubsizeLookup[(int)partition][(int)bsize];
  905. if (hbs == 0)
  906. {
  907. // Calculate bmode block dimensions (log 2)
  908. xd.BmodeBlocksWl = (byte)(1 >> ((partition & PartitionType.PartitionVert) != 0 ? 1 : 0));
  909. xd.BmodeBlocksHl = (byte)(1 >> ((partition & PartitionType.PartitionHorz) != 0 ? 1 : 0));
  910. DecodeBlock(ref twd, ref cm, miRow, miCol, subsize, 1, 1);
  911. }
  912. else
  913. {
  914. switch (partition)
  915. {
  916. case PartitionType.PartitionNone:
  917. DecodeBlock(ref twd, ref cm, miRow, miCol, subsize, n4x4L2, n4x4L2);
  918. break;
  919. case PartitionType.PartitionHorz:
  920. DecodeBlock(ref twd, ref cm, miRow, miCol, subsize, n4x4L2, n8x8L2);
  921. if (hasRows)
  922. {
  923. DecodeBlock(ref twd, ref cm, miRow + hbs, miCol, subsize, n4x4L2, n8x8L2);
  924. }
  925. break;
  926. case PartitionType.PartitionVert:
  927. DecodeBlock(ref twd, ref cm, miRow, miCol, subsize, n8x8L2, n4x4L2);
  928. if (hasCols)
  929. {
  930. DecodeBlock(ref twd, ref cm, miRow, miCol + hbs, subsize, n8x8L2, n4x4L2);
  931. }
  932. break;
  933. case PartitionType.PartitionSplit:
  934. DecodePartition(ref twd, ref cm, miRow, miCol, subsize, n8x8L2);
  935. DecodePartition(ref twd, ref cm, miRow, miCol + hbs, subsize, n8x8L2);
  936. DecodePartition(ref twd, ref cm, miRow + hbs, miCol, subsize, n8x8L2);
  937. DecodePartition(ref twd, ref cm, miRow + hbs, miCol + hbs, subsize, n8x8L2);
  938. break;
  939. default: Debug.Assert(false, "Invalid partition type"); break;
  940. }
  941. }
  942. // Update partition context
  943. if (bsize >= BlockSize.Block8x8 && (bsize == BlockSize.Block8x8 || partition != PartitionType.PartitionSplit))
  944. {
  945. DecUpdatePartitionContext(ref twd, miRow, miCol, subsize, num8x8Wh);
  946. }
  947. }
  948. private static void SetupTokenDecoder(
  949. ArrayPtr<byte> data,
  950. int readSize,
  951. ref InternalErrorInfo errorInfo,
  952. ref Reader r)
  953. {
  954. // Validate the calculated partition length. If the buffer described by the
  955. // partition can't be fully read then throw an error.
  956. if (!ReadIsValid(data, readSize))
  957. {
  958. errorInfo.InternalError(CodecErr.CodecCorruptFrame, "Truncated packet or corrupt tile length");
  959. }
  960. if (r.Init(data, readSize))
  961. {
  962. errorInfo.InternalError(CodecErr.CodecMemError, "Failed to allocate bool decoder 1");
  963. }
  964. }
  965. // Reads the next tile returning its size and adjusting '*data' accordingly
  966. // based on 'isLast'.
  967. private static void GetTileBuffer(
  968. bool isLast,
  969. ref InternalErrorInfo errorInfo,
  970. ref ArrayPtr<byte> data,
  971. ref TileBuffer buf)
  972. {
  973. int size;
  974. if (!isLast)
  975. {
  976. if (!ReadIsValid(data, 4))
  977. {
  978. errorInfo.InternalError(CodecErr.CodecCorruptFrame, "Truncated packet or corrupt tile length");
  979. }
  980. size = BinaryPrimitives.ReadInt32BigEndian(data.ToSpan());
  981. data = data.Slice(4);
  982. if (size > data.Length)
  983. {
  984. errorInfo.InternalError(CodecErr.CodecCorruptFrame, "Truncated packet or corrupt tile size");
  985. }
  986. }
  987. else
  988. {
  989. size = data.Length;
  990. }
  991. buf.Data = data;
  992. buf.Size = size;
  993. data = data.Slice(size);
  994. }
  995. private static void GetTileBuffers(
  996. ref Vp9Common cm,
  997. ArrayPtr<byte> data,
  998. int tileCols,
  999. int tileRows,
  1000. ref Array4<Array64<TileBuffer>> tileBuffers)
  1001. {
  1002. int r, c;
  1003. for (r = 0; r < tileRows; ++r)
  1004. {
  1005. for (c = 0; c < tileCols; ++c)
  1006. {
  1007. bool isLast = (r == tileRows - 1) && (c == tileCols - 1);
  1008. ref TileBuffer buf = ref tileBuffers[r][c];
  1009. GetTileBuffer(isLast, ref cm.Error, ref data, ref buf);
  1010. }
  1011. }
  1012. }
  1013. public static unsafe ArrayPtr<byte> DecodeTiles(ref Vp9Common cm, ArrayPtr<byte> data)
  1014. {
  1015. int alignedCols = TileInfo.MiColsAlignedToSb(cm.MiCols);
  1016. int tileCols = 1 << cm.Log2TileCols;
  1017. int tileRows = 1 << cm.Log2TileRows;
  1018. Array4<Array64<TileBuffer>> tileBuffers = new Array4<Array64<TileBuffer>>();
  1019. int tileRow, tileCol;
  1020. int miRow, miCol;
  1021. Debug.Assert(tileRows <= 4);
  1022. Debug.Assert(tileCols <= (1 << 6));
  1023. // Note: this memset assumes above_context[0], [1] and [2]
  1024. // are allocated as part of the same buffer.
  1025. MemoryUtil.Fill(cm.AboveContext.ToPointer(), (sbyte)0, Constants.MaxMbPlane * 2 * alignedCols);
  1026. MemoryUtil.Fill(cm.AboveSegContext.ToPointer(), (sbyte)0, alignedCols);
  1027. LoopFilter.ResetLfm(ref cm);
  1028. GetTileBuffers(ref cm, data, tileCols, tileRows, ref tileBuffers);
  1029. // Load all tile information into tile_data.
  1030. for (tileRow = 0; tileRow < tileRows; ++tileRow)
  1031. {
  1032. for (tileCol = 0; tileCol < tileCols; ++tileCol)
  1033. {
  1034. ref TileBuffer buf = ref tileBuffers[tileRow][tileCol];
  1035. ref TileWorkerData tileData = ref cm.TileWorkerData[tileCols * tileRow + tileCol];
  1036. tileData.Xd = cm.Mb;
  1037. tileData.Xd.Corrupted = false;
  1038. tileData.Xd.Counts = cm.Counts;
  1039. tileData.Dqcoeff = new Array32<Array32<int>>();
  1040. tileData.Xd.Tile.Init(ref cm, tileRow, tileCol);
  1041. SetupTokenDecoder(buf.Data, buf.Size, ref cm.Error, ref tileData.BitReader);
  1042. cm.InitMacroBlockD(ref tileData.Xd, new ArrayPtr<int>(ref tileData.Dqcoeff[0][0], 32 * 32));
  1043. }
  1044. }
  1045. for (tileRow = 0; tileRow < tileRows; ++tileRow)
  1046. {
  1047. TileInfo tile = new TileInfo();
  1048. tile.SetRow(ref cm, tileRow);
  1049. for (miRow = tile.MiRowStart; miRow < tile.MiRowEnd; miRow += Constants.MiBlockSize)
  1050. {
  1051. for (tileCol = 0; tileCol < tileCols; ++tileCol)
  1052. {
  1053. int col = tileCol;
  1054. ref TileWorkerData tileData = ref cm.TileWorkerData[tileCols * tileRow + col];
  1055. tile.SetCol(ref cm, col);
  1056. tileData.Xd.LeftContext = new Array3<Array16<sbyte>>();
  1057. tileData.Xd.LeftSegContext = new Array8<sbyte>();
  1058. for (miCol = tile.MiColStart; miCol < tile.MiColEnd; miCol += Constants.MiBlockSize)
  1059. {
  1060. DecodePartition(ref tileData, ref cm, miRow, miCol, BlockSize.Block64x64, 4);
  1061. }
  1062. cm.Mb.Corrupted |= tileData.Xd.Corrupted;
  1063. if (cm.Mb.Corrupted)
  1064. {
  1065. cm.Error.InternalError(CodecErr.CodecCorruptFrame, "Failed to decode tile data");
  1066. };
  1067. }
  1068. }
  1069. }
  1070. // Get last tile data.
  1071. return cm.TileWorkerData[tileCols * tileRows - 1].BitReader.FindEnd();
  1072. }
  1073. }
  1074. }