Media.cs 44.5 KB
Newer Older
1 2
using LibVLCSharp.Shared.Helpers;
using System;
Martin Finkel's avatar
Martin Finkel committed
3
using System.Collections.Concurrent;
Martin Finkel's avatar
Martin Finkel committed
4 5 6 7
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
8 9
using System.Threading;
using System.Threading.Tasks;
Martin Finkel's avatar
Martin Finkel committed
10

11
namespace LibVLCSharp.Shared
Martin Finkel's avatar
Martin Finkel committed
12
{
Martin Finkel's avatar
Martin Finkel committed
13 14 15
    /// <summary>
    /// Media is an abstract representation of a playable media. It can be a network stream or a local video/audio file.
    /// </summary>
16
    public class Media : Internal
Martin Finkel's avatar
Martin Finkel committed
17
    {
Martin Finkel's avatar
Martin Finkel committed
18 19 20
        static readonly ConcurrentDictionary<IntPtr, StreamData> DicStreams = new ConcurrentDictionary<IntPtr, StreamData>();
        static int _streamIndex;
        
21
        internal struct Native
Martin Finkel's avatar
Martin Finkel committed
22
        {
23
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
24
                EntryPoint = "libvlc_media_new_location")]
Martin Finkel's avatar
Martin Finkel committed
25
            internal static extern IntPtr LibVLCMediaNewLocation(IntPtr libVLC, IntPtr mrl);
Martin Finkel's avatar
Martin Finkel committed
26

27
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
28
                EntryPoint = "libvlc_media_new_path")]
Martin Finkel's avatar
Martin Finkel committed
29
            internal static extern IntPtr LibVLCMediaNewPath(IntPtr libVLC, IntPtr path);
Martin Finkel's avatar
Martin Finkel committed
30

31
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
32
                EntryPoint = "libvlc_media_new_as_node")]
Martin Finkel's avatar
Martin Finkel committed
33
            internal static extern IntPtr LibVLCMediaNewAsNode(IntPtr libVLC, IntPtr name);
Martin Finkel's avatar
Martin Finkel committed
34

35
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
36
                EntryPoint = "libvlc_media_new_fd")]
Martin Finkel's avatar
Martin Finkel committed
37
            internal static extern IntPtr LibVLCMediaNewFd(IntPtr libVLC, int fd);
Martin Finkel's avatar
Martin Finkel committed
38

39
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
40 41 42
                EntryPoint = "libvlc_media_release")]
            internal static extern void LibVLCMediaRelease(IntPtr media);

43
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
44 45 46
                EntryPoint = "libvlc_media_list_media")]
            internal static extern IntPtr LibVLCMediaListMedia(IntPtr mediaList);

47
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
48
                EntryPoint = "libvlc_media_new_callbacks")]
Martin Finkel's avatar
Martin Finkel committed
49
            internal static extern IntPtr LibVLCMediaNewCallbacks(IntPtr libVLC, IntPtr openCb, IntPtr readCb, IntPtr seekCb, IntPtr closeCb, IntPtr opaque);
Martin Finkel's avatar
Martin Finkel committed
50

51
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
52 53 54
                EntryPoint = "libvlc_media_add_option")]
            internal static extern void LibVLCMediaAddOption(IntPtr media, [MarshalAs(UnmanagedType.LPStr)] string options);

55
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
56 57
                EntryPoint = "libvlc_media_add_option_flag")]
            internal static extern void LibVLCMediaAddOptionFlag(IntPtr media, [MarshalAs(UnmanagedType.LPStr)] string options, uint flags);
58

59
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
60 61 62
                EntryPoint = "libvlc_media_get_mrl")]
            internal static extern IntPtr LibVLCMediaGetMrl(IntPtr media);

63
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
64 65 66
                EntryPoint = "libvlc_media_duplicate")]
            internal static extern IntPtr LibVLCMediaDuplicate(IntPtr media);

67
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
68 69 70
                EntryPoint = "libvlc_media_get_meta")]
            internal static extern IntPtr LibVLCMediaGetMeta(IntPtr media, MetadataType metadataType);

71
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
72 73 74
                EntryPoint = "libvlc_media_set_meta")]
            internal static extern void LibVLCMediaSetMeta(IntPtr media, MetadataType metadataType, [MarshalAs(UnmanagedType.LPStr)] string value);

75
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
76 77 78
                EntryPoint = "libvlc_media_save_meta")]
            internal static extern int LibVLCMediaSaveMeta(IntPtr media);

79
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
80 81 82
                EntryPoint = "libvlc_media_get_state")]
            internal static extern VLCState LibVLCMediaGetState(IntPtr media);

83
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
84 85 86
                EntryPoint = "libvlc_media_event_manager")]
            internal static extern IntPtr LibVLCMediaEventManager(IntPtr media);

87
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
88 89 90
                EntryPoint = "libvlc_media_get_stats")]
            internal static extern int LibVLCMediaGetStats(IntPtr media, out MediaStats statistics);

91
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
92 93 94
                EntryPoint = "libvlc_media_get_duration")]
            internal static extern long LibVLCMediaGetDuration(IntPtr media);

95
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
96 97 98
                EntryPoint = "libvlc_media_is_parsed")]
            internal static extern int LibVLCMediaIsParsed(IntPtr media);

99
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
100 101 102
                EntryPoint = "libvlc_media_parse_with_options")]
            internal static extern int LibVLCMediaParseWithOptions(IntPtr media, MediaParseOptions mediaParseOptions, int timeout);

103
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
104 105 106
                EntryPoint = "libvlc_media_get_parsed_status")]
            internal static extern MediaParsedStatus LibVLCMediaGetParsedStatus(IntPtr media);

107
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
108 109 110
                EntryPoint = "libvlc_media_parse_stop")]
            internal static extern void LibVLCMediaParseStop(IntPtr media);

111
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
112 113 114
                EntryPoint = "libvlc_media_set_user_data")]
            internal static extern void LibVLCMediaSetUserData(IntPtr media, IntPtr userData);

115
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
116 117 118
                EntryPoint = "libvlc_media_get_user_data")]
            internal static extern IntPtr LibVLCMediaGetUserData(IntPtr media);

119
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
120
                EntryPoint = "libvlc_media_tracks_get")]
121
            internal static extern uint LibVLCMediaTracksGet(IntPtr media, out IntPtr tracksPtr);
Martin Finkel's avatar
Martin Finkel committed
122

123
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
124 125
                EntryPoint = "libvlc_media_tracks_release")]
            internal static extern void LibVLCMediaTracksRelease(IntPtr tracks, uint count);
