Media.cs 43.7 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
        /// <param name="cancellationToken">token to cancel the operation</param>
Martin Finkel's avatar
Martin Finkel committed
417
        public async Task<MediaParsedStatus> Parse(MediaParseOptions options = MediaParseOptions.ParseLocal, int timeout = -1, CancellationToken cancellationToken = default)
418
        {
Martin Finkel's avatar
Martin Finkel committed
419 420
            var tcs = new TaskCompletionSource<MediaParsedStatus>();
            var cancellationTokenRegistration = cancellationToken.Register(() =>
421
            {
Martin Finkel's avatar
Martin Finkel committed
422 423 424 425
                ParsedChanged -= OnParsedChanged;
                Native.LibVLCMediaParseStop(NativeReference);
                tcs?.TrySetCanceled();
            });
426

Martin Finkel's avatar
Martin Finkel committed
427 428 429 430
            void OnParsedChanged(object sender, MediaParsedChangedEventArgs mediaParsedChangedEventArgs)
            {
                tcs?.TrySetResult(mediaParsedChangedEventArgs.ParsedStatus);             
            }
431

Martin Finkel's avatar
Martin Finkel committed
432 433 434
            try
            {
                cancellationToken.ThrowIfCancellationRequested();
435

Martin Finkel's avatar
Martin Finkel committed
436
                ParsedChanged += OnParsedChanged;
437 438 439 440

                var result = Native.LibVLCMediaParseWithOptions(NativeReference, options, timeout);
                if (result == -1)
                {
Martin Finkel's avatar
Martin Finkel committed
441
                   tcs.TrySetResult(ParsedStatus);
442 443
                }

Martin Finkel's avatar
Martin Finkel committed
444
                return await tcs.Task.ConfigureAwait(false);
445
            }
Martin Finkel's avatar
Martin Finkel committed
446
            
447 448
            finally
            {
Martin Finkel's avatar
Martin Finkel committed
449
                cancellationTokenRegistration.Dispose();
450 451
                ParsedChanged -= OnParsedChanged;
            }
Martin Finkel's avatar
Martin Finkel committed
452
        }        
Martin Finkel's avatar
Martin Finkel committed
453

Martin Finkel's avatar
Martin Finkel committed
454 455
        /// <summary>Return true is the media descriptor object is parsed</summary>
        /// <returns>true if media object has been parsed otherwise it returns false</returns>
456
        public bool IsParsed => Native.LibVLCMediaIsParsed(NativeReference) != 0;
Martin Finkel's avatar
Martin Finkel committed
457 458 459 460 461 462 463 464

        /// <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>
465
        public MediaParsedStatus ParsedStatus => Native.LibVLCMediaGetParsedStatus(NativeReference);
Martin Finkel's avatar
Martin Finkel committed
466 467 468 469 470 471 472 473

        /// <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
474
        public void ParseStop() => Native.LibVLCMediaParseStop(NativeReference);
Martin Finkel's avatar
Martin Finkel committed
475

Martin Finkel's avatar
Martin Finkel committed
476
        /// <summary>Get media descriptor's elementary streams description
Martin Finkel's avatar
Martin Finkel committed
477 478 479 480 481 482 483 484 485 486
        /// <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
487
        /// </summary>
488
        public MediaTrack[] Tracks => MarshalUtils.Retrieve(NativeReference, (IntPtr nativeRef, out IntPtr array) => Native.LibVLCMediaTracksGet(nativeRef, out array),
Martin Finkel's avatar
Martin Finkel committed
489 490 491
            MarshalUtils.PtrToStructure<MediaTrackStructure>,
            m => m.Build(),
            Native.LibVLCMediaTracksRelease);
Martin Finkel's avatar
Martin Finkel committed
492 493 494 495 496 497 498

        /// <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
499 500
        public MediaList SubItems => new MediaList(Native.LibVLCMediaSubitems(NativeReference));
       
501
        public MediaType Type => Native.LibVLCMediaGetType(NativeReference);
Martin Finkel's avatar
Martin Finkel committed
502 503 504 505 506 507 508 509 510 511 512 513 514 515

        /// <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
516 517 518
        public bool AddSlave(MediaSlaveType type, uint priority, string uri) => 
            Native.LibVLCMediaAddSlaves(NativeReference, type, priority, uri) != 0;

Martin Finkel's avatar
Martin Finkel committed
519 520 521 522 523 524

        /// <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
525
        public void ClearSlaves() => Native.LibVLCMediaClearSlaves(NativeReference);
Martin Finkel's avatar
Martin Finkel committed
526 527 528 529 530 531 532 533 534 535 536 537

        /// <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>
538 539 540 541
        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
542 543 544 545 546 547 548

        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
