Skip to main content
Up and Coming
May 14, 2015

MovieTexture on Gear VR

Hello guys, I know that MovieTexture don't work to Android and the plugin EasyMovieTexture don't work to Gear VR

On Oculus SDK has a script called MoviePlayerSample.cs, and I'm trying to use it, but I don't know if i'm doing right, because I follow the instructions and when I build the video dont play. I tryied to use the example scene to but it still dont play: Thats what I done:

(Instructions by the developper):

" Place a simple textured quad surface with the correct aspect ratio in your scene.
Add the MoviePlayerSample.cs script to the surface object.

Modify it for the correct media location (currently hardcoded)

Modify it to start when you want, instead of on the very first Update()."

On the third instruction that need to modify the media location I changed the line of the example code to this:

 mediaPlayer.Call("setDataSource", "/Card/oculus/Movies/Trailers/Interstellar.mp4");


And I done the other instructions too I just don't know if the last instruction works and if I done right on the third instruction.

I will send the developper code from sdk with my changes to be easy to understand:

 /************************************************************************************

Filename : MoviePlayerSample.cs
Content : An example of how to use the Moonlight video player
Created : July 12, 2014

Copyright : Copyright 2014 Oculus VR, LLC. All Rights reserved.

Use of this software is subject to the terms of the Oculus LLC license
agreement provided at the time of installation or download, or which
otherwise accompanies this software in either electronic or hard copy form.

************************************************************************************/

using UnityEngine;
using System.Collections; // required for Coroutines
using System.Runtime.InteropServices; // required for DllImport
using System; // requred for IntPtr


/************************************************************************************
Usage:

Place a simple textured quad surface with the correct aspect ratio in your scene.

Add the MoviePlayerSample.cs script to the surface object.

Modify it for the correct media location (currently hardcoded)

Modify it to start when you want, instead of on the very first Update().

Implementation:

In the MoviePlayerSample Awake() call, GetNativeTextureID() is called on
renderer.material.mainTexture.

When the Oculus plugin gets the initialization event on the render thread,
it creates a new Android SurfaceTexture and Surface object in preparation
for receiving media.

When the game wants to start the video playing, it calls the StartVideoPlayerOnTextureId()
script call, which creates an Android MediaPlayer java object, issues a
native plugin call to tell the native code which texture id to put the video
on and return the Android Surface object to pass to MediaPlayer, then sets
up the media stream and starts it.

Every frame, right after VrApi::WarpSwap() is called by the native plugin,
the SurfaceTexture object is checked for updates. If there is one, the
target texId is re-created at the correct dimensions and format if it is
the first frame, then the video image is rendered to it and mipmapped.
The following frame, instead of Unity drawing the image that was placed
on the surface in the Unity editor, it will draw the current video frame.

It is important to note that the texture is actually replaced -- the original
version is gone, and the video will now show up everywhere that texture was
used, not just on sthe GameObject that ran the script.

NOTE: The resolution of the movie texture is hard coded to 960x540 in MediaSurface.cpp.

************************************************************************************/