126

127
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
128 129
                EntryPoint = "libvlc_media_subitems")]
            internal static extern IntPtr LibVLCMediaSubitems(IntPtr media);
130

131
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
132 133 134
                EntryPoint = "libvlc_media_get_type")]
            internal static extern MediaType LibVLCMediaGetType(IntPtr media);

135
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
136 137 138
                EntryPoint = "libvlc_media_slaves_add")]
            internal static extern int LibVLCMediaAddSlaves(IntPtr media, MediaSlaveType slaveType, uint priority, [MarshalAs(UnmanagedType.LPStr)] string uri);

139
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
140 141 142
                EntryPoint = "libvlc_media_slaves_clear")]
            internal static extern void LibVLCMediaClearSlaves(IntPtr media);

143
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
144
                EntryPoint = "libvlc_media_slaves_get")]
145
            internal static extern uint LibVLCMediaGetSlaves(IntPtr media, out IntPtr slaves);
Martin Finkel's avatar
Martin Finkel committed
146

147
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
148 149 150
                EntryPoint = "libvlc_media_slaves_release")]
            internal static extern void LibVLCMediaReleaseSlaves(IntPtr slaves, uint count);

151
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
Martin Finkel committed
152 153
                EntryPoint = "libvlc_media_retain")]
            internal static extern void LibVLCMediaRetain(IntPtr media);
Martin Finkel's avatar
cleanup  
Martin Finkel committed
154

155
            [DllImport(Constants.LibraryName, CallingConvention = CallingConvention.Cdecl,
Martin Finkel's avatar
cleanup  
Martin Finkel committed
156 157
                            EntryPoint = "libvlc_media_get_codec_description")]
            internal static extern string LibvlcMediaGetCodecDescription(TrackType type, uint codec);
Martin Finkel's avatar
Martin Finkel committed
158
        }
159
        
Martin Finkel's avatar
Martin Finkel committed
160 161 162
        /// <summary>
        /// Media Constructs a libvlc Media instance
        /// </summary>
Martin Finkel's avatar
Martin Finkel committed
163
        /// <param name="libVLC">A libvlc instance</param>
Martin Finkel's avatar
Martin Finkel committed
164
        /// <param name="mrl">A path, location, or node name, depending on the 3rd parameter</param>
165
        /// <param name="type">The type of the 2nd argument.</param>
Martin Finkel's avatar
Martin Finkel committed
166 167
        public Media(LibVLC libVLC, string mrl, FromType type = FromType.FromPath)
            : base(() => SelectNativeCtor(libVLC, mrl, type), Native.LibVLCMediaRelease)
168 169 170
        {
        }

Martin Finkel's avatar
Martin Finkel committed
171
        static IntPtr SelectNativeCtor(LibVLC libVLC, string mrl, FromType type)
Martin Finkel's avatar
Martin Finkel committed
172
        {
Martin Finkel's avatar
Martin Finkel committed
173
            if (libVLC == null) throw new ArgumentNullException(nameof(libVLC));
174
            if (string.IsNullOrEmpty(mrl)) throw new ArgumentNullException(nameof(mrl));
Martin Finkel's avatar
Martin Finkel committed
175

Martin Finkel's avatar
Martin Finkel committed
176 177 178 179
            var mrlPtr = Utf8StringMarshaler.GetInstance().MarshalManagedToNative(mrl);
            if (mrlPtr == IntPtr.Zero)
                throw new ArgumentException($"error marshalling {mrl} to UTF-8 for native interop");

Martin Finkel's avatar
Martin Finkel committed
180 181 182
            switch (type)
            {
                case FromType.FromLocation:
Martin Finkel's avatar
Martin Finkel committed
183
                    return Native.LibVLCMediaNewLocation(libVLC.NativeReference, mrlPtr);
Martin Finkel's avatar
Martin Finkel committed
184
                case FromType.FromPath:
Martin Finkel's avatar
Martin Finkel committed
185
                    return Native.LibVLCMediaNewPath(libVLC.NativeReference, mrlPtr);
Martin Finkel's avatar
Martin Finkel committed
186
                case FromType.AsNode:
Martin Finkel's avatar
Martin Finkel committed
187
                    return Native.LibVLCMediaNewAsNode(libVLC.NativeReference, mrlPtr);
188 189
                default:
                    return IntPtr.Zero;
Martin Finkel's avatar
Martin Finkel committed
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
            }
        }

        /// <summary>
        /// Create a media for an already open file descriptor.
        /// The file descriptor shall be open for reading(or reading and writing).
        ///
        /// Regular file descriptors, pipe read descriptors and character device
        /// descriptors(including TTYs) are supported on all platforms.
        /// Block device descriptors are supported where available.
        /// Directory descriptors are supported on systems that provide fdopendir().
        /// Sockets are supported on all platforms where they are file descriptors,
        /// i.e.all except Windows.
        /// 
        /// \note This library will <b>not</b> automatically close the file descriptor
        /// under any circumstance.Nevertheless, a file descriptor can usually only be
        /// rendered once in a media player.To render it a second time, the file
        /// descriptor should probably be rewound to the beginning with lseek().
        /// </summary>
Martin Finkel's avatar
Martin Finkel committed
209
        /// <param name="libVLC">A libvlc instance</param>
Martin Finkel's avatar
Martin Finkel committed
210
        /// <param name="fd">open file descriptor</param>
Martin Finkel's avatar
Martin Finkel committed
211 212
        public Media(LibVLC libVLC, int fd)
            : base(() => Native.LibVLCMediaNewFd(libVLC.NativeReference, fd), Native.LibVLCMediaRelease)
Martin Finkel's avatar
Martin Finkel committed
213 214 215
        {
        }

Martin Finkel's avatar
Martin Finkel committed
216 217 218 219
        /// <summary>
        /// Create a media from a media list
        /// </summary>
        /// <param name="mediaList">media list to create media from</param>
Martin Finkel's avatar
Martin Finkel committed
220
        public Media(MediaList mediaList)
Martin Finkel's avatar
cleanup  
Martin Finkel committed
221
            : base(() => Native.LibVLCMediaListMedia(mediaList.NativeReference), Native.LibVLCMediaRelease)
Martin Finkel's avatar
Martin Finkel committed
222 223 224 225
        {
        }

        /// <summary>
Martin Finkel's avatar
Martin Finkel committed
226
        /// Create a media from a .NET Stream
Martin Finkel's avatar
Martin Finkel committed
227 228
        /// requires libvlc 3.0 or higher
        /// </summary>
