aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Nvdec.FFmpeg/FFmpegContext.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics.Nvdec.FFmpeg/FFmpegContext.cs')
-rw-r--r--Ryujinx.Graphics.Nvdec.FFmpeg/FFmpegContext.cs121
1 files changed, 54 insertions, 67 deletions
diff --git a/Ryujinx.Graphics.Nvdec.FFmpeg/FFmpegContext.cs b/Ryujinx.Graphics.Nvdec.FFmpeg/FFmpegContext.cs
index e0ef05a5..8c2e94c3 100644
--- a/Ryujinx.Graphics.Nvdec.FFmpeg/FFmpegContext.cs
+++ b/Ryujinx.Graphics.Nvdec.FFmpeg/FFmpegContext.cs
@@ -1,23 +1,21 @@
-using FFmpeg.AutoGen;
-using Ryujinx.Common.Logging;
+using Ryujinx.Common.Logging;
+using Ryujinx.Graphics.Nvdec.FFmpeg.Native;
using System;
-using System.Diagnostics;
-using System.IO;
using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.Nvdec.FFmpeg
{
unsafe class FFmpegContext : IDisposable
{
- private readonly AVCodec_decode _decodeFrame;
- private static readonly av_log_set_callback_callback _logFunc;
+ private readonly FFCodec.AVCodec_decode _decodeFrame;
+ private static readonly FFmpegApi.av_log_set_callback_callback _logFunc;
private readonly AVCodec* _codec;
private AVPacket* _packet;
private AVCodecContext* _context;
public FFmpegContext(AVCodecID codecId)
{
- _codec = ffmpeg.avcodec_find_decoder(codecId);
+ _codec = FFmpegApi.avcodec_find_decoder(codecId);
if (_codec == null)
{
Logger.Error?.PrintMsg(LogClass.FFmpeg, $"Codec wasn't found. Make sure you have the {codecId} codec present in your FFmpeg installation.");
@@ -25,7 +23,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg
return;
}
- _context = ffmpeg.avcodec_alloc_context3(_codec);
+ _context = FFmpegApi.avcodec_alloc_context3(_codec);
if (_context == null)
{
Logger.Error?.PrintMsg(LogClass.FFmpeg, "Codec context couldn't be allocated.");
@@ -33,14 +31,14 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg
return;
}
- if (ffmpeg.avcodec_open2(_context, _codec, null) != 0)
+ if (FFmpegApi.avcodec_open2(_context, _codec, null) != 0)
{
Logger.Error?.PrintMsg(LogClass.FFmpeg, "Codec couldn't be opened.");
return;
}
- _packet = ffmpeg.av_packet_alloc();
+ _packet = FFmpegApi.av_packet_alloc();
if (_packet == null)
{
Logger.Error?.PrintMsg(LogClass.FFmpeg, "Packet couldn't be allocated.");
@@ -48,52 +46,39 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg
return;
}
- _decodeFrame = Marshal.GetDelegateForFunctionPointer<AVCodec_decode>(_codec->decode.Pointer);
+ int avCodecRawVersion = FFmpegApi.avcodec_version();
+ int avCodecMajorVersion = avCodecRawVersion >> 16;
+ int avCodecMinorVersion = (avCodecRawVersion >> 8) & 0xFF;
+
+ // libavcodec 59.24 changed AvCodec to move its private API and also move the codec function to an union.
+ if (avCodecMajorVersion > 59 || (avCodecMajorVersion == 59 && avCodecMinorVersion > 24))
+ {
+ _decodeFrame = Marshal.GetDelegateForFunctionPointer<FFCodec.AVCodec_decode>(((FFCodec*)_codec)->CodecCallback);
+ }
+ // libavcodec 59.x changed AvCodec private API layout.
+ else if (avCodecMajorVersion == 59)
+ {
+ _decodeFrame = Marshal.GetDelegateForFunctionPointer<FFCodec.AVCodec_decode>(((FFCodecLegacy<AVCodec>*)_codec)->Decode);
+ }
+ // libavcodec 58.x and lower
+ else
+ {
+ _decodeFrame = Marshal.GetDelegateForFunctionPointer<FFCodec.AVCodec_decode>(((FFCodecLegacy<AVCodecLegacy>*)_codec)->Decode);
+ }
}
static FFmpegContext()
{
- SetRootPath();
-
_logFunc = Log;
// Redirect log output.
- ffmpeg.av_log_set_level(ffmpeg.AV_LOG_MAX_OFFSET);
- ffmpeg.av_log_set_callback(_logFunc);
+ FFmpegApi.av_log_set_level(AVLog.MaxOffset);
+ FFmpegApi.av_log_set_callback(_logFunc);
}
- private static void SetRootPath()
+ private static void Log(void* ptr, AVLog level, string format, byte* vl)
{
- if (OperatingSystem.IsLinux())
- {
- // Configure FFmpeg search path
- Process lddProcess = Process.Start(new ProcessStartInfo
- {
- FileName = "/bin/sh",
- Arguments = "-c \"ldd $(which ffmpeg 2>/dev/null) | grep libavfilter\" 2>/dev/null",
- UseShellExecute = false,
- RedirectStandardOutput = true
- });
-
- string lddOutput = lddProcess.StandardOutput.ReadToEnd();
-
- lddProcess.WaitForExit();
- lddProcess.Close();
-
- if (lddOutput.Contains(" => "))
- {
- ffmpeg.RootPath = Path.GetDirectoryName(lddOutput.Split(" => ")[1]);
- }
- else
- {
- Logger.Error?.PrintMsg(LogClass.FFmpeg, "FFmpeg wasn't found. Make sure that you have it installed and up to date.");
- }
- }
- }
-
- private static void Log(void* p0, int level, string format, byte* vl)
- {
- if (level > ffmpeg.av_log_get_level())
+ if (level > FFmpegApi.av_log_get_level())
{
return;
}
@@ -102,65 +87,67 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg
byte* lineBuffer = stackalloc byte[lineSize];
int printPrefix = 1;
- ffmpeg.av_log_format_line(p0, level, format, vl, lineBuffer, lineSize, &printPrefix);
+ FFmpegApi.av_log_format_line(ptr, level, format, vl, lineBuffer, lineSize, &printPrefix);
string line = Marshal.PtrToStringAnsi((IntPtr)lineBuffer).Trim();
switch (level)
{
- case ffmpeg.AV_LOG_PANIC:
- case ffmpeg.AV_LOG_FATAL:
- case ffmpeg.AV_LOG_ERROR:
+ case AVLog.Panic:
+ case AVLog.Fatal:
+ case AVLog.Error:
Logger.Error?.Print(LogClass.FFmpeg, line);
break;
- case ffmpeg.AV_LOG_WARNING:
+ case AVLog.Warning:
Logger.Warning?.Print(LogClass.FFmpeg, line);
break;
- case ffmpeg.AV_LOG_INFO:
+ case AVLog.Info:
Logger.Info?.Print(LogClass.FFmpeg, line);
break;
- case ffmpeg.AV_LOG_VERBOSE:
- case ffmpeg.AV_LOG_DEBUG:
- case ffmpeg.AV_LOG_TRACE:
+ case AVLog.Verbose:
+ case AVLog.Debug:
Logger.Debug?.Print(LogClass.FFmpeg, line);
break;
+ case AVLog.Trace:
+ Logger.Trace?.Print(LogClass.FFmpeg, line);
+ break;
}
}
public int DecodeFrame(Surface output, ReadOnlySpan<byte> bitstream)
{
- ffmpeg.av_frame_unref(output.Frame);
+ FFmpegApi.av_frame_unref(output.Frame);
int result;
int gotFrame;
fixed (byte* ptr = bitstream)
{
- _packet->data = ptr;
- _packet->size = bitstream.Length;
+ _packet->Data = ptr;
+ _packet->Size = bitstream.Length;
result = _decodeFrame(_context, output.Frame, &gotFrame, _packet);
}
if (gotFrame == 0)
{
- ffmpeg.av_frame_unref(output.Frame);
+ FFmpegApi.av_frame_unref(output.Frame);
// If the frame was not delivered, it was probably delayed.
// Get the next delayed frame by passing a 0 length packet.
- _packet->data = null;
- _packet->size = 0;
+ _packet->Data = null;
+ _packet->Size = 0;
result = _decodeFrame(_context, output.Frame, &gotFrame, _packet);
// We need to set B frames to 0 as we already consumed all delayed frames.
// This prevents the decoder from trying to return a delayed frame next time.
- _context->has_b_frames = 0;
+ _context->HasBFrames = 0;
}
- ffmpeg.av_packet_unref(_packet);
+ FFmpegApi.av_packet_unref(_packet);
if (gotFrame == 0)
{
- ffmpeg.av_frame_unref(output.Frame);
+ FFmpegApi.av_frame_unref(output.Frame);
return -1;
}
@@ -172,14 +159,14 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg
{
fixed (AVPacket** ppPacket = &_packet)
{
- ffmpeg.av_packet_free(ppPacket);
+ FFmpegApi.av_packet_free(ppPacket);
}
- ffmpeg.avcodec_close(_context);
+ FFmpegApi.avcodec_close(_context);
fixed (AVCodecContext** ppContext = &_context)
{
- ffmpeg.avcodec_free_context(ppContext);
+ FFmpegApi.avcodec_free_context(ppContext);
}
}
}