diff --git a/src/LibVLCSharp/Shared/LibVLC.cs b/src/LibVLCSharp/Shared/LibVLC.cs index 3bfd7a66..c7a7658a 100644 --- a/src/LibVLCSharp/Shared/LibVLC.cs +++ b/src/LibVLCSharp/Shared/LibVLC.cs @@ -189,6 +189,38 @@ internal struct Native #endif } + /// + /// Create and initialize a libvlc instance using a object. + /// This constructor allows for strongly-typed, flexible configuration of libvlc command-line parameters, + /// including platform-specific defaults, logging verbosity, resamplers, caching, and rendering settings. + /// LibVLC may create threads. Therefore, any thread-unsafe process + /// initialization must be performed before calling libvlc_new(). In particular: + /// - setlocale() and textdomain(), + /// - setenv(), unsetenv(), and putenv(), + /// - On Microsoft Windows, SetErrorMode(). + /// On POSIX systems, certain signals must be handled properly (e.g., SIGCHLD must not be ignored). + /// This will throw a if the native libvlc libraries cannot be found or loaded. + /// It may also throw a if the LibVLC and LibVLCSharp major versions do not match. + /// See https://code.videolan.org/videolan/LibVLCSharp/-/blob/master/docs/versioning.md for more info about the versioning strategy. + /// + /// + /// var options = new LibVLCOptionsBuilder() + /// .EnableDebugLogs() + /// .SetAudioResampler("soxr") + /// .Build(); + /// + /// using var libvlc = new LibVLC(options); + /// + /// + /// + /// An instance of containing libvlc configuration parameters. + + public LibVLC(LibVLCOptions options) + : base(() => MarshalUtils.CreateWithOptions(options.Options, Native.LibVLCNew), Native.LibVLCRelease) + { + _gcHandle = GCHandle.Alloc(this); + } + /// /// Create and initialize a libvlc instance. /// This functions accept a list of "command line" arguments similar to the @@ -239,10 +271,8 @@ internal struct Native /// list of arguments, in the form "--option=value" /// the libvlc instance or NULL in case of error public LibVLC(params string[] options) - : base(() => MarshalUtils.CreateWithOptions(PatchOptions(options), Native.LibVLCNew), Native.LibVLCRelease) - { - _gcHandle = GCHandle.Alloc(this); - } + : this(new LibVLCOptionsBuilder().AddOptions(options).Build()) { } + /// /// Create and initialize a libvlc instance. @@ -286,31 +316,11 @@ public LibVLC(params string[] options) /// enable verbose debug logs /// list of arguments (should be NULL) public LibVLC(bool enableDebugLogs, params string[] options) - : base(() => MarshalUtils.CreateWithOptions(PatchOptions(options, enableDebugLogs), Native.LibVLCNew), Native.LibVLCRelease) - { - _gcHandle = GCHandle.Alloc(this); - } - - /// - /// Make dirty hacks to include necessary defaults on some platforms. - /// - /// The options given by the user - /// enable debug logs - /// The patched options - static string[] PatchOptions(string[] options, bool enableDebugLogs = false) - { - if(enableDebugLogs) - { - options = options.Concat(new[] { "--verbose=2" }).ToArray(); - } -#if UWP - return options.Concat(new[] {"--aout=winstore", "--audio-resampler=speex_resampler"}).ToArray(); -#elif ANDROID - return options.Concat(new[] {"--audio-resampler=soxr"}).ToArray(); -#else - return options; -#endif - } + : this(new LibVLCOptionsBuilder() + .AddOptions(options) + .EnableDebugLogs() + .Build()) + { } /// /// Dispose of this libvlc instance diff --git a/src/LibVLCSharp/Shared/LibVLCOptions.cs b/src/LibVLCSharp/Shared/LibVLCOptions.cs new file mode 100644 index 00000000..1f95ebd4 --- /dev/null +++ b/src/LibVLCSharp/Shared/LibVLCOptions.cs @@ -0,0 +1,219 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace LibVLCSharp.Shared +{ + /// + /// Fluent builder for constructing LibVLC options. + /// Mirrors many common libvlc command line parameters. + /// See https://wiki.videolan.org/VLC_command-line_help for more details about available parameters. + /// OPTIONS ARE PROVIDED AS-IS, WITHOUT ANY GUARANTEE OF FORWARD/BACKWARD COMPATIBILITY. + /// + public class LibVLCOptionsBuilder + { + private readonly List _options = new(); + private bool _includeDebugLogs = false; + +#if UWP || ANDROID + private bool _audioResamplerOverridden = false; +#endif + + /// + /// Enables verbose debug logging by adding "--verbose=2". + /// + public LibVLCOptionsBuilder EnableDebugLogs() + { + _includeDebugLogs = true; + return this; + } + + /// + /// Sets the verbosity level of the log output. + /// + /// Verbosity level (e.g. 0=errors only, 2=debug). + public LibVLCOptionsBuilder SetVerbosity(int level) + { + _options.Add($"--verbose={level}"); + return this; + } + + /// + /// Sets the audio resampler module. + /// + /// The name of the resampler (e.g. speex_resampler, soxr). + public LibVLCOptionsBuilder SetAudioResampler(string resampler) + { + _options.Add($"--audio-resampler={resampler}"); +#if UWP || ANDROID + _audioResamplerOverridden = true; +#endif + return this; + } + +#if UWP || ANDROID + /// + /// Disables the default resampler for the current platform. + /// + public LibVLCOptionsBuilder DisableDefaultResampler() + { + _audioResamplerOverridden = true; + return this; + } +#endif + + /// + /// Sets the audio output module (e.g. "--aout=directsound"). + /// + /// The audio output module name. + public LibVLCOptionsBuilder SetAudioOutput(string output) + { + _options.Add($"--aout={output}"); + return this; + } + + /// + /// Disables video output. + /// + public LibVLCOptionsBuilder DisableVideo() + { + _options.Add("--no-video"); + return this; + } + + /// + /// Disables audio output. + /// + public LibVLCOptionsBuilder DisableAudio() + { + _options.Add("--no-audio"); + return this; + } + + /// + /// Sets the network caching value in milliseconds. + /// + /// Caching delay in ms (e.g. 300). + public LibVLCOptionsBuilder SetNetworkCaching(int milliseconds) + { + _options.Add($"--network-caching={milliseconds}"); + return this; + } + + /// + /// Sets the file caching value in milliseconds. + /// + /// Caching delay in ms (e.g. 300). + public LibVLCOptionsBuilder SetFileCaching(int milliseconds) + { + _options.Add($"--file-caching={milliseconds}"); + return this; + } + + /// + /// Enables hardware-accelerated decoding using the specified method. + /// + /// Decoding method (e.g. dxva2, vaapi, d3d11va). + public LibVLCOptionsBuilder EnableHardwareDecoding(string method) + { + _options.Add($"--avcodec-hw={method}"); + return this; + } + + /// + /// Enables dropping of late video frames. + /// + public LibVLCOptionsBuilder DropLateFrames() + { + _options.Add("--drop-late-frames"); + return this; + } + + /// + /// Enables frame skipping. + /// + public LibVLCOptionsBuilder SkipFrames() + { + _options.Add("--skip-frames"); + return this; + } + + /// + /// Enables or disables use of Xlib. + /// + /// True to enable Xlib, false to disable. + public LibVLCOptionsBuilder UseXlib(bool enabled) + { + _options.Add(enabled ? "--xlib" : "--no-xlib"); + return this; + } + + /// + /// Adds a custom libvlc option. + /// + /// The command-line option to add. + public LibVLCOptionsBuilder AddOption(string option) + { + _options.Add(option); + return this; + } + + /// + /// Adds multiple custom libvlc options. + /// + /// The options to add. + public LibVLCOptionsBuilder AddOptions(IEnumerable options) + { + _options.AddRange(options); + return this; + } + + + /// + /// Builds the final LibVLCOptions object including any platform-specific defaults. + /// + public LibVLCOptions Build() + { + var finalOptions = _options; + + if (_includeDebugLogs) + finalOptions.Add("--verbose=2"); + +#if UWP + finalOptions.Add("--aout=winstore"); + if (!_audioResamplerOverridden) + finalOptions.Add("--audio-resampler=speex_resampler"); +#elif ANDROID + if (!_audioResamplerOverridden) + finalOptions.Add("--audio-resampler=soxr"); +#endif + + return new LibVLCOptions(finalOptions); + } + } + + /// + /// Represents the finalized LibVLC options as an array of command-line arguments. + /// + public class LibVLCOptions + { + /// + /// Gets the collection of command-line arguments. + /// + public string[] Options { get; } + + /// + /// Initializes a new instance of LibVLCOptions with the specified options. + /// + /// The options to include. + public LibVLCOptions(IEnumerable? options) + { + Options = options?.ToArray() ?? new string[0]; + } + + /// + /// Gets an empty LibVLCOptions instance. + /// + public static LibVLCOptions Empty => new LibVLCOptions(new string[0]); + } +}