using System; using System.Collections; using System.Runtime.InteropServices; using System.Collections.Generic; using System.Linq; using System.Threading; using UnityEngine; using UMP.Wrappers; namespace UMP { public class MediaPlayerStandalone : IPlayer, IPlayerAudio, IPlayerSpu { private MonoBehaviour _monoObject; private WrapperStandalone _wrapper; /// Native VLC library callback pointers private IntPtr _lockPtr; private IntPtr _displayPtr; private IntPtr _formatSetupPtr; private IntPtr _audioPlayPtr; private IntPtr _audioFormatPtr; private IntPtr _eventHandlerPtr; private IntPtr _eventManagerPtr; private IntPtr _vlcObj; private IntPtr _mediaObj; private IntPtr _playerObj; private int _framesCounter; private float _frameRate; private float _tmpTime; private int _tmpFramesCounter; private bool _isStarted; private bool _isPlaying; private bool _isLoad; private bool _isReady; private bool _isImageReady; private bool _isTextureExist; private LogLevels _logDetail; private Action _logListener; private string _dataSource; private PlayerBufferVideo _videoBuffer; private PlayerManagerLogs _logManager; private PlayerManagerEvents _eventManager; private PlayerOptionsStandalone _options; private MediaStats _mediaStats; private string[] _arguments; private Texture2D _videoTexture; private GameObject[] _videoOutputObjects; private PlayerManagerAudios _audioManager; private GCHandle _audioDataHandle = default(GCHandle); private delegate void ManageBufferSizeCallback(int width, int height); private ManageBufferSizeCallback _manageBufferSizeCallback; private IEnumerator _updateVideoTextureEnum; #region Constructors /// /// Create instance of MediaPlayerStandalone object with additional arguments /// /// MonoBehaviour instanse /// Objects that will be rendering video output /// Additional player options public MediaPlayerStandalone(MonoBehaviour monoObject, GameObject[] videoOutputObjects, PlayerOptionsStandalone options) { _monoObject = monoObject; _videoOutputObjects = videoOutputObjects; _options = options; _wrapper = new WrapperStandalone(_options); if (_wrapper.NativeIndex < 0) { Debug.LogError("Don't support video playback on current platform or you use incorrect UMP libraries!"); throw new Exception(); } if (_options != null) { if (!string.IsNullOrEmpty(_options.DirectAudioDevice)) _options.DirectAudioDevice = GetAudioDevice(_options.DirectAudioDevice); _wrapper.NativeSetPixelsVerticalFlip(_options.FlipVertically); if (_options.AudioOutputs != null && _options.AudioOutputs.Length > 0) { _audioManager = new PlayerManagerAudios(_options.AudioOutputs); _audioManager.AddListener(OnAudioFilterRead); } _arguments = _options.GetOptions('\n').Split('\n'); _logDetail = _options.LogDetail; _logListener = _options.LogListener; } MediaPlayerInit(); } #endregion private void MediaPlayerInit() { _vlcObj = _wrapper.ExpandedLibVLCNew(_arguments); if (_vlcObj == IntPtr.Zero) throw new Exception("Can't create new libVLC object instance"); _playerObj = _wrapper.ExpandedMediaPlayerNew(_vlcObj); if (_playerObj == IntPtr.Zero) throw new Exception("Can't create new media player object instance"); _eventManagerPtr = _wrapper.ExpandedEventManager(_playerObj); _eventHandlerPtr = _wrapper.NativeMediaPlayerEventCallback(); EventsAttach(_eventManagerPtr, _eventHandlerPtr); _eventManager = new PlayerManagerEvents(_monoObject, this); _eventManager.PlayerPlayingListener += OnPlayerPlaying; _eventManager.PlayerPausedListener += OnPlayerPaused; if (_logDetail != LogLevels.Disable) _wrapper.ExpandedLogSet(_vlcObj, _wrapper.NativeGetLogMessageCallback(), new IntPtr(_wrapper.NativeIndex)); _logManager = new PlayerManagerLogs(_monoObject, this); _logManager.LogDetail = _logDetail; _logManager.LogMessageListener += _logListener; _lockPtr = _wrapper.NativeGetVideoLockCallback(); _displayPtr = _wrapper.NativeGetVideoDisplayCallback(); _formatSetupPtr = _wrapper.NativeGetVideoFormatCallback(); _audioFormatPtr = _wrapper.NativeGetAudioSetupCallback(); _audioPlayPtr = _wrapper.NativeGetAudioPlayCallback(); _wrapper.ExpandedVideoSetCallbacks(_playerObj, _lockPtr, IntPtr.Zero, _displayPtr, new IntPtr(_wrapper.NativeIndex)); if (_options.FixedVideoSize == Vector2.zero) _wrapper.ExpandedVideoSetFormatCallbacks(_playerObj, _formatSetupPtr, IntPtr.Zero); else _wrapper.ExpandedVideoSetFormat(_playerObj, PlayerBufferVideo.Chroma, (int)_options.FixedVideoSize.x, (int)_options.FixedVideoSize.y, PlayerBufferVideo.CalculatePitch((int)_options.FixedVideoSize.x)); _manageBufferSizeCallback = InitBufferSize; _wrapper.NativeSetBufferSizeCallback(Marshal.GetFunctionPointerForDelegate(_manageBufferSizeCallback)); if (_audioManager != null && _audioManager.IsValid) { _wrapper.ExpandedAudioSetFormatCallbacks(_playerObj, _audioFormatPtr, IntPtr.Zero); _wrapper.ExpandedAudioSetCallbacks(_playerObj, _audioPlayPtr, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, new IntPtr(_wrapper.NativeIndex)); _wrapper.NativeSetAudioParams(2, AudioSettings.outputSampleRate); } _mediaStats = new MediaStats(); } #region Private methods private void OnRelease() { bool threadDone = false; while (!threadDone) { threadDone = _monoObject == null; Thread.Sleep(1000); } Release(); } private void InitBufferSize(int width, int height) { _wrapper.NativePixelsBufferRelease(); if (_videoBuffer != null) { if (_videoBuffer.Width != width || _videoBuffer.Height != height) { _videoBuffer.ClearFramePixels(); _videoBuffer = null; } } if (_videoBuffer == null) { _videoBuffer = new PlayerBufferVideo(width, height); _wrapper.NativeSetPixelsBuffer(_videoBuffer.FramePixelsAddr, _videoBuffer.Width, _videoBuffer.Height); _isTextureExist = false; } } private string GetAudioDevice(string description) { var audioDevicesAoutNames = new string[] { "directsound", "directx" }; var vlcObj = _wrapper.ExpandedLibVLCNew(null); var audioDevicePtr = _wrapper.ExpandedAudioOutputListGet(vlcObj); var audioDevicesPtr = IntPtr.Zero; var audioDeviceName = string.Empty; var audioDevice = new AudioDescription { NextDescription = audioDevicePtr, Description = null, Name = null }; while (audioDevice.NextDescription != IntPtr.Zero) { audioDevice = (AudioDescription)Marshal.PtrToStructure(audioDevice.NextDescription, typeof(AudioDescription)); for (int i = 0; i < audioDevicesAoutNames.Length; i += 2) { if (audioDevice.Name.Contains(audioDevicesAoutNames[i])) { audioDevicesPtr = _wrapper.ExpandedAudioOutputDeviceListGet(vlcObj, audioDevicesAoutNames[i + 1]); break; } } } if (audioDevicesPtr == IntPtr.Zero) { Debug.Log("GetAudioDevice: Can't get audio output device list for " + audioDevice.Name); return audioDeviceName; } AudioOutputDevice outputDevice = new AudioOutputDevice { NextDevice = audioDevicesPtr, Description = null, Device = null }; try { while (outputDevice.NextDevice != IntPtr.Zero) { outputDevice = (AudioOutputDevice)Marshal.PtrToStructure(outputDevice.NextDevice, typeof(AudioOutputDevice)); if (outputDevice.Description.Contains(description)) { Debug.Log("GetAudioDevice: New audio output device \n" + "Device: " + outputDevice.Device + "\n" + "Description: " + outputDevice.Description); audioDeviceName = outputDevice.Device; } } } finally { if (audioDevicePtr != IntPtr.Zero) _wrapper.ExpandedAudioOutputListRelease(audioDevicePtr); if (audioDevicesPtr != IntPtr.Zero) _wrapper.ExpandedAudioOutputDeviceListRelease(audioDevicesPtr); _wrapper.ExpandedLibVLCRelease(vlcObj); } if (string.IsNullOrEmpty(audioDeviceName)) Debug.Log("GetAudioDevice: Can't find audio output device - switched to Default"); return audioDeviceName; } private void UpdateFpsCounter(int frameCounter) { float currentTime = UnityEngine.Time.time; currentTime = (currentTime > _tmpTime) ? currentTime - _tmpTime : 0; if (currentTime >= 1f) { _frameRate = frameCounter - _tmpFramesCounter; _tmpFramesCounter = frameCounter; _tmpTime = UnityEngine.Time.time; } } private void EventsAttach(IntPtr eventManager, IntPtr enentHandlerPtr) { string exceptionMsg = "Failed to subscribe to event notification"; if (_wrapper.ExpandedEventAttach(eventManager, EventTypes.MediaPlayerOpening, enentHandlerPtr, (IntPtr)_wrapper.NativeIndex) != 0) throw new OutOfMemoryException(exceptionMsg + " (Opening)"); if (_wrapper.ExpandedEventAttach(eventManager, EventTypes.MediaPlayerBuffering, enentHandlerPtr, (IntPtr)_wrapper.NativeIndex) != 0) throw new OutOfMemoryException(exceptionMsg + " (Buffering)"); //if (_wrapper.ExpandedEventAttach(eventManager, EventTypes.MediaPlayerPlaying, enentHandlerPtr, (IntPtr)_wrapper.NativeIndex) != 0) // throw new OutOfMemoryException(exceptionMsg + " (Playing)"); if (_wrapper.ExpandedEventAttach(eventManager, EventTypes.MediaPlayerPaused, enentHandlerPtr, (IntPtr)_wrapper.NativeIndex) != 0) throw new OutOfMemoryException(exceptionMsg + " (Paused)"); if (_wrapper.ExpandedEventAttach(eventManager, EventTypes.MediaPlayerStopped, enentHandlerPtr, (IntPtr)_wrapper.NativeIndex) != 0) throw new OutOfMemoryException(exceptionMsg + " (Stopped)"); if (_wrapper.ExpandedEventAttach(eventManager, EventTypes.MediaPlayerEndReached, enentHandlerPtr, (IntPtr)_wrapper.NativeIndex) != 0) throw new OutOfMemoryException(exceptionMsg + " (EndReached)"); if (_wrapper.ExpandedEventAttach(eventManager, EventTypes.MediaPlayerEncounteredError, enentHandlerPtr, (IntPtr)_wrapper.NativeIndex) != 0) throw new OutOfMemoryException(exceptionMsg + " (EncounteredError)"); if (_wrapper.ExpandedEventAttach(eventManager, EventTypes.MediaPlayerTimeChanged, enentHandlerPtr, (IntPtr)_wrapper.NativeIndex) != 0) throw new OutOfMemoryException(exceptionMsg + " (TimeChanged)"); if (_wrapper.ExpandedEventAttach(eventManager, EventTypes.MediaPlayerPositionChanged, enentHandlerPtr, (IntPtr)_wrapper.NativeIndex) != 0) throw new OutOfMemoryException(exceptionMsg + " (PositionChanged)"); if (_wrapper.ExpandedEventAttach(eventManager, EventTypes.MediaPlayerSnapshotTaken, enentHandlerPtr, (IntPtr)_wrapper.NativeIndex) != 0) throw new OutOfMemoryException(exceptionMsg + " (SnapshotTaken)"); } private void EventsDettach(IntPtr eventManager, IntPtr enentHandlerPtr) { _wrapper.ExpandedEventDetach(eventManager, EventTypes.MediaPlayerOpening, enentHandlerPtr, (IntPtr)_wrapper.NativeIndex); _wrapper.ExpandedEventDetach(eventManager, EventTypes.MediaPlayerBuffering, enentHandlerPtr, (IntPtr)_wrapper.NativeIndex); //_wrapper.ExpandedEventDetach(eventManager, EventTypes.MediaPlayerPlaying, enentHandlerPtr, (IntPtr)_wrapper.NativeIndex); _wrapper.ExpandedEventDetach(eventManager, EventTypes.MediaPlayerPaused, enentHandlerPtr, (IntPtr)_wrapper.NativeIndex); _wrapper.ExpandedEventDetach(eventManager, EventTypes.MediaPlayerStopped, enentHandlerPtr, (IntPtr)_wrapper.NativeIndex); _wrapper.ExpandedEventDetach(eventManager, EventTypes.MediaPlayerEndReached, enentHandlerPtr, (IntPtr)_wrapper.NativeIndex); _wrapper.ExpandedEventDetach(eventManager, EventTypes.MediaPlayerEncounteredError, enentHandlerPtr, (IntPtr)_wrapper.NativeIndex); _wrapper.ExpandedEventDetach(eventManager, EventTypes.MediaPlayerTimeChanged, enentHandlerPtr, (IntPtr)_wrapper.NativeIndex); _wrapper.ExpandedEventDetach(eventManager, EventTypes.MediaPlayerPositionChanged, enentHandlerPtr, (IntPtr)_wrapper.NativeIndex); _wrapper.ExpandedEventDetach(eventManager, EventTypes.MediaPlayerSnapshotTaken, enentHandlerPtr, (IntPtr)_wrapper.NativeIndex); } private IEnumerator UpdateVideoTexture() { MediaTrackInfoExpanded[] tracks = null; var hasVideo = false; while (true) { if (_playerObj != IntPtr.Zero && _wrapper.PlayerIsPlaying(_playerObj)) { if (tracks == null) { tracks = TracksInfo; if (tracks != null) { foreach (var track in tracks) { if (track is MediaTrackInfoVideo) hasVideo = true; } } else { yield return null; continue; } } if (FramesCounter != _framesCounter) { _framesCounter = FramesCounter; UpdateFpsCounter(_framesCounter); if (!_isTextureExist) { if (_videoTexture != null) { UnityEngine.Object.Destroy(_videoTexture); _videoTexture = null; } _videoTexture = MediaPlayerHelper.GenPluginTexture(_videoBuffer.Width, _videoBuffer.Height); MediaPlayerHelper.ApplyTextureToRenderingObjects(_videoTexture, _videoOutputObjects); _wrapper.NativeSetTexture(_videoTexture.GetNativeTexturePtr()); _isTextureExist = true; _isImageReady = false; } GL.IssuePluginEvent(_wrapper.NativeGetUnityRenderCallback(), _wrapper.NativeIndex); if (!_isImageReady) { _eventManager.SetEvent(PlayerState.ImageReady, _videoTexture); _isImageReady = true; } } if (!_isReady && (hasVideo ? (_videoTexture != null && _videoBuffer != null) : tracks != null)) { _isReady = true; if (_isLoad) { _eventManager.ReplaceEvent(PlayerState.Paused, PlayerState.Prepared, new Vector2(VideoWidth, VideoHeight)); Pause(); } else { _eventManager.SetEvent(PlayerState.Prepared, new Vector2(VideoWidth, VideoHeight)); _eventManager.SetEvent(PlayerState.Playing); } } } yield return null; } } private IEnumerator InitAudioOutput() { while (true) { var paramsLine = _wrapper.NativeGetAudioParams('@'); int channels, rate = 0; if (!string.IsNullOrEmpty(paramsLine)) { var options = paramsLine.Split('@'); if (options.Length >= 1) { int.TryParse(options[0], out channels); int.TryParse(options[1], out rate); if (channels > 0 || rate > 0) break; } } yield return null; } } private void OnAudioFilterRead(int id, float[] data, AudioOutput.AudioChannels audioChannel) { var samplesCount = _wrapper.NativeGetAudioSamples(IntPtr.Zero, 0, audioChannel); if (samplesCount >= data.Length) { if (!_audioDataHandle.IsAllocated) _audioDataHandle = GCHandle.Alloc(data, GCHandleType.Pinned); _wrapper.NativeGetAudioSamples(_audioDataHandle.AddrOfPinnedObject(), data.Length, audioChannel); _audioManager.SetOutputData(id, data); } if (_audioManager.OutputsDataUpdated) { _wrapper.NativeClearAudioSamples(data.Length); _audioManager.ResetOutputsData(); } } private void OnPlayerPlaying() { _isPlaying = true; } private void OnPlayerPaused() { _isPlaying = false; } #endregion #region Public methods public GameObject[] VideoOutputObjects { set { _videoOutputObjects = value; MediaPlayerHelper.ApplyTextureToRenderingObjects(_videoTexture, _videoOutputObjects); } get { return _videoOutputObjects; } } public PlayerManagerEvents EventManager { get { return _eventManager; } } public PlayerOptions Options { get { return _options; } } public PlayerState State { get { if (_eventManagerPtr != IntPtr.Zero) return _wrapper.PlayerGetState(); return PlayerState.Empty; } } public object StateValue { get { if (_eventManagerPtr != IntPtr.Zero) return _wrapper.PlayerGetStateValue(); return null; } } public void AddMediaListener(IMediaListener listener) { if (_eventManager != null) { _eventManager.PlayerOpeningListener += listener.OnPlayerOpening; _eventManager.PlayerBufferingListener += listener.OnPlayerBuffering; _eventManager.PlayerImageReadyListener += listener.OnPlayerImageReady; _eventManager.PlayerPreparedListener += listener.OnPlayerPrepared; _eventManager.PlayerPlayingListener += listener.OnPlayerPlaying; _eventManager.PlayerPausedListener += listener.OnPlayerPaused; _eventManager.PlayerStoppedListener += listener.OnPlayerStopped; _eventManager.PlayerEndReachedListener += listener.OnPlayerEndReached; _eventManager.PlayerEncounteredErrorListener += listener.OnPlayerEncounteredError; } } public void RemoveMediaListener(IMediaListener listener) { if (_eventManager != null) { _eventManager.PlayerOpeningListener -= listener.OnPlayerOpening; _eventManager.PlayerBufferingListener -= listener.OnPlayerBuffering; _eventManager.PlayerImageReadyListener -= listener.OnPlayerImageReady; _eventManager.PlayerPreparedListener -= listener.OnPlayerPrepared; _eventManager.PlayerPlayingListener -= listener.OnPlayerPlaying; _eventManager.PlayerPausedListener -= listener.OnPlayerPaused; _eventManager.PlayerStoppedListener -= listener.OnPlayerStopped; _eventManager.PlayerEndReachedListener -= listener.OnPlayerEndReached; _eventManager.PlayerEncounteredErrorListener -= listener.OnPlayerEncounteredError; } } public void Prepare() { _isLoad = true; Play(); } /// /// Play or resume (True if playback started (and was already started), or False on error. /// /// public bool Play() { if (_playerObj != IntPtr.Zero) { if (!_isStarted) { if (_eventManager != null) _eventManager.StartListener(); if (_logManager != null) _logManager.StartListener(); if (_options.FixedVideoSize != Vector2.zero) InitBufferSize((int)_options.FixedVideoSize.x, (int)_options.FixedVideoSize.y); _wrapper.NativeUpdateFramesCounter(0); } if (_updateVideoTextureEnum == null) { _updateVideoTextureEnum = UpdateVideoTexture(); _monoObject.StartCoroutine(_updateVideoTextureEnum); } _isStarted = _wrapper.PlayerPlay(_playerObj); if (_isStarted) { if (_audioManager != null) _audioManager.Play(); if (_isReady && !_isPlaying) _eventManager.SetEvent(PlayerState.Playing); } else { Stop(); } } return _isStarted; } /// /// Pause current video playback /// public void Pause() { if (_playerObj != IntPtr.Zero) { if (_videoOutputObjects == null && _updateVideoTextureEnum != null) { _monoObject.StopCoroutine(_updateVideoTextureEnum); _updateVideoTextureEnum = null; } _wrapper.PlayerPause(_playerObj); if (_audioManager != null && _videoOutputObjects != null) _audioManager.Pause(); } } /// /// Stop current video playback /// /// Clear previous playback texture public void Stop(bool resetTexture) { if (_playerObj != IntPtr.Zero && _isStarted) { _wrapper.PlayerStop(_playerObj); if (_updateVideoTextureEnum != null) { _monoObject.StopCoroutine(_updateVideoTextureEnum); _updateVideoTextureEnum = null; } _framesCounter = 0; _frameRate = 0; _tmpFramesCounter = 0; _tmpTime = 0; _isStarted = false; _isPlaying = false; _isLoad = false; _isReady = false; _isImageReady = false; _wrapper.NativeUpdateFramesCounter(0); _wrapper.NativeClearAudioSamples(0); _wrapper.NativePixelsBufferRelease(); _isTextureExist = !resetTexture; if (resetTexture) { if (_videoTexture != null) { UnityEngine.Object.Destroy(_videoTexture); _videoTexture = null; } if (_videoBuffer != null) { _videoBuffer.ClearFramePixels(); _videoBuffer = null; } } if (_audioDataHandle.IsAllocated) _audioDataHandle.Free(); if (_audioManager != null) _audioManager.Stop(); if (_eventManager != null) _eventManager.StopListener(); if (_logManager != null) _logManager.StopListener(); } } /// /// Stop current video playback /// public void Stop() { Stop(true); } /// /// Release current video player /// public void Release() { if (_playerObj != IntPtr.Zero) Stop(); if (_eventManager != null) { _eventManager.RemoveAllEvents(); _eventManager = null; if (_eventHandlerPtr != IntPtr.Zero) EventsDettach(_eventManagerPtr, _eventHandlerPtr); } if (_logManager != null) { _logManager.RemoveAllEvents(); if (_logDetail != LogLevels.Disable && _vlcObj != IntPtr.Zero) _wrapper.ExpandedLogUnset(_vlcObj); } if (_audioManager != null) _audioManager.RemoveAllListeners(); if (_playerObj != IntPtr.Zero) _wrapper.PlayerRelease(_playerObj); _playerObj = IntPtr.Zero; if (_vlcObj != IntPtr.Zero) _wrapper.ExpandedLibVLCRelease(_vlcObj); _vlcObj = IntPtr.Zero; } public string DataSource { get { return _dataSource; } set { if (_playerObj != IntPtr.Zero) { _dataSource = value; if (_mediaObj != IntPtr.Zero) _wrapper.ExpandedMediaRelease(_mediaObj); _mediaObj = _wrapper.ExpandedMediaNewLocation(_vlcObj, MediaPlayerHelper.GetDataSourcePath(_dataSource)); if (_arguments != null) { foreach (string option in _arguments) { if (option.Contains(":")) _wrapper.ExpandedAddOption(_mediaObj, option); } } _wrapper.ExpandedSetMedia(_playerObj, _mediaObj); } } } public bool IsPlaying { get { return _isPlaying; } } public bool IsReady { get { return _isReady; } } public bool AbleToPlay { get { if (_playerObj != IntPtr.Zero) return _wrapper.PlayerWillPlay(_playerObj); return false; } } /// /// Get the current movie length (in ms). /// /// public long Length { get { if (_playerObj != IntPtr.Zero) return _wrapper.PlayerGetLength(_playerObj); return 0; } } /// /// Get the current movie formatted length (hh:mm:ss[:ms]). /// /// True: formatted length will be with [:ms] /// public string GetFormattedLength(bool detail) { var length = TimeSpan.FromMilliseconds(Length); var format = detail ? "{0:D2}:{1:D2}:{2:D2}:{3:D3}" : "{0:D2}:{1:D2}:{2:D2}"; return string.Format(format, length.Hours, length.Minutes, length.Seconds, length.Milliseconds); } public float FrameRate { get { return _frameRate; } } public byte[] FramePixels { get { if (_videoBuffer != null) return _videoBuffer.FramePixels; return new byte[] { }; } } public int FramesCounter { get { return _wrapper.NativeGetFramesCounter(); } } public long Time { get { if (_playerObj != IntPtr.Zero) return _wrapper.PlayerGetTime(_playerObj); return 0; } set { _wrapper.NativeClearAudioSamples(0); if (_playerObj != IntPtr.Zero) _wrapper.PlayerSetTime(value, _playerObj); } } public float Position { get { if (_playerObj != IntPtr.Zero) return _wrapper.PlayerGetPosition(_playerObj); return 0; } set { _wrapper.NativeClearAudioSamples(0); if (_playerObj != IntPtr.Zero) _wrapper.PlayerSetPosition(value, _playerObj); _wrapper.NativeUpdateFramesCounter(FramesAmount > 0 ? (int)(value * FramesAmount) : 0); } } public float PlaybackRate { get { if (_playerObj != IntPtr.Zero) return _wrapper.PlayerGetRate(_playerObj); return 0; } set { if (_playerObj != IntPtr.Zero) { bool res = _wrapper.PlayerSetRate(value, _playerObj); if (!res) { throw new Exception("Native library problem: can't change playback rate"); } } } } public int Volume { get { if (_playerObj != IntPtr.Zero) return _wrapper.PlayerGetVolume(_playerObj); return 0; } set { if (_playerObj != IntPtr.Zero) _wrapper.PlayerSetVolume(value, _playerObj); } } public bool Mute { get { if (_playerObj != IntPtr.Zero) return _wrapper.PlayerGetMute(_playerObj); return false; } set { if (_playerObj != IntPtr.Zero) _wrapper.PlayerSetMute(value, _playerObj); } } public int VideoWidth { get { var width = 0; if (_playerObj != IntPtr.Zero) { width = _wrapper.PlayerVideoWidth(_playerObj); if (_videoBuffer != null && (width <= 0 || _options.FixedVideoSize != Vector2.zero || _options.VideoBufferSize)) width = _videoBuffer.Width; } return width; } } public int VideoHeight { get { var height = 0; if (_playerObj != IntPtr.Zero) { height = _wrapper.PlayerVideoHeight(_playerObj); if (_videoBuffer != null && (height <= 0 || _options.FixedVideoSize != Vector2.zero || _options.VideoBufferSize)) height = _videoBuffer.Height; } return height; } } public Vector2 VideoSize { get { return new Vector2(VideoWidth, VideoHeight); } } /// /// Get available audio tracks. /// public MediaTrackInfo[] AudioTracks { get { return _playerObj != IntPtr.Zero ? _wrapper.PlayerAudioGetTracks(_playerObj) : null; } } /// /// Get/Set current audio track. /// public MediaTrackInfo AudioTrack { get { if (_playerObj == IntPtr.Zero) return null; var id = _wrapper.PlayerAudioGetTrack(_playerObj); return AudioTracks.SingleOrDefault(t => t.Id == id); } set { var status = _wrapper.PlayerAudioSetTrack(value.Id, _playerObj); if (status == -1) throw new Exception("Native library problem: can't set new audio track"); } } /// /// Get available spu tracks. /// public MediaTrackInfo[] SpuTracks { get { return _playerObj != IntPtr.Zero ? _wrapper.PlayerSpuGetTracks(_playerObj) : null; } } /// /// Get/Set current spu track. /// public MediaTrackInfo SpuTrack { get { if (_playerObj == IntPtr.Zero) return null; var id = _wrapper.PlayerSpuGetTrack(_playerObj); return SpuTracks.SingleOrDefault(t => t.Id == id); } set { var status = _wrapper.PlayerSpuSetTrack(value.Id, _playerObj); if (status == -1) throw new Exception("Native library problem: can't set new spu track"); } } #region Platform dependent functionality /// /// Set new video subtitle file /// /// Path to the new video subtitle file /// public bool SetSubtitleFile(Uri path) { if (_playerObj != IntPtr.Zero) return _wrapper.ExpandedSpuSetFile(_playerObj, path.AbsolutePath) == 1; return false; } /// /// Get the current statistics about the media /// public MediaStats MediaStats { get { if (_mediaObj != IntPtr.Zero) _wrapper.ExpandedMediaGetStats(_mediaObj, out _mediaStats); return _mediaStats; } } /// /// Get media descriptor's elementary streams description. /// public MediaTrackInfoExpanded[] TracksInfo { get { if (_mediaObj != IntPtr.Zero) { var tracks = _wrapper.ExpandedMediaGetTracksInfo(_mediaObj); if (tracks != null && tracks.Length > 0) { var result = new List(tracks.Length); foreach (var trackInfo in tracks) { switch (trackInfo.Type) { case TrackTypes.Unknown: result.Add(new MediaTrackInfoUnknown(trackInfo.Codec, trackInfo.Id, trackInfo.Profile, trackInfo.Level)); break; case TrackTypes.Video: result.Add(new MediaTrackInfoVideo(trackInfo.Codec, trackInfo.Id, trackInfo.Profile, trackInfo.Level, trackInfo.Video.Width, trackInfo.Video.Height)); break; case TrackTypes.Audio: result.Add(new MediaTrackInfoAudio(trackInfo.Codec, trackInfo.Id, trackInfo.Profile, trackInfo.Level, trackInfo.Audio.Channels, trackInfo.Audio.Rate)); break; case TrackTypes.Text: result.Add(new MediaTrackInfoSpu(trackInfo.Codec, trackInfo.Id, trackInfo.Profile, trackInfo.Level)); break; } } return result.ToArray(); } } return null; } } /// /// Get/Set current audio delay. /// public long AudioDelay { get { if (_playerObj != IntPtr.Zero) return _wrapper.ExpandedGetAudioDelay(_playerObj); return 0; } set { if (_playerObj != IntPtr.Zero) _wrapper.ExpandedSetAudioDelay(_playerObj, value); } } /// /// Get/Set video scale. /// public float VideoScale { get { if (_playerObj != IntPtr.Zero) return _wrapper.ExpandedVideoGetScale(_playerObj); return 0; } set { if (_playerObj != IntPtr.Zero) _wrapper.ExpandedVideoSetScale(_playerObj, value); } } /// /// Get parsed media fps rate /// public float FrameRateStable { get { if (_playerObj != IntPtr.Zero && IsReady) return _wrapper.ExpandedVideoFrameRate(_playerObj); return 0; } } /// /// Get current video frames amount /// public int FramesAmount { get { if (_playerObj != IntPtr.Zero && IsReady) return (int)(Length * FrameRateStable * 0.001f); return 0; } } /// /// Take a snapshot of the current video window. /// /// The path of a file or a folder to save the screenshot into public void TakeSnapShot(string path) { if (_playerObj != IntPtr.Zero) _wrapper.ExpandedVideoTakeSnapshot(_playerObj, 0, path, 0, 0); } public string LogMessage { get { if (_vlcObj != IntPtr.Zero) return _wrapper.NativeGetLogMessage(); return null; } } public int LogLevel { get { if (_vlcObj != IntPtr.Zero) return _wrapper.NativeGetLogLevel(); return -1; } } public string GetLastError() { if (_logManager != null) return _logManager.LastError; return string.Empty; } #endregion #endregion } }