Search Unity

Video VideoPlayer WebGL from StreamingAssets to IndexedDB.

Discussion in 'Audio & Video' started by jocyf, Apr 19, 2018.

  1. jocyf

    jocyf

    Joined:
    Jan 30, 2007
    Posts:
    288
    I'm trying to play a videoclip from streaming assets with using the direct http:// url.
    My idea is to store in idbfs browser (IndexedDB). So, I download the videoclip file from StreamigAssets and store it in the IndexedDB -> FileData in the browser (it is there acording to the browser's console) using this code:


    Code (CSharp):
    1. IEnumerator RetrieveStreamingAsset(string mediaFileName)
    2.     {
    3.         string streamingMediaPath = Application.streamingAssetsPath + "/" + mediaFileName;
    4.         string persistentPath = Application.persistentDataPath + "/" + mediaFileName;
    5.         if (!File.Exists(persistentPath))
    6.         {
    7.             WWW wwwReader = new WWW(streamingMediaPath);
    8.             yield return wwwReader;
    9.  
    10.             if (wwwReader.error != null)
    11.             {
    12.                 Debug.LogError("wwwReader error: " + wwwReader.error);
    13.             }
    14.  
    15.             System.IO.File.WriteAllBytes(persistentPath, wwwReader.bytes);
    16.  
    17.             wwwReader.Dispose();
    18.             wwwReader = null;
    19.             Resources.UnloadUnusedAssets();
    20.         }
    21.  
    22.         video.url = persistentPath; // this is resulting idbfs 'cache' path!
    23.         Debug.Log("Movie FullPath: "+persistentPath);  // write it in browser console
    24.     }
    This code return a debug.log in browser's console:
    Movie FullPath: /idbfs/a13f4f24e93b2e180eb5e8540a4a38ea/VideoTest B2.mp4

    But every time try to Prepare() the video i get a 404 not found msg.
    GET http://www.jocyf.com/idbfs/a13f4f24e93b2e180eb5e8540a4a38ea/VideoTest B2.mp4 404 (Not Found)

    I mean, Unity always attemp to load from this url (whitch is wrong):
    http://www.jocyf.com/idbfs/a13f4f24e93b2e180eb5e8540a4a38ea/VideoTest B2.mp4
    and I get an 404 error msg, because that url doesn't exitst, it's nothing there!

    The video file itself is saved in IndexedDB memory FILE because I can see all the content using the browser's console, so the www process part seems to work.

    I'm asking if it's posible to access my "/idfbs/xxxx/ xxx.mp4" direction using video.url and play that already downloaded video. Maybe I have to ReadAllBytes from that idbfs direction and fill it in the video component using some method.

    I just don't know how to proceed, I've been testing a lot of things and looking all over internet about this matter but I didn't find anything that could help me in this particular case.

    It works on the editor (persistentdatapath is a local file in the HD, so at the end, it points to a local file) but it's imposible to make it work on WebGL.

    Any idea / advice?
     
    Last edited: Apr 19, 2018
    TKaminaga likes this.
  2. jocyf

    jocyf

    Joined:
    Jan 30, 2007
    Posts:
    288
    Another posibility I'm working on is to use AssetBundles to do it, but it seems not to work either.

    So, I created my WebGL, uncompressed assetbundle and place it in StreamingAssets.
    I've tried to download my bundle to get my videoclip from there
    (Unity's original doc: https://docs.unity3d.com/Manual/UnityWebRequest-DownloadingAssetBundle.html)

    Code (CSharp):
    1. IEnumerator DownloadAssetBundle(string assetBundleName, string fileName)
    2.     {
    3.         string uri = System.IO.Path.Combine(Application.streamingAssetsPath, assetBundleName);
    4.         Debug.Log("0.- Download AssetBundle url: "+uri);
    5.  
    6.         // Get my AssetBundle.
    7.         UnityWebRequest request = UnityWebRequest.GetAssetBundle(uri);
    8.         yield return request.SendWebRequest();
    9.         if(request.isNetworkError || request.isHttpError)
    10.         {
    11.             Debug.LogWarning(request.error);
    12.         }
    13.         AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(request);
    14.  
    15.         // Get VideoClip from my Bundle!
    16.         if(bundle != null){
    17.             video.source = VideoSource.VideoClip;
    18.             video.clip = bundle.LoadAsset<VideoClip>(fileName);
    19.             Debug.Log("Assigned AsetBundle VideoClip: "+video.clip.name);
    20.         }
    21.         else
    22.             Debug.LogError("The AssetBundle "+assetBundleName+" doesn't exists");
    23.     }
    This code returns normally (no errors there) so videoclip.clip gets the bundle stored clip.

    It works on the editor and I can see how the VideoPlayer gets a clip that doesn't exist in the project (besause it has been downloaded). The videoclip is like any "runtime made" asset witch makes sense.

    In WebGL it doesn't work at all. When I prepare(), the videoplayer try to load it from the videoclip.originalpath value and return an error because in that path there is nothing.

    So, I'm trying different aproaches to get some kind of "local video cache" in webgl (using AssetBundles or IndexedDB) without any luck.

    Note: If anyone is interested, I've tried to get a general idea about working WebGL by reading this:
    https://blogs.unity3d.com/es/2016/09/20/understanding-memory-in-unity-webgl/
    https://unity3d.com/learn/tutorials...-usage-patterns#Distribution_Streaming_Assets
    https://docs.unity3d.com/ScriptRefe...590.252661696.1523946521-267020154.1468842864


    Anyone has a really good Idea out there?
     
    Last edited: Apr 19, 2018
    DryreL, TKaminaga and ulissescad like this.
  3. ldeplaen

    ldeplaen

    Joined:
    Nov 8, 2016
    Posts:
    4
    Hi,

    It's possible to play video from IndexedDB in Unity!

    Code (JavaScript):
    1. SaveVideoInIndexedDB : function (path, idVideo) {
    2.   var jPath = Pointer_stringify(path);
    3.   var jIdVideo = Pointer_stringify(idVideo);
    4.   window.indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.OIndexedDB || window.msIndexedDB,
    5.   IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.OIDBTransaction || window.msIDBTransaction,
    6.     dbVersion = 1.0;
    7.   if (!window.indexedDB)
    8.     {
    9.       alert("Your browser doesn't support IndexedDB");
    10.                     return -1;
    11.   }
    12.   var request = indexedDB.open("YourDB", dbVersion),
    13.   db,
    14.   createObjectStore = function (dataBase)
    15.   {
    16.         dataBase.createObjectStore("Videos");
    17.     },
    18.     getVideoFile = function ()
    19.     {
    20.      var xhr = new XMLHttpRequest(),
    21.        blob;
    22.        // Get the Video file from the server.
    23.        xhr.open("GET", jPath, true);  
    24.        xhr.responseType = "blob";
    25.        xhr.addEventListener("load", function ()
    26.        {
    27.           if (xhr.status === 200)
    28.           {
    29.               blob = xhr.response;
    30.               console.log("SUCCESS: Video file downloaded " + jIdVideo)
    31.               putVideoInDb(blob);
    32.           }
    33.           else
    34.           {
    35.               console.log("ERROR: Unable to download video.")
    36.           }
    37.         }, false);
    38.         xhr.send();
    39.       },
    40.       putVideoInDb = function (blob) {
    41.          var transaction = db.transaction(["Videos"], "readwrite");
    42.          var put = transaction.objectStore("Videos").put(blob, jIdVideo);
    43.       };
    44.   request.onerror = function (event) {
    45.           console.log("IndexedDB error: " + event.target.errorCode);
    46.     };
    47.  
    48.     request.onsuccess = function (event) {
    49.       console.log("Success creating/accessing IndexedDB database");
    50.     db = request.result;
    51.         db.onerror = function (event) {
    52.             console.log("Error creating/accessing IndexedDB database");
    53.         };      
    54.         window.onload = getVideoFile();
    55.     }
    56.   request.onupgradeneeded = function (event) {
    57.         createObjectStore(event.target.result);
    58.     };
    59.   },
    • After my video is in the IndexedDB I convert the blob into a URL with this function and send the URL to Unity. Normally the URL start with "blob:".
    Code (JavaScript):
    1. GetUrlFromIndexedDB: function (str) {
    2.   var jStr = Pointer_stringify(str);
    3.         console.log("jSTR : " + jStr);
    4.   window.indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.OIndexedDB || window.msIndexedDB,
    5.   IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.OIDBTransaction || window.msIDBTransaction,
    6.     dbVersion = 1.0;
    7.     if (!window.indexedDB)
    8.     {
    9.       alert("Your browser doesn't support IndexedDB");
    10.   }
    11.     var indexedDB = window.indexedDB;
    12.     var request = indexedDB.open("YourDB", dbVersion);
    13.    
    14.     request.onerror = function (event) {
    15.           console.log("IndexedDB error: " + event.target.errorCode);
    16.     };
    17.  
    18.     request.onsuccess = function (event) {
    19.         db = request.result;      
    20.         // Open a transaction to the database
    21.         var transaction = db.transaction(["Videos"], "readwrite");
    22.         // Retrieve the video file
    23.         transaction.objectStore("Videos").get(jStr).onsuccess =
    24.         function (event) {              
    25.         var videoFile = event.target.result;
    26.         var URL = window.URL || window.webkitURL;
    27.         var videoURL = URL.createObjectURL(videoFile);
    28.         console.log("VIDEO URL " + videoURL);
    29.         SendMessage('PanelVideo', 'GetUrlFromWebGL', videoURL);
    30.       };
    31.   };
    32.   },
    • Now you can play the video with the URL (if you use AVPro, the plugin can't parse URL with blob for the moment, So you can go and edit Assets/AVProVideo/Scripts/Internal/WebGLMediaPlayer.cs, around line 175 and adding the line :

      path.StartsWith("blob:") ||

    I hope it will work for you
     
    Last edited: Aug 29, 2018
    DryreL, Kareem_Hesham and yty like this.
  4. jocyf

    jocyf

    Joined:
    Jan 30, 2007
    Posts:
    288
    Omg! Thanks a lot for sharing your method and code. I'll give it a try in a few days.
     
    ldeplaen likes this.
  5. dpond

    dpond

    Joined:
    Feb 27, 2017
    Posts:
    2
    Thanks for the code sample. It is working well for putting video data into IndexedDB from the JS side. However, I'm running into problems trying to use the blob on the C# side. A couple of questions:
    1. Have you successfully used this approach with Unity's VideoPlayer? When I set the blob: URL on the VideoPlayer it generates an error when I call Prepare(). By comparison, setting the original URL of the video works fine.
    2. I tried using AVPro as well, but only the audio seems to play. Similar to the VideoPlayer, if I set the original URL, I get both video and audio, but when using the blob: I'm only getting audio. Is there something additional needed between opening the file using the blob and calling Play()? I tried setting the video track explicitly, but that doesn't seem to help.
    Thanks.
     
  6. ldeplaen

    ldeplaen

    Joined:
    Nov 8, 2016
    Posts:
    4
    No sorry i don't try this approach because we use AVPro in our application.

    Do you have the last version of AVPro?
    Did you edit the AVPro's script WebGLMediaPlayer.cs ?
    If you use the blob url in your browser, what happen?

    Here is my code in the c# side

    My function header in JS

    [DllImport("__Internal")]
    private static extern string GetUrlFromIndexedDB(string str);


    When i Start Loading the video

    if (Application.platform == RuntimePlatform.WebGLPlayer && !Application.isEditor)
    {
    StartCoroutine(LoadVideoForWebGL(mediaPlayer, imageName, autoStart));
    }


    My function who is trying to get the blob url with a ugly timer who is waiting the JS side

    private IEnumerator LoadVideoForWebGL(MediaPlayer mediaPlayer, string imageName, bool autoStart)
    {
    m_IsURLFromWebGLReceive = false;

    GetUrlFromIndexedDB(imageName);

    for (int i = 0; !m_IsURLFromWebGLReceive; i++)
    {
    if (i > 100)
    {
    Debug.LogError("Url don't receive..." + path);
    break;
    }
    yield return new WaitForSeconds(0.1f);

    }

    if (m_IsURLFromWebGLReceive)
    {
    mediaPlayer.OpenVideoFromFile(MediaPlayer.FileLocation.AbsolutePathOrURL, m_UrlFromWebGL, autoStart);
    m_IsURLFromWebGLReceive = false;
    }
    }


    The function called by the JS side when the blob url is send

    public void GetUrlFromWebGL(string url)
    {
    Debug.Log("URL video : " + url);
    m_UrlFromWebGL = url;
    m_IsURLFromWebGLReceive = true;
    }



    I hope it will help you. You can send a mail to the AVPro team if the problem persist.
     
    Kareem_Hesham likes this.
  7. psrivatsan

    psrivatsan

    Joined:
    Mar 29, 2019
    Posts:
    2
    Bump! Did anyone succeed in getting the video player to play from the blob url or any workaround to use the blob using movie textures ?
     
  8. asotelo94

    asotelo94

    Joined:
    Jan 26, 2013
    Posts:
    14
    No luck. I got the videoplayer to throw this error
    "Can't play movie [blob:null/e6fb45e0-d487-471d-8590-39c96ce200c1]"
     
  9. Coopervr

    Coopervr

    Joined:
    Mar 24, 2020
    Posts:
    5
    I don't know if this is the solution to your problem, but I solved "video from URL" using a WebGL build on itch.io and video hosted on AWS.

    I used AWS to host it, followed their tutorial on activating AWS as CORS configuration and hosting a video. But, now I'm streaming from URL via webgl upload to itch.io.

    I hope this helps someone else. So much relief. Took 5 minutes to implement the solution.
     
    jocyf likes this.
  10. blabberbytes

    blabberbytes

    Joined:
    Nov 22, 2014
    Posts:
    13
    How do you link it to AWS? Can you share some code or explain it so a noob can understand? THANKS!
     
  11. TadeuszKantor

    TadeuszKantor

    Joined:
    Jul 28, 2019
    Posts:
    4
    Hi Coopervr could you explain how you did that ? it looks great and it would be a great help ! thanks a lot !
     
  12. mjamie

    mjamie

    Joined:
    Sep 4, 2017
    Posts:
    11
    Just Follow the link CooperVr gave till step 2. Don't have to go further than that. Then use the link they show you to use from S3 and write the code to point to that url on video player. EG: videoPlayer.url = "https://s3....".

    That should get the video playing/streaming from the S3 Bucket you created. If you still don't understand I'll try explain better.
     
  13. TadeuszKantor

    TadeuszKantor

    Joined:
    Jul 28, 2019
    Posts:
    4
    Thank you CooperVr solution is amazing ! I hosted it on AWS, it shows seamlessly in the Unity Editor but it still doesn't show into the WebGI version..i get this error "Uncaught (in promise) DOMException: The play method is not allowed by the user agent or the platform in the current context, possibly because the user denied permission." Do you how i could resolve it, without having the user change the settings of the web navigator ? I'm on firefox btw !
    Thanks a lot !