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  }