DecodeFrame.cs 49 KB

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