DecodeFrame.cs 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190
  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. [StructLayout(LayoutKind.Sequential, Size = 80 * 2 * 80 * 2)]
  342. struct McBufHigh
  343. {
  344. }
  345. private static unsafe void ExtendAndPredict(
  346. byte* bufPtr1,
  347. int preBufStride,
  348. int x0,
  349. int y0,
  350. int bW,
  351. int bH,
  352. int frameWidth,
  353. int frameHeight,
  354. int borderOffset,
  355. byte* dst,
  356. int dstBufStride,
  357. int subpelX,
  358. int subpelY,
  359. Array8<short>[] kernel,
  360. ref ScaleFactors sf,
  361. ref MacroBlockD xd,
  362. int w,
  363. int h,
  364. int refr,
  365. int xs,
  366. int ys)
  367. {
  368. McBufHigh mcBufHighStruct;
  369. ushort* mcBufHigh = (ushort*)Unsafe.AsPointer(ref mcBufHighStruct); // Avoid zero initialization.
  370. if (xd.CurBuf.HighBd)
  371. {
  372. HighBuildMcBorder(bufPtr1, preBufStride, mcBufHigh, bW, x0, y0, bW, bH, frameWidth, frameHeight);
  373. ReconInter.HighbdInterPredictor(
  374. mcBufHigh + borderOffset,
  375. bW,
  376. (ushort*)dst,
  377. dstBufStride,
  378. subpelX,
  379. subpelY,
  380. ref sf,
  381. w,
  382. h,
  383. refr,
  384. kernel,
  385. xs,
  386. ys,
  387. xd.Bd);
  388. }
  389. else
  390. {
  391. BuildMcBorder(bufPtr1, preBufStride, (byte*)mcBufHigh, bW, x0, y0, bW, bH, frameWidth, frameHeight);
  392. ReconInter.InterPredictor(
  393. (byte*)mcBufHigh + borderOffset,
  394. bW,
  395. dst,
  396. dstBufStride,
  397. subpelX,
  398. subpelY,
  399. ref sf,
  400. w,
  401. h,
  402. refr,
  403. kernel,
  404. xs,
  405. ys);
  406. }
  407. }
  408. private static unsafe void DecBuildInterPredictors(
  409. ref MacroBlockD xd,
  410. int plane,
  411. int bw,
  412. int bh,
  413. int x,
  414. int y,
  415. int w,
  416. int h,
  417. int miX,
  418. int miY,
  419. Array8<short>[] kernel,
  420. ref ScaleFactors sf,
  421. ref Buf2D preBuf,
  422. ref Buf2D dstBuf,
  423. ref Mv mv,
  424. ref Surface refFrameBuf,
  425. bool isScaled,
  426. int refr)
  427. {
  428. ref MacroBlockDPlane pd = ref xd.Plane[plane];
  429. byte* dst = dstBuf.Buf.ToPointer() + dstBuf.Stride * y + x;
  430. Mv32 scaledMv;
  431. int xs, ys, x0, y0, x0_16, y0_16, frameWidth, frameHeight, bufStride, subpelX, subpelY;
  432. byte* refFrame;
  433. byte* bufPtr;
  434. // Get reference frame pointer, width and height.
  435. if (plane == 0)
  436. {
  437. frameWidth = refFrameBuf.Width;
  438. frameHeight = refFrameBuf.Height;
  439. refFrame = refFrameBuf.YBuffer.ToPointer();
  440. }
  441. else
  442. {
  443. frameWidth = refFrameBuf.UvWidth;
  444. frameHeight = refFrameBuf.UvHeight;
  445. refFrame = plane == 1 ? refFrameBuf.UBuffer.ToPointer() : refFrameBuf.VBuffer.ToPointer();
  446. }
  447. if (isScaled)
  448. {
  449. Mv mvQ4 = ReconInter.ClampMvToUmvBorderSb(ref xd, ref mv, bw, bh, pd.SubsamplingX, pd.SubsamplingY);
  450. // Co-ordinate of containing block to pixel precision.
  451. int xStart = (-xd.MbToLeftEdge >> (3 + pd.SubsamplingX));
  452. int yStart = (-xd.MbToTopEdge >> (3 + pd.SubsamplingY));
  453. // Co-ordinate of the block to 1/16th pixel precision.
  454. x0_16 = (xStart + x) << Filter.SubpelBits;
  455. y0_16 = (yStart + y) << Filter.SubpelBits;
  456. // Co-ordinate of current block in reference frame
  457. // to 1/16th pixel precision.
  458. x0_16 = sf.ScaleValueX(x0_16);
  459. y0_16 = sf.ScaleValueY(y0_16);
  460. // Map the top left corner of the block into the reference frame.
  461. x0 = sf.ScaleValueX(xStart + x);
  462. y0 = sf.ScaleValueY(yStart + y);
  463. // Scale the MV and incorporate the sub-pixel offset of the block
  464. // in the reference frame.
  465. scaledMv = sf.ScaleMv(ref mvQ4, miX + x, miY + y);
  466. xs = sf.XStepQ4;
  467. ys = sf.YStepQ4;
  468. }
  469. else
  470. {
  471. // Co-ordinate of containing block to pixel precision.
  472. x0 = (-xd.MbToLeftEdge >> (3 + pd.SubsamplingX)) + x;
  473. y0 = (-xd.MbToTopEdge >> (3 + pd.SubsamplingY)) + y;
  474. // Co-ordinate of the block to 1/16th pixel precision.
  475. x0_16 = x0 << Filter.SubpelBits;
  476. y0_16 = y0 << Filter.SubpelBits;
  477. scaledMv.Row = mv.Row * (1 << (1 - pd.SubsamplingY));
  478. scaledMv.Col = mv.Col * (1 << (1 - pd.SubsamplingX));
  479. xs = ys = 16;
  480. }
  481. subpelX = scaledMv.Col & Filter.SubpelMask;
  482. subpelY = scaledMv.Row & Filter.SubpelMask;
  483. // Calculate the top left corner of the best matching block in the
  484. // reference frame.
  485. x0 += scaledMv.Col >> Filter.SubpelBits;
  486. y0 += scaledMv.Row >> Filter.SubpelBits;
  487. x0_16 += scaledMv.Col;
  488. y0_16 += scaledMv.Row;
  489. // Get reference block pointer.
  490. bufPtr = refFrame + y0 * preBuf.Stride + x0;
  491. bufStride = preBuf.Stride;
  492. // Do border extension if there is motion or the
  493. // width/height is not a multiple of 8 pixels.
  494. if (isScaled || scaledMv.Col != 0 || scaledMv.Row != 0 || (frameWidth & 0x7) != 0 || (frameHeight & 0x7) != 0)
  495. {
  496. int y1 = ((y0_16 + (h - 1) * ys) >> Filter.SubpelBits) + 1;
  497. // Get reference block bottom right horizontal coordinate.
  498. int x1 = ((x0_16 + (w - 1) * xs) >> Filter.SubpelBits) + 1;
  499. int xPad = 0, yPad = 0;
  500. if (subpelX != 0 || (sf.XStepQ4 != Filter.SubpelShifts))
  501. {
  502. x0 -= Constants.Vp9InterpExtend - 1;
  503. x1 += Constants.Vp9InterpExtend;
  504. xPad = 1;
  505. }
  506. if (subpelY != 0 || (sf.YStepQ4 != Filter.SubpelShifts))
  507. {
  508. y0 -= Constants.Vp9InterpExtend - 1;
  509. y1 += Constants.Vp9InterpExtend;
  510. yPad = 1;
  511. }
  512. // Skip border extension if block is inside the frame.
  513. if (x0 < 0 || x0 > frameWidth - 1 || x1 < 0 || x1 > frameWidth - 1 ||
  514. y0 < 0 || y0 > frameHeight - 1 || y1 < 0 || y1 > frameHeight - 1)
  515. {
  516. // Extend the border.
  517. byte* bufPtr1 = refFrame + y0 * bufStride + x0;
  518. int bW = x1 - x0 + 1;
  519. int bH = y1 - y0 + 1;
  520. int borderOffset = yPad * 3 * bW + xPad * 3;
  521. ExtendAndPredict(
  522. bufPtr1,
  523. bufStride,
  524. x0,
  525. y0,
  526. bW,
  527. bH,
  528. frameWidth,
  529. frameHeight,
  530. borderOffset,
  531. dst,
  532. dstBuf.Stride,
  533. subpelX,
  534. subpelY,
  535. kernel,
  536. ref sf,
  537. ref xd,
  538. w,
  539. h,
  540. refr,
  541. xs,
  542. ys);
  543. return;
  544. }
  545. }
  546. if (xd.CurBuf.HighBd)
  547. {
  548. ReconInter.HighbdInterPredictor(
  549. (ushort*)bufPtr,
  550. bufStride,
  551. (ushort*)dst,
  552. dstBuf.Stride,
  553. subpelX,
  554. subpelY,
  555. ref sf,
  556. w,
  557. h,
  558. refr,
  559. kernel,
  560. xs,
  561. ys,
  562. xd.Bd);
  563. }
  564. else
  565. {
  566. ReconInter.InterPredictor(
  567. bufPtr,
  568. bufStride,
  569. dst,
  570. dstBuf.Stride,
  571. subpelX,
  572. subpelY,
  573. ref sf,
  574. w,
  575. h,
  576. refr,
  577. kernel,
  578. xs,
  579. ys);
  580. }
  581. }
  582. private static void DecBuildInterPredictorsSb(ref Vp9Common cm, ref MacroBlockD xd, int miRow, int miCol)
  583. {
  584. int plane;
  585. int miX = miCol * Constants.MiSize;
  586. int miY = miRow * Constants.MiSize;
  587. ref ModeInfo mi = ref xd.Mi[0].Value;
  588. Array8<short>[] kernel = Luts.Vp9FilterKernels[mi.InterpFilter];
  589. BlockSize sbType = mi.SbType;
  590. int isCompound = mi.HasSecondRef() ? 1 : 0;
  591. int refr;
  592. bool isScaled;
  593. for (refr = 0; refr < 1 + isCompound; ++refr)
  594. {
  595. int frame = mi.RefFrame[refr];
  596. ref RefBuffer refBuf = ref cm.FrameRefs[frame - Constants.LastFrame];
  597. ref ScaleFactors sf = ref refBuf.Sf;
  598. ref Surface refFrameBuf = ref refBuf.Buf;
  599. if (!sf.IsValidScale())
  600. {
  601. xd.ErrorInfo.Value.InternalError(CodecErr.CodecUnsupBitstream, "Reference frame has invalid dimensions");
  602. }
  603. isScaled = sf.IsScaled();
  604. ReconInter.SetupPrePlanes(ref xd, refr, ref refFrameBuf, miRow, miCol, isScaled ? new Ptr<ScaleFactors>(ref sf) : Ptr<ScaleFactors>.Null);
  605. xd.BlockRefs[refr] = new Ptr<RefBuffer>(ref refBuf);
  606. if (sbType < BlockSize.Block8x8)
  607. {
  608. for (plane = 0; plane < Constants.MaxMbPlane; ++plane)
  609. {
  610. ref MacroBlockDPlane pd = ref xd.Plane[plane];
  611. ref Buf2D dstBuf = ref pd.Dst;
  612. int num4x4W = pd.N4W;
  613. int num4x4H = pd.N4H;
  614. int n4Wx4 = 4 * num4x4W;
  615. int n4Hx4 = 4 * num4x4H;
  616. ref Buf2D preBuf = ref pd.Pre[refr];
  617. int i = 0, x, y;
  618. for (y = 0; y < num4x4H; ++y)
  619. {
  620. for (x = 0; x < num4x4W; ++x)
  621. {
  622. Mv mv = ReconInter.AverageSplitMvs(ref pd, ref mi, refr, i++);
  623. DecBuildInterPredictors(
  624. ref xd,
  625. plane,
  626. n4Wx4,
  627. n4Hx4,
  628. 4 * x,
  629. 4 * y,
  630. 4,
  631. 4,
  632. miX,
  633. miY,
  634. kernel,
  635. ref sf,
  636. ref preBuf,
  637. ref dstBuf,
  638. ref mv,
  639. ref refFrameBuf,
  640. isScaled,
  641. refr);
  642. }
  643. }
  644. }
  645. }
  646. else
  647. {
  648. Mv mv = mi.Mv[refr];
  649. for (plane = 0; plane < Constants.MaxMbPlane; ++plane)
  650. {
  651. ref MacroBlockDPlane pd = ref xd.Plane[plane];
  652. ref Buf2D dstBuf = ref pd.Dst;
  653. int num4x4W = pd.N4W;
  654. int num4x4H = pd.N4H;
  655. int n4Wx4 = 4 * num4x4W;
  656. int n4Hx4 = 4 * num4x4H;
  657. ref Buf2D preBuf = ref pd.Pre[refr];
  658. DecBuildInterPredictors(
  659. ref xd,
  660. plane,
  661. n4Wx4,
  662. n4Hx4,
  663. 0,
  664. 0,
  665. n4Wx4,
  666. n4Hx4,
  667. miX,
  668. miY,
  669. kernel,
  670. ref sf,
  671. ref preBuf,
  672. ref dstBuf,
  673. ref mv,
  674. ref refFrameBuf,
  675. isScaled,
  676. refr);
  677. }
  678. }
  679. }
  680. }
  681. private static unsafe void DecResetSkipContext(ref MacroBlockD xd)
  682. {
  683. int i;
  684. for (i = 0; i < Constants.MaxMbPlane; i++)
  685. {
  686. ref MacroBlockDPlane pd = ref xd.Plane[i];
  687. MemoryUtil.Fill(pd.AboveContext.ToPointer(), (sbyte)0, pd.N4W);
  688. MemoryUtil.Fill(pd.LeftContext.ToPointer(), (sbyte)0, pd.N4H);
  689. }
  690. }
  691. private static void SetPlaneN4(ref MacroBlockD xd, int bw, int bh, int bwl, int bhl)
  692. {
  693. int i;
  694. for (i = 0; i < Constants.MaxMbPlane; i++)
  695. {
  696. xd.Plane[i].N4W = (ushort)((bw << 1) >> xd.Plane[i].SubsamplingX);
  697. xd.Plane[i].N4H = (ushort)((bh << 1) >> xd.Plane[i].SubsamplingY);
  698. xd.Plane[i].N4Wl = (byte)(bwl - xd.Plane[i].SubsamplingX);
  699. xd.Plane[i].N4Hl = (byte)(bhl - xd.Plane[i].SubsamplingY);
  700. }
  701. }
  702. private static ref ModeInfo SetOffsets(
  703. ref Vp9Common cm,
  704. ref MacroBlockD xd,
  705. BlockSize bsize,
  706. int miRow,
  707. int miCol,
  708. int bw,
  709. int bh,
  710. int xMis,
  711. int yMis,
  712. int bwl,
  713. int bhl)
  714. {
  715. int offset = miRow * cm.MiStride + miCol;
  716. int x, y;
  717. ref TileInfo tile = ref xd.Tile;
  718. xd.Mi = cm.MiGridVisible.Slice(offset);
  719. xd.Mi[0] = new Ptr<ModeInfo>(ref cm.Mi[offset]);
  720. xd.Mi[0].Value.SbType = bsize;
  721. for (y = 0; y < yMis; ++y)
  722. {
  723. for (x = y == 0 ? 1 : 0; x < xMis; ++x)
  724. {
  725. xd.Mi[y * cm.MiStride + x] = xd.Mi[0];
  726. }
  727. }
  728. SetPlaneN4(ref xd, bw, bh, bwl, bhl);
  729. xd.SetSkipContext(miRow, miCol);
  730. // Distance of Mb to the various image edges. These are specified to 8th pel
  731. // as they are always compared to values that are in 1/8th pel units
  732. xd.SetMiRowCol(ref tile, miRow, bh, miCol, bw, cm.MiRows, cm.MiCols);
  733. ReconInter.SetupDstPlanes(ref xd.Plane, ref xd.CurBuf, miRow, miCol);
  734. return ref xd.Mi[0].Value;
  735. }
  736. private static void DecodeBlock(
  737. ref TileWorkerData twd,
  738. ref Vp9Common cm,
  739. int miRow,
  740. int miCol,
  741. BlockSize bsize,
  742. int bwl,
  743. int bhl)
  744. {
  745. bool less8x8 = bsize < BlockSize.Block8x8;
  746. int bw = 1 << (bwl - 1);
  747. int bh = 1 << (bhl - 1);
  748. int xMis = Math.Min(bw, cm.MiCols - miCol);
  749. int yMis = Math.Min(bh, cm.MiRows - miRow);
  750. ref Reader r = ref twd.BitReader;
  751. ref MacroBlockD xd = ref twd.Xd;
  752. ref ModeInfo mi = ref SetOffsets(ref cm, ref xd, bsize, miRow, miCol, bw, bh, xMis, yMis, bwl, bhl);
  753. if (bsize >= BlockSize.Block8x8 && (cm.SubsamplingX != 0 || cm.SubsamplingY != 0))
  754. {
  755. BlockSize uvSubsize = Luts.SsSizeLookup[(int)bsize][cm.SubsamplingX][cm.SubsamplingY];
  756. if (uvSubsize == BlockSize.BlockInvalid)
  757. {
  758. xd.ErrorInfo.Value.InternalError(CodecErr.CodecCorruptFrame, "Invalid block size.");
  759. }
  760. }
  761. DecodeMv.ReadModeInfo(ref twd, ref cm, miRow, miCol, xMis, yMis);
  762. if (mi.Skip != 0)
  763. {
  764. DecResetSkipContext(ref xd);
  765. }
  766. if (!mi.IsInterBlock())
  767. {
  768. int plane;
  769. for (plane = 0; plane < Constants.MaxMbPlane; ++plane)
  770. {
  771. ref MacroBlockDPlane pd = ref xd.Plane[plane];
  772. TxSize txSize = plane != 0 ? mi.GetUvTxSize(ref pd) : mi.TxSize;
  773. int num4x4W = pd.N4W;
  774. int num4x4H = pd.N4H;
  775. int step = 1 << (int)txSize;
  776. int row, col;
  777. int maxBlocksWide = num4x4W + (xd.MbToRightEdge >= 0 ? 0 : xd.MbToRightEdge >> (5 + pd.SubsamplingX));
  778. int maxBlocksHigh = num4x4H + (xd.MbToBottomEdge >= 0 ? 0 : xd.MbToBottomEdge >> (5 + pd.SubsamplingY));
  779. xd.MaxBlocksWide = (uint)(xd.MbToRightEdge >= 0 ? 0 : maxBlocksWide);
  780. xd.MaxBlocksHigh = (uint)(xd.MbToBottomEdge >= 0 ? 0 : maxBlocksHigh);
  781. for (row = 0; row < maxBlocksHigh; row += step)
  782. {
  783. for (col = 0; col < maxBlocksWide; col += step)
  784. {
  785. PredictAndReconstructIntraBlock(ref twd, ref mi, plane, row, col, txSize);
  786. }
  787. }
  788. }
  789. }
  790. else
  791. {
  792. // Prediction
  793. DecBuildInterPredictorsSb(ref cm, ref xd, miRow, miCol);
  794. // Reconstruction
  795. if (mi.Skip == 0)
  796. {
  797. int eobtotal = 0;
  798. int plane;
  799. for (plane = 0; plane < Constants.MaxMbPlane; ++plane)
  800. {
  801. ref MacroBlockDPlane pd = ref xd.Plane[plane];
  802. TxSize txSize = plane != 0 ? mi.GetUvTxSize(ref pd) : mi.TxSize;
  803. int num4x4W = pd.N4W;
  804. int num4x4H = pd.N4H;
  805. int step = 1 << (int)txSize;
  806. int row, col;
  807. int maxBlocksWide = num4x4W + (xd.MbToRightEdge >= 0 ? 0 : xd.MbToRightEdge >> (5 + pd.SubsamplingX));
  808. int maxBlocksHigh = num4x4H + (xd.MbToBottomEdge >= 0 ? 0 : xd.MbToBottomEdge >> (5 + pd.SubsamplingY));
  809. xd.MaxBlocksWide = (uint)(xd.MbToRightEdge >= 0 ? 0 : maxBlocksWide);
  810. xd.MaxBlocksHigh = (uint)(xd.MbToBottomEdge >= 0 ? 0 : maxBlocksHigh);
  811. for (row = 0; row < maxBlocksHigh; row += step)
  812. {
  813. for (col = 0; col < maxBlocksWide; col += step)
  814. {
  815. eobtotal += ReconstructInterBlock(ref twd, ref mi, plane, row, col, txSize);
  816. }
  817. }
  818. }
  819. if (!less8x8 && eobtotal == 0)
  820. {
  821. mi.Skip = 1; // Skip loopfilter
  822. }
  823. }
  824. }
  825. xd.Corrupted |= r.HasError();
  826. if (cm.Lf.FilterLevel != 0)
  827. {
  828. LoopFilter.BuildMask(ref cm, ref mi, miRow, miCol, bw, bh);
  829. }
  830. }
  831. private static int DecPartitionPlaneContext(ref TileWorkerData twd, int miRow, int miCol, int bsl)
  832. {
  833. ref sbyte aboveCtx = ref twd.Xd.AboveSegContext[miCol];
  834. ref sbyte leftCtx = ref twd.Xd.LeftSegContext[miRow & Constants.MiMask];
  835. int above = (aboveCtx >> bsl) & 1, left = (leftCtx >> bsl) & 1;
  836. return (left * 2 + above) + bsl * Constants.PartitionPloffset;
  837. }
  838. private static void DecUpdatePartitionContext(
  839. ref TileWorkerData twd,
  840. int miRow,
  841. int miCol,
  842. BlockSize subsize,
  843. int bw)
  844. {
  845. Span<sbyte> aboveCtx = twd.Xd.AboveSegContext.Slice(miCol).ToSpan();
  846. Span<sbyte> leftCtx = MemoryMarshal.CreateSpan(ref twd.Xd.LeftSegContext[miRow & Constants.MiMask], 8 - (miRow & Constants.MiMask));
  847. // Update the partition context at the end notes. Set partition bits
  848. // of block sizes larger than the current one to be one, and partition
  849. // bits of smaller block sizes to be zero.
  850. aboveCtx.Slice(0, bw).Fill(Luts.PartitionContextLookup[(int)subsize].Above);
  851. leftCtx.Slice(0, bw).Fill(Luts.PartitionContextLookup[(int)subsize].Left);
  852. }
  853. private static PartitionType ReadPartition(
  854. ref TileWorkerData twd,
  855. int miRow,
  856. int miCol,
  857. int hasRows,
  858. int hasCols,
  859. int bsl)
  860. {
  861. int ctx = DecPartitionPlaneContext(ref twd, miRow, miCol, bsl);
  862. ReadOnlySpan<byte> probs = MemoryMarshal.CreateReadOnlySpan(ref twd.Xd.PartitionProbs[ctx][0], 3);
  863. PartitionType p;
  864. ref Reader r = ref twd.BitReader;
  865. if (hasRows != 0 && hasCols != 0)
  866. {
  867. p = (PartitionType)r.ReadTree(Luts.Vp9PartitionTree, probs);
  868. }
  869. else if (hasRows == 0 && hasCols != 0)
  870. {
  871. p = r.Read(probs[1]) != 0 ? PartitionType.PartitionSplit : PartitionType.PartitionHorz;
  872. }
  873. else if (hasRows != 0 && hasCols == 0)
  874. {
  875. p = r.Read(probs[2]) != 0 ? PartitionType.PartitionSplit : PartitionType.PartitionVert;
  876. }
  877. else
  878. {
  879. p = PartitionType.PartitionSplit;
  880. }
  881. if (!twd.Xd.Counts.IsNull)
  882. {
  883. ++twd.Xd.Counts.Value.Partition[ctx][(int)p];
  884. }
  885. return p;
  886. }
  887. private static void DecodePartition(
  888. ref TileWorkerData twd,
  889. ref Vp9Common cm,
  890. int miRow,
  891. int miCol,
  892. BlockSize bsize,
  893. int n4x4L2)
  894. {
  895. int n8x8L2 = n4x4L2 - 1;
  896. int num8x8Wh = 1 << n8x8L2;
  897. int hbs = num8x8Wh >> 1;
  898. PartitionType partition;
  899. BlockSize subsize;
  900. bool hasRows = (miRow + hbs) < cm.MiRows;
  901. bool hasCols = (miCol + hbs) < cm.MiCols;
  902. ref MacroBlockD xd = ref twd.Xd;
  903. if (miRow >= cm.MiRows || miCol >= cm.MiCols)
  904. {
  905. return;
  906. }
  907. partition = ReadPartition(ref twd, miRow, miCol, hasRows ? 1 : 0, hasCols ? 1 : 0, n8x8L2);
  908. subsize = Luts.SubsizeLookup[(int)partition][(int)bsize];
  909. if (hbs == 0)
  910. {
  911. // Calculate bmode block dimensions (log 2)
  912. xd.BmodeBlocksWl = (byte)(1 >> ((partition & PartitionType.PartitionVert) != 0 ? 1 : 0));
  913. xd.BmodeBlocksHl = (byte)(1 >> ((partition & PartitionType.PartitionHorz) != 0 ? 1 : 0));
  914. DecodeBlock(ref twd, ref cm, miRow, miCol, subsize, 1, 1);
  915. }
  916. else
  917. {
  918. switch (partition)
  919. {
  920. case PartitionType.PartitionNone:
  921. DecodeBlock(ref twd, ref cm, miRow, miCol, subsize, n4x4L2, n4x4L2);
  922. break;
  923. case PartitionType.PartitionHorz:
  924. DecodeBlock(ref twd, ref cm, miRow, miCol, subsize, n4x4L2, n8x8L2);
  925. if (hasRows)
  926. {
  927. DecodeBlock(ref twd, ref cm, miRow + hbs, miCol, subsize, n4x4L2, n8x8L2);
  928. }
  929. break;
  930. case PartitionType.PartitionVert:
  931. DecodeBlock(ref twd, ref cm, miRow, miCol, subsize, n8x8L2, n4x4L2);
  932. if (hasCols)
  933. {
  934. DecodeBlock(ref twd, ref cm, miRow, miCol + hbs, subsize, n8x8L2, n4x4L2);
  935. }
  936. break;
  937. case PartitionType.PartitionSplit:
  938. DecodePartition(ref twd, ref cm, miRow, miCol, subsize, n8x8L2);
  939. DecodePartition(ref twd, ref cm, miRow, miCol + hbs, subsize, n8x8L2);
  940. DecodePartition(ref twd, ref cm, miRow + hbs, miCol, subsize, n8x8L2);
  941. DecodePartition(ref twd, ref cm, miRow + hbs, miCol + hbs, subsize, n8x8L2);
  942. break;
  943. default: Debug.Assert(false, "Invalid partition type"); break;
  944. }
  945. }
  946. // Update partition context
  947. if (bsize >= BlockSize.Block8x8 && (bsize == BlockSize.Block8x8 || partition != PartitionType.PartitionSplit))
  948. {
  949. DecUpdatePartitionContext(ref twd, miRow, miCol, subsize, num8x8Wh);
  950. }
  951. }
  952. private static void SetupTokenDecoder(
  953. ArrayPtr<byte> data,
  954. int readSize,
  955. ref InternalErrorInfo errorInfo,
  956. ref Reader r)
  957. {
  958. // Validate the calculated partition length. If the buffer described by the
  959. // partition can't be fully read then throw an error.
  960. if (!ReadIsValid(data, readSize))
  961. {
  962. errorInfo.InternalError(CodecErr.CodecCorruptFrame, "Truncated packet or corrupt tile length");
  963. }
  964. if (r.Init(data, readSize))
  965. {
  966. errorInfo.InternalError(CodecErr.CodecMemError, "Failed to allocate bool decoder 1");
  967. }
  968. }
  969. // Reads the next tile returning its size and adjusting '*data' accordingly
  970. // based on 'isLast'.
  971. private static void GetTileBuffer(
  972. bool isLast,
  973. ref InternalErrorInfo errorInfo,
  974. ref ArrayPtr<byte> data,
  975. ref TileBuffer buf)
  976. {
  977. int size;
  978. if (!isLast)
  979. {
  980. if (!ReadIsValid(data, 4))
  981. {
  982. errorInfo.InternalError(CodecErr.CodecCorruptFrame, "Truncated packet or corrupt tile length");
  983. }
  984. size = BinaryPrimitives.ReadInt32BigEndian(data.ToSpan());
  985. data = data.Slice(4);
  986. if (size > data.Length)
  987. {
  988. errorInfo.InternalError(CodecErr.CodecCorruptFrame, "Truncated packet or corrupt tile size");
  989. }
  990. }
  991. else
  992. {
  993. size = data.Length;
  994. }
  995. buf.Data = data;
  996. buf.Size = size;
  997. data = data.Slice(size);
  998. }
  999. private static void GetTileBuffers(
  1000. ref Vp9Common cm,
  1001. ArrayPtr<byte> data,
  1002. int tileCols,
  1003. int tileRows,
  1004. ref Array4<Array64<TileBuffer>> tileBuffers)
  1005. {
  1006. int r, c;
  1007. for (r = 0; r < tileRows; ++r)
  1008. {
  1009. for (c = 0; c < tileCols; ++c)
  1010. {
  1011. bool isLast = (r == tileRows - 1) && (c == tileCols - 1);
  1012. ref TileBuffer buf = ref tileBuffers[r][c];
  1013. GetTileBuffer(isLast, ref cm.Error, ref data, ref buf);
  1014. }
  1015. }
  1016. }
  1017. public static unsafe ArrayPtr<byte> DecodeTiles(ref Vp9Common cm, ArrayPtr<byte> data)
  1018. {
  1019. int alignedCols = TileInfo.MiColsAlignedToSb(cm.MiCols);
  1020. int tileCols = 1 << cm.Log2TileCols;
  1021. int tileRows = 1 << cm.Log2TileRows;
  1022. Array4<Array64<TileBuffer>> tileBuffers = new Array4<Array64<TileBuffer>>();
  1023. int tileRow, tileCol;
  1024. int miRow, miCol;
  1025. Debug.Assert(tileRows <= 4);
  1026. Debug.Assert(tileCols <= (1 << 6));
  1027. // Note: this memset assumes above_context[0], [1] and [2]
  1028. // are allocated as part of the same buffer.
  1029. MemoryUtil.Fill(cm.AboveContext.ToPointer(), (sbyte)0, Constants.MaxMbPlane * 2 * alignedCols);
  1030. MemoryUtil.Fill(cm.AboveSegContext.ToPointer(), (sbyte)0, alignedCols);
  1031. LoopFilter.ResetLfm(ref cm);
  1032. GetTileBuffers(ref cm, data, tileCols, tileRows, ref tileBuffers);
  1033. // Load all tile information into tile_data.
  1034. for (tileRow = 0; tileRow < tileRows; ++tileRow)
  1035. {
  1036. for (tileCol = 0; tileCol < tileCols; ++tileCol)
  1037. {
  1038. ref TileBuffer buf = ref tileBuffers[tileRow][tileCol];
  1039. ref TileWorkerData tileData = ref cm.TileWorkerData[tileCols * tileRow + tileCol];
  1040. tileData.Xd = cm.Mb;
  1041. tileData.Xd.Corrupted = false;
  1042. tileData.Xd.Counts = cm.Counts;
  1043. tileData.Dqcoeff = new Array32<Array32<int>>();
  1044. tileData.Xd.Tile.Init(ref cm, tileRow, tileCol);
  1045. SetupTokenDecoder(buf.Data, buf.Size, ref cm.Error, ref tileData.BitReader);
  1046. cm.InitMacroBlockD(ref tileData.Xd, new ArrayPtr<int>(ref tileData.Dqcoeff[0][0], 32 * 32));
  1047. }
  1048. }
  1049. for (tileRow = 0; tileRow < tileRows; ++tileRow)
  1050. {
  1051. TileInfo tile = new TileInfo();
  1052. tile.SetRow(ref cm, tileRow);
  1053. for (miRow = tile.MiRowStart; miRow < tile.MiRowEnd; miRow += Constants.MiBlockSize)
  1054. {
  1055. for (tileCol = 0; tileCol < tileCols; ++tileCol)
  1056. {
  1057. int col = tileCol;
  1058. ref TileWorkerData tileData = ref cm.TileWorkerData[tileCols * tileRow + col];
  1059. tile.SetCol(ref cm, col);
  1060. tileData.Xd.LeftContext = new Array3<Array16<sbyte>>();
  1061. tileData.Xd.LeftSegContext = new Array8<sbyte>();
  1062. for (miCol = tile.MiColStart; miCol < tile.MiColEnd; miCol += Constants.MiBlockSize)
  1063. {
  1064. DecodePartition(ref tileData, ref cm, miRow, miCol, BlockSize.Block64x64, 4);
  1065. }
  1066. cm.Mb.Corrupted |= tileData.Xd.Corrupted;
  1067. if (cm.Mb.Corrupted)
  1068. {
  1069. cm.Error.InternalError(CodecErr.CodecCorruptFrame, "Failed to decode tile data");
  1070. };
  1071. }
  1072. }
  1073. }
  1074. // Get last tile data.
  1075. return cm.TileWorkerData[tileCols * tileRows - 1].BitReader.FindEnd();
  1076. }
  1077. }
  1078. }