549 550 551 552 553
        public override int GetHashCode()
        {
            return this.NativeReference.GetHashCode();
        }

Martin Finkel's avatar
Martin Finkel committed
554 555
        internal class StreamData
        {
Martin Finkel's avatar
Martin Finkel committed
556 557 558 559 560 561 562
            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
563 564 565 566
        }

        #region private

567
        [MonoPInvokeCallback(typeof(OpenMedia))]
568
        static int CallbackOpenMedia(IntPtr opaque, ref IntPtr data, out ulong size)
Martin Finkel's avatar
Martin Finkel committed
569 570 571 572 573
        {
            data = opaque;

            try
            {
Martin Finkel's avatar
Martin Finkel committed
574
                var streamData = GetStream(opaque);
Martin Finkel's avatar
Martin Finkel committed
575 576
                try
                {
Martin Finkel's avatar
Martin Finkel committed
577
                    size = (ulong)streamData.Stream.Length;
Martin Finkel's avatar
Martin Finkel committed
578 579 580 581 582 583 584
                }
                catch (Exception)
                {
                    // byte length of the bitstream or UINT64_MAX if unknown
                    size = ulong.MaxValue;
                }

Martin Finkel's avatar
Martin Finkel committed
585
                if (streamData.Stream.CanSeek)
Martin Finkel's avatar
Martin Finkel committed
586
                {
Martin Finkel's avatar
Martin Finkel committed
587
                    streamData.Stream.Seek(0L, SeekOrigin.Begin);
Martin Finkel's avatar
Martin Finkel committed
588 589 590 591 592 593 594 595 596 597 598
                }

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

599
        [MonoPInvokeCallback(typeof(ReadMedia))]
600
        static int CallbackReadMedia(IntPtr opaque, IntPtr buf, uint len)
Martin Finkel's avatar
Martin Finkel committed
601 602 603
        {
            try
            {
Martin Finkel's avatar
Martin Finkel committed
604
                var streamData = GetStream(opaque);
Martin Finkel's avatar
Martin Finkel committed
605 606
                int read;

Martin Finkel's avatar
Martin Finkel committed
607
                lock (streamData)
Martin Finkel's avatar
Martin Finkel committed
608
                {
Martin Finkel's avatar
Martin Finkel committed
609 610 611
                    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
612 613 614 615 616 617 618 619 620 621
                }

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

622 623
        [MonoPInvokeCallback(typeof(SeekMedia))]
        static int CallbackSeekMedia(IntPtr opaque, ulong offset)
Martin Finkel's avatar
Martin Finkel committed
624 625 626
        {
            try
            {
Martin Finkel's avatar
Martin Finkel committed
627 628
                var streamData = GetStream(opaque);
                streamData.Stream.Seek((long)offset, SeekOrigin.Begin);
Martin Finkel's avatar
Martin Finkel committed
629 630 631 632 633 634 635 636
                return 0;
            }
            catch (Exception)
            {
                return -1;
            }
        }

637
        [MonoPInvokeCallback(typeof(CloseMedia))]
638
        static void CallbackCloseMedia(IntPtr opaque)
Martin Finkel's avatar
Martin Finkel committed
639 640 641
        {
            try
            {
Martin Finkel's avatar
Martin Finkel committed
642 643 644 645
                var streamData = GetStream(opaque);

                if (streamData.Stream.CanSeek)
                    streamData.Stream.Seek(0, SeekOrigin.Begin);
Martin Finkel's avatar
Martin Finkel committed
646 647 648 649 650 651 652
            }
            catch (Exception)
            {
                // ignored
            }
        }

Martin Finkel's avatar
Martin Finkel committed
653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690
        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
691 692
        void Retain()
        {
693
            if (NativeReference != IntPtr.Zero)
694
                Native.LibVLCMediaRetain(NativeReference);
Martin Finkel's avatar
Martin Finkel committed
695 696 697
        }

        #endregion
Martin Finkel's avatar
Martin Finkel committed
698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730

        #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
731
        public event EventHandler<MediaStateChangedEventArgs> StateChanged
Martin Finkel's avatar
Martin Finkel committed
732 733 734 735 736
        {
            add => EventManager.AttachEvent(EventType.MediaStateChanged, value);
            remove => EventManager.DetachEvent(EventType.MediaStateChanged, value);
        }

Martin Finkel's avatar
Martin Finkel committed
737
        public event EventHandler<MediaSubItemAddedEventArgs> SubItemTreeAdded
Martin Finkel's avatar
Martin Finkel committed
738 739 740 741
        {
            add => EventManager.AttachEvent(EventType.MediaSubItemTreeAdded, value);
            remove => EventManager.DetachEvent(EventType.MediaSubItemTreeAdded, value);
        }
742

Martin Finkel's avatar
Martin Finkel committed
743
        #endregion
744

745 746 747 748
        /// <summary>
        /// Dispose of this media
        /// </summary>
        /// <param name="disposing"></param>
749 750 751 752 753 754 755
        protected override void Dispose(bool disposing)
        {
            if (IsDisposed || NativeReference == IntPtr.Zero)
                return;

            base.Dispose(disposing);
        }
Martin Finkel's avatar
Martin Finkel committed
756 757
    }

758 759
    #region Callbacks

Martin Finkel's avatar
Martin Finkel committed
760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781
    /// <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>
782
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
783
    internal delegate int OpenMedia(IntPtr opaque, ref IntPtr data, out ulong size);
Martin Finkel's avatar
Martin Finkel committed
784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799

    /// <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>
800
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
801
    internal delegate int ReadMedia(IntPtr opaque, IntPtr buf, uint len);
Martin Finkel's avatar
Martin Finkel committed
802 803 804 805 806 807

    /// <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>
808
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
809
    internal delegate int SeekMedia(IntPtr opaque, ulong offset);
Martin Finkel's avatar
Martin Finkel committed
810 811 812 813

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

817 818
    #endregion

819
    #region enums
820

821 822 823 824 825 826 827 828 829 830 831
    /// <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
832 833 834
        /// <summary>
        /// Nothing special happening
        /// </summary>
835
        NothingSpecial = 0,
Martin Finkel's avatar
Martin Finkel committed
836 837 838 839

        /// <summary>
        /// Opening media
        /// </summary>
840
        Opening = 1,
Martin Finkel's avatar
Martin Finkel committed
841 842 843 844

        /// <summary>
        /// Buffering media
        /// </summary>
845
        Buffering = 2,
Martin Finkel's avatar
Martin Finkel committed
846 847 848 849

        /// <summary>
        /// Playing media
        /// </summary>
850
        Playing = 3,
Martin Finkel's avatar
Martin Finkel committed
851 852 853 854

        /// <summary>
        /// Paused media
        /// </summary>
855
        Paused = 4,
Martin Finkel's avatar
Martin Finkel committed
856 857 858 859

        /// <summary>
        /// Stopped media
        /// </summary>
860
        Stopped = 5,
Martin Finkel's avatar
Martin Finkel committed
861 862 863 864

        /// <summary>
        /// Ended media
        /// </summary>
865
        Ended = 6,
Martin Finkel's avatar
Martin Finkel committed
866 867 868 869

        /// <summary>
        /// Error media
        /// </summary>
870 871 872
        Error = 7
    }

Martin Finkel's avatar
Martin Finkel committed
873 874 875
    /// <summary>
    /// Media track type such as Audio, Video or Text
    /// </summary>
876 877
    public enum TrackType
    {
Martin Finkel's avatar
Martin Finkel committed
878 879 880
        /// <summary>
        /// Unknown track
        /// </summary>
881
        Unknown = -1,
Martin Finkel's avatar
Martin Finkel committed
882 883 884 885

        /// <summary>
        /// Audio track
        /// </summary>
886
        Audio = 0,
Martin Finkel's avatar
Martin Finkel committed
887 888 889 890

        /// <summary>
        /// Video track
        /// </summary>
891
        Video = 1,
Martin Finkel's avatar
Martin Finkel committed
892 893 894 895

        /// <summary>
        /// Text track
        /// </summary>
896 897 898
        Text = 2
    }

Martin Finkel's avatar
Martin Finkel committed
899 900 901
    /// <summary>
    /// Video orientation
    /// </summary>
902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921
    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
922 923 924
    /// <summary>
    /// Video projection
    /// </summary>
925 926 927
    [Flags]
    public enum VideoProjection
    {
Martin Finkel's avatar
Martin Finkel committed
928 929 930
        /// <summary>
        /// Rectangular
        /// </summary>
931 932 933
        Rectangular = 0,
        /// <summary>360 spherical</summary>
        Equirectangular = 1,
Martin Finkel's avatar
Martin Finkel committed
934 935 936 937

        /// <summary>
        /// Cubemap layout standard
        /// </summary>
938 939 940 941 942 943
        CubemapLayoutStandard = 256
    }

    /// <summary>Type of a media slave: subtitle or audio.</summary>
    public enum MediaSlaveType
    {
944 945 946
        /// <summary>
        /// Subtitle
        /// </summary>
947
        Subtitle = 0,
948 949 950 951
        
        /// <summary>
        /// Audio
        /// </summary>
952 953
        Audio = 1
    }
954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 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

    /// <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
    }

1062
    #endregion
1063

Martin Finkel's avatar
Martin Finkel committed
1064 1065 1066
    /// <summary>
    /// Small configuration helper
    /// </summary>
1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080
    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
1081
}