You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
601 lines
14 KiB
601 lines
14 KiB
2 years ago
|
#if UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX || UNITY_IPHONE || UNITY_IOS || UNITY_TVOS
|
||
|
#if UNITY_5
|
||
|
#if !UNITY_5_0 && !UNITY_5_1
|
||
|
#define AVPROVIDEO_ISSUEPLUGINEVENT_UNITY52
|
||
|
#endif
|
||
|
#endif
|
||
|
using UnityEngine;
|
||
|
using System;
|
||
|
using System.Collections;
|
||
|
using System.Runtime.InteropServices;
|
||
|
using AOT;
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Copyright 2015-2016 RenderHeads Ltd. All rights reserverd.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
namespace RenderHeads.Media.AVProVideo
|
||
|
{
|
||
|
|
||
|
// IMediaInfo
|
||
|
//
|
||
|
// float GetDurationMs();
|
||
|
// int GetVideoWidth();
|
||
|
// int GetVideoHeight();
|
||
|
//
|
||
|
// float GetVideoPlaybackRate();
|
||
|
//
|
||
|
// bool HasVideo();
|
||
|
// bool HasAudio();
|
||
|
|
||
|
// BaseMediaPlayer
|
||
|
//
|
||
|
// public abstract String GetVersion();
|
||
|
//
|
||
|
// public abstract bool OpenVideoFromFile( string path );
|
||
|
// public abstract void CloseVideo();
|
||
|
//
|
||
|
// public abstract void SetLooping( bool bLooping );
|
||
|
// public abstract bool IsLooping();
|
||
|
//
|
||
|
// public abstract bool HasMetaData();
|
||
|
// public abstract bool CanPlay();
|
||
|
// public abstract void Play();
|
||
|
// public abstract void Pause();
|
||
|
// public abstract void Stop();
|
||
|
// public abstract void Rewind();
|
||
|
//
|
||
|
// public abstract void Seek(float timeMs);
|
||
|
// public abstract float GetCurrentTimeMs();
|
||
|
//
|
||
|
// public abstract float GetDurationMs();
|
||
|
// public abstract int GetVideoWidth();
|
||
|
// public abstract int GetVideoHeight();
|
||
|
// public abstract float GetVideoPlaybackRate();
|
||
|
//
|
||
|
// public abstract bool IsSeeking();
|
||
|
// public abstract bool IsPlaying();
|
||
|
// public abstract bool IsPaused();
|
||
|
// public abstract bool IsFinished();
|
||
|
// public abstract bool IsBuffering();
|
||
|
//
|
||
|
// public abstract Texture GetTexture();
|
||
|
// public abstract int GetTextureFrameCount();
|
||
|
// public abstract bool RequiresVerticalFlip();
|
||
|
//
|
||
|
//
|
||
|
// public abstract void MuteAudio(bool bMuted);
|
||
|
// public abstract void SetVolume(float volume);
|
||
|
// public abstract float GetVolume();
|
||
|
//
|
||
|
// public abstract void Update();
|
||
|
// public abstract void Render();
|
||
|
// public abstract void Dispose();
|
||
|
|
||
|
public class OSXMediaPlayer : BaseMediaPlayer
|
||
|
{
|
||
|
#if UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX
|
||
|
private const string PluginName = "AVProVideo";
|
||
|
#elif UNITY_IPHONE || UNITY_IOS || UNITY_TVOS
|
||
|
private const string PluginName = "__Internal";
|
||
|
#endif
|
||
|
|
||
|
// Native Interface
|
||
|
|
||
|
private enum AVPPluginEventType
|
||
|
{
|
||
|
Nop,
|
||
|
PlayerUpdate,
|
||
|
PlayerShutdown,
|
||
|
FreeTextureResources,
|
||
|
}
|
||
|
|
||
|
private enum AVPPlayerStatus
|
||
|
{
|
||
|
Unknown,
|
||
|
ReadyToPlay,
|
||
|
Playing,
|
||
|
Finished,
|
||
|
Seeking,
|
||
|
Failed
|
||
|
}
|
||
|
|
||
|
private enum AVPLogFlag
|
||
|
{
|
||
|
Error = 1 << 0,
|
||
|
Warning = 1 << 1,
|
||
|
Info = 1 << 2,
|
||
|
Debug = 1 << 3,
|
||
|
Verbose = 1 << 4,
|
||
|
};
|
||
|
|
||
|
private enum AVPLogLevel
|
||
|
{
|
||
|
Off = 0,
|
||
|
Error = AVPLogFlag.Error,
|
||
|
Warning = AVPLogFlag.Error | AVPLogFlag.Warning,
|
||
|
Info = AVPLogFlag.Error | AVPLogFlag.Warning | AVPLogFlag.Info,
|
||
|
Debug = AVPLogFlag.Error | AVPLogFlag.Warning | AVPLogFlag.Info | AVPLogFlag.Debug,
|
||
|
Verbose = AVPLogFlag.Error | AVPLogFlag.Warning | AVPLogFlag.Info | AVPLogFlag.Debug | AVPLogFlag.Verbose,
|
||
|
All = -1
|
||
|
};
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern string AVPGetVersion();
|
||
|
|
||
|
#if AVPROVIDEO_ISSUEPLUGINEVENT_UNITY52
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern IntPtr AVPGetRenderEventFunc();
|
||
|
#endif
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern double AVPPlayerGetCurrentTime(IntPtr player);
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern double AVPPlayerGetDuration(IntPtr player);
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern int AVPPlayerGetFrameCount(IntPtr player);
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern double AVPPlayerGetFrameRate(IntPtr player);
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern double AVPPlayerGetNominalFrameRate(IntPtr player);
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern int AVPPlayerGetHandle(IntPtr player);
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern AVPPlayerStatus AVPPlayerGetStatus(IntPtr player);
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern bool AVPlayerIsBuffering(IntPtr player);
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern IntPtr AVPPlayerGetTextureHandle(IntPtr player);
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern void AVPPlayerGetTextureSize(IntPtr player, out int width, out int height);
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern bool AVPPlayerTextureIsFlipped(IntPtr player);
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern bool AVPPlayerTextureSizeHasChanged(IntPtr player);
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern float AVPPlayerGetVolume(IntPtr player);
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern bool AVPPlayerHasAudio(IntPtr player);
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern bool AVPPlayerHasVideo(IntPtr player);
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern bool AVPPlayerHasMetaData(IntPtr player);
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern bool AVPPlayerIsLooping(IntPtr player);
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern void AVPPlayerSetLooping(IntPtr player, bool looping);
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern bool AVPPlayerIsMuted(IntPtr player);
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern void AVPPlayerSetMuted(IntPtr player, bool muted);
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern void AVPPlayerSetVolume(IntPtr player, float volume);
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern IntPtr AVPPlayerNew();
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern IntPtr AVPPlayerRelease(IntPtr player);
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern bool AVPPlayerOpenFile(IntPtr player, string path);
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern bool AVPPlayerOpenURL(IntPtr player, string url);
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern void AVPPlayerClose(IntPtr player);
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern void AVPPlayerPlay(IntPtr player);
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern void AVPPlayerPause(IntPtr player);
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern void AVPPlayerSeekToTime(IntPtr player, double time, bool fast);
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern float AVPPlayerGetPlaybackRate(IntPtr player);
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern void AVPPlayerSetPlaybackRate(IntPtr player, float rate);
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern void AVPPluginRegister();
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern void AVPPluginInitialise();
|
||
|
|
||
|
[DllImport(PluginName)]
|
||
|
private static extern void AVPPluginSetDebugLogFunction(IntPtr fn);
|
||
|
|
||
|
// MediaPlayer Interface
|
||
|
|
||
|
private static bool _initialised = false;
|
||
|
#if AVPROVIDEO_ISSUEPLUGINEVENT_UNITY52
|
||
|
private static IntPtr _renderEventFunc = IntPtr.Zero;
|
||
|
#endif
|
||
|
|
||
|
#if UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX
|
||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||
|
#endif
|
||
|
private delegate void DebugLogCallbackDelegate(int level, int flags, string str);
|
||
|
|
||
|
#if UNITY_IPHONE || UNITY_IOS || UNITY_TVOS
|
||
|
[MonoPInvokeCallback(typeof(DebugLogCallbackDelegate))]
|
||
|
#endif
|
||
|
private static void DebugLogCallback(int level, int flags, string str)
|
||
|
{
|
||
|
if ((flags & (int)AVPLogFlag.Error) == (int)AVPLogFlag.Error)
|
||
|
{
|
||
|
Debug.LogError(str);
|
||
|
}
|
||
|
else if ((flags & (int)AVPLogFlag.Warning) == (int)AVPLogFlag.Warning)
|
||
|
{
|
||
|
Debug.LogWarning(str);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Debug.Log(str);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static void IssuePluginEvent(AVPPluginEventType type, int param)
|
||
|
{
|
||
|
// Build eventId from the type and param.
|
||
|
int eventId = 0x0FA60000 | ((int)type << 12);
|
||
|
|
||
|
switch (type)
|
||
|
{
|
||
|
case AVPPluginEventType.PlayerUpdate:
|
||
|
case AVPPluginEventType.PlayerShutdown:
|
||
|
eventId |= param & 0xfff;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
#if AVPROVIDEO_ISSUEPLUGINEVENT_UNITY52
|
||
|
GL.IssuePluginEvent(_renderEventFunc, eventId);
|
||
|
#else
|
||
|
GL.IssuePluginEvent(eventId);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
static void Initialise()
|
||
|
{
|
||
|
if (!_initialised)
|
||
|
{
|
||
|
_initialised = true;
|
||
|
|
||
|
#if ((UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX) && !UNITY_5) || (UNITY_IPHONE || UNITY_IOS || UNITY_TVOS)
|
||
|
AVPPluginRegister();
|
||
|
#endif
|
||
|
|
||
|
DebugLogCallbackDelegate callbackDelegate = new DebugLogCallbackDelegate(DebugLogCallback);
|
||
|
IntPtr func = Marshal.GetFunctionPointerForDelegate(callbackDelegate);
|
||
|
AVPPluginSetDebugLogFunction(func);
|
||
|
|
||
|
AVPPluginInitialise();
|
||
|
|
||
|
#if AVPROVIDEO_ISSUEPLUGINEVENT_UNITY52
|
||
|
_renderEventFunc = AVPGetRenderEventFunc();
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private IntPtr _player = IntPtr.Zero; // Handle to the native player.
|
||
|
private Texture2D _texture = null;
|
||
|
private IntPtr _native = IntPtr.Zero;
|
||
|
private int _width = 0;
|
||
|
private int _height = 0;
|
||
|
private bool _isMetaDataReady = false;
|
||
|
|
||
|
static OSXMediaPlayer()
|
||
|
{
|
||
|
Initialise();
|
||
|
}
|
||
|
|
||
|
public OSXMediaPlayer()
|
||
|
{
|
||
|
_player = AVPPlayerNew();
|
||
|
}
|
||
|
|
||
|
// BaseMediaPlayer Overrides
|
||
|
|
||
|
public override string GetVersion()
|
||
|
{
|
||
|
return AVPGetVersion();
|
||
|
}
|
||
|
|
||
|
public override bool OpenVideoFromFile(string path)
|
||
|
{
|
||
|
if (path.StartsWith("http://") || path.StartsWith("https://") || path.StartsWith("file://"))
|
||
|
{
|
||
|
return AVPPlayerOpenURL(_player, path);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return AVPPlayerOpenFile(_player, path);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override void CloseVideo()
|
||
|
{
|
||
|
if (_texture != null)
|
||
|
{
|
||
|
// Have to update with zero to release Metal textures!
|
||
|
_texture.UpdateExternalTexture(IntPtr.Zero);
|
||
|
Texture2D.Destroy(_texture);
|
||
|
_texture = null;
|
||
|
}
|
||
|
|
||
|
_width = 0;
|
||
|
_height = 0;
|
||
|
_native = IntPtr.Zero;
|
||
|
_isMetaDataReady = false;
|
||
|
|
||
|
AVPPlayerClose(_player);
|
||
|
}
|
||
|
|
||
|
public override bool IsLooping()
|
||
|
{
|
||
|
return AVPPlayerIsLooping(_player);
|
||
|
}
|
||
|
|
||
|
public override void SetLooping(bool looping)
|
||
|
{
|
||
|
AVPPlayerSetLooping(_player, looping);
|
||
|
}
|
||
|
|
||
|
public override bool HasAudio()
|
||
|
{
|
||
|
return AVPPlayerHasAudio(_player);
|
||
|
}
|
||
|
|
||
|
public override bool HasVideo()
|
||
|
{
|
||
|
return AVPPlayerHasVideo(_player);
|
||
|
}
|
||
|
|
||
|
public override bool HasMetaData()
|
||
|
{
|
||
|
return _isMetaDataReady;
|
||
|
}
|
||
|
|
||
|
public override bool CanPlay()
|
||
|
{
|
||
|
return AVPPlayerGetStatus(_player) >= AVPPlayerStatus.ReadyToPlay;
|
||
|
}
|
||
|
|
||
|
public override void Play()
|
||
|
{
|
||
|
AVPPlayerPlay(_player);
|
||
|
}
|
||
|
|
||
|
public override void Pause()
|
||
|
{
|
||
|
AVPPlayerPause(_player);
|
||
|
}
|
||
|
|
||
|
public override void Stop()
|
||
|
{
|
||
|
AVPPlayerPause(_player);
|
||
|
}
|
||
|
|
||
|
public override void Rewind()
|
||
|
{
|
||
|
AVPPlayerSeekToTime(_player, 0.0, true);
|
||
|
}
|
||
|
|
||
|
public override void Seek(float ms)
|
||
|
{
|
||
|
AVPPlayerSeekToTime(_player, ms / 1000.0, false);
|
||
|
}
|
||
|
|
||
|
public override void SeekFast(float ms)
|
||
|
{
|
||
|
AVPPlayerSeekToTime(_player, ms / 1000.0, true);
|
||
|
}
|
||
|
|
||
|
public override float GetCurrentTimeMs()
|
||
|
{
|
||
|
return (float)(AVPPlayerGetCurrentTime(_player) * 1000.0f);
|
||
|
}
|
||
|
|
||
|
public override void SetPlaybackRate(float rate)
|
||
|
{
|
||
|
AVPPlayerSetPlaybackRate(_player, rate);
|
||
|
}
|
||
|
|
||
|
public override float GetPlaybackRate()
|
||
|
{
|
||
|
return AVPPlayerGetPlaybackRate(_player);
|
||
|
}
|
||
|
|
||
|
public override float GetDurationMs()
|
||
|
{
|
||
|
return (float)(AVPPlayerGetDuration(_player) * 1000.0f);
|
||
|
}
|
||
|
|
||
|
public override int GetVideoWidth()
|
||
|
{
|
||
|
return _width;
|
||
|
}
|
||
|
|
||
|
public override int GetVideoHeight()
|
||
|
{
|
||
|
return _height;
|
||
|
}
|
||
|
|
||
|
public override float GetVideoPlaybackRate()
|
||
|
{
|
||
|
return (float)AVPPlayerGetFrameRate(_player);
|
||
|
}
|
||
|
|
||
|
public override bool IsSeeking()
|
||
|
{
|
||
|
return AVPPlayerGetStatus(_player) == AVPPlayerStatus.Seeking;
|
||
|
}
|
||
|
|
||
|
public override bool IsPlaying()
|
||
|
{
|
||
|
return AVPPlayerGetStatus(_player) == AVPPlayerStatus.Playing;
|
||
|
}
|
||
|
|
||
|
public override bool IsPaused()
|
||
|
{
|
||
|
return AVPPlayerGetStatus(_player) == AVPPlayerStatus.ReadyToPlay;
|
||
|
}
|
||
|
|
||
|
public override bool IsFinished()
|
||
|
{
|
||
|
return AVPPlayerGetStatus(_player) == AVPPlayerStatus.Finished;
|
||
|
}
|
||
|
|
||
|
public override bool IsBuffering()
|
||
|
{
|
||
|
return AVPlayerIsBuffering(_player);
|
||
|
}
|
||
|
|
||
|
public override Texture GetTexture()
|
||
|
{
|
||
|
return _texture;
|
||
|
}
|
||
|
|
||
|
public override int GetTextureFrameCount()
|
||
|
{
|
||
|
return AVPPlayerGetFrameCount(_player);
|
||
|
}
|
||
|
|
||
|
public override bool RequiresVerticalFlip()
|
||
|
{
|
||
|
return AVPPlayerTextureIsFlipped(_player);
|
||
|
}
|
||
|
|
||
|
public override bool IsMuted()
|
||
|
{
|
||
|
return AVPPlayerIsMuted(_player);
|
||
|
}
|
||
|
|
||
|
public override void MuteAudio( bool bMute )
|
||
|
{
|
||
|
AVPPlayerSetMuted(_player, bMute);
|
||
|
}
|
||
|
|
||
|
public override void SetVolume(float volume)
|
||
|
{
|
||
|
AVPPlayerSetVolume(_player, volume);
|
||
|
}
|
||
|
|
||
|
public override float GetVolume()
|
||
|
{
|
||
|
return AVPPlayerGetVolume(_player);
|
||
|
}
|
||
|
|
||
|
public override void Render()
|
||
|
{
|
||
|
// Nothing to do!
|
||
|
}
|
||
|
|
||
|
public override void Update()
|
||
|
{
|
||
|
// Only call this once per frame!
|
||
|
OSXMediaPlayer.IssuePluginEvent(AVPPluginEventType.PlayerUpdate, AVPPlayerGetHandle(_player));
|
||
|
|
||
|
int width = 0;
|
||
|
int height = 0;
|
||
|
AVPPlayerGetTextureSize(_player, out width, out height);
|
||
|
IntPtr native = AVPPlayerGetTextureHandle(_player);
|
||
|
|
||
|
if (_texture != null && (_width != width || _height != height))
|
||
|
{
|
||
|
// Have to update with zero to release Metal textures!
|
||
|
_texture.UpdateExternalTexture(IntPtr.Zero);
|
||
|
Texture2D.Destroy(_texture);
|
||
|
_texture = null;
|
||
|
}
|
||
|
|
||
|
if (_texture == null && native != IntPtr.Zero)
|
||
|
{
|
||
|
TextureFormat format = TextureFormat.BGRA32;
|
||
|
bool mipmap = false;
|
||
|
bool linear = false;
|
||
|
_texture = Texture2D.CreateExternalTexture(width, height, format, mipmap, linear, native);
|
||
|
_width = width;
|
||
|
_height = height;
|
||
|
_native = native;
|
||
|
ApplyTextureProperties(_texture);
|
||
|
}
|
||
|
else if (_texture != null && native != _native)
|
||
|
{
|
||
|
_texture.UpdateExternalTexture(native);
|
||
|
_native = native;
|
||
|
}
|
||
|
|
||
|
// Check for meta data to become available
|
||
|
if (!_isMetaDataReady)
|
||
|
{
|
||
|
if (AVPPlayerHasMetaData(_player) || CanPlay())
|
||
|
{
|
||
|
if (HasVideo())
|
||
|
{
|
||
|
if (width > 0 && height > 0)
|
||
|
{
|
||
|
if (Mathf.Max(width, height) > SystemInfo.maxTextureSize)
|
||
|
{
|
||
|
Debug.LogError("[AVProVideo] Video dimensions larger than maxTextureSize");
|
||
|
}
|
||
|
_isMetaDataReady = true;
|
||
|
}
|
||
|
}
|
||
|
else if (HasAudio())
|
||
|
{
|
||
|
_isMetaDataReady = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override void Dispose()
|
||
|
{
|
||
|
if (_texture != null)
|
||
|
{
|
||
|
// Have to update with zero to release Metal textures!
|
||
|
_texture.UpdateExternalTexture(IntPtr.Zero);
|
||
|
Texture2D.Destroy(_texture);
|
||
|
_texture = null;
|
||
|
}
|
||
|
|
||
|
if (_player != IntPtr.Zero)
|
||
|
{
|
||
|
|
||
|
OSXMediaPlayer.IssuePluginEvent(AVPPluginEventType.FreeTextureResources, AVPPlayerGetHandle(_player));
|
||
|
AVPPlayerRelease(_player);
|
||
|
_player = IntPtr.Zero;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
#endif
|