From 14fd9aa640936d2455c9f0929fc904a5bdb2fada Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
Date: Sun, 11 Oct 2020 06:09:38 -0300
Subject: [PATCH] Fix H264 output frame size when decoding videos of different
 sizes (#1606)

---
 Ryujinx.Graphics.Nvdec.H264/Decoder.cs | 21 ++++++++++++++++++---
 Ryujinx.Graphics.Nvdec.H264/Surface.cs |  8 +++++++-
 2 files changed, 25 insertions(+), 4 deletions(-)

diff --git a/Ryujinx.Graphics.Nvdec.H264/Decoder.cs b/Ryujinx.Graphics.Nvdec.H264/Decoder.cs
index 6dbe517693..fed64af4f3 100644
--- a/Ryujinx.Graphics.Nvdec.H264/Decoder.cs
+++ b/Ryujinx.Graphics.Nvdec.H264/Decoder.cs
@@ -11,18 +11,33 @@ namespace Ryujinx.Graphics.Nvdec.H264
 
         private readonly byte[] _workBuffer = new byte[WorkBufferSize];
 
-        private readonly FFmpegContext _context = new FFmpegContext();
+        private FFmpegContext _context = new FFmpegContext();
+
+        private int _oldOutputWidth;
+        private int _oldOutputHeight;
 
         public ISurface CreateSurface(int width, int height)
         {
-            return new Surface();
+            return new Surface(width, height);
         }
 
         public bool Decode(ref H264PictureInfo pictureInfo, ISurface output, ReadOnlySpan<byte> bitstream)
         {
+            Surface outSurf = (Surface)output;
+
+            if (outSurf.RequestedWidth != _oldOutputWidth ||
+                outSurf.RequestedHeight != _oldOutputHeight)
+            {
+                _context.Dispose();
+                _context = new FFmpegContext();
+
+                _oldOutputWidth = outSurf.RequestedWidth;
+                _oldOutputHeight = outSurf.RequestedHeight;
+            }
+
             Span<byte> bs = Prepend(bitstream, SpsAndPpsReconstruction.Reconstruct(ref pictureInfo, _workBuffer));
 
-            return _context.DecodeFrame((Surface)output, bs) == 0;
+            return _context.DecodeFrame(outSurf, bs) == 0;
         }
 
         private static byte[] Prepend(ReadOnlySpan<byte> data, ReadOnlySpan<byte> prep)
diff --git a/Ryujinx.Graphics.Nvdec.H264/Surface.cs b/Ryujinx.Graphics.Nvdec.H264/Surface.cs
index a6c16ba38a..3dbc980e36 100644
--- a/Ryujinx.Graphics.Nvdec.H264/Surface.cs
+++ b/Ryujinx.Graphics.Nvdec.H264/Surface.cs
@@ -8,6 +8,9 @@ namespace Ryujinx.Graphics.Nvdec.H264
     {
         public AVFrame* Frame { get; }
 
+        public int RequestedWidth { get; }
+        public int RequestedHeight { get; }
+
         public Plane YPlane => new Plane((IntPtr)Frame->data[0], Stride * Height);
         public Plane UPlane => new Plane((IntPtr)Frame->data[1], UvStride * UvHeight);
         public Plane VPlane => new Plane((IntPtr)Frame->data[2], UvStride * UvHeight);
@@ -19,8 +22,11 @@ namespace Ryujinx.Graphics.Nvdec.H264
         public int UvHeight => (Frame->height + 1) >> 1;
         public int UvStride => Frame->linesize[1];
 
-        public Surface()
+        public Surface(int width, int height)
         {
+            RequestedWidth = width;
+            RequestedHeight = height;
+
             Frame = ffmpeg.av_frame_alloc();
         }