FFmpegApi.cs
1 using System; 2 using System.Collections.Generic; 3 using System.Reflection; 4 using System.Runtime.InteropServices; 5 6 namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native 7 { 8 static partial class FFmpegApi 9 { 10 public const string AvCodecLibraryName = "avcodec"; 11 public const string AvUtilLibraryName = "avutil"; 12 13 private static readonly Dictionary<string, (int, int)> _librariesWhitelist = new() 14 { 15 { AvCodecLibraryName, (58, 59) }, 16 { AvUtilLibraryName, (56, 57) }, 17 }; 18 19 private static string FormatLibraryNameForCurrentOs(string libraryName, int version) 20 { 21 if (OperatingSystem.IsWindows()) 22 { 23 return $"{libraryName}-{version}.dll"; 24 } 25 else if (OperatingSystem.IsLinux()) 26 { 27 return $"lib{libraryName}.so.{version}"; 28 } 29 else if (OperatingSystem.IsMacOS()) 30 { 31 return $"lib{libraryName}.{version}.dylib"; 32 } 33 else 34 { 35 throw new NotImplementedException($"Unsupported OS for FFmpeg: {RuntimeInformation.RuntimeIdentifier}"); 36 } 37 } 38 39 40 private static bool TryLoadWhitelistedLibrary(string libraryName, Assembly assembly, DllImportSearchPath? searchPath, out IntPtr handle) 41 { 42 handle = IntPtr.Zero; 43 44 if (_librariesWhitelist.TryGetValue(libraryName, out var value)) 45 { 46 (int minVersion, int maxVersion) = value; 47 48 for (int version = maxVersion; version >= minVersion; version--) 49 { 50 if (NativeLibrary.TryLoad(FormatLibraryNameForCurrentOs(libraryName, version), assembly, searchPath, out handle)) 51 { 52 return true; 53 } 54 } 55 } 56 57 return false; 58 } 59 60 static FFmpegApi() 61 { 62 NativeLibrary.SetDllImportResolver(typeof(FFmpegApi).Assembly, (name, assembly, path) => 63 { 64 65 if (name == AvUtilLibraryName && TryLoadWhitelistedLibrary(AvUtilLibraryName, assembly, path, out nint handle)) 66 { 67 return handle; 68 } 69 else if (name == AvCodecLibraryName && TryLoadWhitelistedLibrary(AvCodecLibraryName, assembly, path, out handle)) 70 { 71 return handle; 72 } 73 74 return IntPtr.Zero; 75 }); 76 } 77 78 public unsafe delegate void av_log_set_callback_callback(void* a0, AVLog level, [MarshalAs(UnmanagedType.LPUTF8Str)] string a2, byte* a3); 79 80 [LibraryImport(AvUtilLibraryName)] 81 internal static unsafe partial AVFrame* av_frame_alloc(); 82 83 [LibraryImport(AvUtilLibraryName)] 84 internal static unsafe partial void av_frame_unref(AVFrame* frame); 85 86 [LibraryImport(AvUtilLibraryName)] 87 internal static unsafe partial void av_free(AVFrame* frame); 88 89 [LibraryImport(AvUtilLibraryName)] 90 internal static unsafe partial void av_log_set_level(AVLog level); 91 92 [LibraryImport(AvUtilLibraryName)] 93 internal static unsafe partial void av_log_set_callback(av_log_set_callback_callback callback); 94 95 [LibraryImport(AvUtilLibraryName)] 96 internal static unsafe partial AVLog av_log_get_level(); 97 98 [LibraryImport(AvUtilLibraryName)] 99 internal static unsafe partial void av_log_format_line(void* ptr, AVLog level, [MarshalAs(UnmanagedType.LPUTF8Str)] string fmt, byte* vl, byte* line, int lineSize, int* printPrefix); 100 101 [LibraryImport(AvCodecLibraryName)] 102 internal static unsafe partial AVCodec* avcodec_find_decoder(AVCodecID id); 103 104 [LibraryImport(AvCodecLibraryName)] 105 internal static unsafe partial AVCodecContext* avcodec_alloc_context3(AVCodec* codec); 106 107 [LibraryImport(AvCodecLibraryName)] 108 internal static unsafe partial int avcodec_open2(AVCodecContext* avctx, AVCodec* codec, void** options); 109 110 [LibraryImport(AvCodecLibraryName)] 111 internal static unsafe partial int avcodec_close(AVCodecContext* avctx); 112 113 [LibraryImport(AvCodecLibraryName)] 114 internal static unsafe partial void avcodec_free_context(AVCodecContext** avctx); 115 116 [LibraryImport(AvCodecLibraryName)] 117 internal static unsafe partial AVPacket* av_packet_alloc(); 118 119 [LibraryImport(AvCodecLibraryName)] 120 internal static unsafe partial void av_packet_unref(AVPacket* pkt); 121 122 [LibraryImport(AvCodecLibraryName)] 123 internal static unsafe partial void av_packet_free(AVPacket** pkt); 124 125 [LibraryImport(AvCodecLibraryName)] 126 internal static unsafe partial int avcodec_version(); 127 } 128 }