Martin Finkel's avatar
Martin Finkel committed
229 230 231
        /// <param name="libVLC">the libvlc instance</param>
        /// <param name="stream">the .NET Stream to be used by libvlc. LibVLCSharp will NOT dispose or close it.</param>
        /// <param name="options">the libvlc options</param>
Martin Finkel's avatar
Martin Finkel committed
232 233
        public Media(LibVLC libVLC, Stream stream, params string[] options)
            : base(() => CtorFromCallbacks(libVLC, stream), Native.LibVLCMediaRelease)
234 235
        {
            if (options.Any())
236 237 238
                Native.LibVLCMediaAddOption(NativeReference, options.ToString());
        }

Martin Finkel's avatar
Martin Finkel committed
239
        
240

Martin Finkel's avatar
Martin Finkel committed
241
        static IntPtr CtorFromCallbacks(LibVLC libVLC, Stream stream)
Martin Finkel's avatar
Martin Finkel committed
242
        {
Martin Finkel's avatar
Martin Finkel committed
243
            if (libVLC == null) throw new ArgumentNullException(nameof(libVLC));
Martin Finkel's avatar
Martin Finkel committed
244 245
            if (stream == null) throw new ArgumentNullException(nameof(stream));

Martin Finkel's avatar
Martin Finkel committed
246 247 248 249 250 251
            var openMedia = new OpenMedia(CallbackOpenMedia);
            var readMedia = new ReadMedia(CallbackReadMedia);
            var seekMedia = new SeekMedia(CallbackSeekMedia);
            var closeMedia = new CloseMedia(CallbackCloseMedia);

            var opaque = AddStream(stream, openMedia, readMedia, seekMedia, closeMedia);
Martin Finkel's avatar
Martin Finkel committed
252

Martin Finkel's avatar
Martin Finkel committed
253 254
            if (opaque == IntPtr.Zero)
                throw new InvalidOperationException("Cannot create opaque parameter");
Martin Finkel's avatar
Martin Finkel committed
255

Martin Finkel's avatar
Martin Finkel committed
256
            return Native.LibVLCMediaNewCallbacks(libVLC.NativeReference,
Martin Finkel's avatar
Martin Finkel committed
257 258 259 260 261
                Marshal.GetFunctionPointerForDelegate(openMedia),
                Marshal.GetFunctionPointerForDelegate(readMedia),
                Marshal.GetFunctionPointerForDelegate(seekMedia),
                Marshal.GetFunctionPointerForDelegate(closeMedia),
                opaque);
Martin Finkel's avatar
Martin Finkel committed
262 263
        }

Martin Finkel's avatar
Martin Finkel committed
264
        internal Media(IntPtr mediaPtr)
265
            : base(() => mediaPtr, Native.LibVLCMediaRelease)
Martin Finkel's avatar
Martin Finkel committed
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
        {
        }

        /// <summary>Add an option to the media.</summary>
        /// <param name="options">the options (as a string)</param>
        /// <remarks>
        /// <para>This option will be used to determine how the media_player will</para>
        /// <para>read the media. This allows to use VLC's advanced</para>
        /// <para>reading/streaming options on a per-media basis.</para>
        /// <para>The options are listed in 'vlc --long-help' from the command line,</para>
        /// <para>e.g. &quot;-sout-all&quot;. Keep in mind that available options and their semantics</para>
        /// <para>vary across LibVLC versions and builds.</para>
        /// <para>Not all options affects libvlc_media_t objects:</para>
        /// <para>Specifically, due to architectural issues most audio and video options,</para>
        /// <para>such as text renderer options, have no effects on an individual media.</para>
        /// <para>These options must be set through libvlc_new() instead.</para>
        /// </remarks>
        public void AddOption(string options)
        {
            if(string.IsNullOrEmpty(options)) throw new ArgumentNullException(nameof(options));

287
            Native.LibVLCMediaAddOption(NativeReference, options);
Martin Finkel's avatar
Martin Finkel committed
288 289
        }

290 291 292 293 294 295 296 297
        /// <summary>
        /// Convenience method for crossplatform media configuration
        /// </summary>
        /// <param name="mediaConfiguration">mediaConfiguration translate to strings parsed by the vlc engine, some are platform specific</param>
        public void AddOption(MediaConfiguration mediaConfiguration)
        {
            if (mediaConfiguration == null) throw new ArgumentNullException(nameof(mediaConfiguration));

Martin Finkel's avatar
Martin Finkel committed
298
            AddOption(mediaConfiguration.Build());
299 300
        }

Martin Finkel's avatar
Martin Finkel committed
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
        /// <summary>Add an option to the media with configurable flags.</summary>
        /// <param name="options">the options (as a string)</param>
        /// <param name="flags">the flags for this option</param>
        /// <remarks>
        /// <para>This option will be used to determine how the media_player will</para>
        /// <para>read the media. This allows to use VLC's advanced</para>
        /// <para>reading/streaming options on a per-media basis.</para>
        /// <para>The options are detailed in vlc --long-help, for instance</para>
        /// <para>&quot;--sout-all&quot;. Note that all options are not usable on medias:</para>
        /// <para>specifically, due to architectural issues, video-related options</para>
        /// <para>such as text renderer options cannot be set on a single media. They</para>
        /// <para>must be set on the whole libvlc instance instead.</para>
        /// </remarks>
        public void AddOptionFlag(string options, uint flags)
        {
            if (string.IsNullOrEmpty(options)) throw new ArgumentNullException(nameof(options));

318
            Native.LibVLCMediaAddOptionFlag(NativeReference, options, flags);
Martin Finkel's avatar
Martin Finkel committed
319 320 321 322 323 324 325 326 327 328
        }

        string _mrl;
        /// <summary>Get the media resource locator (mrl) from a media descriptor object</summary>
        public string Mrl
        {
            get
            {
                if (string.IsNullOrEmpty(_mrl))
                {
329
                    var mrlPtr = Native.LibVLCMediaGetMrl(NativeReference);
Martin Finkel's avatar
Martin Finkel committed
330 331 332 333 334 335 336 337 338
                    _mrl = Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(mrlPtr) as string;
                }
                return _mrl;
            }
        }

        /// <summary>Duplicate a media descriptor object.</summary>
        public Media Duplicate()
        {
339
            var duplicatePtr = Native.LibVLCMediaDuplicate(NativeReference);
Martin Finkel's avatar
Martin Finkel committed
340 341 342 343 344 345 346 347 348 349 350 351
            if(duplicatePtr == IntPtr.Zero) throw new Exception("Failure to duplicate");
            return new Media(duplicatePtr);
        }

        /// <summary>Read the meta of the media.</summary>
        /// <param name="metadataType">the meta to read</param>
        /// <returns>the media's meta</returns>
        /// <remarks>
        /// If the media has not yet been parsed this will return NULL.
        /// </remarks>
        public string Meta(MetadataType metadataType)
        {
352
            var metaPtr = Native.LibVLCMediaGetMeta(NativeReference, metadataType);
Martin Finkel's avatar
Martin Finkel committed
353 354 355 356 357 358 359 360 361 362 363 364 365 366
            if (metaPtr == IntPtr.Zero) return string.Empty;
            return Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(metaPtr) as string;
        }

        /// <summary>
        /// <para>Set the meta of the media (this function will not save the meta, call</para>
        /// <para>libvlc_media_save_meta in order to save the meta)</para>
        /// </summary>
        /// <param name="metadataType">the <see cref="MetadataType"/>  to write</param>
        /// <param name="value">the media's meta</param>
        public void SetMeta(MetadataType metadataType, string value)
        {
            if(string.IsNullOrEmpty(value)) throw new ArgumentNullException(value);

367
            Native.LibVLCMediaSetMeta(NativeReference, metadataType, value);
Martin Finkel's avatar
Martin Finkel committed
368 369 370 371
        }

        /// <summary>Save the meta previously set</summary>
        /// <returns>true if the write operation was successful</returns>
