FfmpegUtils.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. using System.ComponentModel;
  2. using System.Runtime.InteropServices;
  3. using Bmp.Core.FFMpeg.CsCorePorts.FFMpegWrap.Interops;
  4. namespace Bmp.Core.FFMpeg.CsCorePorts.FFMpegWrap;
  5. /// <summary>
  6. /// Contains some utilities for working with ffmpeg.
  7. /// </summary>
  8. public static class FfmpegUtils
  9. {
  10. // ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
  11. private static readonly FfmpegCalls.LogCallback LogCallback;
  12. private static readonly FfmpegCalls.LogCallback DefaultLogCallback;
  13. private static readonly object LockObj = new object();
  14. /// <summary>
  15. /// Occurs when a ffmpeg log entry was received.
  16. /// </summary>
  17. public static event EventHandler<FfmpegLogReceivedEventArgs> FfmpegLogReceived;
  18. /// <summary>
  19. /// Occurs when the location of the native FFmpeg binaries has get resolved.
  20. /// Note: This is currently only available for Windows Platforms.
  21. /// </summary>
  22. public static event EventHandler<ResolveFfmpegAssemblyLocationEventArgs> ResolveFfmpegAssemblyLocation;
  23. static unsafe FfmpegUtils()
  24. {
  25. LogCallback = OnLogMessage;
  26. DefaultLogCallback = FfmpegCalls.GetDefaultLogCallback();
  27. FfmpegCalls.SetLogCallback(LogCallback);
  28. }
  29. /// <summary>
  30. /// Gets the output formats.
  31. /// </summary>
  32. /// <returns>All supported output formats.</returns>
  33. public static IEnumerable<Format> GetOutputFormats()
  34. {
  35. var outputFormats = FfmpegCalls.GetOutputFormats();
  36. return outputFormats.Select(format => new Format(format));
  37. }
  38. /// <summary>
  39. /// Gets the input formats.
  40. /// </summary>
  41. /// <returns>All supported input formats.</returns>
  42. public static IEnumerable<Format> GetInputFormats()
  43. {
  44. var inputFormats = FfmpegCalls.GetInputFormats();
  45. return inputFormats.Select(format => new Format(format));
  46. }
  47. /// <summary>
  48. /// Gets or sets the log level.
  49. /// </summary>
  50. /// <value>
  51. /// The log level.
  52. /// </value>
  53. /// <exception cref="InvalidEnumArgumentException">value</exception>
  54. public static LogLevel LogLevel
  55. {
  56. get { return FfmpegCalls.GetLogLevel(); }
  57. set
  58. {
  59. if ((int)value < (int)LogLevel.Quit || (int)value > (int)LogLevel.Debug || (int)value % 8 != 0)
  60. throw new InvalidEnumArgumentException("value", (int)value, typeof(LogLevel));
  61. FfmpegCalls.SetLogLevel(value);
  62. }
  63. }
  64. /// <summary>
  65. /// Gets or sets a value indicating whether log entries should be passed to the default ffmpeg logger.
  66. /// </summary>
  67. /// <value>
  68. /// <c>true</c> if log messages should be passed to the default ffmpeg logger; otherwise, <c>false</c>.
  69. /// </value>
  70. public static bool LogToDefaultLogger { get; set; }
  71. private static unsafe void OnLogMessage(void* ptr, int level, byte* fmt, nint vl)
  72. {
  73. lock (LockObj)
  74. {
  75. if (level >= 0)
  76. {
  77. level &= 0xFF;
  78. }
  79. if (level > (int)LogLevel)
  80. return;
  81. if (LogToDefaultLogger)
  82. {
  83. DefaultLogCallback(ptr, level, fmt, vl);
  84. }
  85. var eventHandler = FfmpegLogReceived;
  86. if (eventHandler != null)
  87. {
  88. AVClass? avClass = null;
  89. AVClass? parentLogContext = null;
  90. AVClass** ppParent = default;
  91. if (ptr != null)
  92. {
  93. avClass = **(AVClass**)ptr;
  94. if (avClass.Value.parent_log_context_offset != 0)
  95. {
  96. ppParent = *(AVClass***)((byte*)ptr + avClass.Value.parent_log_context_offset);
  97. if (ppParent != null && *ppParent != null)
  98. {
  99. parentLogContext = **ppParent;
  100. }
  101. }
  102. }
  103. var printPrefix = 1;
  104. var line = FfmpegCalls.FormatLine(ptr, level, Marshal.PtrToStringAnsi((nint)fmt), vl, ref printPrefix);
  105. eventHandler(null,
  106. new FfmpegLogReceivedEventArgs(avClass, parentLogContext, (LogLevel)level, line, ptr, ppParent));
  107. }
  108. }
  109. }
  110. internal static DirectoryInfo FindFfmpegDirectory(PlatformID platform)
  111. {
  112. var resolveEvent = ResolveFfmpegAssemblyLocation;
  113. var eventArgs = new ResolveFfmpegAssemblyLocationEventArgs(platform);
  114. if (resolveEvent != null)
  115. resolveEvent(null, eventArgs);
  116. return eventArgs.FfmpegDirectory;
  117. }
  118. }