using System.ComponentModel;
using System.Runtime.InteropServices;
using Bmp.Core.FFMpeg.CsCorePorts.FFMpegWrap.Interops;
namespace Bmp.Core.FFMpeg.CsCorePorts.FFMpegWrap;
///
/// Contains some utilities for working with ffmpeg.
///
public static class FfmpegUtils
{
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
private static readonly FfmpegCalls.LogCallback LogCallback;
private static readonly FfmpegCalls.LogCallback DefaultLogCallback;
private static readonly object LockObj = new object();
///
/// Occurs when a ffmpeg log entry was received.
///
public static event EventHandler FfmpegLogReceived;
///
/// Occurs when the location of the native FFmpeg binaries has get resolved.
/// Note: This is currently only available for Windows Platforms.
///
public static event EventHandler ResolveFfmpegAssemblyLocation;
static unsafe FfmpegUtils()
{
LogCallback = OnLogMessage;
DefaultLogCallback = FfmpegCalls.GetDefaultLogCallback();
FfmpegCalls.SetLogCallback(LogCallback);
}
///
/// Gets the output formats.
///
/// All supported output formats.
public static IEnumerable GetOutputFormats()
{
var outputFormats = FfmpegCalls.GetOutputFormats();
return outputFormats.Select(format => new Format(format));
}
///
/// Gets the input formats.
///
/// All supported input formats.
public static IEnumerable GetInputFormats()
{
var inputFormats = FfmpegCalls.GetInputFormats();
return inputFormats.Select(format => new Format(format));
}
///
/// Gets or sets the log level.
///
///
/// The log level.
///
/// value
public static LogLevel LogLevel
{
get { return FfmpegCalls.GetLogLevel(); }
set
{
if ((int)value < (int)LogLevel.Quit || (int)value > (int)LogLevel.Debug || (int)value % 8 != 0)
throw new InvalidEnumArgumentException("value", (int)value, typeof(LogLevel));
FfmpegCalls.SetLogLevel(value);
}
}
///
/// Gets or sets a value indicating whether log entries should be passed to the default ffmpeg logger.
///
///
/// true if log messages should be passed to the default ffmpeg logger; otherwise, false.
///
public static bool LogToDefaultLogger { get; set; }
private static unsafe void OnLogMessage(void* ptr, int level, byte* fmt, nint vl)
{
lock (LockObj)
{
if (level >= 0)
{
level &= 0xFF;
}
if (level > (int)LogLevel)
return;
if (LogToDefaultLogger)
{
DefaultLogCallback(ptr, level, fmt, vl);
}
var eventHandler = FfmpegLogReceived;
if (eventHandler != null)
{
AVClass? avClass = null;
AVClass? parentLogContext = null;
AVClass** ppParent = default;
if (ptr != null)
{
avClass = **(AVClass**)ptr;
if (avClass.Value.parent_log_context_offset != 0)
{
ppParent = *(AVClass***)((byte*)ptr + avClass.Value.parent_log_context_offset);
if (ppParent != null && *ppParent != null)
{
parentLogContext = **ppParent;
}
}
}
var printPrefix = 1;
var line = FfmpegCalls.FormatLine(ptr, level, Marshal.PtrToStringAnsi((nint)fmt), vl, ref printPrefix);
eventHandler(null,
new FfmpegLogReceivedEventArgs(avClass, parentLogContext, (LogLevel)level, line, ptr, ppParent));
}
}
}
internal static DirectoryInfo FindFfmpegDirectory(PlatformID platform)
{
var resolveEvent = ResolveFfmpegAssemblyLocation;
var eventArgs = new ResolveFfmpegAssemblyLocationEventArgs(platform);
if (resolveEvent != null)
resolveEvent(null, eventArgs);
return eventArgs.FfmpegDirectory;
}
}