Martin Finkel's avatar
cleanup  
Martin Finkel committed
372
        public bool SaveMeta() => Native.LibVLCMediaSaveMeta(NativeReference) != 0;
Martin Finkel's avatar
Martin Finkel committed
373 374 375 376

        /// <summary>
        /// Get current <see cref="VLCState"/> of media descriptor object.
        /// </summary>
377
        public VLCState State => Native.LibVLCMediaGetState(NativeReference);
Martin Finkel's avatar
Martin Finkel committed
378 379 380 381

        /// <summary>Get the current statistics about the media
        /// structure that contain the statistics about the media
        /// </summary>
Martin Finkel's avatar
cleanup  
Martin Finkel committed
382 383
        public MediaStats Statistics => Native.LibVLCMediaGetStats(NativeReference, out var mediaStats) == 0 
            ? default(MediaStats) : mediaStats;
Martin Finkel's avatar
Martin Finkel committed
384

Martin Finkel's avatar
Martin Finkel committed
385
        MediaEventManager _eventManager;
Martin Finkel's avatar
Martin Finkel committed
386 387 388 389 390
        /// <summary>
        /// <para>Get event manager from media descriptor object.</para>
        /// <para>NOTE: this function doesn't increment reference counting.</para>
        /// </summary>
        /// <returns>event manager object</returns>
Martin Finkel's avatar
Martin Finkel committed
391
        MediaEventManager EventManager
Martin Finkel's avatar
Martin Finkel committed
392 393 394 395
        {
            get
            {
                if (_eventManager != null) return _eventManager;
396
                var eventManagerPtr = Native.LibVLCMediaEventManager(NativeReference);
Martin Finkel's avatar
Martin Finkel committed
397
                _eventManager = new MediaEventManager(eventManagerPtr);
Martin Finkel's avatar
Martin Finkel committed
398 399 400 401 402 403
                return _eventManager;
            }
        }

        /// <summary>Get duration (in ms) of media descriptor object item.</summary>
        /// <returns>duration of media item or -1 on error</returns>
404
        public long Duration => Native.LibVLCMediaGetDuration(NativeReference);
Martin Finkel's avatar
Martin Finkel committed
405

Martin Finkel's avatar
Martin Finkel committed
406
        /// <summary>
407
        /// Parse the media asynchronously with options.      
Martin Finkel's avatar
Martin Finkel committed
408 409 410 411 412 413 414 415
        /// It uses a flag to specify parse options (see <see cref="MediaParseOptions"/>). All these flags can be combined. By default, media is parsed if it's a local file.
        /// <para/> Note: Parsing can be aborted with ParseStop().
        /// </summary>
        /// <param name="options">parse options</param>
        /// <param name="timeout">maximum time allowed to preparse the media. 
        /// <para/>If -1, the default "preparse-timeout" option will be used as a timeout. 
        /// <para/>If 0, it will wait indefinitely. If > 0, the timeout will be used (in milliseconds). 
        /// </param>
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479
        /// <param name="cancellationToken">token to cancel the operation</param>
        public async Task<bool> Parse(MediaParseOptions options = MediaParseOptions.ParseLocal, int timeout = -1, CancellationToken cancellationToken = default)
        {
            try
            {
                if (cancellationToken.IsCancellationRequested)
                    cancellationToken.ThrowIfCancellationRequested();

                _tcs = new TaskCompletionSource<bool>();
                var timeoutToken = new CancellationTokenSource(timeout);

                ParsedChanged += OnParsedChanged;

                cancellationToken.Register(() =>
                {
                    ParsedChanged -= OnParsedChanged;
                    Native.LibVLCMediaParseStop(NativeReference);
                    _tcs?.TrySetCanceled();
                });

                timeoutToken.Token.Register(() =>
                {
                    ParsedChanged -= OnParsedChanged;
                    Native.LibVLCMediaParseStop(NativeReference);
                    _tcs?.TrySetCanceled();
                });

                var result = Native.LibVLCMediaParseWithOptions(NativeReference, options, timeout);
                if (result == -1)
                {
                    timeoutToken.Cancel();
                    timeoutToken.Dispose();
                    _tcs.TrySetResult(false);
                    return false;
                }

                return await _tcs.Task;
            }
            catch (OperationCanceledException)
            {
                _tcs?.TrySetCanceled();
                return false;
            }
            catch (Exception ex)
            {
                _tcs?.TrySetException(ex);
                return false;
            }
            finally
            {
                ParsedChanged -= OnParsedChanged;
            }
        }

        TaskCompletionSource<bool> _tcs;

        void OnParsedChanged(object sender, MediaParsedChangedEventArgs mediaParsedChangedEventArgs)
        {
            if (ParsedStatus == MediaParsedStatus.Done)
                _tcs?.TrySetResult(true);
            else if (ParsedStatus == MediaParsedStatus.Failed)
                _tcs?.TrySetException(new VLCException($"parsing of {this} failed"));
            else _tcs?.TrySetResult(false);
        }
Martin Finkel's avatar
Martin Finkel committed
480

Martin Finkel's avatar
Martin Finkel committed
481 482
        /// <summary>Return true is the media descriptor object is parsed</summary>
        /// <returns>true if media object has been parsed otherwise it returns false</returns>
