Vp9Decoder.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. using Ryujinx.Common.Memory;
  2. using Ryujinx.Graphics.Nvdec.Vp9.Common;
  3. using Ryujinx.Graphics.Video;
  4. using System.Diagnostics;
  5. namespace Ryujinx.Graphics.Nvdec.Vp9.Types
  6. {
  7. internal struct Vp9Decoder
  8. {
  9. public Vp9Common Common;
  10. public int ReadyForNewData;
  11. public int RefreshFrameFlags;
  12. public int NeedResync; // Wait for key/intra-only frame.
  13. public int HoldRefBuf; // Hold the reference buffer.
  14. private static void DecreaseRefCount(int idx, ref Array12<RefCntBuffer> frameBufs, ref BufferPool pool)
  15. {
  16. if (idx >= 0 && frameBufs[idx].RefCount > 0)
  17. {
  18. --frameBufs[idx].RefCount;
  19. // A worker may only get a free framebuffer index when calling GetFreeFb.
  20. // But the private buffer is not set up until finish decoding header.
  21. // So any error happens during decoding header, the frame_bufs will not
  22. // have valid priv buffer.
  23. if (frameBufs[idx].Released == 0 && frameBufs[idx].RefCount == 0 &&
  24. !frameBufs[idx].RawFrameBuffer.Priv.IsNull)
  25. {
  26. FrameBuffers.ReleaseFrameBuffer(pool.CbPriv, ref frameBufs[idx].RawFrameBuffer);
  27. frameBufs[idx].Released = 1;
  28. }
  29. }
  30. }
  31. public void Create(MemoryAllocator allocator, ref BufferPool pool)
  32. {
  33. ref Vp9Common cm = ref Common;
  34. cm.CheckMemError(ref cm.Fc,
  35. new Ptr<Vp9EntropyProbs>(ref allocator.Allocate<Vp9EntropyProbs>(1)[0]));
  36. cm.CheckMemError(ref cm.FrameContexts,
  37. allocator.Allocate<Vp9EntropyProbs>(Constants.FrameContexts));
  38. for (int i = 0; i < EntropyMode.KfYModeProb.Length; i++)
  39. {
  40. for (int j = 0; j < EntropyMode.KfYModeProb[i].Length; j++)
  41. {
  42. for (int k = 0; k < EntropyMode.KfYModeProb[i][j].Length; k++)
  43. {
  44. cm.Fc.Value.KfYModeProb[i][j][k] = EntropyMode.KfYModeProb[i][j][k];
  45. }
  46. }
  47. }
  48. for (int i = 0; i < EntropyMode.KfUvModeProb.Length; i++)
  49. {
  50. for (int j = 0; j < EntropyMode.KfUvModeProb[i].Length; j++)
  51. {
  52. cm.Fc.Value.KfUvModeProb[i][j] = EntropyMode.KfUvModeProb[i][j];
  53. }
  54. }
  55. byte[][] kfPartitionProbs =
  56. [
  57. // 8x8 . 4x4
  58. [158, 97, 94], // a/l both not split
  59. [93, 24, 99], // a split, l not split
  60. [85, 119, 44], // l split, a not split
  61. [62, 59, 67], // a/l both split
  62. // 16x16 . 8x8
  63. [149, 53, 53], // a/l both not split
  64. [94, 20, 48], // a split, l not split
  65. [83, 53, 24], // l split, a not split
  66. [52, 18, 18], // a/l both split
  67. // 32x32 . 16x16
  68. [150, 40, 39], // a/l both not split
  69. [78, 12, 26], // a split, l not split
  70. [67, 33, 11], // l split, a not split
  71. [24, 7, 5], // a/l both split
  72. // 64x64 . 32x32
  73. [174, 35, 49], // a/l both not split
  74. [68, 11, 27], // a split, l not split
  75. [57, 15, 9], // l split, a not split
  76. [12, 3, 3] // a/l both split
  77. ];
  78. for (int i = 0; i < kfPartitionProbs.Length; i++)
  79. {
  80. for (int j = 0; j < kfPartitionProbs[i].Length; j++)
  81. {
  82. cm.Fc.Value.KfPartitionProb[i][j] = kfPartitionProbs[i][j];
  83. }
  84. }
  85. cm.Counts = new Ptr<Vp9BackwardUpdates>(ref allocator.Allocate<Vp9BackwardUpdates>(1)[0]);
  86. NeedResync = 1;
  87. // Initialize the references to not point to any frame buffers.
  88. for (int i = 0; i < 8; i++)
  89. {
  90. cm.RefFrameMap[i] = -1;
  91. cm.NextRefFrameMap[i] = -1;
  92. }
  93. cm.CurrentVideoFrame = 0;
  94. ReadyForNewData = 1;
  95. Common.BufferPool = new Ptr<BufferPool>(ref pool);
  96. cm.BitDepth = BitDepth.Bits8;
  97. cm.DequantBitDepth = BitDepth.Bits8;
  98. // vp9_loop_filter_init(ref cm);
  99. }
  100. /* If any buffer updating is signaled it should be done here. */
  101. private void SwapFrameBuffers()
  102. {
  103. int refIndex = 0, mask;
  104. ref Vp9Common cm = ref Common;
  105. ref BufferPool pool = ref cm.BufferPool.Value;
  106. ref Array12<RefCntBuffer> frameBufs = ref cm.BufferPool.Value.FrameBufs;
  107. for (mask = RefreshFrameFlags; mask != 0; mask >>= 1)
  108. {
  109. int oldIdx = cm.RefFrameMap[refIndex];
  110. // Current thread releases the holding of reference frame.
  111. DecreaseRefCount(oldIdx, ref frameBufs, ref pool);
  112. // Release the reference frame in reference map.
  113. if ((mask & 1) != 0)
  114. {
  115. DecreaseRefCount(oldIdx, ref frameBufs, ref pool);
  116. }
  117. cm.RefFrameMap[refIndex] = cm.NextRefFrameMap[refIndex];
  118. ++refIndex;
  119. }
  120. // Current thread releases the holding of reference frame.
  121. for (; refIndex < Constants.RefFrames && cm.ShowExistingFrame == 0; ++refIndex)
  122. {
  123. int oldIdx = cm.RefFrameMap[refIndex];
  124. DecreaseRefCount(oldIdx, ref frameBufs, ref pool);
  125. cm.RefFrameMap[refIndex] = cm.NextRefFrameMap[refIndex];
  126. }
  127. HoldRefBuf = 0;
  128. cm.FrameToShow = new Ptr<Surface>(ref cm.GetFrameNewBuffer());
  129. --frameBufs[cm.NewFbIdx].RefCount;
  130. // Invalidate these references until the next frame starts.
  131. for (refIndex = 0; refIndex < 3; refIndex++)
  132. {
  133. cm.FrameRefs[refIndex].Idx = RefBuffer.InvalidIdx;
  134. }
  135. }
  136. public CodecErr ReceiveCompressedData(MemoryAllocator allocator, ulong size, ref ArrayPtr<byte> psource)
  137. {
  138. ref Vp9Common cm = ref Common;
  139. ref BufferPool pool = ref cm.BufferPool.Value;
  140. ref Array12<RefCntBuffer> frameBufs = ref cm.BufferPool.Value.FrameBufs;
  141. ArrayPtr<byte> source = psource;
  142. CodecErr retcode = 0;
  143. cm.Error.ErrorCode = CodecErr.Ok;
  144. if (size == 0)
  145. {
  146. // This is used to signal that we are missing frames.
  147. // We do not know if the missing frame(s) was supposed to update
  148. // any of the reference buffers, but we act conservative and
  149. // mark only the last buffer as corrupted.
  150. if (cm.FrameRefs[0].Idx > 0)
  151. {
  152. cm.FrameRefs[0].Buf.Corrupted = 1;
  153. }
  154. }
  155. ReadyForNewData = 0;
  156. // Check if the previous frame was a frame without any references to it.
  157. if (cm.NewFbIdx >= 0 && frameBufs[cm.NewFbIdx].RefCount == 0 &&
  158. frameBufs[cm.NewFbIdx].Released == 0)
  159. {
  160. FrameBuffers.ReleaseFrameBuffer(pool.CbPriv, ref frameBufs[cm.NewFbIdx].RawFrameBuffer);
  161. frameBufs[cm.NewFbIdx].Released = 1;
  162. }
  163. // Find a free frame buffer. Return error if can not find any.
  164. cm.NewFbIdx = cm.GetFreeFb();
  165. if (cm.NewFbIdx == RefBuffer.InvalidIdx)
  166. {
  167. ReadyForNewData = 1;
  168. cm.Error.InternalError(CodecErr.MemError, "Unable to find free frame buffer");
  169. return cm.Error.ErrorCode;
  170. }
  171. // Assign a MV array to the frame buffer.
  172. cm.CurFrame = new Ptr<RefCntBuffer>(ref pool.FrameBufs[cm.NewFbIdx]);
  173. HoldRefBuf = 0;
  174. DecodeFrame.Decode(allocator, ref this, new ArrayPtr<byte>(ref source[0], (int)size), out psource);
  175. SwapFrameBuffers();
  176. // vpx_clear_system_state();
  177. if (cm.ShowExistingFrame == 0)
  178. {
  179. cm.LastShowFrame = cm.ShowFrame;
  180. cm.PrevFrame = cm.CurFrame;
  181. if (cm.PrevFrameMvs.IsNull || cm.PrevFrameMvs.Length != cm.CurFrameMvs.Length)
  182. {
  183. allocator.Free(cm.PrevFrameMvs);
  184. cm.PrevFrameMvs = allocator.Allocate<MvRef>(cm.CurFrameMvs.Length);
  185. }
  186. cm.CurFrameMvs.AsSpan().CopyTo(cm.PrevFrameMvs.AsSpan());
  187. if (cm.Seg.Enabled)
  188. {
  189. cm.SwapCurrentAndLastSegMap();
  190. }
  191. }
  192. if (cm.ShowFrame != 0)
  193. {
  194. cm.CurShowFrameFbIdx = cm.NewFbIdx;
  195. }
  196. // Update progress in frame parallel decode.
  197. cm.LastWidth = cm.Width;
  198. cm.LastHeight = cm.Height;
  199. if (cm.ShowFrame != 0)
  200. {
  201. cm.CurrentVideoFrame++;
  202. }
  203. return retcode;
  204. }
  205. public int GetRawFrame(ref Surface sd)
  206. {
  207. ref Vp9Common cm = ref Common;
  208. int ret = -1;
  209. if (ReadyForNewData == 1)
  210. {
  211. return ret;
  212. }
  213. ReadyForNewData = 1;
  214. if (cm.ShowFrame == 0)
  215. {
  216. return ret;
  217. }
  218. ReadyForNewData = 1;
  219. sd = cm.FrameToShow.Value;
  220. ret = 0;
  221. return ret;
  222. }
  223. public CodecErr Decode(MemoryAllocator allocator, ArrayPtr<byte> data)
  224. {
  225. ArrayPtr<byte> dataStart = data;
  226. CodecErr res;
  227. Array8<uint> frameSizes = new();
  228. int frameCount = 0;
  229. res = Decoder.ParseSuperframeIndex(data, (ulong)data.Length, ref frameSizes, out frameCount);
  230. if (res != CodecErr.Ok)
  231. {
  232. return res;
  233. }
  234. // Decode in serial mode.
  235. if (frameCount > 0)
  236. {
  237. for (int i = 0; i < frameCount; ++i)
  238. {
  239. ArrayPtr<byte> dataStartCopy = dataStart;
  240. uint frameSize = frameSizes[i];
  241. if (frameSize > (uint)dataStart.Length)
  242. {
  243. return CodecErr.CorruptFrame;
  244. }
  245. res = ReceiveCompressedData(allocator, frameSize, ref dataStartCopy);
  246. if (res != CodecErr.Ok)
  247. {
  248. return res;
  249. }
  250. dataStart = dataStart.Slice((int)frameSize);
  251. }
  252. }
  253. else
  254. {
  255. while (dataStart.Length != 0)
  256. {
  257. uint frameSize = (uint)dataStart.Length;
  258. res = ReceiveCompressedData(allocator, frameSize, ref dataStart);
  259. if (res != CodecErr.Ok)
  260. {
  261. return res;
  262. }
  263. // Account for suboptimal termination by the encoder.
  264. while (dataStart.Length != 0)
  265. {
  266. byte marker = Decoder.ReadMarker(dataStart);
  267. if (marker != 0)
  268. {
  269. break;
  270. }
  271. dataStart = dataStart.Slice(1);
  272. }
  273. }
  274. }
  275. return res;
  276. }
  277. }
  278. internal static class Decoder
  279. {
  280. public static byte ReadMarker(ArrayPtr<byte> data)
  281. {
  282. return data[0];
  283. }
  284. public static CodecErr ParseSuperframeIndex(ArrayPtr<byte> data, ulong dataSz, ref Array8<uint> sizes, out int count)
  285. {
  286. // A chunk ending with a byte matching 0xc0 is an invalid chunk unless
  287. // it is a super frame index. If the last byte of real video compression
  288. // data is 0xc0 the encoder must add a 0 byte. If we have the marker but
  289. // not the associated matching marker byte at the front of the index we have
  290. // an invalid bitstream and need to return an error.
  291. byte marker;
  292. Debug.Assert(dataSz != 0);
  293. marker = ReadMarker(data.Slice((int)dataSz - 1));
  294. count = 0;
  295. if ((marker & 0xe0) == 0xc0)
  296. {
  297. uint frames = (uint)(marker & 0x7) + 1;
  298. uint mag = (uint)((marker >> 3) & 0x3) + 1;
  299. ulong indexSz = 2 + (mag * frames);
  300. // This chunk is marked as having a superframe index but doesn't have
  301. // enough data for it, thus it's an invalid superframe index.
  302. if (dataSz < indexSz)
  303. {
  304. return CodecErr.CorruptFrame;
  305. }
  306. {
  307. byte marker2 = ReadMarker(data.Slice((int)(dataSz - indexSz)));
  308. // This chunk is marked as having a superframe index but doesn't have
  309. // the matching marker byte at the front of the index therefore it's an
  310. // invalid chunk.
  311. if (marker != marker2)
  312. {
  313. return CodecErr.CorruptFrame;
  314. }
  315. }
  316. {
  317. // Found a valid superframe index.
  318. ArrayPtr<byte> x = data.Slice((int)(dataSz - indexSz + 1));
  319. for (int i = 0; i < frames; ++i)
  320. {
  321. uint thisSz = 0;
  322. for (int j = 0; j < mag; ++j)
  323. {
  324. thisSz |= (uint)x[0] << j * 8;
  325. x = x.Slice(1);
  326. }
  327. sizes[i] = thisSz;
  328. }
  329. count = (int)frames;
  330. }
  331. }
  332. return CodecErr.Ok;
  333. }
  334. }
  335. }