public class MoviePlayerSample : MonoBehaviour
{
private int nativeTextureID;

bool startedVideo = false;

#if (UNITY_ANDROID && !UNITY_EDITOR)
bool videoPaused = false;
AndroidJavaObject mediaPlayer = null;
#endif

/// <summary>
/// Initialization of the movie surface
/// </summary>
void Awake()
{
Debug.Log("Awake");

if (GetComponent<Renderer>().material == null || GetComponent<Renderer>().material.mainTexture == null)
{
Debug.LogError("Can't GetNativeTextureID() for movie surface");
}

// This aparently has to be done at Awake time, before
// multithreaded rendering starts;
nativeTextureID = GetComponent<Renderer>().material.mainTexture.GetNativeTextureID();
Debug.Log("Movie Texture id: " + nativeTextureID);
}

/// <summary>
/// Auto-starts video playback
/// </summary>
void DelayedStartVideo()
{
if (!startedVideo)
{
startedVideo = true;
#if (UNITY_ANDROID && !UNITY_EDITOR)
// This can only be done once multithreaded rendering is running
mediaPlayer = StartVideoPlayerOnTextureId(nativeTextureID);
#endif
}
}

void Start()
{
#if (UNITY_ANDROID && !UNITY_EDITOR)
// delay one frame because OVRCameraController initializes the render thread in Start()
Invoke("DelayedStartVideo", 0.1f);
#endif
}

/// <summary>
/// Pauses video playback when the app loses or gains focus
/// </summary>
void OnApplicationPause(bool wasPaused)
{
Debug.Log("OnApplicationPause: " + wasPaused);
#if (UNITY_ANDROID && !UNITY_EDITOR)
if (mediaPlayer != null)
{
videoPaused = wasPaused;
mediaPlayer.Call(( videoPaused ) ? "pause" : "start");
}
#endif
}

#if (UNITY_ANDROID && !UNITY_EDITOR)
// This function returns an Android Surface object that is
// bound to a SurfaceTexture object on an independent OpenGL texture id.
// Each frame, before the TimeWarp processing, the SurfaceTexture is checked
// for updates, and if one is present, the contents of the SurfaceTexture
// will be copied over to the provided surfaceTexId and mipmaps will be
// generated so normal Unity rendering can use it.
[DllImport("OculusPlugin")]
private static extern IntPtr OVR_Media_Surface(int surfaceTexId);
#endif

#if (UNITY_ANDROID && !UNITY_EDITOR)
/// <summary>
/// Set up the video player with the movie surface texture id
/// </summary>
AndroidJavaObject StartVideoPlayerOnTextureId(int textureId)
{
Debug.Log("SetUpVideoPlayer ");

IntPtr androidSurface = OVR_Media_Surface(textureId);
c
AndroidJavaObject mediaPlayer = new AndroidJavaObject("android/media/MediaPlayer");

// Can't use AndroidJavaObject.Call() with a jobject, must use low level interface
//mediaPlayer.Call("setSurface", androidSurface);
IntPtr setSurfaceMethodId = AndroidJNI.GetMethodID(mediaPlayer.GetRawClass(),"setSurface","(Landroid/view/Surface;)V");
jvalue[] parms = new jvalue[1];
parms[0] = new jvalue();
parms[0].l = androidSurface;
AndroidJNI.CallObjectMethod(mediaPlayer.GetRawObject(), setSurfaceMethodId, parms);


mediaPlayer.Call("setDataSource", "/Card/oculus/Movies/Trailers/Interstellar.mp4");
mediaPlayer.Call("prepare");
mediaPlayer.Call("setLooping", true);
mediaPlayer.Call("start");

return mediaPlayer;
}
#endif
}
    This topic has been closed for replies.

    29 replies

    Up and Coming
    July 27, 2015
    One other question...

    I have multiple scenes, with a single video sphere in each scene. Each scene needs to play a different video when the scene is loaded. As of now, my main menu video is working, but when I trigger another level to load, the new video will not play. I hear the audio from the main menu video continuing to play, so I assume that loading a new level doesn't re-initialize the video using the one noted in the new script on the new sphere. Correct? How do I go about stopping the movie on one level and playing the movie on the new level whenever the level is switched. Thanks.
    July 30, 2015
    "barryzundel" wrote:
    How do I go about stopping the movie on one level and playing the movie on the new level whenever the level is switched.
    The way I've been going about this problem is to use a persistent singleton object, initialized in your first scene, that calls GetNativeTextureID() in Awake(). GetNativeTextureID() must be called before multithreaded rendering starts, otherwise the app will crash, so you can really only do this once.

    Add a Mesh Renderer to your singleton. This object's texture will be what is replaced with the movie, so assign the same texture to what ever object you want (your spheres). You could keep a string array of paths to your videos in the singleton and use OnLevelWasLoaded load the new video when you switch levels.

    To play a new video, you could do the following in MoviePlayerSample.cs:


    string videoPath = "path/to/video.mp4";

    mediaPlayer.Call("stop");
    mediaPlayer.Call("reset");
    mediaPlayer.Call("setDataSource", videoPath);
    mediaPlayer.Call("prepare");
    mediaPlayer.Call("start");
    August 4, 2015
    "cybereality" wrote:
    Media Surface functionality is currently removed with First Party support. It will be added as a separate plugin to the First Party Utilities package in the very near future.


    Hi! Meanwhile, and just in case... Did someone manage to have two movies playing in the same scene?

    I've tried using the movieplayer_sample scene... duplicated moviesurfaces, assigning different video paths, material and texture to each moviesurface game object. But I couldn't have two movies playing in different textures.

    If I use the same texture for both materials, the same movie is played in both moviesurface game objects, but if I assign different texture, then it is only one moviesurface that plays video.

    Is there a way to do this?
    New Participant
    August 13, 2015
    Is there any way to loop the Video ??
    August 14, 2015
    "SreerajVK" wrote:
    Is there any way to loop the Video ??
    mediaPlayer.Call("setLooping", true);

    http://developer.android.com/reference/ ... layer.html
    New Participant
    September 29, 2015
    "gconvergen" wrote:
    "barryzundel" wrote:
    How do I go about stopping the movie on one level and playing the movie on the new level whenever the level is switched.
    The way I've been going about this problem is to use a persistent singleton object, initialized in your first scene, that calls GetNativeTextureID() in Awake(). GetNativeTextureID() must be called before multithreaded rendering starts, otherwise the app will crash, so you can really only do this once.

    Add a Mesh Renderer to your singleton. This object's texture will be what is replaced with the movie, so assign the same texture to what ever object you want (your spheres). You could keep a string array of paths to your videos in the singleton and use OnLevelWasLoaded load the new video when you switch levels.

    To play a new video, you could do the following in MoviePlayerSample.cs:


    string videoPath = "path/to/video.mp4";

    mediaPlayer.Call("stop");
    mediaPlayer.Call("reset");
    mediaPlayer.Call("setDataSource", videoPath);
    mediaPlayer.Call("prepare");
    mediaPlayer.Call("start");


    I've tried this and it works! Thank you very much!

    Now I have a problem, I have a scene with 360 videos and another scene with 2D videos, I can change the video changing the videoPath but when I change from 360 to 2D scene it doesn't work... any ideas?
    September 30, 2015
    "FuturescoGames" wrote:
    Now I have a problem, I have a scene with 360 videos and another scene with 2D videos, I can change the video changing the videoPath but when I change from 360 to 2D scene it doesn't work... any ideas?
    Can you go into more detail on what's happening? Is the singleton working properly? i.e. is it still present in the scene with your 2D videos? Also, are you using the same texture on your sphere as your quad?
    New Participant
    September 30, 2015
    Yes, I have two singleton objects: 2D screen and 360 screen, both have a script to make the singleton, they have two different textures

    Both have a movie player script based on the Oculus MovieSample, different scripts but the same (I would like to refactor when it will work), the only difference is about the path of the video to use 2D videos or 360, I don't know if the android MediaPlayer or the texture is failing when both executes.

    Here's the code of the 2D movie player:

    /************************************************************************************

    Filename : MoviePlayerSample.cs
    Content : An example of how to use the Moonlight video player
    Created : July 12, 2014

    Copyright : Copyright 2014 Oculus VR, LLC. All Rights reserved.

    Use of this software is subject to the terms of the Oculus LLC license
    agreement provided at the time of installation or download, or which
    otherwise accompanies this software in either electronic or hard copy form.

    ************************************************************************************/

    using UnityEngine;
    using System.Collections; // required for Coroutines
    using System.Runtime.InteropServices; // required for DllImport
    using System; // requred for IntPtr


    /************************************************************************************
    Usage:

    Place a simple textured quad surface with the correct aspect ratio in your scene.

    Add the MoviePlayerSample.cs script to the surface object.

    Modify it for the correct media location (currently hardcoded)

    Modify it to start when you want, instead of on the very first Update().

    Implementation:

    In the MoviePlayerSample Awake() call, GetNativeTextureID() is called on
    renderer.material.mainTexture.

    When the Oculus plugin gets the initialization event on the render thread,
    it creates a new Android SurfaceTexture and Surface object in preparation
    for receiving media.

    When the game wants to start the video playing, it calls the StartVideoPlayerOnTextureId()
    script call, which creates an Android MediaPlayer java object, issues a
    native plugin call to tell the native code which texture id to put the video
    on and return the Android Surface object to pass to MediaPlayer, then sets
    up the media stream and starts it.

    Every frame, right after VrApi::WarpSwap() is called by the native plugin,
    the SurfaceTexture object is checked for updates. If there is one, the
    target texId is re-created at the correct dimensions and format if it is
    the first frame, then the video image is rendered to it and mipmapped.
    The following frame, instead of Unity drawing the image that was placed
    on the surface in the Unity editor, it will draw the current video frame.

    It is important to note that the texture is actually replaced -- the original
    version is gone, and the video will now show up everywhere that texture was
    used, not just on sthe GameObject that ran the script.

    NOTE: The resolution of the movie texture is hard coded to 960x540 in MediaSurface.cpp.

    ************************************************************************************/

    public class MoviePlayer2D : MonoBehaviour
    {
    private int nativeTextureID;

    bool startedVideo = false;

    //string videoPath = "/storage/emulated/0/DCIM/Camera/20150806_191825.mp4";

    public string[] myVideos = new string[2];

    int maxVideos;
    int arrayPos = -1;

    //object objectVideo;

    #if (UNITY_ANDROID && !UNITY_EDITOR)
    bool videoPaused = false;
    AndroidJavaObject mediaPlayer2 = null;
    #endif

    /// <summary>
    /// Initialization of the movie surface
    /// </summary>
    void Awake()
    {
    Debug.Log("Awake");

    if (GetComponent<Renderer>().material == null || GetComponent<Renderer>().material.mainTexture == null)
    {
    Debug.LogError("Can't GetNativeTextureID() for movie surface");
    }

    // This aparently has to be done at Awake time, before
    // multithreaded rendering starts;
    nativeTextureID = GetComponent<Renderer>().material.mainTexture.GetNativeTextureID();
    Debug.Log("Movie Texture id: " + nativeTextureID);
    }

    /// <summary>
    /// Auto-starts video playback
    /// </summary>
    void DelayedStartVideo()
    {
    if (!startedVideo)
    {
    startedVideo = true;
    #if (UNITY_ANDROID && !UNITY_EDITOR)
    // This can only be done once multithreaded rendering is running
    mediaPlayer2 = StartVideoPlayerOnTextureId(nativeTextureID);
    #endif
    }
    }

    void Start()
    {
    maxVideos = myVideos.Length-1;

    #if (UNITY_ANDROID && !UNITY_EDITOR)
    // delay one frame because OVRCameraController initializes the render thread in Start()
    Invoke("DelayedStartVideo", 0.1f);
    //mediaPlayer2 = StartVideoPlayerOnTextureId(nativeTextureID);
    #endif

    }

    Void LateUpdate()
    {
    if(Application.loadedLevelName =="2DVideoPlayer" && startedVideo)
    {
    PlayPauseVideo(true);
    }
    }

    void Update()
    {
    //if(Input.GetMouseButtonUp(0) || Input.GetKeyUp ("joystick button 0") )
    //{
    // #if (UNITY_ANDROID && !UNITY_EDITOR)
    // delay one frame because OVRCameraController initializes the render thread in Start()
    //Invoke("DelayedStartVideo", 0.1f);
    // #endif
    //}

    if(Application.loadedLevelName !="2DVideoPlayer")
    {
    PlayPauseVideo(false);
    }
    else
    {
    if(Input.GetMouseButtonUp(0) || Input.GetKeyUp ("joystick button 0") )
    {
    PlayPauseVideo(startedVideo);

    // if (videoPath == "/storage/emulated/0/Oculus/360Videos/BatucadaResumenHD.mp4")
    // videoPath = "/storage/emulated/0/DCIM/Camera/20150806_191825.mp4";
    // else
    // videoPath = "/storage/emulated/0/Oculus/360Videos/BatucadaResumenHD.mp4";

    if(arrayPos == maxVideos || arrayPos ==-1)
    arrayPos = 0;
    else
    arrayPos++;


    #if (UNITY_ANDROID && !UNITY_EDITOR)
    if (mediaPlayer2 != null)
    {

    mediaPlayer2.Call("stop");
    mediaPlayer2.Call("reset");
    mediaPlayer2.Call("setDataSource", myVideos[arrayPos]);
    mediaPlayer2.Call("prepare");
    mediaPlayer2.Call("setLooping", true);
    mediaPlayer2.Call("start");
    }
    #endif

    }
    }


    }

    public void PlayPauseVideo(bool playVideo)
    {
    #if (UNITY_ANDROID && !UNITY_EDITOR)
    if (mediaPlayer2 != null)
    {
    if (!playVideo)
    {
    mediaPlayer2.Call("pause");

    }
    else
    {
    mediaPlayer2.Call("start");
    }
    startedVideo = !playVideo;
    }
    #endif

    MeshRenderer m = this.GetComponent<MeshRenderer>();
    m.enabled = playVideo;

    }

    /// <summary>
    /// Pauses video playback when the app loses or gains focus
    /// </summary>
    void OnApplicationPause(bool wasPaused)
    {
    Debug.Log("OnApplicationPause: " + wasPaused);
    #if (UNITY_ANDROID && !UNITY_EDITOR)
    if (mediaPlayer2 != null)
    {
    videoPaused = wasPaused;
    mediaPlayer2.Call(( videoPaused ) ? "pause" : "start");
    }
    #endif
    }

    #if (UNITY_ANDROID && !UNITY_EDITOR)
    // This function returns an Android Surface object that is
    // bound to a SurfaceTexture object on an independent OpenGL texture id.
    // Each frame, before the TimeWarp processing, the SurfaceTexture is checked
    // for updates, and if one is present, the contents of the SurfaceTexture
    // will be copied over to the provided surfaceTexId and mipmaps will be
    // generated so normal Unity rendering can use it.
    [DllImport("OculusPlugin")]
    private static extern IntPtr OVR_Media_Surface( int surfaceTexId, int surfaceWidth, int surfaceHeight );
    #endif

    #if (UNITY_ANDROID && !UNITY_EDITOR)
    /// <summary>
    /// Set up the video player with the movie surface texture id
    /// </summary>
    AndroidJavaObject StartVideoPlayerOnTextureId(int textureId)
    {
    Debug.Log("SetUpVideoPlayer ");

    //textureId = GetComponent<Renderer>().material.mainTexture.GetNativeTextureID();

    IntPtr androidSurface = OVR_Media_Surface( textureId, 2880, 1440 );

    AndroidJavaObject mediaPlayer2 = new AndroidJavaObject("android/media/MediaPlayer");

    // Can't use AndroidJavaObject.Call() with a jobject, must use low level interface
    //mediaPlayer2.Call("setSurface", androidSurface);
    IntPtr setSurfaceMethodId = AndroidJNI.GetMethodID(mediaPlayer2.GetRawClass(),"setSurface","(Landroid/view/Surface;)V");
    jvalue[] parms = new jvalue[1];
    parms[0] = new jvalue();
    parms[0].l = androidSurface;
    AndroidJNI.CallVoidMethod(mediaPlayer2.GetRawObject(), setSurfaceMethodId, parms);

    mediaPlayer2.Call("stop");
    mediaPlayer2.Call("reset");

    //mediaPlayer2.Call("setDataSource", "/storage/emulated/0/DCIM/Camera/20150806_191825.mp4");
    //mediaPlayer2.Call("setDataSource", "/storage/emulated/0/Oculus/360Videos/BatucadaResumenHD.mp4");
    mediaPlayer2.Call("setDataSource", myVideos[arrayPos]);
    mediaPlayer2.Call("prepare");
    mediaPlayer2.Call("setLooping", true);
    mediaPlayer2.Call("start");

    return mediaPlayer2;
    }
    #endif
    }


    Here's the code of the 360 movie player:

    /************************************************************************************

    Filename : MoviePlayerSample.cs
    Content : An example of how to use the Moonlight video player
    Created : July 12, 2014

    Copyright : Copyright 2014 Oculus VR, LLC. All Rights reserved.

    Use of this software is subject to the terms of the Oculus LLC license
    agreement provided at the time of installation or download, or which
    otherwise accompanies this software in either electronic or hard copy form.

    ************************************************************************************/

    using UnityEngine;
    using System.Collections; // required for Coroutines
    using System.Runtime.InteropServices; // required for DllImport
    using System; // requred for IntPtr


    /************************************************************************************
    Usage:

    Place a simple textured quad surface with the correct aspect ratio in your scene.

    Add the MoviePlayerSample.cs script to the surface object.

    Modify it for the correct media location (currently hardcoded)

    Modify it to start when you want, instead of on the very first Update().

    Implementation:

    In the MoviePlayerSample Awake() call, GetNativeTextureID() is called on
    renderer.material.mainTexture.

    When the Oculus plugin gets the initialization event on the render thread,
    it creates a new Android SurfaceTexture and Surface object in preparation
    for receiving media.

    When the game wants to start the video playing, it calls the StartVideoPlayerOnTextureId()
    script call, which creates an Android MediaPlayer java object, issues a
    native plugin call to tell the native code which texture id to put the video
    on and return the Android Surface object to pass to MediaPlayer, then sets
    up the media stream and starts it.

    Every frame, right after VrApi::WarpSwap() is called by the native plugin,
    the SurfaceTexture object is checked for updates. If there is one, the
    target texId is re-created at the correct dimensions and format if it is
    the first frame, then the video image is rendered to it and mipmapped.
    The following frame, instead of Unity drawing the image that was placed
    on the surface in the Unity editor, it will draw the current video frame.

    It is important to note that the texture is actually replaced -- the original
    version is gone, and the video will now show up everywhere that texture was
    used, not just on sthe GameObject that ran the script.

    NOTE: The resolution of the movie texture is hard coded to 960x540 in MediaSurface.cpp.

    ************************************************************************************/

    public class MoviePlayer360 : MonoBehaviour
    {
    private int nativeTextureID;

    bool startedVideo = false;

    object objectVideo;

    //public string videoLoad = "/storage/emulated/0/Oculus/360Videos/BatucadaResumenHD.mp4";

    public string[] myVideos = new string[2];

    int maxVideos;
    int arrayPos = -1;

    #if (UNITY_ANDROID && !UNITY_EDITOR)
    bool videoPaused = false;
    AndroidJavaObject mediaPlayer = null;
    #endif

    /// <summary>
    /// Initialization of the movie surface
    /// </summary>
    void Awake()
    {
    Debug.Log("Awake");

    if (GetComponent<Renderer>().material == null || GetComponent<Renderer>().material.mainTexture == null)
    {
    Debug.LogError("Can't GetNativeTextureID() for movie surface");
    }

    // This aparently has to be done at Awake time, before
    // multithreaded rendering starts;
    nativeTextureID = GetComponent<Renderer>().material.mainTexture.GetNativeTextureID();
    Debug.Log("Movie Texture id: " + nativeTextureID);
    }

    /// <summary>
    /// Auto-starts video playback
    /// </summary>
    void DelayedStartVideo()
    {
    if (!startedVideo)
    {
    startedVideo = true;
    #if (UNITY_ANDROID && !UNITY_EDITOR)
    // This can only be done once multithreaded rendering is running
    mediaPlayer = StartVideoPlayerOnTextureId(nativeTextureID);
    #endif
    }
    }

    void Start()
    {
    maxVideos = myVideos.Length-1;

    #if (UNITY_ANDROID && !UNITY_EDITOR)
    // delay one frame because OVRCameraController initializes the render thread in Start()
    Invoke("DelayedStartVideo", 0.1f);
    #endif

    }

    Void LateUpdate()
    {
    if(Application.loadedLevelName =="360VideoPlayer" && startedVideo)
    {
    PlayPauseVideo(true);
    }
    }

    void Update()
    {
    //if(Input.GetMouseButtonUp(0) || Input.GetKeyUp ("joystick button 0") )
    //{
    // #if (UNITY_ANDROID && !UNITY_EDITOR)
    // delay one frame because OVRCameraController initializes the render thread in Start()
    //Invoke("DelayedStartVideo", 0.1f);
    // #endif
    //}

    if(Application.loadedLevelName !="360VideoPlayer")
    {
    PlayPauseVideo(false);
    }
    else
    {
    if(Input.GetMouseButtonUp(0) || Input.GetKeyUp ("joystick button 0") )
    {
    PlayPauseVideo(startedVideo);

    if(arrayPos == maxVideos || arrayPos ==-1)
    arrayPos = 0;
    else
    arrayPos++;

    #if (UNITY_ANDROID && !UNITY_EDITOR)
    // delay one frame because OVRCameraController initializes the render thread in Start()
    //Invoke("DelayedStartVideo", 0.1f);
    mediaPlayer.Call("stop");
    mediaPlayer.Call("reset");

    mediaPlayer.Call("setDataSource", myVideos[arrayPos]);
    mediaPlayer.Call("prepare");
    mediaPlayer.Call("setLooping", true);
    mediaPlayer.Call("start");
    #endif

    }

    //UpdateVideo ();
    }


    }

    public void PlayPauseVideo(bool playVideo)
    {
    #if (UNITY_ANDROID && !UNITY_EDITOR)
    if (mediaPlayer != null)
    {
    if (!playVideo)
    {
    mediaPlayer.Call("pause");

    }
    else
    {
    mediaPlayer.Call("start");
    }
    startedVideo = !playVideo;
    }
    #endif

    MeshRenderer m = this.GetComponent<MeshRenderer>();
    m.enabled = playVideo;

    }

    /// <summary>
    /// Pauses video playback when the app loses or gains focus
    /// </summary>
    void OnApplicationPause(bool wasPaused)
    {
    Debug.Log("OnApplicationPause: " + wasPaused);
    #if (UNITY_ANDROID && !UNITY_EDITOR)
    if (mediaPlayer != null)
    {
    videoPaused = wasPaused;
    mediaPlayer.Call(( videoPaused ) ? "pause" : "start");
    }
    #endif
    }

    #if (UNITY_ANDROID && !UNITY_EDITOR)
    // This function returns an Android Surface object that is
    // bound to a SurfaceTexture object on an independent OpenGL texture id.
    // Each frame, before the TimeWarp processing, the SurfaceTexture is checked
    // for updates, and if one is present, the contents of the SurfaceTexture
    // will be copied over to the provided surfaceTexId and mipmaps will be
    // generated so normal Unity rendering can use it.
    [DllImport("OculusPlugin")]
    private static extern IntPtr OVR_Media_Surface( int surfaceTexId, int surfaceWidth, int surfaceHeight );
    #endif

    #if (UNITY_ANDROID && !UNITY_EDITOR)
    /// <summary>
    /// Set up the video player with the movie surface texture id
    /// </summary>
    AndroidJavaObject StartVideoPlayerOnTextureId(int textureId)
    {
    Debug.Log("SetUpVideoPlayer ");

    //textureId = GetComponent<Renderer>().material.mainTexture.GetNativeTextureID();

    IntPtr androidSurface = OVR_Media_Surface( textureId, 2880, 1440 );

    AndroidJavaObject mediaPlayer = new AndroidJavaObject("android/media/MediaPlayer");

    // Can't use AndroidJavaObject.Call() with a jobject, must use low level interface
    //mediaPlayer.Call("setSurface", androidSurface);
    IntPtr setSurfaceMethodId = AndroidJNI.GetMethodID(mediaPlayer.GetRawClass(),"setSurface","(Landroid/view/Surface;)V");
    jvalue[] parms = new jvalue[1];
    parms[0] = new jvalue();
    parms[0].l = androidSurface;
    AndroidJNI.CallVoidMethod(mediaPlayer.GetRawObject(), setSurfaceMethodId, parms);


    //mediaPlayer.Call("setDataSource", "/storage/emulated/0/DCIM/Camera/20150806_191825.mp4");
    mediaPlayer.Call("stop");
    mediaPlayer.Call("reset");

    mediaPlayer.Call("setDataSource", myVideos[arrayPos]);
    mediaPlayer.Call("prepare");
    mediaPlayer.Call("setLooping", true);
    mediaPlayer.Call("start");

    return mediaPlayer;
    }
    #endif
    }


    Here's the code for the singleton:
    public class MovieSingleton : MonoBehaviour 
    {
    private static MovieSingleton instanceRef;

    void Start () {
    if(instanceRef == null) {
    instanceRef = this;
    DontDestroyOnLoad(gameObject);
    } else {
    DestroyImmediate(gameObject);
    }
    }
    }


    Thanks
    October 1, 2015
    "FuturescoGames" wrote:
    Yes, I have two singleton objects: 2D screen and 360 screen, both have a script to make the singleton, they have two different textures
    Use one singleton to control all videos. Unfortunately this means you aren't going to be able to play multiple streams simultaneously. I'm fairly sure this is a limitation of the plugin (however, I could be very wrong about that).

    So, one singleton, all videos share same texture, and some logic to decide when to play a 360 video and when to play a 2D video.

    Hope that helps!

    Edit: Hmm, one thing to try before you make that change is to put your singleton logic into Awake() instead of Start(). Then again, I don't think this will fix your problem, but it might avoid a crash if you try to load your original scene a second time.