483
        public bool IsParsed => Native.LibVLCMediaIsParsed(NativeReference) != 0;
Martin Finkel's avatar
Martin Finkel committed
484 485 486 487 488 489 490 491

        /// <summary>Get Parsed status for media descriptor object.</summary>
        /// <returns>a value of the libvlc_media_parsed_status_t enum</returns>
        /// <remarks>
        /// <para>libvlc_MediaParsedChanged</para>
        /// <para>libvlc_media_parsed_status_t</para>
        /// <para>LibVLC 3.0.0 or later</para>
        /// </remarks>
492
        public MediaParsedStatus ParsedStatus => Native.LibVLCMediaGetParsedStatus(NativeReference);
Martin Finkel's avatar
Martin Finkel committed
493 494 495 496 497 498 499 500

        /// <summary>Stop the parsing of the media</summary>
        /// <remarks>
        /// <para>When the media parsing is stopped, the libvlc_MediaParsedChanged event will</para>
        /// <para>be sent with the libvlc_media_parsed_status_timeout status.</para>
        /// <para>libvlc_media_parse_with_options</para>
        /// <para>LibVLC 3.0.0 or later</para>
        /// </remarks>
Martin Finkel's avatar
cleanup  
Martin Finkel committed
501
        public void ParseStop() => Native.LibVLCMediaParseStop(NativeReference);
Martin Finkel's avatar
Martin Finkel committed
502

Martin Finkel's avatar
Martin Finkel committed
503
        /// <summary>Get media descriptor's elementary streams description
Martin Finkel's avatar
Martin Finkel committed
504 505 506 507 508 509 510 511 512 513
        /// <para>address to store an allocated array of Elementary Streams</para>
        /// <para>descriptions (must be freed with libvlc_media_tracks_release</para>
        /// <para>by the caller) [OUT]</para>
        /// <returns>the number of Elementary Streams (zero on error)</returns>
        /// <remarks>
        /// <para>Note, you need to call libvlc_media_parse() or play the media at least once</para>
        /// <para>before calling this function.</para>
        /// <para>Not doing this will result in an empty array.</para>
        /// <para>LibVLC 2.1.0 and later.</para>
        /// </remarks>
Martin Finkel's avatar
Martin Finkel committed
514
        /// </summary>
515
        public MediaTrack[] Tracks => MarshalUtils.Retrieve(NativeReference, (IntPtr nativeRef, out IntPtr array) => Native.LibVLCMediaTracksGet(nativeRef, out array),
Martin Finkel's avatar
Martin Finkel committed
516 517 518
            MarshalUtils.PtrToStructure<MediaTrackStructure>,
            m => m.Build(),
            Native.LibVLCMediaTracksRelease);
Martin Finkel's avatar
Martin Finkel committed
519 520 521 522 523 524 525

        /// <summary>
        /// <para>Get subitems of media descriptor object. This will increment</para>
        /// <para>the reference count of supplied media descriptor object. Use</para>
        /// <para>libvlc_media_list_release() to decrement the reference counting.</para>
        /// </summary>
        /// <returns>list of media descriptor subitems or NULL</returns>
Martin Finkel's avatar
Martin Finkel committed
526 527
        public MediaList SubItems => new MediaList(Native.LibVLCMediaSubitems(NativeReference));
       
528
        public MediaType Type => Native.LibVLCMediaGetType(NativeReference);
Martin Finkel's avatar
Martin Finkel committed
529 530 531 532 533 534 535 536 537 538 539 540 541 542

        /// <summary>Add a slave to the current media.</summary>
        /// <param name="type">subtitle or audio</param>
        /// <param name="priority">from 0 (low priority) to 4 (high priority)</param>
        /// <param name="uri">Uri of the slave (should contain a valid scheme).</param>
        /// <returns>0 on success, -1 on error.</returns>
        /// <remarks>
        /// <para>A slave is an external input source that may contains an additional subtitle</para>
        /// <para>track (like a .srt) or an additional audio track (like a .ac3).</para>
        /// <para>This function must be called before the media is parsed (via</para>
        /// <para>libvlc_media_parse_with_options()) or before the media is played (via</para>
        /// <para>libvlc_media_player_play())</para>
        /// <para>LibVLC 3.0.0 and later.</para>
        /// </remarks>
Martin Finkel's avatar
cleanup  
Martin Finkel committed
543 544 545
        public bool AddSlave(MediaSlaveType type, uint priority, string uri) => 
            Native.LibVLCMediaAddSlaves(NativeReference, type, priority, uri) != 0;

Martin Finkel's avatar
Martin Finkel committed
546 547 548 549 550 551

        /// <summary>
        /// <para>Clear all slaves previously added by libvlc_media_slaves_add() or</para>
        /// <para>internally.</para>
        /// </summary>
        /// <remarks>LibVLC 3.0.0 and later.</remarks>
Martin Finkel's avatar
cleanup  
Martin Finkel committed
552
        public void ClearSlaves() => Native.LibVLCMediaClearSlaves(NativeReference);
Martin Finkel's avatar
Martin Finkel committed
553 554 555 556 557 558 559 560 561 562 563 564

        /// <summary>Get a media descriptor's slave list</summary>
        /// <para>address to store an allocated array of slaves (must be</para>
        /// <para>freed with libvlc_media_slaves_release()) [OUT]</para>
        /// <returns>the number of slaves (zero on error)</returns>
        /// <remarks>
        /// <para>The list will contain slaves parsed by VLC or previously added by</para>
        /// <para>libvlc_media_slaves_add(). The typical use case of this function is to save</para>
        /// <para>a list of slave in a database for a later use.</para>
        /// <para>LibVLC 3.0.0 and later.</para>
        /// <para>libvlc_media_slaves_add</para>
        /// </remarks>
565 566 567 568
        public MediaSlave[] Slaves => MarshalUtils.Retrieve(NativeReference, (IntPtr nativeRef, out IntPtr array) => Native.LibVLCMediaGetSlaves(nativeRef, out array),
            MarshalUtils.PtrToStructure<MediaSlaveStructure>,
            s => s.Build(),
            Native.LibVLCMediaReleaseSlaves);
Martin Finkel's avatar
Martin Finkel committed
569 570 571 572 573 574 575

        public override bool Equals(object obj)
        {
            return obj is Media media &&
                   EqualityComparer<IntPtr>.Default.Equals(NativeReference, media.NativeReference);
        }

Jérémy VIGNELLES's avatar
Jérémy VIGNELLES committed
576 577 578 579 580
        public override int GetHashCode()
        {
            return this.NativeReference.GetHashCode();
        }

