// %BANNER_BEGIN% // --------------------------------------------------------------------- // %COPYRIGHT_BEGIN% // Copyright (c) (2018-2022) Magic Leap, Inc. All Rights Reserved. // Use of this file is governed by the Software License Agreement, located here: https://www.magicleap.com/software-license-agreement-ml2 // Terms and conditions applicable to third-party materials accompanying this distribution may also be found in the top-level NOTICE file appearing herein. // %COPYRIGHT_END% // --------------------------------------------------------------------- // %BANNER_END% namespace UnityEngine.XR.MagicLeap { using System; using System.Runtime.InteropServices; using UnityEngine.XR.MagicLeap.Native; /// /// MLMedia APIs. /// public sealed partial class MLMedia { /// /// Media player script that allows playback of a streaming video (either from file or web URL) /// This script will update the main texture parameter of the Renderer attached as a sibling /// with the video frame from playback. Audio is also handled through this class and will /// playback audio from the file. /// public partial class Player { /// /// See the MLMediaPlayer native plugin "ml_mediaplayer_plugin.cpp" for additional comments. /// internal partial class NativeBindings : Native.MagicLeapNativeBindings { /// /// Delegate for the OnTimedTextUpdate event. /// public delegate void OnTimedTextUpdateDelegate(ulong mediaPlayerHandle, ulong timedTextHandle, IntPtr data); /// /// Delegate for the OnMediaSubtitleUpdate event. /// public delegate void OnMediaSubtitleUpdateDelegate(ulong mediaPlayerHandle, MLMediaPlayerSubtitleData subtitleData, IntPtr data); /// /// Delegate for the OnFrameAvailable event /// public delegate void OnFrameAvailableDelegate(ulong mediaPlayerHandle, IntPtr Data); /// /// Delegate for the OnVideoSizeChanged event /// public delegate void OnVideoSizeChangedDelegate(ulong mediaPlayerHandle, ref MLMediaPlayerOnVideoSizeChangedInfo videoSizeInfo); /// /// Delegate for the OnFramePacking event /// public delegate void OnFramePackingDelegate(ulong mediaPlayerHandle, IntPtr framePackingInfo); /// /// Delegate for the OnInfo event /// public delegate void OnInfoDelegate(ulong mediaPlayerHandle, ref MLMediaPlayerOnInfoInfo info); /// /// Delegate for the OnPrepared event /// public delegate void OnPreparedDelegate(ulong mediaPlayerHandle, ref MLMediaPlayerOnPreparedInfo preparedInfo); /// /// Delegate for the OnBufferingUpdate event /// public delegate void OnBufferingUpdateDelegate(ulong mediaPlayerHandle, ref MLMediaPlayerOnBufferingUpdateInfo updateInfo); /// /// Delegate for the OnCompletion event /// public delegate void OnCompletionDelegate(ulong mediaPlayerHandle, ref MLMediaPlayerOnCompletionInfo completionInfo); /// /// Delegate for the OnError event /// public delegate void OnErrorDelegate(ulong mediaPlayerHandle, ref MLMediaPlayerOnErrorInfo errorInfo); /// /// Delegate for the OnSeekComplete event /// public delegate void OnSeekCompleteDelegate(ulong mediaPlayerHandle, ref MLMediaPlayerOnSeekCompleteInfo seekCompleteInfo); /// /// Delegate for the OnTrackDRMInfo event /// public delegate void OnTrackDRMInfoDelegate(ulong mediaPlayerHandle, ref MLMediaPlayerOnTrackDRMInfo trackDrmInfo); /// /// Delegate for the OnResetComplete event /// public delegate void OnResetCompleteDelegate(ulong mediaPlayerHandle, ref MLMediaPlayerOnResetCompleteInfo resetCompleteInfo); /// /// MediaPlayer Video Size Changed callback Info. /// [StructLayout(LayoutKind.Sequential)] public struct MLMediaPlayerOnVideoSizeChangedInfo { /// /// The new surface width. /// public int Width; /// /// The new surface height. /// public int Height; /// /// User data as passed to MLMediaPlayerSetEventCallbacksEx(). /// public IntPtr Data; }; /// /// MediaPlayer Track Information. /// [StructLayout(LayoutKind.Sequential)] public struct MLMediaPlayerTrackInfo { /// /// Struct version. /// public uint Version; /// /// Media track type, can be either audio or video. /// public Track.Type TrackType; public MLMediaPlayerTrackInfo(Track.Type type) { this.Version = 1; this.TrackType = type; } }; /// /// MediaPlayer DRM Info for a Media Track. /// [StructLayout(LayoutKind.Sequential)] public struct MLMediaPlayerTrackDRMInfo { /// /// Number of PSSH entries. /// public ulong PsshInfoCount; /// /// Pointer to array of #MLMediaPlayerPSSHEntry of size pssh_info_count. /// public IntPtr PsshInfo; /// /// Number of supported DRM UUID entries. /// public ulong UuidCount; /// /// Pointer to array of #MLUUID of size uuid_count. /// public IntPtr UUIDs; /// /// Media track type, can be either audio or video. /// public Track.Type TrackType; public MLMedia.Player.Track.DRM.Info Data { get { var drmTrackInfo = new MLMedia.Player.Track.DRM.Info(); drmTrackInfo.TrackType = this.TrackType; drmTrackInfo.UUIDS = ConvertArray(this.UUIDs, this.UuidCount); drmTrackInfo.PSSHEntries = ConvertArray(this.PsshInfo, this.PsshInfoCount); return drmTrackInfo; } } }; /// /// PSSH entry. /// [StructLayout(LayoutKind.Sequential)] public struct MLMediaPlayerPSSHEntry { /// /// 16 bytes UUID specifying crypto scheme. /// public MagicLeapNativeBindings.MLUUID uuid; /// /// Size of the data payload. /// public ulong size; /// /// Data specific to that scheme. /// public IntPtr data; }; /// /// MediaPlayer Playback prepared callback Info. /// [StructLayout(LayoutKind.Sequential)] public struct MLMediaPlayerOnPreparedInfo { /// /// User data as passed to MLMediaPlayerSetEventCallbacksEx(). /// public IntPtr Data; }; /// /// MediaPlayer subtitle data. /// [StructLayout(LayoutKind.Sequential)] public struct MLMediaPlayerSubtitleData { /// /// Index of the track the subtitle is on. /// public uint TrackIndex; /// /// Start time of the subtitle. /// public ulong StartTimeUs; /// /// Duration of the subtitle. /// public ulong DurationUs; /// /// Size of the Data array. /// public uint DataSize; /// /// Data of the subtitle. /// public IntPtr Data; }; /// /// Indicate the buffering settings. /// [StructLayout(LayoutKind.Sequential)] public struct MLMediaPlayerBufferingSettings { /// /// For prepare. /// public BufferingMode InitialBufferingMode; /// /// For playback. /// public BufferingMode RebufferingMode; /// /// Time based. /// public int InitialWatermarkMs; /// /// Size based. /// public int InitialWatermarkKb; /// /// When cached data is below this mark, playback will be paused for buffering until data reaches /// |mRebufferingWatermarkHighMs| or end of stream. /// public int RebufferingWatermarkLowMs; /// /// When cached data is above this mark, buffering will be paused. /// public int RebufferingWatermarkHighMs; /// /// When cached data is below this mark, playback will be paused for buffering until data reaches /// |mRebufferingWatermarkHighKB| or end of stream. /// public int RebufferingWatermarkLowKb; /// /// When cached data is above this mark, buffering will be paused. /// public int RebufferingWatermarkHighKb; }; /// /// MediaPlayer Buffering update callback Info. /// [StructLayout(LayoutKind.Sequential)] public struct MLMediaPlayerOnBufferingUpdateInfo { /// /// The new percentage of buffered content. /// public int Percent; /// /// User data as passed to MLMediaPlayerSetEventCallbacksEx(). /// public IntPtr Data; }; /// /// MediaPlayer Playback completion callback Info. /// [StructLayout(LayoutKind.Sequential)] public struct MLMediaPlayerOnCompletionInfo { /// /// User data as passed to MLMediaPlayerSetEventCallbacksEx(). /// public IntPtr Data; }; /// /// MediaPlayer Error callback Info. /// [StructLayout(LayoutKind.Sequential)] public struct MLMediaPlayerOnErrorInfo { /// /// Error/result code indicating failure reason. /// public MLResult.Code Result; /// /// User data as passed to MLMediaPlayerSetEventCallbacksEx(). /// public IntPtr Data; }; /// /// MediaPlayer Information callback Info. /// [StructLayout(LayoutKind.Sequential)] public struct MLMediaPlayerOnInfoInfo { /// /// Type of informational event. /// public Info Info; /// /// MLMediaPlayerInfo type specific extra information. When info is MLMediaPlayerInfo_NetworkBandwidth, this holds /// bandwidth in kbps. It is 0 for others. /// public int Extra; /// /// User data as passed to MLMediaPlayerSetEventCallbacksEx(). /// public IntPtr Data; }; /// /// MediaPlayer Playback seek completion callback Info. /// [StructLayout(LayoutKind.Sequential)] public struct MLMediaPlayerOnSeekCompleteInfo { /// /// User data as passed to MLMediaPlayerSetEventCallbacksEx(). /// public IntPtr Data; }; /// /// MediaPlayer Track DRM Info callback Info. /// [StructLayout(LayoutKind.Sequential)] public struct MLMediaPlayerOnTrackDRMInfo { /// /// Pointer to MLMediaPlayerTrackDRMInfo. /// public IntPtr TrackInfo; /// /// User data as passed to MLMediaPlayerSetEventCallbacksEx(). /// public IntPtr Data; }; /// /// MediaPlayer reset completion callback Info. /// [StructLayout(LayoutKind.Sequential)] public struct MLMediaPlayerOnResetCompleteInfo { /// /// User data as passed to MLMediaPlayerSetEventCallbacksEx(). /// public IntPtr Data; }; /// /// MediaPlayer frame packing callback Info. /// [StructLayout(LayoutKind.Sequential)] public struct MLMediaPlayerOnFramePackingInfo { /// /// Frame packing more. /// public FramePackingMode Mode; /// /// Frame packing flag. /// public FramePackingFlags Flags; /// /// User data as passed to MLMediaPlayerSetEventCallbacksEx(). /// public IntPtr Data; }; /// /// Callbacks for notifying client about /// [StructLayout(LayoutKind.Sequential)] public struct MLMediaPlayerEventCallbacksEx { /// /// Struct version. /// private uint version; /// /// This callback function is invoked when buffered contents percentage changed. /// public OnBufferingUpdateDelegate OnBufferingUpdate; /// /// This callback is invoked when media player played back until end of media and has now come to a stop. Note that this /// callback does not fire when 'looping = true', because /// public OnCompletionDelegate OnCompletion; /// /// This callback function is invoked when media player encounters an error. /// public OnErrorDelegate OnError; /// /// This callback function is invoked when /// public OnInfoDelegate OnInfo; /// /// This callback is invoked when the player has finished preparing media and is ready to playback. /// public OnPreparedDelegate OnPrepared; /// /// This callback function is invoked when a seek operation has completed. /// public OnSeekCompleteDelegate OnSeekComplete; /// /// This callback function is invoked when the internal surface has changed size. /// public OnVideoSizeChangedDelegate OnVideoSizeChanged; /// /// This callback function is invoked when source has DRM protected media track(s). /// public OnTrackDRMInfoDelegate OnTrackDRMInfo; /// /// This callback function is invoked when an async reset operation has completed. /// public OnResetCompleteDelegate OnResetComplete; /// /// This callback function is invoked when a stereoscopic video frame packing change. /// public OnFramePackingDelegate OnFramePacking; /// /// Create and return an initialized version of this struct. /// /// A new instance of this struct. public static MLMediaPlayerEventCallbacksEx Create() { return new MLMediaPlayerEventCallbacksEx() { version = 2, OnBufferingUpdate = NativeBindings.OnBufferingUpdate, OnCompletion = NativeBindings.OnCompletion, OnError = NativeBindings.OnError, OnInfo = NativeBindings.OnInfo, OnPrepared = NativeBindings.OnPrepared, OnSeekComplete = NativeBindings.OnSeekComplete, OnVideoSizeChanged = NativeBindings.OnVideoSizeChanged, OnTrackDRMInfo = NativeBindings.OnTrackDRMInfo, OnResetComplete = NativeBindings.OnResetComplete, OnFramePacking = NativeBindings.OnFramePacking }; } }; /// /// DRM Session information for a MediaPlayer Track. /// [StructLayout(LayoutKind.Sequential)] public struct MLMediaPlayerTrackDRMSessionInfo { internal MLMediaPlayerTrackDRMSessionInfo(Track.Type type) { this.Version = 1; this.TrackType = type; this.Uuid = IntPtr.Zero; this.SessionId = IntPtr.Zero; } internal void AllocResources(MagicLeapNativeBindings.MLUUID uuid, Player.Track.DRM.NativeBindings.MLMediaDRMByteArray sessionId) { this.Uuid = Marshal.AllocHGlobal(Marshal.SizeOf()); Marshal.StructureToPtr(uuid, this.Uuid, true); this.SessionId = Marshal.AllocHGlobal(Marshal.SizeOf()); Marshal.StructureToPtr(sessionId, this.SessionId, true); } internal void FreeResources() { Marshal.FreeHGlobal(this.Uuid); Marshal.FreeHGlobal(this.SessionId); } public uint Version; /// /// Media track type, can be either audio or video. /// public Track.Type TrackType; /// /// UUID of the DRM Scheme of type #MLUUID. /// public IntPtr Uuid; /// /// DRM Session ID of type #MLMediaDRMByteArray. /// public IntPtr SessionId; }; /// /// MediaPlayer metrics data. /// [StructLayout(LayoutKind.Sequential)] public struct MLMediaPlayerMetrics { /// /// The average framerate (fps) of video playback /// public float AverageFramerate; /// /// The average bitrate (bps) of video playbac /// public int AverageVideoBitrate; /// /// The average bitrate (bps) of audio playbac /// public int AverageAudioBitrate; }; public enum TTMLLayoutAlignment : uint { Unspecified = 0xFFFFFFFF, Normal = 0, Center = 1, Opposite = 2 } public enum TTMLLineType : uint { Unset = 0xFFFFFFFF, Fraciton = 0, Number = 1 } public enum TTMLAnchorType : uint { Unset = 0xFFFFFFFF, Start = 0, Middle = 1, End = 2 } public enum TTMLTextSizeType : uint { Unset = 0xFFFFFFFF, Fractional = 0, FractionalIgnorePadding = 1, Absolute = 2 } /// /// TTMLData data structure. /// [StructLayout(LayoutKind.Sequential)] public struct TTMLImage { /// /// Image size in bytes. /// public ushort Size; /// /// Byte data of the image. /// public IntPtr Data; } /// /// TTMLData data structure. /// [StructLayout(LayoutKind.Sequential)] public struct TTMLData { /// /// Track cue start time in milliseconds. /// long startTimeMs; /// /// Track cue end time in milliseconds. /// long endTimeMs; /// /// The cue text encoded as UTF-8. Or null if this is an image cue. /// public string text; /// /// The alignment of the cue text within the cue box. /// TTMLLayoutAlignment textAlignment; /// /// The cue image if this is an image cue, an empty image otherwise. /// TTMLImage bitmap; /// /// The cue position within the viewport in the direction orthogonal to the writing direction. /// float line; /// /// The cue line type. /// TTMLLineType lineType; /// /// The cue box anchor in the direction of line. /// TTMLAnchorType lineAnchor; /// /// The cue position within the viewport in the direction orthogonal to line. /// float position; /// /// The cue box anchor in the direction of position. /// TTMLAnchorType positionAnchor; /// /// The cue box size in the writing direction, as a fraction of the viewport size. /// float size; /// /// The cue bitmap height as a fraction of the viewport size. /// float bitmapHeight; /// /// Whether the cue box has a window color. /// bool windowColorSet; /// /// The cue window fill color in ARGB format. /// uint windowColor; /// /// The cue default text size type, or MLTTMLTextSizeType_Unset if this cue has no default text size. /// TTMLTextSizeType textSizeType; /// /// The cue default text size, or MLTTMLDimen_Unset if this cue has no default. /// float textSize; } public enum WebVTTOrientation { Horizontal = 0, Vertical } public enum WebVTTDirection { Default = 0, LeftToRight, RightToLeft } public enum WebVTTAlign { Start = 0, Middle, End, Left, Right } /// /// WebVTT data structure. /// [StructLayout(LayoutKind.Sequential)] public struct WebVTTData { /// /// Track cue start time in milliseconds. /// public long StartTimeMS; /// /// Track cue end time in milliseconds. /// public long EndTimeMs; /// /// WebVTT file body encoded as UTF-8. /// [MarshalAs(UnmanagedType.LPStr)] public string Body; /// /// A sequence of characters unique amongst all the WebVTT cue identifiers. /// [MarshalAs(UnmanagedType.LPStr)] public string Id; /// /// A boolean indicating whether the line is an integer number of lines. /// [MarshalAs(UnmanagedType.I1)] public bool SnapToLines; /// /// Orientation of the cue. /// public WebVTTOrientation Orientation; /// /// The writing direction. /// public WebVTTDirection Direction; /// /// Relative cue line position. /// public float RelativeLinePosition; /// /// WebVTT cue line number. /// public int LineNumber; /// /// The indent of the cue box in the direction defined by the writing direction. /// public float TextPosition; /// /// WebVTT cue size. /// public float Size; /// /// WebVTT cue text alignment. /// public WebVTTAlign align; }; /// /// Converts an unmanged array to a managed array of type T. /// public static T[] ConvertArray(IntPtr arrayPtr, ulong count) { T[] convertedArray = new T[count]; IntPtr walkPtr = arrayPtr; for (ulong i = 0; i < count; ++i) { convertedArray[i] = Marshal.PtrToStructure(walkPtr); walkPtr = new IntPtr(walkPtr.ToInt64() + Marshal.SizeOf()); } return convertedArray; } /// /// Set callbacks to notify clients about player events. This structure must be initialized by calling /// MLMediaPlayerEventCallbacksExInit() before use. Client needs to implement the callback functions declared in /// #MLMediaPlayerEventCallbacksEx, but can set to NULL the ones he does not care about. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerSetEventCallbacksEx(ulong mediaPlayerHandle, [In] ref MLMediaPlayerEventCallbacksEx callbacks, IntPtr Data); /// /// Create a new /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerCreate(out ulong handle); /// /// Reset the /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerReset(ulong mediaPlayerHandle); /// /// Set the 'next' /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerSetNextPlayer(ulong mediaPlayerHandle, ulong NextMediaPlayer); /// /// Stop playback after playback has been stopped or paused. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerStop(ulong mediaPlayerHandle); /// /// Set the looping mode of the player. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerSetLooping(ulong mediaPlayerHandle, [MarshalAs(UnmanagedType.I1)] bool loop); /// /// Return current position of playback. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerGetCurrentPosition(ulong mediaPlayerHandle, out int ms); /// /// Get the handle of the audio stream. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerGetAudioHandle(ulong mediaPlayerHandle, out ulong handle); /// /// Prepare DRM for the selected media (either audio or video) track /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerPrepareTrackDRM(ulong mediaPlayerHandle, [In] ref MLMediaPlayerTrackDRMSessionInfo drmSessionInfo); /// /// Add a timedtext source from a URI. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerAddTimedTextSourceForURI(ulong mediaPlayerHandle, [MarshalAs(UnmanagedType.LPStr)] string Uri, [MarshalAs(UnmanagedType.LPStr)] string MimeType); /// /// Destroy a MediaPlayer object. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerDestroy(ulong mediaPlayerHandle); [DllImport(CUtilsDLL, CallingConvention = CallingConvention.Cdecl)] public static extern void MLUnityQueueMediaPlayerResetAndDestroy(ulong mediaPlayerHandle); /// /// Set a file descriptor as the data source. The file descriptor must be seekable. It is the caller's responsibility to /// close the file descriptor. It is safe to do so as soon as this call returns. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerSetDataSourceForFD(ulong mediaPlayerHandle, int Fd); /// /// Set a file descriptor as the data source with offset. The file descriptor must be seekable. It is the caller's /// responsibility to close the file descriptor. It is safe to do so as soon as this call returns. This API is useful for /// specifying playable media located in resource files. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerSetOffsetDataSourceForFD(ulong mediaPlayerHandle, int Fd, long Offset, long Length); /// /// Set a local file path as the data source. The path should be an absolute path and should reference a world-readable /// file. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerSetDataSourceForPath(ulong mediaPlayerHandle, [MarshalAs(UnmanagedType.LPStr)] string Path); /// /// Set a URI string as the data source. Supported URI schemes are `file`, `http`, `https`, and `rtsp`. If looking to /// provide headers, use MLMediaPlayerSetRemoteDataSourceForURI(). /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerSetDataSourceForURI(ulong mediaPlayerHandle, [MarshalAs(UnmanagedType.LPStr)] string Uri); /// /// Return last info received by internal /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerGetInfo(ulong mediaPlayerHandle, IntPtr OutCode, IntPtr OutExtra); /// /// Set a URI string as the remote data source. Supported URI schemes are `file`, `http`, `https`, and `rtsp`. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerSetRemoteDataSourceForURI(ulong mediaPlayerHandle, [MarshalAs(UnmanagedType.LPStr)] string Uri, out IntPtr Headers, uint Len); /// /// Set the data source to use. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerSetMediaStreamSource(ulong mediaPlayerHandle, ulong MediaStreamSource); /// /// Set the data source to use. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerSetMediaDataSource(ulong mediaPlayerHandle, ulong MediaDataSource); /// /// Add a timedtext source from a file descriptor. The file descriptor must be seekable. It is the caller's responsibility /// to close the file descriptor. It is safe to do so as soon as this call returns. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerAddTimedTextSourceForFD(ulong mediaPlayerHandle, int Fd, long Offset, long Length, [MarshalAs(UnmanagedType.LPStr)] string MimeType); /// /// Return last timed text event information. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerGetTimedText(ulong mediaPlayerHandle, IntPtr OutText, IntPtr OutStart, IntPtr OutEnd); /// /// Reset the /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerResetAsync(ulong mediaPlayerHandle); /// /// Prepare the player for playback, synchronously. After setting the data source and the #GraphicBufferProducer, you need /// to either call prepare() or prepareAsync(). For files, it is OK to call prepare(), which blocks until /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerPrepare(ulong mediaPlayerHandle); /// /// Prepare the player for playback, asynchronously. After setting the data's source and the #GraphicBufferProducer, you /// need to either call prepare() or prepareAsync(). For streams, you should call prepareAsync(), which returns immediately, /// rather than blocking until enough data has been buffered. Prepared state will then be obtained via the 'on_prepared' /// callback if already registered (see MLMediaPlayerSetEventCallbacksEx), or polled for via the MLMediaPlayerPollStates() /// call with the MLMediaPlayerPollingStateFlag_HasBeenPrepared flag set. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerPrepareAsync(ulong mediaPlayerHandle); /// /// Start or resumes playback. If playback had previously been paused, playback will continue from where it was paused. If /// playback had been stopped, or never started before, playback will start at the beginning. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerStart(ulong mediaPlayerHandle); /// /// Pause playback. Calling pause() is a NOOP if /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerPause(ulong mediaPlayerHandle); /// /// Seek to specified time position. Note that SeekTo is an async. function and returns immediately. Successful seek /// result has to be obtained either via the 'on_seek_complete' if already registered (see MLMediaPlayerSetEventCallbacksEx) or /// by polling for the flag 'MLMediaPlayerPollingStateFlag_HasSeekCompleted' when calling MLMediaPlayerPollStates(). /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerSeekTo(ulong mediaPlayerHandle, int Msec, SeekMode Mode); /// /// Return the size of the video frame. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerGetVideoSize(ulong mediaPlayerHandle, out int width, out int height); /// /// Return media duration. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerGetDuration(ulong mediaPlayerHandle, out int durationMS); /// /// Return current buffering percentage. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerGetBufferingUpdate(ulong mediaPlayerHandle, IntPtr OutPercentage); /// /// Return last error received by internal /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerGetError(ulong mediaPlayerHandle, IntPtr OutResult); /// /// Return last subtitle event information. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerGetSubtitleEx(ulong mediaPlayerHandle, IntPtr OutSubtitleData); /// /// Release last subtitle event information. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerReleaseSubtitleEx(ulong mediaPlayerHandle); /// /// Set callback to get notified when a subtitle update is available along with its data. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerSetOnMediaSubtitleUpdateCallback(ulong mediaPlayerHandle, OnMediaSubtitleUpdateDelegate OnMediaSubtitleCallback, IntPtr Data); /// /// Return last metadata event information. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerGetMetadata(ulong mediaPlayerHandle, IntPtr OutTime, IntPtr OutSize, IntPtr OutBuffer); /// /// Set video scaling mode. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerSetVideoScalingMode(ulong mediaPlayerHandle, VideoScalingMode Mode); /// /// Set the volume on this player. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerSetVolume(ulong mediaPlayerHandle, float Volume); /// /// Poll the desired states from internal /// The "is_XXX" states can be polled multiples times and the return value will /// be the same if internal state hasn't changed since last call. /// When polling the "has_XXX" states however, internal state is set to false, /// since they mean : has happened/changed since I last polled /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerPollStates(ulong mediaPlayerHandle, PollingStateFlags flags, out PollingStateFlags polledStates); /// /// Get the DRM info of the selected media (either audio or video) track. This function has to be called only after /// DataSource has been set and the MediaPlayer is completely prepared. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerGetTrackDRMInfo(ulong mediaPlayerHandle, ref MLMediaPlayerTrackInfo trackInfo, ref IntPtr drmInfo); /// /// Get WebVTT data represented by a timed text handle. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerGetWebVTTData(ulong mediaPlayerHandle, ulong TimedText, ref IntPtr webVTTData); /// /// Release DRM. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerReleaseDRM(ulong mediaPlayerHandle); /// /// Get default Buffering settings. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerGetDefaultBufferingSettings(ulong mediaPlayerHandle, IntPtr OutBufSettings); /// /// Get current Buffering settings. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerGetBufferingSettings(ulong mediaPlayerHandle, IntPtr OutBufSettings); /// /// Set Buffering settings. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerSetBufferingSettings(ulong mediaPlayerHandle, NativeBindings.MLMediaPlayerBufferingSettings BufSettings); /// /// Set callback to get invoked when a Timed Text update is available along with its data. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerSetOnMediaTimedTextUpdateCallback(ulong mediaPlayerHandle, OnTimedTextUpdateDelegate OnMediaTimedTextCallback, IntPtr Data); /// /// Retrieve metrics recorded on the MediaPlayer. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerGetMetrics(ulong mediaPlayerHandle, out MLMediaPlayerMetrics metrics); /// /// Select a track. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerSelectTrack(ulong mediaPlayerHandle, uint trackIndex); /// /// Unselect a track. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerUnselectTrack(ulong mediaPlayerHandle, uint trackIndex); /// /// Count the number of tracks found in the data source. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerGetTrackCount(ulong mediaPlayerHandle, out uint trackCount); /// /// Get TTML data represented by a timed text handle. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerGetTTMLData(ulong mediaPlayerHandle, ulong timedTextHandle, ref IntPtr ttmlData); /// /// Sets the Native surface to be used as the sink for displaying the video portion of the media. /// [DllImport(MLMediaPlayerDll, CallingConvention = CallingConvention.Cdecl)] public static extern MLResult.Code MLMediaPlayerSetSurface(ulong mediaPlayerHandle, ulong surface); /// /// Callback for the OnVideoSizeChanged event. /// [AOT.MonoPInvokeCallback(typeof(NativeBindings.OnVideoSizeChangedDelegate))] private static void OnVideoSizeChanged(ulong mediaPlayerHandle, ref NativeBindings.MLMediaPlayerOnVideoSizeChangedInfo videoSizeInfo) { GCHandle gcHandle = GCHandle.FromIntPtr(videoSizeInfo.Data); Player mediaPlayer = gcHandle.Target as Player; var resultCode = NativeBindings.MLMediaPlayerGetVideoSize(mediaPlayer.handle, out int width, out int height); MLResult.DidNativeCallSucceed(resultCode, nameof(NativeBindings.MLMediaPlayerGetVideoSize)); MLThreadDispatch.Call(mediaPlayer, width, height, mediaPlayer.OnVideoSizeChanged); } /// /// Callback for the OnFramePacking event. /// [AOT.MonoPInvokeCallback(typeof(NativeBindings.OnFramePackingDelegate))] private static void OnFramePacking(ulong mediaPlayerHandle, IntPtr FramePackingInfo) { throw new System.NotImplementedException(); } /// /// Callback for the OnInfo event. /// [AOT.MonoPInvokeCallback(typeof(NativeBindings.OnInfoDelegate))] private static void OnInfo(ulong mediaPlayerHandle, ref NativeBindings.MLMediaPlayerOnInfoInfo info) { GCHandle gcHandle = GCHandle.FromIntPtr(info.Data); Player mediaPlayer = gcHandle.Target as Player; if (info.Info == Info.MetadataUpdate) { MLThreadDispatch.Call(mediaPlayer.GetTracks); } MLThreadDispatch.Call(mediaPlayer, info.Info, mediaPlayer.OnInfo); } /// /// Callback for the OnPrepared event. /// [AOT.MonoPInvokeCallback(typeof(NativeBindings.OnPreparedDelegate))] private static void OnPrepared(ulong mediaPlayerHandle, ref NativeBindings.MLMediaPlayerOnPreparedInfo preparedInfo) { GCHandle gcHandle = GCHandle.FromIntPtr(preparedInfo.Data); Player mediaPlayer = gcHandle.Target as Player; mediaPlayer.IsPrepared = true; MLThreadDispatch.Call(mediaPlayer.GetTracks); MLThreadDispatch.Call(mediaPlayer, mediaPlayer.OnPrepared); foreach (MLMedia.Player.Track.DRM.Info info in mediaPlayer.drmTrackInfos) MLThreadDispatch.Call(mediaPlayer, info, mediaPlayer.OnDRMTrackInfo); } /// /// Callback for the OnBufferingUpdate event. /// [AOT.MonoPInvokeCallback(typeof(NativeBindings.OnBufferingUpdateDelegate))] private static void OnBufferingUpdate(ulong mediaPlayerHandle, ref NativeBindings.MLMediaPlayerOnBufferingUpdateInfo updateInfo) { GCHandle gcHandle = GCHandle.FromIntPtr(updateInfo.Data); Player mediaPlayer = gcHandle.Target as Player; float percent = updateInfo.Percent; MLThreadDispatch.Call(mediaPlayer, percent, mediaPlayer.OnBufferingUpdate); } /// /// Callback for the OnCompletion event. /// [AOT.MonoPInvokeCallback(typeof(NativeBindings.OnCompletionDelegate))] private static void OnCompletion(ulong mediaPlayerHandle, ref NativeBindings.MLMediaPlayerOnCompletionInfo completionInfo) { GCHandle gcHandle = GCHandle.FromIntPtr(completionInfo.Data); Player mediaPlayer = gcHandle.Target as Player; MLThreadDispatch.Call(mediaPlayer, mediaPlayer.OnCompletion); } /// /// Callback for the OnError event. /// [AOT.MonoPInvokeCallback(typeof(NativeBindings.OnErrorDelegate))] private static void OnError(ulong mediaPlayerHandle, ref NativeBindings.MLMediaPlayerOnErrorInfo errorInfo) { GCHandle gcHandle = GCHandle.FromIntPtr(errorInfo.Data); Player mediaPlayer = gcHandle.Target as Player; MLThreadDispatch.Call(mediaPlayer, errorInfo.Result, mediaPlayer.OnError); } /// /// Callback for the OnSeekComplete event. /// [AOT.MonoPInvokeCallback(typeof(NativeBindings.OnSeekCompleteDelegate))] private static void OnSeekComplete(ulong mediaPlayerHandle, ref NativeBindings.MLMediaPlayerOnSeekCompleteInfo seekCompleteInfo) { GCHandle gcHandle = GCHandle.FromIntPtr(seekCompleteInfo.Data); Player mediaPlayer = gcHandle.Target as Player; MLThreadDispatch.Call(mediaPlayer, mediaPlayer.OnSeekComplete); } /// /// Callback for the OnTrackDRMInfo event. This happens before media player is fully prepared. /// [AOT.MonoPInvokeCallback(typeof(NativeBindings.OnTrackDRMInfoDelegate))] private static void OnTrackDRMInfo(ulong mediaPlayerHandle, ref NativeBindings.MLMediaPlayerOnTrackDRMInfo trackDrmInfo) { GCHandle gcHandle = GCHandle.FromIntPtr(trackDrmInfo.Data); Player mediaPlayer = gcHandle.Target as Player; MLMediaPlayerTrackDRMInfo trackInfo = Marshal.PtrToStructure(trackDrmInfo.TrackInfo); mediaPlayer.drmTrackInfos.Add(trackInfo.Data); } /// /// Callback for the OnResetComplete event. /// [AOT.MonoPInvokeCallback(typeof(NativeBindings.OnResetCompleteDelegate))] private static void OnResetComplete(ulong mediaPlayerHandle, ref NativeBindings.MLMediaPlayerOnResetCompleteInfo resetCompleteInfo) { GCHandle gcHandle = GCHandle.FromIntPtr(resetCompleteInfo.Data); Player mediaPlayer = gcHandle.Target as Player; MLThreadDispatch.Call(mediaPlayer, mediaPlayer.OnResetComplete); } /// /// Callback for the OnTimedTextUpdate event. /// [AOT.MonoPInvokeCallback(typeof(NativeBindings.OnTimedTextUpdateDelegate))] public static void OnTimedTextUpdate(ulong mediaPlayerHandle, ulong timedTextHandle, IntPtr data) { GCHandle gcHandle = GCHandle.FromIntPtr(data); Player mediaPlayer = gcHandle.Target as Player; Track selectedTrack = mediaPlayer.trackContainers[Track.Type.TimedText].SelectedTrack; switch (selectedTrack.MimeType) { case VTTMime: { var resultCode = NativeBindings.MLMediaPlayerGetWebVTTData(mediaPlayerHandle, timedTextHandle, ref mediaPlayer.WebVTTDataPtr); MLResult.DidNativeCallSucceed(resultCode, nameof(NativeBindings.MLMediaPlayerGetWebVTTData)); WebVTTData webVTTData = Marshal.PtrToStructure(mediaPlayer.WebVTTDataPtr); MLThreadDispatch.Call(mediaPlayer, webVTTData.Body, mediaPlayer.OnTimedText); break; } case TTMLMime: { var resultCode = NativeBindings.MLMediaPlayerGetTTMLData(mediaPlayerHandle, timedTextHandle, ref mediaPlayer.TTMLDataPtr); MLResult.DidNativeCallSucceed(resultCode, nameof(NativeBindings.MLMediaPlayerGetTTMLData)); TTMLData ttmlData = Marshal.PtrToStructure(mediaPlayer.TTMLDataPtr); MLThreadDispatch.Call(mediaPlayer, ttmlData.text, mediaPlayer.OnTimedText); break; } } } /// /// Callback for the OnMediaSubtitleUpdate event. /// [AOT.MonoPInvokeCallback(typeof(NativeBindings.OnMediaSubtitleUpdateDelegate))] public static void OnMediaSubtitleUpdate(ulong mediaPlayerHandle, MLMediaPlayerSubtitleData subtitleData, IntPtr data) { GCHandle gcHandle = GCHandle.FromIntPtr(data); Player mediaPlayer = gcHandle.Target as Player; Track selectedTrack = mediaPlayer.trackContainers[Track.Type.Subtitle].SelectedTrack; // TODO : improve this. We can probably determine the available subtitle track formats once the media is prepared // and we receive the respective MLMediaFormat objects and only initialize the apt parser. switch (selectedTrack.MimeType) { case ParserCEA608.Mime: { mediaPlayer.parser608.ParseAsync(subtitleData.Data, subtitleData.DataSize); break; } case ParserCEA708.Mime: { mediaPlayer.parser708.ParseAsync(subtitleData.Data, subtitleData.DataSize); break; } } } } } } }