mirror of
https://github.com/Ryujinx/Ryujinx.git
synced 2024-12-18 21:32:01 +00:00
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:
parent
70ec5def9c
commit
c5bddfeab8
19 changed files with 563 additions and 89 deletions
|
@ -28,7 +28,7 @@
|
|||
<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.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="SPB" Version="0.0.4-build17" />
|
||||
<PackageReference Include="SharpZipLib" Version="1.3.3" />
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using FFmpeg.AutoGen;
|
||||
using Ryujinx.Graphics.Nvdec.FFmpeg.Native;
|
||||
using Ryujinx.Graphics.Video;
|
||||
using System;
|
||||
|
||||
|
|
25
Ryujinx.Graphics.Nvdec.FFmpeg/Native/AVCodec.cs
Normal file
25
Ryujinx.Graphics.Nvdec.FFmpeg/Native/AVCodec.cs
Normal 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
|
||||
}
|
||||
}
|
171
Ryujinx.Graphics.Nvdec.FFmpeg/Native/AVCodecContext.cs
Normal file
171
Ryujinx.Graphics.Nvdec.FFmpeg/Native/AVCodecContext.cs
Normal 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
|
||||
}
|
||||
}
|
8
Ryujinx.Graphics.Nvdec.FFmpeg/Native/AVCodecID.cs
Normal file
8
Ryujinx.Graphics.Nvdec.FFmpeg/Native/AVCodecID.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
|
||||
{
|
||||
enum AVCodecID
|
||||
{
|
||||
AV_CODEC_ID_H264 = 27,
|
||||
AV_CODEC_ID_VP8 = 139,
|
||||
}
|
||||
}
|
26
Ryujinx.Graphics.Nvdec.FFmpeg/Native/AVCodecLegacy.cs
Normal file
26
Ryujinx.Graphics.Nvdec.FFmpeg/Native/AVCodecLegacy.cs
Normal 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
|
||||
}
|
||||
}
|
37
Ryujinx.Graphics.Nvdec.FFmpeg/Native/AVFrame.cs
Normal file
37
Ryujinx.Graphics.Nvdec.FFmpeg/Native/AVFrame.cs
Normal 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.
|
||||
}
|
||||
}
|
15
Ryujinx.Graphics.Nvdec.FFmpeg/Native/AVLog.cs
Normal file
15
Ryujinx.Graphics.Nvdec.FFmpeg/Native/AVLog.cs
Normal 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
|
||||
}
|
||||
}
|
26
Ryujinx.Graphics.Nvdec.FFmpeg/Native/AVPacket.cs
Normal file
26
Ryujinx.Graphics.Nvdec.FFmpeg/Native/AVPacket.cs
Normal 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
|
||||
}
|
||||
}
|
8
Ryujinx.Graphics.Nvdec.FFmpeg/Native/AVRational.cs
Normal file
8
Ryujinx.Graphics.Nvdec.FFmpeg/Native/AVRational.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native
|
||||
{
|
||||
public struct AVRational
|
||||
{
|
||||
public int Numerator;
|
||||
public int Denominator;
|
||||
}
|
||||
}
|
23
Ryujinx.Graphics.Nvdec.FFmpeg/Native/FFCodec.cs
Normal file
23
Ryujinx.Graphics.Nvdec.FFmpeg/Native/FFCodec.cs
Normal 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.
|
||||
}
|
||||
}
|
23
Ryujinx.Graphics.Nvdec.FFmpeg/Native/FFCodecLegacy.cs
Normal file
23
Ryujinx.Graphics.Nvdec.FFmpeg/Native/FFCodecLegacy.cs
Normal 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.
|
||||
}
|
||||
}
|
129
Ryujinx.Graphics.Nvdec.FFmpeg/Native/FFmpegApi.cs
Normal file
129
Ryujinx.Graphics.Nvdec.FFmpeg/Native/FFmpegApi.cs
Normal 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();
|
||||
}
|
||||
}
|
|
@ -1,14 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FFmpeg.AutoGen" Version="4.4.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.Graphics.Video\Ryujinx.Graphics.Video.csproj" />
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using FFmpeg.AutoGen;
|
||||
using Ryujinx.Graphics.Nvdec.FFmpeg.Native;
|
||||
using Ryujinx.Graphics.Video;
|
||||
using System;
|
||||
|
||||
|
@ -11,31 +11,31 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg
|
|||
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);
|
||||
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);
|
||||
|
||||
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 Height => Frame->height;
|
||||
public int Stride => Frame->linesize[0];
|
||||
public int Width => Frame->Width;
|
||||
public int Height => Frame->Height;
|
||||
public int Stride => Frame->LineSize[0];
|
||||
public int UvWidth => (Width + 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)
|
||||
{
|
||||
RequestedWidth = width;
|
||||
RequestedHeight = height;
|
||||
|
||||
Frame = ffmpeg.av_frame_alloc();
|
||||
Frame = FFmpegApi.av_frame_alloc();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
ffmpeg.av_frame_unref(Frame);
|
||||
ffmpeg.av_free(Frame);
|
||||
FFmpegApi.av_frame_unref(Frame);
|
||||
FFmpegApi.av_free(Frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using FFmpeg.AutoGen;
|
||||
using Ryujinx.Graphics.Nvdec.FFmpeg.Native;
|
||||
using Ryujinx.Graphics.Video;
|
||||
using System;
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<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>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<ItemGroup>
|
||||
<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="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="OpenTK.Graphics" Version="4.7.2" />
|
||||
<PackageReference Include="SPB" Version="0.0.4-build17" />
|
||||
|
|
Loading…
Reference in a new issue