Martin Finkel's avatar
Martin Finkel committed
581 582
        internal class StreamData
        {
Martin Finkel's avatar
Martin Finkel committed
583 584 585 586 587 588 589
            internal IntPtr Handle { get; set; }
            internal Stream Stream { get; set; }
            internal byte[] Buffer { get; set; }
            internal OpenMedia OpenMedia { get; set; }
            internal ReadMedia ReadMedia { get; set; }
            internal SeekMedia SeekMedia { get; set; }
            internal CloseMedia CloseMedia { get; set; }
Martin Finkel's avatar
Martin Finkel committed
590 591 592 593
        }

        #region private

594
        [MonoPInvokeCallback(typeof(OpenMedia))]
595
        static int CallbackOpenMedia(IntPtr opaque, ref IntPtr data, out ulong size)
Martin Finkel's avatar
Martin Finkel committed
596 597 598 599 600
        {
            data = opaque;

            try
            {
Martin Finkel's avatar
Martin Finkel committed
601
                var streamData = GetStream(opaque);
Martin Finkel's avatar
Martin Finkel committed
602 603
                try
                {
Martin Finkel's avatar
Martin Finkel committed
604
                    size = (ulong)streamData.Stream.Length;
Martin Finkel's avatar
Martin Finkel committed
605 606 607 608 609 610 611
                }
                catch (Exception)
                {
                    // byte length of the bitstream or UINT64_MAX if unknown
                    size = ulong.MaxValue;
                }

Martin Finkel's avatar
Martin Finkel committed
612
                if (streamData.Stream.CanSeek)
Martin Finkel's avatar
Martin Finkel committed
613
                {
Martin Finkel's avatar
Martin Finkel committed
614
                    streamData.Stream.Seek(0L, SeekOrigin.Begin);
Martin Finkel's avatar
Martin Finkel committed
615 616 617 618 619 620 621 622 623 624 625
                }

                return 0;
            }
            catch (Exception)
            {
                size = 0UL;
                return -1;
            }
        }

626
        [MonoPInvokeCallback(typeof(ReadMedia))]
627
        static int CallbackReadMedia(IntPtr opaque, IntPtr buf, uint len)
Martin Finkel's avatar
Martin Finkel committed
628 629 630
        {
            try
            {
Martin Finkel's avatar
Martin Finkel committed
631
                var streamData = GetStream(opaque);
Martin Finkel's avatar
Martin Finkel committed
632 633
                int read;

Martin Finkel's avatar
Martin Finkel committed
634
                lock (streamData)
Martin Finkel's avatar
Martin Finkel committed
635
                {
Martin Finkel's avatar
Martin Finkel committed
636 637 638
                    var canRead = Math.Min((int)len, streamData.Buffer.Length);
                    read = streamData.Stream.Read(streamData.Buffer, 0, canRead);
                    Marshal.Copy(streamData.Buffer, 0, buf, read);
Martin Finkel's avatar
Martin Finkel committed
639 640 641 642 643 644 645 646 647 648
                }

                return read;
            }
            catch (Exception)
            {
                return -1;
            }
        }

649 650
        [MonoPInvokeCallback(typeof(SeekMedia))]
        static int CallbackSeekMedia(IntPtr opaque, ulong offset)
Martin Finkel's avatar
Martin Finkel committed
651 652 653
        {
            try
            {
Martin Finkel's avatar
Martin Finkel committed
654 655
                var streamData = GetStream(opaque);
                streamData.Stream.Seek((long)offset, SeekOrigin.Begin);
Martin Finkel's avatar
Martin Finkel committed
656 657 658 659 660 661 662 663
                return 0;
            }
            catch (Exception)
            {
                return -1;
            }
        }

664
        [MonoPInvokeCallback(typeof(CloseMedia))]
665
        static void CallbackCloseMedia(IntPtr opaque)
Martin Finkel's avatar
Martin Finkel committed
666 667 668
        {
            try
            {
Martin Finkel's avatar
Martin Finkel committed
669 670 671 672
                var streamData = GetStream(opaque);

                if (streamData.Stream.CanSeek)
                    streamData.Stream.Seek(0, SeekOrigin.Begin);
Martin Finkel's avatar
Martin Finkel committed
673 674 675 676 677 678 679
            }
            catch (Exception)
            {
                // ignored
            }
        }

Martin Finkel's avatar
Martin Finkel committed
680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717
        static IntPtr AddStream(Stream stream, OpenMedia openMedia, ReadMedia readMedia, SeekMedia seekMedia, CloseMedia closeMedia)
        {
            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream));
            }

            IntPtr handle;

            lock (DicStreams)
            {
                _streamIndex++;

                handle = new IntPtr(_streamIndex);
                DicStreams[handle] = new StreamData
                {
                    Buffer = new byte[0x4000],
                    Handle = handle,
                    Stream = stream,
                    OpenMedia = openMedia,
                    ReadMedia = readMedia,
                    SeekMedia = seekMedia,
                    CloseMedia = closeMedia
                };
            }
            return handle;
        }

        static StreamData GetStream(IntPtr handle)
        {
            return !DicStreams.TryGetValue(handle, out var result) ? null : result;
        }

        static void RemoveStream(IntPtr handle)
        {
            DicStreams.TryRemove(handle, out var result);
        }

Martin Finkel's avatar
Martin Finkel committed
718 719
        void Retain()
        {
720
            if (NativeReference != IntPtr.Zero)
721
                Native.LibVLCMediaRetain(NativeReference);
Martin Finkel's avatar
Martin Finkel committed
722 723 724
        }

        #endregion
Martin Finkel's avatar
Martin Finkel committed
725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757

        #region Events

        public event EventHandler<MediaMetaChangedEventArgs> MetaChanged
        {
            add => EventManager.AttachEvent(EventType.MediaMetaChanged, value);
            remove => EventManager.DetachEvent(EventType.MediaMetaChanged, value);
        }

        public event EventHandler<MediaParsedChangedEventArgs> ParsedChanged
        {
            add => EventManager.AttachEvent(EventType.MediaParsedChanged, value);
            remove => EventManager.DetachEvent(EventType.MediaParsedChanged, value);
        }

        public event EventHandler<MediaParsedChangedEventArgs> SubItemAdded
        {
            add => EventManager.AttachEvent(EventType.MediaSubItemAdded, value);
            remove => EventManager.DetachEvent(EventType.MediaSubItemAdded, value);
        }

        public event EventHandler<MediaDurationChangedEventArgs> DurationChanged
        {
            add => EventManager.AttachEvent(EventType.MediaDurationChanged, value);
            remove => EventManager.DetachEvent(EventType.MediaDurationChanged, value);
        }

        public event EventHandler<MediaFreedEventArgs> MediaFreed
        {
            add => EventManager.AttachEvent(EventType.MediaFreed, value);
            remove => EventManager.DetachEvent(EventType.MediaFreed, value);
        }

