845 lines
22 KiB
C#
845 lines
22 KiB
C#
#if UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX || UNITY_IPHONE || UNITY_IOS || UNITY_TVOS
|
|
#if UNITY_5 || UNITY_5_4_OR_NEWER
|
|
#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 System.Text.RegularExpressions;
|
|
using AOT;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Copyright 2015-2018 RenderHeads Ltd. All rights reserverd.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
namespace RenderHeads.Media.AVProVideo
|
|
{
|
|
/// <summary>
|
|
/// macOS, iOS and tvOS implementation of BaseMediaPlayer
|
|
/// </summary>
|
|
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
|
|
{
|
|
PlayerRender,
|
|
PlayerFreeResources,
|
|
}
|
|
|
|
private enum AVPPluginColorSpace
|
|
{
|
|
Uninitialized,
|
|
Gamma,
|
|
Linear
|
|
};
|
|
|
|
private enum AVPPlayerStatus
|
|
{
|
|
Failed = -1,
|
|
Unknown,
|
|
ReadyToPlay,
|
|
Playing,
|
|
Finished,
|
|
Seeking,
|
|
Buffering
|
|
}
|
|
|
|
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
|
|
};
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack=4)]
|
|
private struct AVPPlayerTextureInfo
|
|
{
|
|
public IntPtr native;
|
|
public int width;
|
|
public int height;
|
|
public int format;
|
|
public int flipped;
|
|
};
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack=4)]
|
|
private struct AVPPlayerTimeRange
|
|
{
|
|
public double start;
|
|
public double duration;
|
|
};
|
|
|
|
[DllImport(PluginName)]
|
|
private static extern string AVPGetVersion();
|
|
|
|
#if AVPROVIDEO_ISSUEPLUGINEVENT_UNITY52
|
|
[DllImport(PluginName)]
|
|
private static extern IntPtr AVPGetRenderEventFunc();
|
|
#endif
|
|
|
|
[DllImport(PluginName)]
|
|
private static extern ErrorCode AVPPlayerGetLastError(IntPtr player);
|
|
|
|
[DllImport(PluginName)]
|
|
private static extern double AVPPlayerGetCurrentTime(IntPtr player);
|
|
|
|
[DllImport(PluginName)]
|
|
private static extern double AVPPlayerGetCurrentDate(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 long AVPPlayerGetFrameTimeStamp(IntPtr player);
|
|
|
|
[DllImport(PluginName)]
|
|
private static extern float 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 float AVPPlayerGetBufferingProgress(IntPtr player);
|
|
|
|
[DllImport(PluginName)]
|
|
private static extern int AVPPlayerGetBufferedTimeRangeCount(IntPtr player);
|
|
|
|
[DllImport(PluginName)]
|
|
private static extern bool AVPPlayerGetBufferedTimeRange(IntPtr player, int index, out float start, out float end);
|
|
|
|
[DllImport(PluginName)]
|
|
private static extern int AVPPlayerGetSeekableTimeRanges(IntPtr player, [In, Out] AVPPlayerTimeRange[] ranges, ref int count);
|
|
|
|
[DllImport(PluginName)]
|
|
private static extern bool AVPPlayerGetTextures(IntPtr player, [In, Out] AVPPlayerTextureInfo[] textures, ref int count);
|
|
|
|
[DllImport(PluginName)]
|
|
private static extern bool AVPPlayerGetTextureTransform(IntPtr player, [In, Out] float[] transform);
|
|
|
|
[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(bool useYuv);
|
|
|
|
[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, string headers);
|
|
|
|
[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 AVPPlayerSeek(IntPtr player, double time);
|
|
|
|
[DllImport(PluginName)]
|
|
private static extern void AVPPlayerSeekFast(IntPtr player, double time);
|
|
|
|
[DllImport(PluginName)]
|
|
private static extern void AVPPlayerSeekWithTolerance(IntPtr player, double time, double before, double after);
|
|
|
|
[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 bool AVPPlayerUpdate(IntPtr player);
|
|
|
|
[DllImport(PluginName)]
|
|
private static extern int AVPPlayerGetAudioTrackCount(IntPtr player);
|
|
|
|
[DllImport(PluginName)]
|
|
private static extern string AVPPlayerGetAudioTrackId(IntPtr player, int index);
|
|
|
|
[DllImport(PluginName)]
|
|
private static extern int AVPPlayerGetCurrentAudioTrack(IntPtr player);
|
|
|
|
[DllImport(PluginName)]
|
|
private static extern string AVPPlayerGetCurrentAudioTrackId(IntPtr player);
|
|
|
|
[DllImport(PluginName)]
|
|
private static extern int AVPPlayerGetCurrentAudioTrackBitrate(IntPtr player);
|
|
|
|
[DllImport(PluginName)]
|
|
private static extern int AVPPlayerGetVideoTrackCount(IntPtr player);
|
|
|
|
[DllImport(PluginName)]
|
|
private static extern string AVPPlayerGetVideoTrackId(IntPtr player, int index);
|
|
|
|
[DllImport(PluginName)]
|
|
private static extern int AVPPlayerGetCurrentVideoTrack(IntPtr player);
|
|
|
|
[DllImport(PluginName)]
|
|
private static extern string AVPPlayerGetCurrentVideoTrackId(IntPtr player);
|
|
|
|
[DllImport(PluginName)]
|
|
private static extern int AVPPlayerGetCurrentVideoTrackBitrate(IntPtr player);
|
|
|
|
[DllImport(PluginName)]
|
|
private static extern void AVPPlayerSetAudioTrack(IntPtr player, int track);
|
|
|
|
[DllImport(PluginName)]
|
|
private static extern void AVPPlayerSetVideoTrack(IntPtr player, int track);
|
|
|
|
[DllImport(PluginName)]
|
|
private static extern int AVPPlayerExtractFrame(IntPtr player, [In, Out] AVPPlayerTextureInfo[] textures, ref int count, double timeout);
|
|
|
|
[DllImport(PluginName)]
|
|
private static extern void AVPPlayerAddValueDidChangeObserver(IntPtr player, IntPtr self, IntPtr callback, string key, uint flags);
|
|
|
|
[DllImport(PluginName)]
|
|
private static extern void AVPPluginRegister();
|
|
|
|
[DllImport(PluginName)]
|
|
private static extern void AVPPluginInitialise(AVPPluginColorSpace colorSpace);
|
|
|
|
[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
|
|
private static Regex _matchURLRegex = null;
|
|
|
|
#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);
|
|
eventId |= param & 0xfff;
|
|
|
|
#if AVPROVIDEO_ISSUEPLUGINEVENT_UNITY52
|
|
GL.IssuePluginEvent(_renderEventFunc, eventId);
|
|
#else
|
|
GL.IssuePluginEvent(eventId);
|
|
#endif
|
|
}
|
|
|
|
#if UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
#endif
|
|
private delegate void ValueAtKeyPathDidChangeDelegate(IntPtr self, string keyPath);
|
|
|
|
#if UNITY_IPHONE || UNITY_IOS || UNITY_TVOS
|
|
[MonoPInvokeCallback(typeof(ValueAtKeyPathDidChangeDelegate))]
|
|
#endif
|
|
private static void ValueAtKeyPathDidChangeThunk(IntPtr self, string keyPath)
|
|
{
|
|
GCHandle handle = GCHandle.FromIntPtr(self);
|
|
OSXMediaPlayer player = (OSXMediaPlayer)handle.Target;
|
|
player.ValueAtKeyPathDidChange(keyPath);
|
|
}
|
|
|
|
private void ValueAtKeyPathDidChange(string keyPath)
|
|
{
|
|
if (keyPath == "seekableTimeRanges")
|
|
{
|
|
AVPPlayerTimeRange[] ranges = new AVPPlayerTimeRange[4];
|
|
int count = ranges.Length;
|
|
int numRanges = AVPPlayerGetSeekableTimeRanges(_player, ranges, ref count);
|
|
if (numRanges > count)
|
|
{
|
|
ranges = new AVPPlayerTimeRange[numRanges];
|
|
count = numRanges;
|
|
AVPPlayerGetSeekableTimeRanges(_player, ranges, ref count);
|
|
}
|
|
if (_seekableTimeRanges.Length != count)
|
|
{
|
|
_seekableTimeRanges = new TimeRange[count];
|
|
}
|
|
for (int i = 0; i < count; ++i)
|
|
{
|
|
_seekableTimeRanges[i].startTime = (float)(ranges[i].start * 1000.0);
|
|
_seekableTimeRanges[i].duration = (float)(ranges[i].duration * 1000.0);
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
|
|
AVPPluginColorSpace colorSpace = QualitySettings.activeColorSpace == ColorSpace.Linear ? AVPPluginColorSpace.Linear : AVPPluginColorSpace.Gamma;
|
|
AVPPluginInitialise(colorSpace);
|
|
|
|
#if AVPROVIDEO_ISSUEPLUGINEVENT_UNITY52
|
|
_renderEventFunc = AVPGetRenderEventFunc();
|
|
#endif
|
|
|
|
_matchURLRegex = new Regex("^[a-zA-Z][a-zA-Z0-9+-.]*://.*$");
|
|
}
|
|
}
|
|
|
|
private IntPtr _player = IntPtr.Zero; // The native player instance.
|
|
private int _handle = 0; // Handle to the native player for use with IssuePluginEvent.
|
|
private AVPPlayerStatus _status = AVPPlayerStatus.Unknown;
|
|
private int _planeCount = 0;
|
|
private Texture2D[] _texture = new Texture2D[2];
|
|
private int _width = 0;
|
|
private int _height = 0;
|
|
private bool _flipped = false;
|
|
private bool _isMetaDataReady = false;
|
|
private GCHandle _thisHandle;
|
|
|
|
static OSXMediaPlayer()
|
|
{
|
|
Initialise();
|
|
}
|
|
|
|
public OSXMediaPlayer(bool useYuv420Textures = false)
|
|
{
|
|
_player = AVPPlayerNew(useYuv420Textures);
|
|
_handle = AVPPlayerGetHandle(_player);
|
|
|
|
_thisHandle = GCHandle.Alloc(this, GCHandleType.Normal);
|
|
ValueAtKeyPathDidChangeDelegate callbackDelegate = new ValueAtKeyPathDidChangeDelegate(ValueAtKeyPathDidChangeThunk);
|
|
|
|
IntPtr self = GCHandle.ToIntPtr(_thisHandle);
|
|
IntPtr callback = Marshal.GetFunctionPointerForDelegate(callbackDelegate);
|
|
AVPPlayerAddValueDidChangeObserver(_player, self, callback, "seekableTimeRanges", 0);
|
|
}
|
|
|
|
// Convenience method for calling OSXMediaPlayer.IssuePluginEvent.
|
|
//
|
|
private void IssuePluginEvent(AVPPluginEventType type)
|
|
{
|
|
OSXMediaPlayer.IssuePluginEvent(type, _handle);
|
|
}
|
|
|
|
// BaseMediaPlayer Overrides
|
|
|
|
public override string GetVersion()
|
|
{
|
|
return AVPGetVersion();
|
|
}
|
|
|
|
public override bool OpenVideoFromFile(string path, long offset /* ignored */, string httpHeaderJson, uint sourceSamplerate = 0, uint sourceChannels = 0, int forceFileFormat = 0)
|
|
{
|
|
if (_matchURLRegex.IsMatch(path))
|
|
{
|
|
return AVPPlayerOpenURL(_player, path, httpHeaderJson);
|
|
}
|
|
else
|
|
{
|
|
return AVPPlayerOpenFile(_player, path);
|
|
}
|
|
}
|
|
|
|
public override void CloseVideo()
|
|
{
|
|
AVPPlayerClose(_player);
|
|
|
|
if (_texture[0] != null)
|
|
{
|
|
IssuePluginEvent(AVPPluginEventType.PlayerFreeResources);
|
|
// Have to update with zero to release Metal textures!
|
|
for (int i = 0; i < _planeCount; ++i)
|
|
{
|
|
_texture[i].UpdateExternalTexture(IntPtr.Zero);
|
|
Texture2D.Destroy(_texture[i]);
|
|
_texture[i] = null;
|
|
}
|
|
}
|
|
|
|
_width = 0;
|
|
_height = 0;
|
|
_isMetaDataReady = false;
|
|
_planeCount = 0;
|
|
|
|
base.CloseVideo();
|
|
}
|
|
|
|
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 _status >= AVPPlayerStatus.ReadyToPlay;
|
|
}
|
|
|
|
public override void Play()
|
|
{
|
|
AVPPlayerPlay(_player);
|
|
}
|
|
|
|
public override void Pause()
|
|
{
|
|
AVPPlayerPause(_player);
|
|
}
|
|
|
|
public override void Stop()
|
|
{
|
|
AVPPlayerPause(_player);
|
|
}
|
|
|
|
public override void Rewind()
|
|
{
|
|
AVPPlayerSeekFast(_player, 0.0);
|
|
}
|
|
|
|
public override void Seek(float ms)
|
|
{
|
|
AVPPlayerSeek(_player, ms / 1000.0);
|
|
}
|
|
|
|
public override void SeekFast(float ms)
|
|
{
|
|
AVPPlayerSeekFast(_player, ms / 1000.0);
|
|
}
|
|
|
|
public override void SeekWithTolerance(float timeMs, float beforeMs, float afterMs)
|
|
{
|
|
AVPPlayerSeekWithTolerance(_player, timeMs / 1000.0, beforeMs / 1000.0, afterMs / 1000.0);
|
|
}
|
|
|
|
public override float GetCurrentTimeMs()
|
|
{
|
|
return (float)(AVPPlayerGetCurrentTime(_player) * 1000.0f);
|
|
}
|
|
|
|
public override double GetCurrentDateTimeSecondsSince1970()
|
|
{
|
|
return AVPPlayerGetCurrentDate(_player);
|
|
}
|
|
|
|
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 GetVideoDisplayRate()
|
|
{
|
|
return (float)AVPPlayerGetFrameRate(_player);
|
|
}
|
|
|
|
public override bool IsSeeking()
|
|
{
|
|
return _status == AVPPlayerStatus.Seeking;
|
|
}
|
|
|
|
public override bool IsPlaying()
|
|
{
|
|
return _status == AVPPlayerStatus.Playing;
|
|
}
|
|
|
|
public override bool IsPaused()
|
|
{
|
|
return _status == AVPPlayerStatus.ReadyToPlay;
|
|
}
|
|
|
|
public override bool IsFinished()
|
|
{
|
|
return _status == AVPPlayerStatus.Finished;
|
|
}
|
|
|
|
public override bool IsBuffering()
|
|
{
|
|
return _status == AVPPlayerStatus.Buffering;
|
|
}
|
|
|
|
public override float GetBufferingProgress()
|
|
{
|
|
return AVPPlayerGetBufferingProgress(_player);
|
|
}
|
|
|
|
public override int GetBufferedTimeRangeCount()
|
|
{
|
|
return AVPPlayerGetBufferedTimeRangeCount(_player);
|
|
}
|
|
|
|
public override bool GetBufferedTimeRange(int index, ref float startTimeMs, ref float endTimeMs)
|
|
{
|
|
return AVPPlayerGetBufferedTimeRange(_player, index, out startTimeMs, out endTimeMs);
|
|
}
|
|
|
|
public override bool WaitForNextFrame(Camera camera, int previousFrameCount)
|
|
{
|
|
int count = 2;
|
|
AVPPlayerTextureInfo[] textures = new AVPPlayerTextureInfo[count];
|
|
int ret = AVPPlayerExtractFrame(_player, textures, ref count, 0.0);
|
|
if (ret == 0)
|
|
{
|
|
_planeCount = count;
|
|
for (int i = 0; i < count; ++i)
|
|
{
|
|
if (_texture[i] == null || _texture[i].width != textures[i].width || _texture[i].height != textures[i].height || _texture[i].format != (TextureFormat)textures[i].format)
|
|
{
|
|
_texture[i] = Texture2D.CreateExternalTexture(textures[i].width, textures[i].height, (TextureFormat)textures[i].format, /*mipmap*/ false, /*linear*/ false, textures[i].native);
|
|
if (i == 0)
|
|
{
|
|
_width = textures[i].width;
|
|
_height = textures[i].height;
|
|
_flipped = textures[i].flipped != 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_texture[i].UpdateExternalTexture(textures[i].native);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// IMediaProducer
|
|
|
|
public override int GetTextureCount()
|
|
{
|
|
return _planeCount;
|
|
}
|
|
|
|
public override Texture GetTexture(int index)
|
|
{
|
|
return _texture[index];
|
|
}
|
|
|
|
public override int GetTextureFrameCount()
|
|
{
|
|
return AVPPlayerGetFrameCount(_player);
|
|
}
|
|
|
|
public override long GetTextureTimeStamp()
|
|
{
|
|
return AVPPlayerGetFrameTimeStamp(_player);
|
|
}
|
|
|
|
public override bool RequiresVerticalFlip()
|
|
{
|
|
return _flipped;
|
|
}
|
|
|
|
public override float[] GetTextureTransform()
|
|
{
|
|
float[] transform = new float[6];
|
|
AVPPlayerGetTextureTransform(_player, transform);
|
|
return transform;
|
|
}
|
|
|
|
//
|
|
|
|
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 int GetAudioTrackCount()
|
|
{
|
|
return AVPPlayerGetAudioTrackCount(_player);
|
|
}
|
|
|
|
public override string GetAudioTrackId(int index)
|
|
{
|
|
string identifier = AVPPlayerGetAudioTrackId(_player, index);
|
|
if (identifier == null)
|
|
identifier = base.GetAudioTrackId(index);
|
|
return identifier;
|
|
}
|
|
|
|
public override int GetCurrentAudioTrack()
|
|
{
|
|
return AVPPlayerGetCurrentAudioTrack(_player);
|
|
}
|
|
|
|
public override void SetAudioTrack(int track)
|
|
{
|
|
AVPPlayerSetAudioTrack(_player, track);
|
|
}
|
|
|
|
public override string GetCurrentAudioTrackId()
|
|
{
|
|
return AVPPlayerGetCurrentAudioTrackId(_player);
|
|
}
|
|
|
|
public override int GetCurrentAudioTrackBitrate()
|
|
{
|
|
return AVPPlayerGetCurrentAudioTrackBitrate(_player);
|
|
}
|
|
|
|
public override int GetVideoTrackCount()
|
|
{
|
|
return AVPPlayerGetVideoTrackCount(_player);
|
|
}
|
|
|
|
public override int GetCurrentVideoTrack()
|
|
{
|
|
return AVPPlayerGetCurrentVideoTrack(_player);
|
|
}
|
|
|
|
public override void SetVideoTrack(int index)
|
|
{
|
|
AVPPlayerSetVideoTrack(_player, index);
|
|
}
|
|
|
|
public override string GetVideoTrackId(int index)
|
|
{
|
|
string identifier = AVPPlayerGetVideoTrackId(_player, index);
|
|
if (identifier == null)
|
|
identifier = base.GetVideoTrackId(index);
|
|
return identifier;
|
|
}
|
|
|
|
public override string GetCurrentVideoTrackId()
|
|
{
|
|
return AVPPlayerGetCurrentVideoTrackId(_player);
|
|
}
|
|
|
|
public override int GetCurrentVideoTrackBitrate()
|
|
{
|
|
return AVPPlayerGetCurrentVideoTrackBitrate(_player);
|
|
}
|
|
|
|
public override float GetVideoFrameRate()
|
|
{
|
|
return AVPPlayerGetNominalFrameRate(_player);
|
|
}
|
|
|
|
public override void Render()
|
|
{
|
|
|
|
}
|
|
|
|
public void UpdateTextures()
|
|
{
|
|
AVPPlayerTextureInfo[] textures = new AVPPlayerTextureInfo[2];
|
|
int count = textures.Length;
|
|
if (AVPPlayerGetTextures(_player, textures, ref count))
|
|
{
|
|
_planeCount = count;
|
|
for (int i = 0; i < count; ++i)
|
|
{
|
|
if (_texture[i] == null || _texture[i].width != textures[i].width || _texture[i].height != textures[i].height || _texture[i].format != (TextureFormat)textures[i].format)
|
|
{
|
|
_texture[i] = Texture2D.CreateExternalTexture(textures[i].width, textures[i].height, (TextureFormat)textures[i].format, /*mipmap*/ false, /*linear*/ false, textures[i].native);
|
|
if (i == 0)
|
|
{
|
|
_width = textures[i].width;
|
|
_height = textures[i].height;
|
|
_flipped = textures[i].flipped != 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_texture[i].UpdateExternalTexture(textures[i].native);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void Update()
|
|
{
|
|
_status = AVPPlayerGetStatus(_player);
|
|
|
|
if (AVPPlayerUpdate(_player))
|
|
{
|
|
IssuePluginEvent(AVPPluginEventType.PlayerRender);
|
|
}
|
|
|
|
_lastError = AVPPlayerGetLastError(_player);
|
|
UpdateTextures();
|
|
|
|
UpdateSubtitles();
|
|
|
|
// Check for meta data to become available
|
|
if (!_isMetaDataReady)
|
|
{
|
|
if (AVPPlayerHasMetaData(_player) || CanPlay())
|
|
{
|
|
// MOZ - had to move this outside of HasVideo check
|
|
_isMetaDataReady = true;
|
|
|
|
if (HasVideo())
|
|
{
|
|
if (_width > 0 && _height > 0)
|
|
{
|
|
if (Mathf.Max(_width, _height) > SystemInfo.maxTextureSize)
|
|
{
|
|
Debug.LogError("[AVProVideo] Video dimensions larger than maxTextureSize");
|
|
}
|
|
}
|
|
_playerDescription = "AVFoundation";
|
|
Helper.LogInfo("Using playback path: " + _playerDescription + " (" + _width + "x" + _height + "@" + GetVideoFrameRate().ToString("F2") + ")");
|
|
}
|
|
else if (HasAudio())
|
|
{
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void Dispose()
|
|
{
|
|
CloseVideo();
|
|
AVPPlayerRelease(_player);
|
|
_player = IntPtr.Zero;
|
|
_thisHandle.Free();
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
#endif
|