0

I'm working on an Android game made with Unity. You can download videos within the game, and they will be stored in the following path:

Android/data/com.mycompany.mygame/files/Movies/myvideo.mp4

To be more precise, I'm using the following way to download it:

FileStream stream = new FileStream (folder + "/" + fileName, FileMode.Create);
stream.Write(BytesDownload, 0, BytesDownload.Length); 

Where BytesDownload is obtained from a UnityWebRequest. folder + "/" + fileName is the path mentioned above.

I'm calling the Handheld.PlayFullScreenMovie to read this video:

Handheld.PlayFullScreenMovie(videoPath, Color.black, FullScreenMovieControlMode.Hidden);

In this example, videoPath takes the value Movies/myvideo.mp4. However, this is not working (I'm getting a black screen on my Android tablet instead of the video playing).

I read in the documentation that the videos need to be stored in the StreamingAssets folder, and this is indeed working within the Unity editor. But since there's no StreamingAssets folder on Android, I tried to put the videos in the path mentionned above.

How can I download a video and play it on Android?

EDIT - Code used to download the video:

webRequest = UnityWebRequest.Get(serverURL + "/" + serverFolder + "/" + fileName);
DownloadHandler receiveBundle = new DownloadHandlerBuffer();
webRequest.downloadHandler = receiveBundle;
webRequest.Send();

do {
    yield return null;
} while (!webRequest.downloadHandler.isDone);

byte[] BytesDownload = receiveBundle.data;
FileStream stream = new FileStream (folder + "/" + fileName, FileMode.Create);
stream.Write(BytesDownload, 0, BytesDownload.Length); 
stream.Close(); 
Programmer
  • 121,791
  • 22
  • 236
  • 328

2 Answers2

2

You are using UnityWebRequest wrong. You only need to create new instance of DownloadHandler if you created new instance of UnityWebRequest with the new keyword.

You don't have to if you create new instance of UnityWebRequest with the static functions such as UnityWebRequest.Get and UnityWebRequest.Post functions.


To answer your question, here are the steps to download and play video with Handheld.PlayFullScreenMovie.

1.Download the Video with UnityWebRequest.

2.Save the video bytes from UnityWebRequest.downloadHandler.data to Application.persistentDataPath. You missed the Application.persistentDataPath part.

3.Play the video:

Android:

Use Application.persistentDataPath/videoName.mp4 as the path with the Handheld.PlayFullScreenMovie function.

iOS:

Use "file://" + Application.persistentDataPath/videoName.mp4; as the path with the Handheld.PlayFullScreenMovie function.

Note that this will not work in the Editor. That's fine. Handheld.PlayFullScreenMovie is made for Android and iOS not for Desktop Computers. Just Build it for Android/iOS to test it.

Below is fully working download and play sample on mobile devices:

Usage:

void Start()
{
    string url = "http://techslides.com/demos/sample-videos/small.mp4";

    StartCoroutine(downloadAndPlayVideo(url, "myvideo.mp4", true));
}

Sample:

//Downloads, Saves and Plays the Video
IEnumerator downloadAndPlayVideo(string videoUrl, string saveFileName, bool overwriteVideo)
{
    //Where to Save the Video
    string saveDir = Path.Combine(Application.persistentDataPath, saveFileName);

    //Play back Directory
    string playbackDir = saveDir;
#if UNITY_IPHONE
        playbackDir = "file://" + saveDir;
#endif

    bool downloadSuccess = false;
    byte[] vidData = null;

    /*Check if the video file exist before downloading it again. 
     Requires(using System.Linq)
    */
    string[] persistantData = Directory.GetFiles(Application.persistentDataPath);
    if (persistantData.Contains(playbackDir) && !overwriteVideo)
    {
        Debug.Log("Video already exist. Playing it now");
        //Play Video
        playVideo(playbackDir);
        //EXIT
        yield break;
    }
    else if (persistantData.Contains(playbackDir) && overwriteVideo)
    {
        Debug.Log("Video already exist [but] we are [Re-downloading] it");
        yield return downloadData(videoUrl, (status, dowloadData) =>
        {
            downloadSuccess = status;
            vidData = dowloadData;
        });
    }
    else
    {
        Debug.Log("Video Does not exist. Downloading video");
        yield return downloadData(videoUrl, (status, dowloadData) =>
        {
            downloadSuccess = status;
            vidData = dowloadData;
        });
    }

    //Save then Play if there was no download error
    if (downloadSuccess)
    {
        //Save Video
        saveVideoFile(saveDir, vidData);

        //Play Video
        playVideo(playbackDir);
    }
}

//Downloads the Video
IEnumerator downloadData(string videoUrl, Action<bool, byte[]> result)
{
    //Download Video
    UnityWebRequest webRequest = UnityWebRequest.Get(videoUrl);
    webRequest.Send();

    //Wait until download is done
    while (!webRequest.isDone)
    {
        Debug.Log("Downloading: " + webRequest.downloadProgress);
        yield return null;
    }

    //Exit if we encountered error
    if (webRequest.isError)
    {
        Debug.Log("Error while downloading Video: " + webRequest.error);
        yield break; //EXIT
    }

    Debug.Log("Video Downloaded");
    //Retrieve downloaded Data
    result(!webRequest.isError, webRequest.downloadHandler.data);
}

//Saves the video
bool saveVideoFile(string saveDir, byte[] vidData)
{
    try
    {
        FileStream stream = new FileStream(saveDir, FileMode.Create);
        stream.Write(vidData, 0, vidData.Length);
        stream.Close();
        Debug.Log("Video Downloaded to: " + saveDir.Replace("/", "\\"));
        return true;
    }
    catch (Exception e)
    {
        Debug.Log("Error while saving Video File: " + e.Message);
    }
    return false;
}

//Plays the video
void playVideo(string path)
{
    Handheld.PlayFullScreenMovie(path, Color.black,
        FullScreenMovieControlMode.Full, FullScreenMovieScalingMode.AspectFill);
}

This answer is only here to help people that are using Unity 5.5 and below. If you are using anything above, there is a new API to play video, that works on both mobile and desktop computers. You can find the example here.

Community
  • 1
  • 1
Programmer
  • 121,791
  • 22
  • 236
  • 328
0

Don't put the video at your path.

StreamingAssets is a special folder, and videos must be put in it, irrespective of android platform or ios. Secondly, there is no need to give the path to streaming assets, its implicitly understood to unity that the reference path is the streaming assets folder. So put the myvideo.mp4 in streaming assets folder and use it like this:

Handheld.PlayFullScreenMovie("myvideo.mp4", Color.black, FullScreenMovieControlMode.Hidden);

Look here. According to this, you need to check whether the mp4 actually has the correct configuration, codec, resolution etc.

My best guess is that you have a typo. The file name and extension is case sensitive!

Farhan
  • 1,000
  • 1
  • 11
  • 22
  • I don't have a typo since this is working in the editor. The issue on Android is that I can't download a file to the `StreamingAssets` folder (or if it's possible, I don't know how to do it). From https://docs.unity3d.com/ScriptReference/Application-streamingAssetsPath.html `Note that on some platforms it is not possible to directly access the StreamingAssets folder because there is no file system access in the web platforms, and because it is compressed into the .apk file on Android.` –  May 18 '17 at 08:31
  • What do you mean download? You already seem to have the video on disk. Just place the video inside the folder. Your editor can retrieve paths from your computer, but not android. – Farhan May 18 '17 at 08:33
  • See here http://answers.unity3d.com/questions/1084796/playing-video-in-unity-5-on-mobile.html – Farhan May 18 '17 at 08:34
  • There seems to be some misunderstanding, I'll edit my question. –  May 18 '17 at 08:36
  • How about Handheld.PlayFullScreenMovie(urlToMp4, Color.black, FullScreenMovieControlMode.Hidden); ? – Farhan May 18 '17 at 08:36
  • In case you must download and play, make sure to save the file to Application.persistentDataPath – Farhan May 18 '17 at 08:39
  • I'm already saving it to `Application.persistentDataPath`, this is the path mentionned at the start of my question. How can I play a video stored in `Application.persistentDataPath`? How can I obtain urlToMp4 from your example? –  May 18 '17 at 08:40
  • Do you have the permissions to write in your android manifest file? – Farhan May 18 '17 at 08:42
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/144532/discussion-between-eldy-and-farhan). –  May 18 '17 at 08:44