Martin Finkel's avatar
Martin Finkel committed
758
        public event EventHandler<MediaStateChangedEventArgs> StateChanged
Martin Finkel's avatar
Martin Finkel committed
759 760 761 762 763
        {
            add => EventManager.AttachEvent(EventType.MediaStateChanged, value);
            remove => EventManager.DetachEvent(EventType.MediaStateChanged, value);
        }

Martin Finkel's avatar
Martin Finkel committed
764
        public event EventHandler<MediaSubItemAddedEventArgs> SubItemTreeAdded
Martin Finkel's avatar
Martin Finkel committed
765 766 767 768
        {
            add => EventManager.AttachEvent(EventType.MediaSubItemTreeAdded, value);
            remove => EventManager.DetachEvent(EventType.MediaSubItemTreeAdded, value);
        }
769

Martin Finkel's avatar
Martin Finkel committed
770
        #endregion
771

772 773 774 775
        /// <summary>
        /// Dispose of this media
        /// </summary>
        /// <param name="disposing"></param>
776 777 778 779 780 781 782
        protected override void Dispose(bool disposing)
        {
            if (IsDisposed || NativeReference == IntPtr.Zero)
                return;

            base.Dispose(disposing);
        }
Martin Finkel's avatar
Martin Finkel committed
783 784
    }

785 786
    #region Callbacks

Martin Finkel's avatar
Martin Finkel committed
787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808
    /// <summary>
    /// <para>It consists of a media location and various optional meta data.</para>
    /// <para>@{</para>
    /// <para></para>
    /// <para>LibVLC media item/descriptor external API</para>
    /// </summary>
    /// <summary>Callback prototype to open a custom bitstream input media.</summary>
    /// <param name="opaque">private pointer as passed to libvlc_media_new_callbacks()</param>
    /// <param name="data">storage space for a private data pointer [OUT]</param>
    /// <param name="size">byte length of the bitstream or UINT64_MAX if unknown [OUT]</param>
    /// <returns>
    /// <para>0 on success, non-zero on error. In case of failure, the other</para>
    /// <para>callbacks will not be invoked and any value stored in *datap and *sizep is</para>
    /// <para>discarded.</para>
    /// </returns>
    /// <remarks>
    /// <para>The same media item can be opened multiple times. Each time, this callback</para>
    /// <para>is invoked. It should allocate and initialize any instance-specific</para>
    /// <para>resources, then store them in *datap. The instance resources can be freed</para>
    /// <para>in the</para>
    /// <para>For convenience, *datap is initially NULL and *sizep is initially 0.</para>
    /// </remarks>
809
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
810
    internal delegate int OpenMedia(IntPtr opaque, ref IntPtr data, out ulong size);
Martin Finkel's avatar
Martin Finkel committed
811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826

    /// <summary>Callback prototype to read data from a custom bitstream input media.</summary>
    /// <param name="opaque">private pointer as set by the</param>
    /// <param name="buf">start address of the buffer to read data into</param>
    /// <param name="len">bytes length of the buffer</param>
    /// <returns>
    /// <para>strictly positive number of bytes read, 0 on end-of-stream,</para>
    /// <para>or -1 on non-recoverable error</para>
    /// </returns>
    /// <remarks>
    /// <para>callback</para>
    /// <para>If no data is immediately available, then the callback should sleep.</para>
    /// <para>The application is responsible for avoiding deadlock situations.</para>
    /// <para>In particular, the callback should return an error if playback is stopped;</para>
    /// <para>if it does not return, then libvlc_media_player_stop() will never return.</para>
    /// </remarks>
827
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
828
    internal delegate int ReadMedia(IntPtr opaque, IntPtr buf, uint len);
Martin Finkel's avatar
Martin Finkel committed
829 830 831 832 833 834

    /// <summary>Callback prototype to seek a custom bitstream input media.</summary>
    /// <param name="opaque">private pointer as set by the</param>
    /// <param name="offset">absolute byte offset to seek to</param>
    /// <returns>0 on success, -1 on error.</returns>
    /// <remarks>callback</remarks>
835
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
836
    internal delegate int SeekMedia(IntPtr opaque, ulong offset);
Martin Finkel's avatar
Martin Finkel committed
837 838 839 840

    /// <summary>Callback prototype to close a custom bitstream input media.</summary>
    /// <param name="opaque">private pointer as set by the</param>
    /// <remarks>callback</remarks>
841
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
842
    internal delegate void CloseMedia(IntPtr opaque);
843

844 845
    #endregion

846
    #region enums
847

848 849 850 851 852 853 854 855 856 857 858
    /// <summary>Note the order of libvlc_state_t enum must match exactly the order of</summary>
    /// <remarks>
    /// <para>mediacontrol_PlayerStatus,</para>
    /// <para>input_state_e enums,</para>
    /// <para>and VideoLAN.LibVLCSharp.State (at bindings/cil/src/media.cs).</para>
    /// <para>Expected states by web plugins are:</para>
    /// <para>IDLE/CLOSE=0, OPENING=1, PLAYING=3, PAUSED=4,</para>
    /// <para>STOPPING=5, ENDED=6, ERROR=7</para>
    /// </remarks>
    public enum VLCState
    {
Martin Finkel's avatar
Martin Finkel committed
859 860 861
        /// <summary>
        /// Nothing special happening
        /// </summary>
862
        NothingSpecial = 0,
Martin Finkel's avatar
Martin Finkel committed
863 864 865 866

        /// <summary>
        /// Opening media
        /// </summary>
867
        Opening = 1,
Martin Finkel's avatar
Martin Finkel committed
868 869 870 871

        /// <summary>
        /// Buffering media
        /// </summary>
872
        Buffering = 2,
Martin Finkel's avatar
Martin Finkel committed
873 874 875 876

        /// <summary>
        /// Playing media
        /// </summary>
877
        Playing = 3,
Martin Finkel's avatar
Martin Finkel committed
878 879 880 881

        /// <summary>
        /// Paused media
        /// </summary>
882
        Paused = 4,
Martin Finkel's avatar
Martin Finkel committed
883 884 885 886

        /// <summary>
        /// Stopped media
        /// </summary>
887
        Stopped = 5,
Martin Finkel's avatar
Martin Finkel committed
888 889 890 891

        /// <summary>
        /// Ended media
        /// </summary>
892
        Ended = 6,
Martin Finkel's avatar
Martin Finkel committed
893 894 895 896

        /// <summary>
        /// Error media
        /// </summary>
897 898 899
        Error = 7
    }

