// Copyright (C) 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Runtime.InteropServices;
using System;
using System.Collections.Generic;
///
/// Plays video using Exoplayer rendering it on the main texture.
///
public class GvrVideoPlayerTexture : MonoBehaviour {
private const int MIN_BUFFER_SIZE = 3;
private const int MAX_BUFFER_SIZE = 15;
///
/// The video texture array used as a circular buffer to get the video image.
///
private Texture2D[] videoTextures;
private int currentTexture;
///
/// The video player pointer used to uniquely identify the player instance.
///
private IntPtr videoPlayerPtr;
///
/// The video player event base.
///
/// This is added to the event id when issues events to
/// the plugin.
///
private int videoPlayerEventBase;
private Texture initialTexture;
private bool initialized;
private int texWidth = 1024;
private int texHeight = 1024;
private long lastBufferedPosition;
private float framecount = 0;
private Graphic graphicComponent;
private Renderer rendererComponent;
///
/// The render event function.
///
private IntPtr renderEventFunction;
private bool processingRunning;
private bool exitProcessing;
private bool playOnResume;
/// List of callbacks to invoke when the video is ready.
private List> onEventCallbacks;
/// List of callbacks to invoke on exception.
/// The first parameter is the type of exception,
/// the second is the message.
///
private List> onExceptionCallbacks;
private readonly static Queue ExecuteOnMainThread = new Queue();
// Attach a text component to get some debug status info.
public Text statusText;
///
/// Video type.
///
public enum VideoType {
Dash = 0,
HLS = 2,
Other = 3
};
public enum VideoResolution {
Lowest = 1,
_720 = 720,
_1080 = 1080,
_2048 = 2048,
Highest = 4096
};
///
/// Video player state.
///
public enum VideoPlayerState {
Idle = 1,
Preparing = 2,
Buffering = 3,
Ready = 4,
Ended = 5
};
public enum VideoEvents {
VideoReady = 1,
VideoStartPlayback = 2,
VideoFormatChanged = 3,
VideoSurfaceSet = 4,
VideoSizeChanged = 5
};
///
/// Plugin render commands.
///
///
/// These are added to the eventbase for the specific player object and
/// issued to the plugin.
///
private enum RenderCommand {
None = -1,
InitializePlayer = 0,
UpdateVideo = 1,
RenderMono = 2,
RenderLeftEye = 3,
RenderRightEye = 4,
Shutdown = 5
};
// The circular buffer has to be at least 2,
// but in some cases that is too small, so set some reasonable range
// so a slider shows up in the property inspector.
[Range(MIN_BUFFER_SIZE, MAX_BUFFER_SIZE)]
public int bufferSize;
///
/// The type of the video.
///
public VideoType videoType;
public string videoURL;
public string videoContentID;
public string videoProviderId;
public VideoResolution initialResolution = VideoResolution.Highest;
///
/// True for adjusting the aspect ratio of the renderer.
///
public bool adjustAspectRatio;
///
/// The use secure path for DRM protected video.
///
public bool useSecurePath;
public bool VideoReady {
get {
return videoPlayerPtr != IntPtr.Zero && IsVideoReady(videoPlayerPtr);
}
}
public long CurrentPosition {
get {
return videoPlayerPtr != IntPtr.Zero ? GetCurrentPosition(videoPlayerPtr) : 0;
}
set {
// If the position is being set to 0, reset the framecount as well.
// This allows the texture swapping to work correctly at the beginning
// of the stream.
if (value == 0) {
framecount = 0;
}
SetCurrentPosition(videoPlayerPtr, value);
}
}
public long VideoDuration {
get {
return videoPlayerPtr != IntPtr.Zero ? GetDuration(videoPlayerPtr) : 0;
}
}
public long BufferedPosition {
get {
return videoPlayerPtr != IntPtr.Zero ? GetBufferedPosition(videoPlayerPtr) : 0;
}
}
public int BufferedPercentage {
get {
return videoPlayerPtr != IntPtr.Zero ? GetBufferedPercentage(videoPlayerPtr) : 0;
}
}
public bool IsPaused {
get {
return !initialized || videoPlayerPtr == IntPtr.Zero || IsVideoPaused(videoPlayerPtr);
}
}
public VideoPlayerState PlayerState {
get {
return videoPlayerPtr != IntPtr.Zero ? (VideoPlayerState)GetPlayerState(videoPlayerPtr) : VideoPlayerState.Idle;
}
}
public int MaxVolume {
get {
return videoPlayerPtr != IntPtr.Zero ? GetMaxVolume(videoPlayerPtr) : 0;
}
}
public int CurrentVolume {
get {
return videoPlayerPtr != IntPtr.Zero ? GetCurrentVolume(videoPlayerPtr) : 0;
}
set {
SetCurrentVolume(value);
}
}
/// Create the video player instance and the event base id.
void Awake() {
// Find the components on which to set the video texture.
graphicComponent = GetComponent();
rendererComponent = GetComponent();
CreatePlayer();
}
void CreatePlayer() {
bufferSize = bufferSize < MIN_BUFFER_SIZE ? MIN_BUFFER_SIZE : bufferSize;
if (videoTextures != null) {
DestroyVideoTextures();
}
videoTextures = new Texture2D[bufferSize];
currentTexture = 0;
videoPlayerPtr = CreateVideoPlayer();
videoPlayerEventBase = GetVideoPlayerEventBase(videoPlayerPtr);
Debug.Log(" -- " + gameObject.name + " created with base " +
videoPlayerEventBase);
SetOnVideoEventCallback((eventId) => {
Debug.Log("------------- E V E N T " + eventId + " -----------------");
UpdateStatusText();
});
SetOnExceptionCallback((type, msg) => {
Debug.LogError("Exception: " + type + ": " + msg);
});
initialized = false;
if (rendererComponent != null) {
initialTexture = rendererComponent.material.mainTexture;
} else if (graphicComponent) {
initialTexture = graphicComponent.mainTexture;
}
}
IEnumerator Start() {
CreateTextureForVideoMaybe();
renderEventFunction = GetRenderEventFunc();
if (renderEventFunction != IntPtr.Zero) {
IssuePlayerEvent(RenderCommand.InitializePlayer);
yield return StartCoroutine(CallPluginAtEndOfFrames());
}
}
void OnDisable() {
if (videoPlayerPtr != IntPtr.Zero) {
if (GetPlayerState(videoPlayerPtr) == (int)VideoPlayerState.Ready) {
PauseVideo(videoPlayerPtr);
}
}
}
///
/// Sets the display texture.
///
/// Texture to display.
// If null, the initial texture of the renderer is used.
public void SetDisplayTexture(Texture texture) {
if (texture == null) {
texture = initialTexture;
}
if (texture == null) {
return;
}
if (rendererComponent != null) {
rendererComponent.sharedMaterial.mainTexture = initialTexture;
} else if (graphicComponent != null) {
graphicComponent.material.mainTexture = initialTexture;
}
}
public void CleanupVideo() {
Debug.Log("Cleaning Up video!");
exitProcessing = true;
if (videoPlayerPtr != IntPtr.Zero) {
DestroyVideoPlayer(videoPlayerPtr);
videoPlayerPtr = IntPtr.Zero;
}
DestroyVideoTextures();
if (rendererComponent != null) {
rendererComponent.sharedMaterial.mainTexture = initialTexture;
} else if (graphicComponent != null) {
graphicComponent.material.mainTexture = initialTexture;
}
}
public void ReInitializeVideo() {
if (rendererComponent != null) {
rendererComponent.sharedMaterial.mainTexture = initialTexture;
} else if (graphicComponent != null) {
graphicComponent.material.mainTexture = initialTexture;
}
if (videoPlayerPtr == IntPtr.Zero) {
CreatePlayer();
IssuePlayerEvent(RenderCommand.InitializePlayer);
}
if (Init()) {
StartCoroutine(CallPluginAtEndOfFrames());
}
}
void DestroyVideoTextures() {
if (videoTextures != null) {
foreach (Texture2D t in videoTextures) {
if (t != null) {
// Free GPU memory immediately.
t.Resize(1, 1);
t.Apply();
// Unity's destroy is lazy.
Destroy(t);
}
}
videoTextures = null;
}
}
void OnEnable() {
if (videoPlayerPtr != IntPtr.Zero) {
StartCoroutine(CallPluginAtEndOfFrames());
}
}
void OnDestroy() {
if (videoPlayerPtr != IntPtr.Zero) {
DestroyVideoPlayer(videoPlayerPtr);
}
DestroyVideoTextures();
}
void OnValidate() {
Renderer r = GetComponent();
Graphic g = GetComponent();
if (g == null && r == null) {
Debug.LogError("TexturePlayer object must have either " +
"a Renderer component or a Graphic component.");
}
}
void OnApplicationPause(bool bPause) {
if (videoPlayerPtr != IntPtr.Zero) {
if (bPause) {
playOnResume = !IsPaused;
PauseVideo(videoPlayerPtr);
} else {
if (playOnResume) {
PlayVideo(videoPlayerPtr);
}
}
}
}
void OnRenderObject() {
// Don't render if not initialized.
if (videoPlayerPtr == IntPtr.Zero || videoTextures[0] == null) {
return;
}
Texture newTex = videoTextures[currentTexture];
// Handle either the renderer component or the graphic component.
if (rendererComponent != null) {
// Don't render the first texture from the player, it is unitialized.
if (currentTexture <= 1 && framecount <= 1) {
return;
}
// Don't swap the textures if the video ended.
if (PlayerState == VideoPlayerState.Ended) {
return;
}
// Unity may build new a new material instance when assigning
// material.x which can lead to duplicating materials each frame
// whereas using the shared material will modify the original material.
if (rendererComponent.material.mainTexture != null) {
IntPtr currentTexId =
rendererComponent.sharedMaterial.mainTexture.GetNativeTexturePtr();
// Update the material's texture if it is different.
if (currentTexId != newTex.GetNativeTexturePtr()) {
rendererComponent.sharedMaterial.mainTexture = newTex;
framecount += 1f;
}
} else {
rendererComponent.sharedMaterial.mainTexture = newTex;
}
} else if (graphicComponent != null) {
if (graphicComponent.material.mainTexture != null) {
IntPtr currentTexId =
graphicComponent.material.mainTexture.GetNativeTexturePtr();
// Update the material's texture if it is different.
if (currentTexId != newTex.GetNativeTexturePtr()) {
graphicComponent.material.mainTexture = newTex;
framecount += 1f;
}
} else {
graphicComponent.material.mainTexture = newTex;
}
} else {
Debug.LogError("GvrVideoPlayerTexture: No render or graphic component.");
}
}
private void OnRestartVideoEvent(int eventId) {
if (eventId == (int)VideoEvents.VideoReady) {
Debug.Log("Restarting video complete.");
RemoveOnVideoEventCallback(OnRestartVideoEvent);
}
}
///
/// Resets the video player.
///
public void RestartVideo() {
SetOnVideoEventCallback(OnRestartVideoEvent);
string theUrl = ProcessURL();
InitVideoPlayer(videoPlayerPtr, (int) videoType, theUrl,
videoContentID,
videoProviderId,
useSecurePath,
true);
framecount = 0;
}
public void SetCurrentVolume(int val) {
SetCurrentVolume(videoPlayerPtr, val);
}
///
/// Initialize the video player.
///
/// true if successful
public bool Init() {
if (initialized) {
Debug.Log("Skipping initialization: video player already loaded");
return true;
}
if (videoURL == null || videoURL.Length == 0) {
Debug.LogError("Cannot initialize with null videoURL");
return false;
}
videoURL = videoURL == null ? "" : videoURL.Trim();
videoContentID = videoContentID == null ? "" : videoContentID.Trim();
videoProviderId = videoProviderId == null ? "" : videoProviderId.Trim();
SetInitialResolution(videoPlayerPtr, (int) initialResolution);
string theUrl = ProcessURL();
Debug.Log("Playing " + videoType + " " + theUrl);
Debug.Log("videoContentID = " + videoContentID);
Debug.Log("videoProviderId = " + videoProviderId);
videoPlayerPtr = InitVideoPlayer(videoPlayerPtr, (int) videoType, theUrl,
videoContentID, videoProviderId,
useSecurePath, false);
initialized = true;
framecount = 0;
return videoPlayerPtr != IntPtr.Zero;
}
public bool Play() {
if (!initialized) {
Init();
} else if (!processingRunning) {
StartCoroutine(CallPluginAtEndOfFrames());
}
if (videoPlayerPtr != IntPtr.Zero && IsVideoReady(videoPlayerPtr)) {
return PlayVideo(videoPlayerPtr) == 0;
} else {
Debug.LogError("Video player not ready to Play!");
return false;
}
}
public bool Pause() {
if (!initialized) {
Init();
}
if (VideoReady) {
return PauseVideo(videoPlayerPtr) == 0;
} else {
Debug.LogError("Video player not ready to Pause!");
return false;
}
}
///
/// Adjusts the aspect ratio.
///
///
/// This adjusts the transform scale to match the aspect
/// ratio of the texture.
///
private void AdjustAspectRatio() {
float aspectRatio = texWidth / texHeight;
// set the y scale based on the x value
Vector3 newscale = transform.localScale;
newscale.y = Mathf.Min(newscale.y, newscale.x / aspectRatio);
transform.localScale = newscale;
}
///
/// Creates the texture for video if needed.
///
private void CreateTextureForVideoMaybe() {
if (videoTextures[0] == null || (texWidth != videoTextures[0].width ||
texHeight != videoTextures[0].height)) {
// Check the dimensions to make sure they are valid.
if (texWidth < 0 || texHeight < 0) {
// Maybe use the last dimension. This happens when re-initializing the player.
if (videoTextures != null && videoTextures[0].width > 0) {
texWidth = videoTextures[0].width;
texHeight = videoTextures[0].height;
}
}
int[] tex_ids = new int[videoTextures.Length];
for (int idx = 0; idx < videoTextures.Length; idx++) {
// Resize the existing texture if there, otherwise create it.
if (videoTextures[idx] != null) {
if (videoTextures[idx].width != texWidth
|| videoTextures[idx].height != texHeight)
{
videoTextures[idx].Resize(texWidth, texHeight);
videoTextures[idx].Apply();
}
} else {
videoTextures[idx] = new Texture2D(texWidth, texHeight,
TextureFormat.RGBA32, false);
videoTextures[idx].filterMode = FilterMode.Bilinear;
videoTextures[idx].wrapMode = TextureWrapMode.Clamp;
}
tex_ids[idx] = videoTextures[idx].GetNativeTexturePtr().ToInt32();
}
SetExternalTextures(videoPlayerPtr, tex_ids, tex_ids.Length,
texWidth, texHeight);
currentTexture = 0;
UpdateStatusText();
}
if (adjustAspectRatio) {
AdjustAspectRatio();
}
}
private void UpdateStatusText() {
float fps = CurrentPosition > 0 ?
(framecount / (CurrentPosition / 1000f)) : CurrentPosition;
string status = texWidth + " x " + texHeight + " buffer: " +
(BufferedPosition / 1000) + " " + PlayerState + " fps: " + fps;
if (statusText != null) {
if (statusText.text != status) {
statusText.text = status;
Debug.Log("STATUS: " + status);
}
}
}
///
/// Issues the player event.
///
/// The event to send to the video player
/// instance.
///
private void IssuePlayerEvent(RenderCommand evt) {
if (renderEventFunction != IntPtr.Zero && evt != RenderCommand.None) {
GL.IssuePluginEvent(renderEventFunction,
videoPlayerEventBase + (int) evt);
}
}
void Update() {
while (ExecuteOnMainThread.Count > 0) {
ExecuteOnMainThread.Dequeue().Invoke();
}
}
private IEnumerator CallPluginAtEndOfFrames() {
if (processingRunning) {
Debug.LogError("CallPluginAtEndOfFrames invoked while already running.");
yield break;
}
// Only run while the video is playing.
bool running = true;
processingRunning = true;
exitProcessing = false;
WaitForEndOfFrame wfeof = new WaitForEndOfFrame();
while (running) {
// Wait until all frame rendering is done
yield return wfeof;
if (exitProcessing) {
running = false;
break;
}
if (videoPlayerPtr != IntPtr.Zero) {
CreateTextureForVideoMaybe();
}
IntPtr tex = GetRenderableTextureId(videoPlayerPtr);
currentTexture = 0;
for (int i = 0; i < videoTextures.Length; i++) {
if (tex == videoTextures[i].GetNativeTexturePtr()) {
currentTexture = i;
}
}
if (!VideoReady) {
continue;
} else if (framecount > 1 && PlayerState == VideoPlayerState.Ended) {
running = false;
}
IssuePlayerEvent(RenderCommand.UpdateVideo);
IssuePlayerEvent(RenderCommand.RenderMono);
int w = GetWidth(videoPlayerPtr);
int h = GetHeight(videoPlayerPtr);
// Limit total pixel count to the same as 2160p.
// 3840 * 2160 == 2880 * 2880
if (w * h > 2880 * 2880) {
// Clamp the max resolution preserving aspect ratio.
float aspectRoot = (float) Math.Sqrt(w / h);
w = (int) (2880 * aspectRoot);
h = (int) (2880 / aspectRoot);
}
texWidth = w;
texHeight = h;
if ((int) framecount % 30 == 0) {
UpdateStatusText();
}
long bp = BufferedPosition;
if (bp != lastBufferedPosition) {
lastBufferedPosition = bp;
UpdateStatusText();
}
}
processingRunning = false;
}
public void RemoveOnVideoEventCallback(Action callback) {
if (onEventCallbacks != null) {
onEventCallbacks.Remove(callback);
}
}
public void SetOnVideoEventCallback(Action callback) {
if (onEventCallbacks == null) {
onEventCallbacks = new List>();
}
onEventCallbacks.Add(callback);
SetOnVideoEventCallback(videoPlayerPtr, InternalOnVideoEventCallback,
ToIntPtr(this));
}
internal void FireVideoEvent(int eventId) {
if (onEventCallbacks == null) {
return;
}
// Copy the collection so the callbacks can remove themselves from the list.
Action[] cblist = onEventCallbacks.ToArray();
foreach (Action cb in cblist) {
try {
cb(eventId);
} catch (Exception e) {
Debug.LogError("exception calling callback: " + e);
}
}
}
[AOT.MonoPInvokeCallback(typeof(OnVideoEventCallback))]
static void InternalOnVideoEventCallback(IntPtr cbdata, int eventId) {
if (cbdata == IntPtr.Zero) {
return;
}
GvrVideoPlayerTexture player;
var gcHandle = GCHandle.FromIntPtr(cbdata);
try {
player = (GvrVideoPlayerTexture) gcHandle.Target;
}
catch (InvalidCastException e) {
Debug.LogError("GC Handle pointed to unexpected type: " +
gcHandle.Target + ". Expected " +
typeof(GvrVideoPlayerTexture));
throw e;
}
if (player != null) {
ExecuteOnMainThread.Enqueue(() => player.FireVideoEvent(eventId));
}
}
public void SetOnExceptionCallback(Action callback) {
if (onExceptionCallbacks == null) {
onExceptionCallbacks = new List>();
SetOnExceptionCallback(videoPlayerPtr, InternalOnExceptionCallback,
ToIntPtr(this));
}
onExceptionCallbacks.Add(callback);
}
[AOT.MonoPInvokeCallback(typeof(OnExceptionCallback))]
static void InternalOnExceptionCallback(string type, string msg,
IntPtr cbdata) {
if (cbdata == IntPtr.Zero) {
return;
}
GvrVideoPlayerTexture player;
var gcHandle = GCHandle.FromIntPtr(cbdata);
try {
player = (GvrVideoPlayerTexture) gcHandle.Target;
}
catch (InvalidCastException e) {
Debug.LogError("GC Handle pointed to unexpected type: " +
gcHandle.Target + ". Expected " +
typeof(GvrVideoPlayerTexture));
throw e;
}
if (player != null) {
ExecuteOnMainThread.Enqueue(() => player.FireOnException(type, msg));
}
}
internal void FireOnException(string type, string msg) {
if (onExceptionCallbacks == null) {
return;
}
foreach (Action cb in onExceptionCallbacks) {
try {
cb(type, msg);
} catch (Exception e) {
Debug.LogError("exception calling callback: " + e);
}
}
}
internal static IntPtr ToIntPtr(System.Object obj) {
GCHandle handle = GCHandle.Alloc(obj);
return GCHandle.ToIntPtr(handle);
}
internal string ProcessURL() {
return videoURL.Replace("${Application.dataPath}", Application.dataPath);
}
internal delegate void OnVideoEventCallback(IntPtr cbdata, int eventId);
internal delegate void OnExceptionCallback(string type, string msg,
IntPtr cbdata);
#if UNITY_ANDROID && !UNITY_EDITOR
private const string dllName = "gvrvideo";
[DllImport(dllName)]
private static extern IntPtr GetRenderEventFunc();
[DllImport(dllName)]
private static extern void SetExternalTextures(IntPtr videoPlayerPtr,
int[] texIds,
int size,
int w,
int h);
[DllImport(dllName)]
private static extern IntPtr GetRenderableTextureId(IntPtr videoPlayerPtr);
// Keep public so we can check for the dll being present at runtime.
[DllImport(dllName)]
public static extern IntPtr CreateVideoPlayer();
// Keep public so we can check for the dll being present at runtime.
[DllImport(dllName)]
public static extern void DestroyVideoPlayer(IntPtr videoPlayerPtr);
[DllImport(dllName)]
private static extern int GetVideoPlayerEventBase(IntPtr videoPlayerPtr);
[DllImport(dllName)]
private static extern IntPtr InitVideoPlayer(IntPtr videoPlayerPtr,
int videoType,
string videoURL,
string contentID,
string providerId,
bool useSecurePath,
bool useExisting);
[DllImport(dllName)]
private static extern void SetInitialResolution(IntPtr videoPlayerPtr,
int initialResolution);
[DllImport(dllName)]
private static extern int GetPlayerState(IntPtr videoPlayerPtr);
[DllImport(dllName)]
private static extern int GetWidth(IntPtr videoPlayerPtr);
[DllImport(dllName)]
private static extern int GetHeight(IntPtr videoPlayerPtr);
[DllImport(dllName)]
private static extern int PlayVideo(IntPtr videoPlayerPtr);
[DllImport(dllName)]
private static extern int PauseVideo(IntPtr videoPlayerPtr);
[DllImport(dllName)]
private static extern bool IsVideoReady(IntPtr videoPlayerPtr);
[DllImport(dllName)]
private static extern bool IsVideoPaused(IntPtr videoPlayerPtr);
[DllImport(dllName)]
private static extern long GetDuration(IntPtr videoPlayerPtr);
[DllImport(dllName)]
private static extern long GetBufferedPosition(IntPtr videoPlayerPtr);
[DllImport(dllName)]
private static extern long GetCurrentPosition(IntPtr videoPlayerPtr);
[DllImport(dllName)]
private static extern void SetCurrentPosition(IntPtr videoPlayerPtr,
long pos);
[DllImport(dllName)]
private static extern int GetBufferedPercentage(IntPtr videoPlayerPtr);
[DllImport(dllName)]
private static extern int GetMaxVolume(IntPtr videoPlayerPtr);
[DllImport(dllName)]
private static extern int GetCurrentVolume(IntPtr videoPlayerPtr);
[DllImport(dllName)]
private static extern void SetCurrentVolume(IntPtr videoPlayerPtr,
int value);
[DllImport(dllName)]
private static extern bool SetVideoPlayerSupportClassname(
IntPtr videoPlayerPtr,
string classname);
[DllImport(dllName)]
private static extern IntPtr GetRawPlayer(IntPtr videoPlayerPtr);
[DllImport(dllName)]
private static extern void SetOnVideoEventCallback(IntPtr videoPlayerPtr,
OnVideoEventCallback callback,
IntPtr callback_arg);
[DllImport(dllName)]
private static extern void SetOnExceptionCallback(IntPtr videoPlayerPtr,
OnExceptionCallback callback,
IntPtr callback_arg);
#else
private const string NOT_IMPLEMENTED_MSG =
"Not implemented on this platform";
private static IntPtr GetRenderEventFunc() {
Debug.Log(NOT_IMPLEMENTED_MSG);
return IntPtr.Zero;
}
private static void SetExternalTextures(IntPtr videoPlayerPtr,
int[] texIds,
int size,
int w,
int h) {
Debug.Log(NOT_IMPLEMENTED_MSG);
}
private static IntPtr GetRenderableTextureId(IntPtr videoPlayerPtr) {
return IntPtr.Zero;
}
// Make this public so we can test the loading of the DLL.
public static IntPtr CreateVideoPlayer() {
Debug.Log(NOT_IMPLEMENTED_MSG);
return IntPtr.Zero;
}
// Make this public so we can test the loading of the DLL.
public static void DestroyVideoPlayer(IntPtr videoPlayerPtr) {
Debug.Log(NOT_IMPLEMENTED_MSG);
}
private static int GetVideoPlayerEventBase(IntPtr videoPlayerPtr) {
Debug.Log(NOT_IMPLEMENTED_MSG);
return 0;
}
private static IntPtr InitVideoPlayer(IntPtr videoPlayerPtr, int videoType,
string videoURL,
string contentID,
string providerId,
bool useSecurePath,
bool useExisting) {
Debug.Log(NOT_IMPLEMENTED_MSG);
return IntPtr.Zero;
}
private static void SetInitialResolution(IntPtr videoPlayerPtr,
int initialResolution) {
Debug.Log(NOT_IMPLEMENTED_MSG);
}
private static int GetPlayerState(IntPtr videoPlayerPtr) {
Debug.Log(NOT_IMPLEMENTED_MSG);
return -1;
}
private static int GetWidth(IntPtr videoPlayerPtr) {
Debug.Log(NOT_IMPLEMENTED_MSG);
return -1;
}
private static int GetHeight(IntPtr videoPlayerPtr) {
Debug.Log(NOT_IMPLEMENTED_MSG);
return -1;
}
private static int PlayVideo(IntPtr videoPlayerPtr) {
Debug.Log(NOT_IMPLEMENTED_MSG);
return 0;
}
private static int PauseVideo(IntPtr videoPlayerPtr) {
Debug.Log(NOT_IMPLEMENTED_MSG);
return 0;
}
private static bool IsVideoReady(IntPtr videoPlayerPtr) {
Debug.Log(NOT_IMPLEMENTED_MSG);
return false;
}
private static bool IsVideoPaused(IntPtr videoPlayerPtr) {
Debug.Log(NOT_IMPLEMENTED_MSG);
return true;
}
private static long GetDuration(IntPtr videoPlayerPtr) {
Debug.Log(NOT_IMPLEMENTED_MSG);
return -1;
}
private static long GetBufferedPosition(IntPtr videoPlayerPtr) {
Debug.Log(NOT_IMPLEMENTED_MSG);
return -1;
}
private static long GetCurrentPosition(IntPtr videoPlayerPtr) {
Debug.Log(NOT_IMPLEMENTED_MSG);
return -1;
}
private static void SetCurrentPosition(IntPtr videoPlayerPtr, long pos) {
Debug.Log(NOT_IMPLEMENTED_MSG);
}
private static int GetBufferedPercentage(IntPtr videoPlayerPtr) {
Debug.Log(NOT_IMPLEMENTED_MSG);
return 0;
}
private static int GetMaxVolume(IntPtr videoPlayerPtr) {
Debug.Log(NOT_IMPLEMENTED_MSG);
return 0;
}
private static int GetCurrentVolume(IntPtr videoPlayerPtr) {
Debug.Log(NOT_IMPLEMENTED_MSG);
return 0;
}
private static void SetCurrentVolume(IntPtr videoPlayerPtr, int value) {
Debug.Log(NOT_IMPLEMENTED_MSG);
}
private static bool SetVideoPlayerSupportClassname(IntPtr videoPlayerPtr,
string classname) {
Debug.Log(NOT_IMPLEMENTED_MSG);
return false;
}
private static IntPtr GetRawPlayer(IntPtr videoPlayerPtr) {
Debug.Log(NOT_IMPLEMENTED_MSG);
return IntPtr.Zero;
}
private static void SetOnVideoEventCallback(IntPtr videoPlayerPtr,
OnVideoEventCallback callback,
IntPtr callback_arg) {
Debug.Log(NOT_IMPLEMENTED_MSG);
}
private static void SetOnExceptionCallback(IntPtr videoPlayerPtr,
OnExceptionCallback callback,
IntPtr callback_arg) {
Debug.Log(NOT_IMPLEMENTED_MSG);
}
#endif // UNITY_ANDROID && !UNITY_EDITOR
}