Decoder.cs
 1  using Ryujinx.Graphics.Nvdec.FFmpeg.Native;
 2  using Ryujinx.Graphics.Video;
 3  using System;
 4  
 5  namespace Ryujinx.Graphics.Nvdec.FFmpeg.H264
 6  {
 7      public sealed class Decoder : IH264Decoder
 8      {
 9          public bool IsHardwareAccelerated => false;
10  
11          private const int WorkBufferSize = 0x200;
12  
13          private readonly byte[] _workBuffer = new byte[WorkBufferSize];
14  
15          private FFmpegContext _context = new(AVCodecID.AV_CODEC_ID_H264);
16  
17          private int _oldOutputWidth;
18          private int _oldOutputHeight;
19  
20          public ISurface CreateSurface(int width, int height)
21          {
22              return new Surface(width, height);
23          }
24  
25          public bool Decode(ref H264PictureInfo pictureInfo, ISurface output, ReadOnlySpan<byte> bitstream)
26          {
27              Surface outSurf = (Surface)output;
28  
29              if (outSurf.RequestedWidth != _oldOutputWidth ||
30                  outSurf.RequestedHeight != _oldOutputHeight)
31              {
32                  _context.Dispose();
33                  _context = new FFmpegContext(AVCodecID.AV_CODEC_ID_H264);
34  
35                  _oldOutputWidth = outSurf.RequestedWidth;
36                  _oldOutputHeight = outSurf.RequestedHeight;
37              }
38  
39              Span<byte> bs = Prepend(bitstream, SpsAndPpsReconstruction.Reconstruct(ref pictureInfo, _workBuffer));
40  
41              return _context.DecodeFrame(outSurf, bs) == 0;
42          }
43  
44          private static byte[] Prepend(ReadOnlySpan<byte> data, ReadOnlySpan<byte> prep)
45          {
46              byte[] output = new byte[data.Length + prep.Length];
47  
48              prep.CopyTo(output);
49              data.CopyTo(new Span<byte>(output)[prep.Length..]);
50  
51              return output;
52          }
53  
54          public void Dispose() => _context.Dispose();
55      }
56  }