525 lines
15 KiB
C#
525 lines
15 KiB
C#
|
using System;
|
|||
|
using System.Collections;
|
|||
|
using UnityEngine;
|
|||
|
using UMP.Wrappers;
|
|||
|
using System.IO;
|
|||
|
|
|||
|
namespace UMP
|
|||
|
{
|
|||
|
public class MediaPlayerWebGL : IPlayer
|
|||
|
{
|
|||
|
private MonoBehaviour _monoObject;
|
|||
|
private WrapperInternal _wrapper;
|
|||
|
|
|||
|
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 string _dataSource;
|
|||
|
private PlayerBufferVideo _videoBuffer;
|
|||
|
private PlayerManagerEvents _eventManager;
|
|||
|
private PlayerOptions _options;
|
|||
|
|
|||
|
private Texture2D _videoTexture;
|
|||
|
private GameObject[] _videoOutputObjects;
|
|||
|
|
|||
|
private IEnumerator _updateVideoTextureEnum;
|
|||
|
|
|||
|
private delegate void UpdateTexture(int index);
|
|||
|
UpdateTexture _updateTexture;
|
|||
|
IntPtr _updatePointer;
|
|||
|
|
|||
|
#region Constructors
|
|||
|
/// <summary>
|
|||
|
/// Create instance of MediaPlayerWebGL object with additional arguments
|
|||
|
/// </summary>
|
|||
|
/// <param name="monoObject">MonoBehaviour instanse</param>
|
|||
|
/// <param name="videoOutputObjects">Objects that will be rendering video output</param>
|
|||
|
/// <param name="options">Additional player options</param>
|
|||
|
public MediaPlayerWebGL(MonoBehaviour monoObject, GameObject[] videoOutputObjects, PlayerOptions options)
|
|||
|
{
|
|||
|
_monoObject = monoObject;
|
|||
|
_videoOutputObjects = videoOutputObjects;
|
|||
|
_options = options;
|
|||
|
|
|||
|
_wrapper = new WrapperInternal(null);
|
|||
|
|
|||
|
if (_options != null)
|
|||
|
{
|
|||
|
if (_options.FixedVideoSize != Vector2.zero)
|
|||
|
{
|
|||
|
_videoBuffer = new PlayerBufferVideo((int)_options.FixedVideoSize.x, (int)_options.FixedVideoSize.y);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
_eventManager = new PlayerManagerEvents(_monoObject, this);
|
|||
|
_eventManager.PlayerPlayingListener += OnPlayerPlaying;
|
|||
|
_eventManager.PlayerPausedListener += OnPlayerPaused;
|
|||
|
}
|
|||
|
#endregion
|
|||
|
|
|||
|
#region Private methods
|
|||
|
private void UpdateFpsCounter()
|
|||
|
{
|
|||
|
float timeDelta = UnityEngine.Time.time;
|
|||
|
timeDelta = (timeDelta > _tmpTime) ? timeDelta - _tmpTime : 0;
|
|||
|
if (timeDelta >= 1f)
|
|||
|
{
|
|||
|
_frameRate = FramesCounter - _tmpFramesCounter;
|
|||
|
_tmpFramesCounter = FramesCounter;
|
|||
|
_tmpTime = UnityEngine.Time.time;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private IEnumerator UpdateVideoTexture()
|
|||
|
{
|
|||
|
while (true)
|
|||
|
{
|
|||
|
if (FramesCounter > 0)
|
|||
|
{
|
|||
|
UpdateFpsCounter();
|
|||
|
|
|||
|
if (!_isTextureExist)
|
|||
|
{
|
|||
|
if (_videoTexture != null)
|
|||
|
{
|
|||
|
UnityEngine.Object.Destroy(_videoTexture);
|
|||
|
_videoTexture = null;
|
|||
|
}
|
|||
|
|
|||
|
if (_options.FixedVideoSize == Vector2.zero)
|
|||
|
{
|
|||
|
int width = VideoWidth;
|
|||
|
int height = VideoHeight;
|
|||
|
|
|||
|
if (_videoBuffer == null ||
|
|||
|
(_videoBuffer != null &&
|
|||
|
_videoBuffer.Width != width || _videoBuffer.Height != height))
|
|||
|
{
|
|||
|
if (_videoBuffer != null)
|
|||
|
_videoBuffer.ClearFramePixels();
|
|||
|
|
|||
|
_videoBuffer = new PlayerBufferVideo(width, height);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
_videoTexture = MediaPlayerHelper.GenPluginTexture(_videoBuffer.Width, _videoBuffer.Height);
|
|||
|
MediaPlayerHelper.ApplyTextureToRenderingObjects(_videoTexture, _videoOutputObjects);
|
|||
|
_isTextureExist = true;
|
|||
|
_isImageReady = false;
|
|||
|
}
|
|||
|
|
|||
|
_wrapper.NativeUpdateTexture(_videoTexture.GetNativeTexturePtr());
|
|||
|
|
|||
|
if (!_isImageReady)
|
|||
|
{
|
|||
|
_eventManager.SetEvent(PlayerState.ImageReady, _videoTexture);
|
|||
|
_isImageReady = true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (_wrapper.PlayerIsReady() && !_isReady)
|
|||
|
{
|
|||
|
_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 void OnPlayerPlaying()
|
|||
|
{
|
|||
|
_isPlaying = true;
|
|||
|
}
|
|||
|
|
|||
|
private void OnPlayerPaused()
|
|||
|
{
|
|||
|
_isPlaying = false;
|
|||
|
}
|
|||
|
#endregion
|
|||
|
|
|||
|
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
|
|||
|
{
|
|||
|
return _wrapper.PlayerGetState();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public object StateValue
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return _wrapper.PlayerGetStateValue();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
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();
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Play or resume (True if playback started (and was already started), or False on error.
|
|||
|
/// </summary>
|
|||
|
/// <returns></returns>
|
|||
|
public bool Play()
|
|||
|
{
|
|||
|
if (!_isStarted)
|
|||
|
{
|
|||
|
if (_eventManager != null)
|
|||
|
_eventManager.StartListener();
|
|||
|
|
|||
|
_eventManager.SetEvent(PlayerState.Opening);
|
|||
|
}
|
|||
|
|
|||
|
if (_updateVideoTextureEnum == null)
|
|||
|
{
|
|||
|
_updateVideoTextureEnum = UpdateVideoTexture();
|
|||
|
_monoObject.StartCoroutine(_updateVideoTextureEnum);
|
|||
|
}
|
|||
|
|
|||
|
_isStarted = _wrapper.PlayerPlay();
|
|||
|
if (_isStarted)
|
|||
|
{
|
|||
|
if (_isReady && !_isPlaying)
|
|||
|
_eventManager.SetEvent(PlayerState.Playing);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Stop();
|
|||
|
}
|
|||
|
|
|||
|
return _isStarted;
|
|||
|
}
|
|||
|
|
|||
|
public void Pause()
|
|||
|
{
|
|||
|
if (_videoOutputObjects == null && _updateVideoTextureEnum != null)
|
|||
|
{
|
|||
|
_monoObject.StopCoroutine(_updateVideoTextureEnum);
|
|||
|
_updateVideoTextureEnum = null;
|
|||
|
}
|
|||
|
|
|||
|
_wrapper.PlayerPause();
|
|||
|
}
|
|||
|
|
|||
|
public void Stop(bool resetTexture)
|
|||
|
{
|
|||
|
if (_isStarted)
|
|||
|
{
|
|||
|
_wrapper.PlayerStop();
|
|||
|
|
|||
|
if (_updateVideoTextureEnum != null)
|
|||
|
{
|
|||
|
_monoObject.StopCoroutine(_updateVideoTextureEnum);
|
|||
|
_updateVideoTextureEnum = null;
|
|||
|
}
|
|||
|
|
|||
|
_frameRate = 0;
|
|||
|
_tmpFramesCounter = 0;
|
|||
|
_tmpTime = 0;
|
|||
|
|
|||
|
_isStarted = false;
|
|||
|
_isPlaying = false;
|
|||
|
_isLoad = false;
|
|||
|
_isReady = false;
|
|||
|
_isImageReady = false;
|
|||
|
_isTextureExist = !resetTexture;
|
|||
|
|
|||
|
if (resetTexture)
|
|||
|
{
|
|||
|
if (_videoTexture != null)
|
|||
|
{
|
|||
|
UnityEngine.Object.Destroy(_videoTexture);
|
|||
|
_videoTexture = null;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (_eventManager != null)
|
|||
|
_eventManager.StopListener();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void Stop()
|
|||
|
{
|
|||
|
Stop(true);
|
|||
|
}
|
|||
|
|
|||
|
public void Release()
|
|||
|
{
|
|||
|
Stop();
|
|||
|
|
|||
|
if (_eventManager != null)
|
|||
|
{
|
|||
|
_eventManager.RemoveAllEvents();
|
|||
|
_eventManager = null;
|
|||
|
}
|
|||
|
|
|||
|
_wrapper.PlayerRelease();
|
|||
|
}
|
|||
|
|
|||
|
public string DataSource
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return _dataSource;
|
|||
|
}
|
|||
|
set
|
|||
|
{
|
|||
|
_dataSource = value;
|
|||
|
|
|||
|
var path = _dataSource;
|
|||
|
|
|||
|
if (path.StartsWith("file:///"))
|
|||
|
{
|
|||
|
path = path.Substring("file:///".Length);
|
|||
|
|
|||
|
if (!path.Contains(":/"))
|
|||
|
path = Path.Combine(Application.streamingAssetsPath, path);
|
|||
|
}
|
|||
|
|
|||
|
_wrapper.PlayerSetDataSource(path);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public bool IsPlaying
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return _wrapper.PlayerIsPlaying();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public bool IsReady
|
|||
|
{
|
|||
|
get { return _isReady; }
|
|||
|
}
|
|||
|
|
|||
|
public bool AbleToPlay
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return _dataSource != null && !string.IsNullOrEmpty(_dataSource.ToString());
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Get the current movie length (in ms).
|
|||
|
/// </summary>
|
|||
|
/// <returns></returns>
|
|||
|
public long Length
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return _wrapper.PlayerGetLength();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Get the current movie formatted length (hh:mm:ss[:ms]).
|
|||
|
/// </summary>
|
|||
|
/// <param name="detail">True: formatted length will be with [:ms]</param>
|
|||
|
/// <returns></returns>
|
|||
|
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 int FramesCounter
|
|||
|
{
|
|||
|
get { return _wrapper.PlayerVideoFramesCounter(); }
|
|||
|
}
|
|||
|
|
|||
|
public byte[] FramePixels
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return null;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public long Time
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return _wrapper.PlayerGetTime();
|
|||
|
}
|
|||
|
set
|
|||
|
{
|
|||
|
_wrapper.PlayerSetTime(value);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public float Position
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return _wrapper.PlayerGetPosition();
|
|||
|
}
|
|||
|
set
|
|||
|
{
|
|||
|
_wrapper.PlayerSetPosition(value);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public float PlaybackRate
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return _wrapper.PlayerGetRate();
|
|||
|
}
|
|||
|
set
|
|||
|
{
|
|||
|
_wrapper.PlayerSetRate(value);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public int Volume
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return _wrapper.PlayerGetVolume();
|
|||
|
}
|
|||
|
set
|
|||
|
{
|
|||
|
_wrapper.PlayerSetVolume(value);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public bool Mute
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return _wrapper.PlayerGetMute();
|
|||
|
}
|
|||
|
set
|
|||
|
{
|
|||
|
_wrapper.PlayerSetMute(value);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public int VideoWidth
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
var width = _wrapper.PlayerVideoWidth();
|
|||
|
|
|||
|
if (_videoBuffer != null && (width <= 0 || _options.FixedVideoSize != Vector2.zero))
|
|||
|
width = _videoBuffer.Width;
|
|||
|
|
|||
|
return width;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public int VideoHeight
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
var height = _wrapper.PlayerVideoHeight();
|
|||
|
|
|||
|
if (_videoBuffer != null && (height <= 0 || _options.FixedVideoSize != Vector2.zero))
|
|||
|
height = _videoBuffer.Height;
|
|||
|
|
|||
|
return height;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public Vector2 VideoSize
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
return new Vector2(VideoWidth, VideoHeight);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|