FFmpeg.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. using FFmpeg.AutoGen;
  2. using System;
  3. using System.Runtime.InteropServices;
  4. namespace Ryujinx.Graphics.VDec
  5. {
  6. unsafe static class FFmpegWrapper
  7. {
  8. private static AVCodec* Codec;
  9. private static AVCodecContext* Context;
  10. private static AVFrame* Frame;
  11. private static SwsContext* ScalerCtx;
  12. private static int ScalerWidth;
  13. private static int ScalerHeight;
  14. public static bool IsInitialized { get; private set; }
  15. public static void H264Initialize()
  16. {
  17. EnsureCodecInitialized(AVCodecID.AV_CODEC_ID_H264);
  18. }
  19. public static void Vp9Initialize()
  20. {
  21. EnsureCodecInitialized(AVCodecID.AV_CODEC_ID_VP9);
  22. }
  23. private static void EnsureCodecInitialized(AVCodecID CodecId)
  24. {
  25. if (IsInitialized)
  26. {
  27. Uninitialize();
  28. }
  29. Codec = ffmpeg.avcodec_find_decoder(CodecId);
  30. Context = ffmpeg.avcodec_alloc_context3(Codec);
  31. Frame = ffmpeg.av_frame_alloc();
  32. ffmpeg.avcodec_open2(Context, Codec, null);
  33. IsInitialized = true;
  34. }
  35. public static int DecodeFrame(byte[] Data)
  36. {
  37. if (!IsInitialized)
  38. {
  39. throw new InvalidOperationException("Tried to use uninitialized codec!");
  40. }
  41. AVPacket Packet;
  42. ffmpeg.av_init_packet(&Packet);
  43. fixed (byte* Ptr = Data)
  44. {
  45. Packet.data = Ptr;
  46. Packet.size = Data.Length;
  47. ffmpeg.avcodec_send_packet(Context, &Packet);
  48. }
  49. return ffmpeg.avcodec_receive_frame(Context, Frame);
  50. }
  51. public static FFmpegFrame GetFrame()
  52. {
  53. if (!IsInitialized)
  54. {
  55. throw new InvalidOperationException("Tried to use uninitialized codec!");
  56. }
  57. AVFrame ManagedFrame = Marshal.PtrToStructure<AVFrame>((IntPtr)Frame);
  58. byte*[] Data = ManagedFrame.data.ToArray();
  59. return new FFmpegFrame()
  60. {
  61. Width = ManagedFrame.width,
  62. Height = ManagedFrame.height,
  63. LumaPtr = Data[0],
  64. ChromaBPtr = Data[1],
  65. ChromaRPtr = Data[2]
  66. };
  67. }
  68. public static FFmpegFrame GetFrameRgba()
  69. {
  70. if (!IsInitialized)
  71. {
  72. throw new InvalidOperationException("Tried to use uninitialized codec!");
  73. }
  74. AVFrame ManagedFrame = Marshal.PtrToStructure<AVFrame>((IntPtr)Frame);
  75. EnsureScalerSetup(ManagedFrame.width, ManagedFrame.height);
  76. byte*[] Data = ManagedFrame.data.ToArray();
  77. int[] LineSizes = ManagedFrame.linesize.ToArray();
  78. byte[] Dst = new byte[ManagedFrame.width * ManagedFrame.height * 4];
  79. fixed (byte* Ptr = Dst)
  80. {
  81. byte*[] DstData = new byte*[] { Ptr };
  82. int[] DstLineSizes = new int[] { ManagedFrame.width * 4 };
  83. ffmpeg.sws_scale(ScalerCtx, Data, LineSizes, 0, ManagedFrame.height, DstData, DstLineSizes);
  84. }
  85. return new FFmpegFrame()
  86. {
  87. Width = ManagedFrame.width,
  88. Height = ManagedFrame.height,
  89. Data = Dst
  90. };
  91. }
  92. private static void EnsureScalerSetup(int Width, int Height)
  93. {
  94. if (Width == 0 || Height == 0)
  95. {
  96. return;
  97. }
  98. if (ScalerCtx == null || ScalerWidth != Width || ScalerHeight != Height)
  99. {
  100. FreeScaler();
  101. ScalerCtx = ffmpeg.sws_getContext(
  102. Width, Height, AVPixelFormat.AV_PIX_FMT_YUV420P,
  103. Width, Height, AVPixelFormat.AV_PIX_FMT_RGBA, 0, null, null, null);
  104. ScalerWidth = Width;
  105. ScalerHeight = Height;
  106. }
  107. }
  108. public static void Uninitialize()
  109. {
  110. if (IsInitialized)
  111. {
  112. ffmpeg.av_frame_unref(Frame);
  113. ffmpeg.av_free(Frame);
  114. ffmpeg.avcodec_close(Context);
  115. FreeScaler();
  116. IsInitialized = false;
  117. }
  118. }
  119. private static void FreeScaler()
  120. {
  121. if (ScalerCtx != null)
  122. {
  123. ffmpeg.sws_freeContext(ScalerCtx);
  124. ScalerCtx = null;
  125. }
  126. }
  127. }
  128. }