VideoDecoder.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. using Ryujinx.Graphics.Gpu;
  2. using Ryujinx.Graphics.Vic;
  3. using System;
  4. namespace Ryujinx.Graphics.VDec
  5. {
  6. unsafe class VideoDecoder
  7. {
  8. private H264Decoder _h264Decoder;
  9. private Vp9Decoder _vp9Decoder;
  10. private VideoCodec _currentVideoCodec;
  11. private ulong _decoderContextAddress;
  12. private ulong _frameDataAddress;
  13. private ulong _vpxCurrLumaAddress;
  14. private ulong _vpxRef0LumaAddress;
  15. private ulong _vpxRef1LumaAddress;
  16. private ulong _vpxRef2LumaAddress;
  17. private ulong _vpxCurrChromaAddress;
  18. private ulong _vpxRef0ChromaAddress;
  19. private ulong _vpxRef1ChromaAddress;
  20. private ulong _vpxRef2ChromaAddress;
  21. private ulong _vpxProbTablesAddress;
  22. public VideoDecoder()
  23. {
  24. _h264Decoder = new H264Decoder();
  25. _vp9Decoder = new Vp9Decoder();
  26. }
  27. public void Process(GpuContext gpu, int methodOffset, int[] arguments)
  28. {
  29. VideoDecoderMeth method = (VideoDecoderMeth)methodOffset;
  30. switch (method)
  31. {
  32. case VideoDecoderMeth.SetVideoCodec: SetVideoCodec(arguments); break;
  33. case VideoDecoderMeth.Execute: Execute(gpu); break;
  34. case VideoDecoderMeth.SetDecoderCtxAddr: SetDecoderCtxAddr(arguments); break;
  35. case VideoDecoderMeth.SetFrameDataAddr: SetFrameDataAddr(arguments); break;
  36. case VideoDecoderMeth.SetVpxCurrLumaAddr: SetVpxCurrLumaAddr(arguments); break;
  37. case VideoDecoderMeth.SetVpxRef0LumaAddr: SetVpxRef0LumaAddr(arguments); break;
  38. case VideoDecoderMeth.SetVpxRef1LumaAddr: SetVpxRef1LumaAddr(arguments); break;
  39. case VideoDecoderMeth.SetVpxRef2LumaAddr: SetVpxRef2LumaAddr(arguments); break;
  40. case VideoDecoderMeth.SetVpxCurrChromaAddr: SetVpxCurrChromaAddr(arguments); break;
  41. case VideoDecoderMeth.SetVpxRef0ChromaAddr: SetVpxRef0ChromaAddr(arguments); break;
  42. case VideoDecoderMeth.SetVpxRef1ChromaAddr: SetVpxRef1ChromaAddr(arguments); break;
  43. case VideoDecoderMeth.SetVpxRef2ChromaAddr: SetVpxRef2ChromaAddr(arguments); break;
  44. case VideoDecoderMeth.SetVpxProbTablesAddr: SetVpxProbTablesAddr(arguments); break;
  45. }
  46. }
  47. private void SetVideoCodec(int[] arguments)
  48. {
  49. _currentVideoCodec = (VideoCodec)arguments[0];
  50. }
  51. private void Execute(GpuContext gpu)
  52. {
  53. if (_currentVideoCodec == VideoCodec.H264)
  54. {
  55. int frameDataSize = gpu.MemoryAccessor.ReadInt32(_decoderContextAddress + 0x48);
  56. H264ParameterSets Params = gpu.MemoryAccessor.Read<H264ParameterSets>(_decoderContextAddress + 0x58);
  57. H264Matrices matrices = new H264Matrices()
  58. {
  59. ScalingMatrix4 = gpu.MemoryAccessor.ReadBytes(_decoderContextAddress + 0x1c0, 6 * 16),
  60. ScalingMatrix8 = gpu.MemoryAccessor.ReadBytes(_decoderContextAddress + 0x220, 2 * 64)
  61. };
  62. byte[] frameData = gpu.MemoryAccessor.ReadBytes(_frameDataAddress, (ulong)frameDataSize);
  63. _h264Decoder.Decode(Params, matrices, frameData);
  64. }
  65. else if (_currentVideoCodec == VideoCodec.Vp9)
  66. {
  67. int frameDataSize = gpu.MemoryAccessor.ReadInt32(_decoderContextAddress + 0x30);
  68. Vp9FrameKeys keys = new Vp9FrameKeys()
  69. {
  70. CurrKey = (long)gpu.MemoryManager.Translate(_vpxCurrLumaAddress),
  71. Ref0Key = (long)gpu.MemoryManager.Translate(_vpxRef0LumaAddress),
  72. Ref1Key = (long)gpu.MemoryManager.Translate(_vpxRef1LumaAddress),
  73. Ref2Key = (long)gpu.MemoryManager.Translate(_vpxRef2LumaAddress)
  74. };
  75. Vp9FrameHeader header = gpu.MemoryAccessor.Read<Vp9FrameHeader>(_decoderContextAddress + 0x48);
  76. Vp9ProbabilityTables probs = new Vp9ProbabilityTables()
  77. {
  78. SegmentationTreeProbs = gpu.MemoryAccessor.ReadBytes(_vpxProbTablesAddress + 0x387, 0x7),
  79. SegmentationPredProbs = gpu.MemoryAccessor.ReadBytes(_vpxProbTablesAddress + 0x38e, 0x3),
  80. Tx8x8Probs = gpu.MemoryAccessor.ReadBytes(_vpxProbTablesAddress + 0x470, 0x2),
  81. Tx16x16Probs = gpu.MemoryAccessor.ReadBytes(_vpxProbTablesAddress + 0x472, 0x4),
  82. Tx32x32Probs = gpu.MemoryAccessor.ReadBytes(_vpxProbTablesAddress + 0x476, 0x6),
  83. CoefProbs = gpu.MemoryAccessor.ReadBytes(_vpxProbTablesAddress + 0x5a0, 0x900),
  84. SkipProbs = gpu.MemoryAccessor.ReadBytes(_vpxProbTablesAddress + 0x537, 0x3),
  85. InterModeProbs = gpu.MemoryAccessor.ReadBytes(_vpxProbTablesAddress + 0x400, 0x1c),
  86. InterpFilterProbs = gpu.MemoryAccessor.ReadBytes(_vpxProbTablesAddress + 0x52a, 0x8),
  87. IsInterProbs = gpu.MemoryAccessor.ReadBytes(_vpxProbTablesAddress + 0x41c, 0x4),
  88. CompModeProbs = gpu.MemoryAccessor.ReadBytes(_vpxProbTablesAddress + 0x532, 0x5),
  89. SingleRefProbs = gpu.MemoryAccessor.ReadBytes(_vpxProbTablesAddress + 0x580, 0xa),
  90. CompRefProbs = gpu.MemoryAccessor.ReadBytes(_vpxProbTablesAddress + 0x58a, 0x5),
  91. YModeProbs0 = gpu.MemoryAccessor.ReadBytes(_vpxProbTablesAddress + 0x480, 0x20),
  92. YModeProbs1 = gpu.MemoryAccessor.ReadBytes(_vpxProbTablesAddress + 0x47c, 0x4),
  93. PartitionProbs = gpu.MemoryAccessor.ReadBytes(_vpxProbTablesAddress + 0x4e0, 0x40),
  94. MvJointProbs = gpu.MemoryAccessor.ReadBytes(_vpxProbTablesAddress + 0x53b, 0x3),
  95. MvSignProbs = gpu.MemoryAccessor.ReadBytes(_vpxProbTablesAddress + 0x53e, 0x3),
  96. MvClassProbs = gpu.MemoryAccessor.ReadBytes(_vpxProbTablesAddress + 0x54c, 0x14),
  97. MvClass0BitProbs = gpu.MemoryAccessor.ReadBytes(_vpxProbTablesAddress + 0x540, 0x3),
  98. MvBitsProbs = gpu.MemoryAccessor.ReadBytes(_vpxProbTablesAddress + 0x56c, 0x14),
  99. MvClass0FrProbs = gpu.MemoryAccessor.ReadBytes(_vpxProbTablesAddress + 0x560, 0xc),
  100. MvFrProbs = gpu.MemoryAccessor.ReadBytes(_vpxProbTablesAddress + 0x542, 0x6),
  101. MvClass0HpProbs = gpu.MemoryAccessor.ReadBytes(_vpxProbTablesAddress + 0x548, 0x2),
  102. MvHpProbs = gpu.MemoryAccessor.ReadBytes(_vpxProbTablesAddress + 0x54a, 0x2)
  103. };
  104. byte[] frameData = gpu.MemoryAccessor.ReadBytes(_frameDataAddress, (ulong)frameDataSize);
  105. _vp9Decoder.Decode(keys, header, probs, frameData);
  106. }
  107. else
  108. {
  109. ThrowUnimplementedCodec();
  110. }
  111. }
  112. private void SetDecoderCtxAddr(int[] arguments)
  113. {
  114. _decoderContextAddress = GetAddress(arguments);
  115. }
  116. private void SetFrameDataAddr(int[] arguments)
  117. {
  118. _frameDataAddress = GetAddress(arguments);
  119. }
  120. private void SetVpxCurrLumaAddr(int[] arguments)
  121. {
  122. _vpxCurrLumaAddress = GetAddress(arguments);
  123. }
  124. private void SetVpxRef0LumaAddr(int[] arguments)
  125. {
  126. _vpxRef0LumaAddress = GetAddress(arguments);
  127. }
  128. private void SetVpxRef1LumaAddr(int[] arguments)
  129. {
  130. _vpxRef1LumaAddress = GetAddress(arguments);
  131. }
  132. private void SetVpxRef2LumaAddr(int[] arguments)
  133. {
  134. _vpxRef2LumaAddress = GetAddress(arguments);
  135. }
  136. private void SetVpxCurrChromaAddr(int[] arguments)
  137. {
  138. _vpxCurrChromaAddress = GetAddress(arguments);
  139. }
  140. private void SetVpxRef0ChromaAddr(int[] arguments)
  141. {
  142. _vpxRef0ChromaAddress = GetAddress(arguments);
  143. }
  144. private void SetVpxRef1ChromaAddr(int[] arguments)
  145. {
  146. _vpxRef1ChromaAddress = GetAddress(arguments);
  147. }
  148. private void SetVpxRef2ChromaAddr(int[] arguments)
  149. {
  150. _vpxRef2ChromaAddress = GetAddress(arguments);
  151. }
  152. private void SetVpxProbTablesAddr(int[] arguments)
  153. {
  154. _vpxProbTablesAddress = GetAddress(arguments);
  155. }
  156. private static ulong GetAddress(int[] arguments)
  157. {
  158. return (ulong)(uint)arguments[0] << 8;
  159. }
  160. internal void CopyPlanes(GpuContext gpu, SurfaceOutputConfig outputConfig)
  161. {
  162. switch (outputConfig.PixelFormat)
  163. {
  164. case SurfacePixelFormat.Rgba8: CopyPlanesRgba8 (gpu, outputConfig); break;
  165. case SurfacePixelFormat.Yuv420P: CopyPlanesYuv420P(gpu, outputConfig); break;
  166. default: ThrowUnimplementedPixelFormat(outputConfig.PixelFormat); break;
  167. }
  168. }
  169. private void CopyPlanesRgba8(GpuContext gpu, SurfaceOutputConfig outputConfig)
  170. {
  171. FFmpegFrame frame = FFmpegWrapper.GetFrameRgba();
  172. if ((frame.Width | frame.Height) == 0)
  173. {
  174. return;
  175. }
  176. throw new NotImplementedException();
  177. }
  178. private void CopyPlanesYuv420P(GpuContext gpu, SurfaceOutputConfig outputConfig)
  179. {
  180. FFmpegFrame frame = FFmpegWrapper.GetFrame();
  181. if ((frame.Width | frame.Height) == 0)
  182. {
  183. return;
  184. }
  185. int halfSrcWidth = frame.Width / 2;
  186. int halfWidth = frame.Width / 2;
  187. int halfHeight = frame.Height / 2;
  188. int alignedWidth = (outputConfig.SurfaceWidth + 0xff) & ~0xff;
  189. for (int y = 0; y < frame.Height; y++)
  190. {
  191. int src = y * frame.Width;
  192. int dst = y * alignedWidth;
  193. int size = frame.Width;
  194. for (int offset = 0; offset < size; offset++)
  195. {
  196. gpu.MemoryAccessor.WriteByte(outputConfig.SurfaceLumaAddress + (ulong)dst + (ulong)offset, *(frame.LumaPtr + src + offset));
  197. }
  198. }
  199. // Copy chroma data from both channels with interleaving.
  200. for (int y = 0; y < halfHeight; y++)
  201. {
  202. int src = y * halfSrcWidth;
  203. int dst = y * alignedWidth;
  204. for (int x = 0; x < halfWidth; x++)
  205. {
  206. gpu.MemoryAccessor.WriteByte(outputConfig.SurfaceChromaUAddress + (ulong)dst + (ulong)x * 2 + 0, *(frame.ChromaBPtr + src + x));
  207. gpu.MemoryAccessor.WriteByte(outputConfig.SurfaceChromaUAddress + (ulong)dst + (ulong)x * 2 + 1, *(frame.ChromaRPtr + src + x));
  208. }
  209. }
  210. }
  211. private void ThrowUnimplementedCodec()
  212. {
  213. throw new NotImplementedException($"Codec \"{_currentVideoCodec}\" is not supported!");
  214. }
  215. private void ThrowUnimplementedPixelFormat(SurfacePixelFormat pixelFormat)
  216. {
  217. throw new NotImplementedException($"Pixel format \"{pixelFormat}\" is not supported!");
  218. }
  219. }
  220. }