Martin Finkel's avatar
Martin Finkel committed
900 901 902
    /// <summary>
    /// Media track type such as Audio, Video or Text
    /// </summary>
903 904
    public enum TrackType
    {
Martin Finkel's avatar
Martin Finkel committed
905 906 907
        /// <summary>
        /// Unknown track
        /// </summary>
908
        Unknown = -1,
Martin Finkel's avatar
Martin Finkel committed
909 910 911 912

        /// <summary>
        /// Audio track
        /// </summary>
913
        Audio = 0,
Martin Finkel's avatar
Martin Finkel committed
914 915 916 917

        /// <summary>
        /// Video track
        /// </summary>
918
        Video = 1,
Martin Finkel's avatar
Martin Finkel committed
919 920 921 922

        /// <summary>
        /// Text track
        /// </summary>
923 924 925
        Text = 2
    }

Martin Finkel's avatar
Martin Finkel committed
926 927 928
    /// <summary>
    /// Video orientation
    /// </summary>
929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948
    public enum VideoOrientation
    {
        /// <summary>Normal. Top line represents top, left column left.</summary>
        TopLeft = 0,
        /// <summary>Flipped horizontally</summary>
        TopRight = 1,
        /// <summary>Flipped vertically</summary>
        BottomLeft = 2,
        /// <summary>Rotated 180 degrees</summary>
        BottomRight = 3,
        /// <summary>Transposed</summary>
        LeftTop = 4,
        /// <summary>Rotated 90 degrees clockwise (or 270 anti-clockwise)</summary>
        LeftBottom = 5,
        /// <summary>Rotated 90 degrees anti-clockwise</summary>
        RightTop = 6,
        /// <summary>Anti-transposed</summary>
        RightBottom = 7
    }

Martin Finkel's avatar
Martin Finkel committed
949 950 951
    /// <summary>
    /// Video projection
    /// </summary>
952 953 954
    [Flags]
    public enum VideoProjection
    {
Martin Finkel's avatar
Martin Finkel committed
955 956 957
        /// <summary>
        /// Rectangular
        /// </summary>
958 959 960
        Rectangular = 0,
        /// <summary>360 spherical</summary>
        Equirectangular = 1,
Martin Finkel's avatar
Martin Finkel committed
961 962 963 964

        /// <summary>
        /// Cubemap layout standard
        /// </summary>
965 966 967 968 969 970
        CubemapLayoutStandard = 256
    }

    /// <summary>Type of a media slave: subtitle or audio.</summary>
    public enum MediaSlaveType
    {
971 972 973
        /// <summary>
        /// Subtitle
        /// </summary>
974
        Subtitle = 0,
975 976 977 978
        
        /// <summary>
        /// Audio
        /// </summary>
979 980
        Audio = 1
    }
981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088

    /// <summary>Meta data types</summary>
    public enum MetadataType
    {
        Title = 0,
        Artist = 1,
        Genre = 2,
        Copyright = 3,
        Album = 4,
        TrackNumber = 5,
        Description = 6,
        Rating = 7,
        Date = 8,
        Setting = 9,
        URL = 10,
        Language = 11,
        NowPlaying = 12,
        Publisher = 13,
        EncodedBy = 14,
        ArtworkURL = 15,
        TrackID = 16,
        TrackTotal = 17,
        Director = 18,
        Season = 19,
        Episode = 20,
        ShowName = 21,
        Actors = 22,
        AlbumArtist = 23,
        DiscNumber = 24,
        DiscTotal = 25
    }

    /// <summary>
    /// The FromType enum is used to drive the media creation.
    /// A media is usually created using a string, which can represent one of 3 things: FromPath, FromLocation, AsNode.
    /// </summary>
    public enum FromType
    {
        /// <summary>
        /// Create a media for a certain file path.
        /// </summary>
        FromPath,
        /// <summary>
        /// Create a media with a certain given media resource location,
        /// for instance a valid URL.
        /// note To refer to a local file with this function,
        /// the file://... URI syntax <b>must</b> be used (see IETF RFC3986).
        /// We recommend using FromPath instead when dealing with
        ///local files.
        /// </summary>
        FromLocation,
        /// <summary>
        /// Create a media as an empty node with a given name.
        /// </summary>
        AsNode
    }

    /// <summary>
    /// Parse flags used by libvlc_media_parse_with_options()
    /// </summary>
    /// <remarks>libvlc_media_parse_with_options</remarks>
    [Flags]
    public enum MediaParseOptions
    {
        /// <summary>Parse media if it's a local file</summary>
        ParseLocal = 0,
        /// <summary>Parse media even if it's a network file</summary>
        ParseNetwork = 1,
        /// <summary>Fetch meta and covert art using local resources</summary>
        FetchLocal = 2,
        /// <summary>Fetch meta and covert art using network resources</summary>
        FetchNetwork = 4,
        /// <summary>
        /// Interact with the user (via libvlc_dialog_cbs) when preparsing this item
        /// (and not its sub items). Set this flag in order to receive a callback
        /// when the input is asking for credentials.
        /// </summary>
        DoInteract = 8
    }

    /// <summary>
    /// Parse status used sent by libvlc_media_parse_with_options() or returned by
    /// libvlc_media_get_parsed_status()
    /// </summary>
    /// <remarks>
    /// libvlc_media_parse_with_options
    /// libvlc_media_get_parsed_status
    /// </remarks>
    public enum MediaParsedStatus
    {
        Skipped = 1,
        Failed = 2,
        Timeout = 3,
        Done = 4
    }

    /// <summary>Media type</summary>
    /// <remarks>libvlc_media_get_type</remarks>
    public enum MediaType
    {
        Unknown = 0,
        File = 1,
        Directory = 2,
        Disc = 3,
        Stream = 4,
        Playlist = 5
    }

1089
    #endregion
1090

Martin Finkel's avatar
Martin Finkel committed
1091 1092 1093
    /// <summary>
    /// Small configuration helper
    /// </summary>
1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107
    public class MediaConfiguration
    {
        HashSet<string> _options = new HashSet<string>();

        public MediaConfiguration EnableHardwareDecoding()
        {
#if ANDROID
            _options.Add(":codec=mediacodec_ndk");
#endif
            return this;
        }

        public string Build() => string.Join(",", _options);
    }
Martin Finkel's avatar
Martin Finkel committed
1108
}