Remove dependency for FFmpeg.AutoGen and Update FFmpeg to 5.0.1 for Windows (#3466)

* Remove dependency for FFMpeg.AutoGen

Also prepare for FFMpeg 5.0 and 5.1

* Update Ryujinx.Graphics.Nvdec.Dependencies to 5.0.1-build10

* Address gdkchan's comments

* Address Ack's comment

* Address gdkchan's comment
This commit is contained in:
Mary 2022-07-14 15:13:23 +02:00 committed by GitHub
parent 70ec5def9c
commit c5bddfeab8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 563 additions and 89 deletions

View File

@ -28,7 +28,7 @@
<PackageReference Include="FluentAvaloniaUI" Version="1.4.1" /> <PackageReference Include="FluentAvaloniaUI" Version="1.4.1" />
<PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" /> <PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="4.4.0-build9" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" /> <PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build10" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
<PackageReference Include="OpenTK.Graphics" Version="4.7.2" /> <PackageReference Include="OpenTK.Graphics" Version="4.7.2" />
<PackageReference Include="SPB" Version="0.0.4-build17" /> <PackageReference Include="SPB" Version="0.0.4-build17" />
<PackageReference Include="SharpZipLib" Version="1.3.3" /> <PackageReference Include="SharpZipLib" Version="1.3.3" />

View File

@ -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;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.Nvdec.FFmpeg namespace Ryujinx.Graphics.Nvdec.FFmpeg
{ {
unsafe class FFmpegContext : IDisposable unsafe class FFmpegContext : IDisposable
{ {
private readonly AVCodec_decode _decodeFrame; private readonly FFCodec.AVCodec_decode _decodeFrame;
private static readonly av_log_set_callback_callback _logFunc; private static readonly FFmpegApi.av_log_set_callback_callback _logFunc;
private readonly AVCodec* _codec; private readonly AVCodec* _codec;
private AVPacket* _packet; private AVPacket* _packet;
private AVCodecContext* _context; private AVCodecContext* _context;
public FFmpegContext(AVCodecID codecId) public FFmpegContext(AVCodecID codecId)
{ {
_codec = ffmpeg.avcodec_find_decoder(codecId); _codec = FFmpegApi.avcodec_find_decoder(codecId);
if (_codec == null) if (_codec == null)
{ {
Logger.Error?.PrintMsg(LogClass.FFmpeg, $"Codec wasn't found. Make sure you have the {codecId} codec present in your FFmpeg installation."); 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; return;
} }
_context = ffmpeg.avcodec_alloc_context3(_codec); _context = FFmpegApi.avcodec_alloc_context3(_codec);
if (_context == null) if (_context == null)
{ {
Logger.Error?.PrintMsg(LogClass.FFmpeg, "Codec context couldn't be allocated."); Logger.Error?.PrintMsg(LogClass.FFmpeg, "Codec context couldn't be allocated.");
@ -33,14 +31,14 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg
return; 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."); Logger.Error?.PrintMsg(LogClass.FFmpeg, "Codec couldn't be opened.");
return; return;
} }
_packet = ffmpeg.av_packet_alloc(); _packet = FFmpegApi.av_packet_alloc();
if (_packet == null) if (_packet == null)
{ {
Logger.Error?.PrintMsg(LogClass.FFmpeg, "Packet couldn't be allocated."); Logger.Error?.PrintMsg(LogClass.FFmpeg, "Packet couldn't be allocated.");
@ -48,52 +46,39 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg
return; 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() static FFmpegContext()
{ {
SetRootPath();
_logFunc = Log; _logFunc = Log;
// Redirect log output. // Redirect log output.
ffmpeg.av_log_set_level(ffmpeg.AV_LOG_MAX_OFFSET); FFmpegApi.av_log_set_level(AVLog.MaxOffset);
ffmpeg.av_log_set_callback(_logFunc); 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()) if (level > FFmpegApi.av_log_get_level())
{
// 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())
{ {
return; return;
} }
@ -102,65 +87,67 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg
byte* lineBuffer = stackalloc byte[lineSize]; byte* lineBuffer = stackalloc byte[lineSize];
int printPrefix = 1; 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(); string line = Marshal.PtrToStringAnsi((IntPtr)lineBuffer).Trim();
switch (level) switch (level)
{ {
case ffmpeg.AV_LOG_PANIC: case AVLog.Panic:
case ffmpeg.AV_LOG_FATAL: case AVLog.Fatal:
case ffmpeg.AV_LOG_ERROR: case AVLog.Error:
Logger.Error?.Print(LogClass.FFmpeg, line); Logger.Error?.Print(LogClass.FFmpeg, line);
break; break;
case ffmpeg.AV_LOG_WARNING: case AVLog.Warning:
Logger.Warning?.Print(LogClass.FFmpeg, line); Logger.Warning?.Print(LogClass.FFmpeg, line);
break; break;
case ffmpeg.AV_LOG_INFO: case AVLog.Info:
Logger.Info?.Print(LogClass.FFmpeg, line); Logger.Info?.Print(LogClass.FFmpeg, line);
break; break;
case ffmpeg.AV_LOG_VERBOSE: case AVLog.Verbose:
case ffmpeg.AV_LOG_DEBUG: case AVLog.Debug:
case ffmpeg.AV_LOG_TRACE:
Logger.Debug?.Print(LogClass.FFmpeg, line); Logger.Debug?.Print(LogClass.FFmpeg, line);
break; break;
case AVLog.Trace:
Logger.Trace?.Print(LogClass.FFmpeg, line);
break;
} }
} }
public int DecodeFrame(Surface output, ReadOnlySpan<byte> bitstream) public int DecodeFrame(Surface output, ReadOnlySpan<byte> bitstream)
{ {
ffmpeg.av_frame_unref(output.Frame); FFmpegApi.av_frame_unref(output.Frame);
int result; int result;
int gotFrame; int gotFrame;
fixed (byte* ptr = bitstream) fixed (byte* ptr = bitstream)
{ {
_packet->data = ptr; _packet->Data = ptr;
_packet->size = bitstream.Length; _packet->Size = bitstream.Length;
result = _decodeFrame(_context, output.Frame, &gotFrame, _packet); result = _decodeFrame(_context, output.Frame, &gotFrame, _packet);
} }
if (gotFrame == 0) 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. // If the frame was not delivered, it was probably delayed.
// Get the next delayed frame by passing a 0 length packet. // Get the next delayed frame by passing a 0 length packet.
_packet->data = null; _packet->Data = null;
_packet->size = 0; _packet->Size = 0;
result = _decodeFrame(_context, output.Frame, &gotFrame, _packet); result = _decodeFrame(_context, output.Frame, &gotFrame, _packet);
// We need to set B frames to 0 as we already consumed all delayed frames. // 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. // 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) if (gotFrame == 0)
{ {
ffmpeg.av_frame_unref(output.Frame); FFmpegApi.av_frame_unref(output.Frame);
return -1; return -1;
} }
@ -172,14 +159,14 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg
{ {
fixed (AVPacket** ppPacket = &_packet) 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) fixed (AVCodecContext** ppContext = &_context)
{ {
ffmpeg.avcodec_free_context(ppContext); FFmpegApi.avcodec_free_context(ppContext);
} }
} }
} }

View File

@ -1,4 +1,4 @@
using FFmpeg.AutoGen; using Ryujinx.Graphics.Nvdec.FFmpeg.Native;
using Ryujinx.Graphics.Video; using Ryujinx.Graphics.Video;
using System; using System;

View File

@ -0,0 +1,25 @@
using System;
namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
{
struct AVCodec
{
#pragma warning disable CS0649
public unsafe byte* Name;
public unsafe byte* LongName;
public int Type;
public AVCodecID Id;
public int Capabilities;
public byte MaxLowRes;
public unsafe AVRational* SupportedFramerates;
public IntPtr PixFmts;
public IntPtr SupportedSamplerates;
public IntPtr SampleFmts;
// Deprecated
public unsafe ulong* ChannelLayouts;
public unsafe IntPtr PrivClass;
public IntPtr Profiles;
public unsafe byte* WrapperName;
#pragma warning restore CS0649
}
}

View File

@ -0,0 +1,171 @@
using Ryujinx.Common.Memory;
using System;
namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
{
struct AVCodecContext
{
#pragma warning disable CS0649
public unsafe IntPtr AvClass;
public int LogLevelOffset;
public int CodecType;
public unsafe AVCodecLegacy* Codec;
public AVCodecID CodecId;
public uint CodecTag;
public IntPtr PrivData;
public IntPtr Internal;
public IntPtr Opaque;
public long BitRate;
public int BitRateTolerance;
public int GlobalQuality;
public int CompressionLevel;
public int Flags;
public int Flags2;
public IntPtr ExtraData;
public int ExtraDataSize;
public AVRational TimeBase;
public int TicksPerFrame;
public int Delay;
public int Width;
public int Height;
public int CodedWidth;
public int CodedHeight;
public int GopSize;
public int PixFmt;
public IntPtr DrawHorizBand;
public IntPtr GetFormat;
public int MaxBFrames;
public float BQuantFactor;
public float BQuantOffset;
public int HasBFrames;
public float IQuantFactor;
public float IQuantOffset;
public float LumiMasking;
public float TemporalCplxMasking;
public float SpatialCplxMasking;
public float PMasking;
public float DarkMasking;
public int SliceCount;
public IntPtr SliceOffset;
public AVRational SampleAspectRatio;
public int MeCmp;
public int MeSubCmp;
public int MbCmp;
public int IldctCmp;
public int DiaSize;
public int LastPredictorCount;
public int MePreCmp;
public int PreDiaSize;
public int MeSubpelQuality;
public int MeRange;
public int SliceFlags;
public int MbDecision;
public IntPtr IntraMatrix;
public IntPtr InterMatrix;
public int IntraDcPrecision;
public int SkipTop;
public int SkipBottom;
public int MbLmin;
public int MbLmax;
public int BidirRefine;
public int KeyintMin;
public int Refs;
public int Mv0Threshold;
public int ColorPrimaries;
public int ColorPrc;
public int Colorspace;
public int ColorRange;
public int ChromaSampleLocation;
public int Slices;
public int FieldOrder;
public int SampleRate;
public int Channels;
public int SampleFmt;
public int FrameSize;
public int FrameNumber;
public int BlockAlign;
public int CutOff;
public ulong ChannelLayout;
public ulong RequestChannelLayout;
public int AudioServiceType;
public int RequestSampleFmt;
public IntPtr GetBuffer2;
public float QCompress;
public float QBlur;
public int QMin;
public int QMax;
public int MaxQdiff;
public int RcBufferSize;
public int RcOverrideCount;
public IntPtr RcOverride;
public long RcMaxRate;
public long RcMinRate;
public float RcMax_available_vbv_use;
public float RcMin_vbv_overflow_use;
public int RcInitialBufferOccupancy;
public int Trellis;
public IntPtr StatsOut;
public IntPtr StatsIn;
public int WorkaroundBugs;
public int StrictStdCompliance;
public int ErrorConcealment;
public int Debug;
public int ErrRecognition;
public long ReorderedOpaque;
public IntPtr HwAccel;
public IntPtr HwAccelContext;
public Array8<ulong> Error;
public int DctAlgo;
public int IdctAlgo;
public int BitsPerCodedSample;
public int BitsPerRawSample;
public int LowRes;
public int ThreadCount;
public int ThreadType;
public int ActiveThreadType;
public int ThreadSafeCallbacks;
public IntPtr Execute;
public IntPtr Execute2;
public int NsseWeight;
public int Profile;
public int Level;
public int SkipLoopFilter;
public int SkipIdct;
public int SkipFrame;
public IntPtr SubtitleHeader;
public int SubtitleHeaderSize;
public int InitialPadding;
public AVRational Framerate;
public int SwPixFmt;
public AVRational PktTimebase;
public IntPtr CodecDescriptor;
public long PtsCorrectionNumFaultyPts;
public long PtsCorrectionNumFaultyDts;
public long PtsCorrectionLastPts;
public long PtsCorrectionLastDts;
public IntPtr SubCharenc;
public int SubCharencMode;
public int SkipAlpha;
public int SeekPreroll;
public int DebugMv;
public IntPtr ChromaIntraMatrix;
public IntPtr DumpSeparator;
public IntPtr CodecWhitelist;
public uint Properties;
public IntPtr CodedSideData;
public int NbCodedSideData;
public IntPtr HwFramesCtx;
public int SubTextFormat;
public int TrailingPadding;
public long MaxPixels;
public IntPtr HwDeviceCtx;
public int HwAccelFlags;
public int applyCropping;
public int ExtraHwFrames;
public int DiscardDamagedPercentage;
public long MaxSamples;
public int ExportSideData;
public IntPtr GetEncodeBuffer;
#pragma warning restore CS0649
}
}

View File

@ -0,0 +1,8 @@
namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
{
enum AVCodecID
{
AV_CODEC_ID_H264 = 27,
AV_CODEC_ID_VP8 = 139,
}
}

View File

@ -0,0 +1,26 @@
using System;
namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
{
struct AVCodecLegacy
{
#pragma warning disable CS0649
public unsafe byte* Name;
public unsafe byte* LongName;
public int Type;
public AVCodecID Id;
public int Capabilities;
public byte MaxLowRes;
public unsafe AVRational* SupportedFramerates;
public IntPtr PixFmts;
public IntPtr SupportedSamplerates;
public IntPtr SampleFmts;
// Deprecated
public unsafe ulong* ChannelLayouts;
public unsafe IntPtr PrivClass;
public IntPtr Profiles;
public unsafe byte* WrapperName;
public IntPtr ChLayouts;
#pragma warning restore CS0649
}
}

View File

@ -0,0 +1,37 @@
using Ryujinx.Common.Memory;
using System;
namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
{
struct AVFrame
{
#pragma warning disable CS0649
public Array8<IntPtr> Data;
public Array8<int> LineSize;
public IntPtr ExtendedData;
public int Width;
public int Height;
public int NumSamples;
public int Format;
public int KeyFrame;
public int PictureType;
public AVRational SampleAspectRatio;
public long Pts;
public long PktDts;
public AVRational TimeBase;
public int CodedPictureNumber;
public int DisplayPictureNumber;
public int Quality;
public IntPtr Opaque;
public int RepeatPicture;
public int InterlacedFrame;
public int TopFieldFirst;
public int PaletteHasChanged;
public long ReorderedOpaque;
public int SampleRate;
public ulong ChannelLayout;
#pragma warning restore CS0649
// NOTE: There is more after, but the layout kind of changed a bit and we don't need more than this. This is safe as we only manipulate this behind a reference.
}
}

View File

@ -0,0 +1,15 @@
namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
{
enum AVLog
{
Panic = 0,
Fatal = 8,
Error = 16,
Warning = 24,
Info = 32,
Verbose = 40,
Debug = 48,
Trace = 56,
MaxOffset = 64
}
}

View File

@ -0,0 +1,26 @@
using System;
using AVBufferRef = System.IntPtr;
namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
{
struct AVPacket
{
#pragma warning disable CS0649
public unsafe AVBufferRef *Buf;
public long Pts;
public long Dts;
public unsafe byte* Data;
public int Size;
public int StreamIndex;
public int Flags;
public IntPtr SizeData;
public int SizeDataElems;
public long Duration;
public long Position;
public IntPtr Opaque;
public unsafe AVBufferRef *OpaqueRef;
public AVRational TimeBase;
#pragma warning restore CS0649
}
}

View File

@ -0,0 +1,8 @@
namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
{
public struct AVRational
{
public int Numerator;
public int Denominator;
}
}

View File

@ -0,0 +1,23 @@
using System;
namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
{
struct FFCodec
{
public unsafe delegate int AVCodec_decode(AVCodecContext* avctx, void* outdata, int* got_frame_ptr, AVPacket* avpkt);
#pragma warning disable CS0649
public AVCodec Base;
public int CapsInternalOrCbType;
public int PrivDataSize;
public IntPtr UpdateThreadContext;
public IntPtr UpdateThreadContextForUser;
public IntPtr Defaults;
public IntPtr InitStaticData;
public IntPtr Init;
public IntPtr CodecCallback;
#pragma warning restore CS0649
// NOTE: There is more after, but the layout kind of changed a bit and we don't need more than this. This is safe as we only manipulate this behind a reference.
}
}

View File

@ -0,0 +1,23 @@
using System;
namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
{
struct FFCodecLegacy<T> where T: struct
{
#pragma warning disable CS0649
public T Base;
public uint CapsInternalOrCbType;
public int PrivDataSize;
public IntPtr UpdateThreadContext;
public IntPtr UpdateThreadContextForUser;
public IntPtr Defaults;
public IntPtr InitStaticData;
public IntPtr Init;
public IntPtr EncodeSub;
public IntPtr Encode2;
public IntPtr Decode;
#pragma warning restore CS0649
// NOTE: There is more after, but the layout kind of changed a bit and we don't need more than this. This is safe as we only manipulate this behind a reference.
}
}

View File

@ -0,0 +1,129 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
{
static class FFmpegApi
{
public const string AvCodecLibraryName = "avcodec";
public const string AvUtilLibraryName = "avutil";
private static readonly Dictionary<string, (int, int)> _librariesWhitelist = new Dictionary<string, (int, int)>
{
{ AvCodecLibraryName, (58, 59) },
{ AvUtilLibraryName, (56, 57) }
};
private static string FormatLibraryNameForCurrentOs(string libraryName, int version)
{
if (OperatingSystem.IsWindows())
{
return $"{libraryName}-{version}.dll";
}
else if (OperatingSystem.IsLinux())
{
return $"lib{libraryName}.so.{version}";
}
else if (OperatingSystem.IsMacOS())
{
return $"lib{libraryName}.{version}.dylib";
}
else
{
throw new NotImplementedException($"Unsupported OS for FFmpeg: {RuntimeInformation.RuntimeIdentifier}");
}
}
private static bool TryLoadWhitelistedLibrary(string libraryName, Assembly assembly, DllImportSearchPath? searchPath, out IntPtr handle)
{
handle = IntPtr.Zero;
if (_librariesWhitelist.TryGetValue(libraryName, out var value))
{
(int minVersion, int maxVersion) = value;
for (int version = minVersion; version <= maxVersion; version++)
{
if (NativeLibrary.TryLoad(FormatLibraryNameForCurrentOs(libraryName, version), assembly, searchPath, out handle))
{
return true;
}
}
}
return false;
}
static FFmpegApi()
{
NativeLibrary.SetDllImportResolver(typeof(FFmpegApi).Assembly, (name, assembly, path) =>
{
IntPtr handle;
if (name == AvUtilLibraryName && TryLoadWhitelistedLibrary(AvUtilLibraryName, assembly, path, out handle))
{
return handle;
}
else if (name == AvCodecLibraryName && TryLoadWhitelistedLibrary(AvCodecLibraryName, assembly, path, out handle))
{
return handle;
}
return IntPtr.Zero;
});
}
public unsafe delegate void av_log_set_callback_callback(void* a0, AVLog level, [MarshalAs(UnmanagedType.LPUTF8Str)] string a2, byte* a3);
[DllImport(AvUtilLibraryName, CallingConvention = CallingConvention.Cdecl)]
internal static unsafe extern AVFrame* av_frame_alloc();
[DllImport(AvUtilLibraryName, CallingConvention = CallingConvention.Cdecl)]
internal static unsafe extern void av_frame_unref(AVFrame* frame);
[DllImport(AvUtilLibraryName, CallingConvention = CallingConvention.Cdecl)]
internal static unsafe extern void av_free(AVFrame* frame);
[DllImport(AvUtilLibraryName, CallingConvention = CallingConvention.Cdecl)]
internal static unsafe extern void av_log_set_level(AVLog level);
[DllImport(AvUtilLibraryName, CallingConvention = CallingConvention.Cdecl)]
internal static unsafe extern void av_log_set_callback(av_log_set_callback_callback callback);
[DllImport(AvUtilLibraryName, CallingConvention = CallingConvention.Cdecl)]
internal static unsafe extern AVLog av_log_get_level();
[DllImport(AvUtilLibraryName, CallingConvention = CallingConvention.Cdecl)]
internal static unsafe extern void av_log_format_line(void* ptr, AVLog level, [MarshalAs(UnmanagedType.LPUTF8Str)] string fmt, byte* vl, byte* line, int lineSize, int* printPrefix);
[DllImport(AvCodecLibraryName, CallingConvention = CallingConvention.Cdecl)]
internal static unsafe extern AVCodec* avcodec_find_decoder(AVCodecID id);
[DllImport(AvCodecLibraryName, CallingConvention = CallingConvention.Cdecl)]
internal static unsafe extern AVCodecContext* avcodec_alloc_context3(AVCodec* codec);
[DllImport(AvCodecLibraryName, CallingConvention = CallingConvention.Cdecl)]
internal static unsafe extern int avcodec_open2(AVCodecContext* avctx, AVCodec* codec, void **options);
[DllImport(AvCodecLibraryName, CallingConvention = CallingConvention.Cdecl)]
internal static unsafe extern int avcodec_close(AVCodecContext* avctx);
[DllImport(AvCodecLibraryName, CallingConvention = CallingConvention.Cdecl)]
internal static unsafe extern void avcodec_free_context(AVCodecContext** avctx);
[DllImport(AvCodecLibraryName, CallingConvention = CallingConvention.Cdecl)]
internal static unsafe extern AVPacket* av_packet_alloc();
[DllImport(AvCodecLibraryName, CallingConvention = CallingConvention.Cdecl)]
internal static unsafe extern void av_packet_unref(AVPacket* pkt);
[DllImport(AvCodecLibraryName, CallingConvention = CallingConvention.Cdecl)]
internal static unsafe extern void av_packet_free(AVPacket** pkt);
[DllImport(AvCodecLibraryName, CallingConvention = CallingConvention.Cdecl)]
internal static unsafe extern int avcodec_version();
}
}

View File

@ -1,14 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="FFmpeg.AutoGen" Version="4.4.1" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" /> <ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.Video\Ryujinx.Graphics.Video.csproj" /> <ProjectReference Include="..\Ryujinx.Graphics.Video\Ryujinx.Graphics.Video.csproj" />

View File

@ -1,4 +1,4 @@
using FFmpeg.AutoGen; using Ryujinx.Graphics.Nvdec.FFmpeg.Native;
using Ryujinx.Graphics.Video; using Ryujinx.Graphics.Video;
using System; using System;
@ -11,31 +11,31 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg
public int RequestedWidth { get; } public int RequestedWidth { get; }
public int RequestedHeight { get; } public int RequestedHeight { get; }
public Plane YPlane => new Plane((IntPtr)Frame->data[0], Stride * Height); public Plane YPlane => new Plane((IntPtr)Frame->Data[0], Stride * Height);
public Plane UPlane => new Plane((IntPtr)Frame->data[1], UvStride * UvHeight); public Plane UPlane => new Plane((IntPtr)Frame->Data[1], UvStride * UvHeight);
public Plane VPlane => new Plane((IntPtr)Frame->data[2], UvStride * UvHeight); public Plane VPlane => new Plane((IntPtr)Frame->Data[2], UvStride * UvHeight);
public FrameField Field => Frame->interlaced_frame != 0 ? FrameField.Interlaced : FrameField.Progressive; public FrameField Field => Frame->InterlacedFrame != 0 ? FrameField.Interlaced : FrameField.Progressive;
public int Width => Frame->width; public int Width => Frame->Width;
public int Height => Frame->height; public int Height => Frame->Height;
public int Stride => Frame->linesize[0]; public int Stride => Frame->LineSize[0];
public int UvWidth => (Width + 1) >> 1; public int UvWidth => (Width + 1) >> 1;
public int UvHeight => (Height + 1) >> 1; public int UvHeight => (Height + 1) >> 1;
public int UvStride => Frame->linesize[1]; public int UvStride => Frame->LineSize[1];
public Surface(int width, int height) public Surface(int width, int height)
{ {
RequestedWidth = width; RequestedWidth = width;
RequestedHeight = height; RequestedHeight = height;
Frame = ffmpeg.av_frame_alloc(); Frame = FFmpegApi.av_frame_alloc();
} }
public void Dispose() public void Dispose()
{ {
ffmpeg.av_frame_unref(Frame); FFmpegApi.av_frame_unref(Frame);
ffmpeg.av_free(Frame); FFmpegApi.av_free(Frame);
} }
} }
} }

View File

@ -1,4 +1,4 @@
using FFmpeg.AutoGen; using Ryujinx.Graphics.Nvdec.FFmpeg.Native;
using Ryujinx.Graphics.Video; using Ryujinx.Graphics.Video;
using System; using System;

View File

@ -10,7 +10,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="4.4.0-build7" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" /> <PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build10" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -19,7 +19,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="GtkSharp" Version="3.22.25.128" /> <PackageReference Include="GtkSharp" Version="3.22.25.128" />
<PackageReference Include="GtkSharp.Dependencies" Version="1.1.1" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" /> <PackageReference Include="GtkSharp.Dependencies" Version="1.1.1" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="4.4.0-build9" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" /> <PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.1-build10" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
<PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" /> <PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
<PackageReference Include="OpenTK.Graphics" Version="4.7.2" /> <PackageReference Include="OpenTK.Graphics" Version="4.7.2" />
<PackageReference Include="SPB" Version="0.0.4-build17" /> <PackageReference Include="SPB" Version="0.0.4-build17" />