1

I have a Unity app where the engine keeps freezing the main thread when ever i load a large image using LoadImage.

So i decide to try to decode the image on a separate thread from the main thread. Im using a C# jpeg decoder from here

https://gist.github.com/jandk/3889823

I wrote a test code to test it out. The test code spins a cube on the main thread. While the cube is spinning, i create a separate thread where in that the JPG image is downloaded from a website and decoded. After decoding, the main thread takes those decoded bits and applies them to the cube using LoadRawImageData

The idea of using a spinning cube, is so that any engine freeze caused by the image processing will easily be seen because the cube will stop spinning for a moment.

Here is the code

 using System.Collections;     
 using System.Collections.Generic;
 using UnityEngine;
 using System.Threading;
 using System.Net;
 using UnityEngine.UI;
 using System.IO;
 using Unity.Collections;
 using UnityEngine.Networking;
 using Jpeg;

 public class Spin : MonoBehaviour
 {

class ThreadedImageLoader : MonoBehaviour
{
    public Thread thread = null;
    public byte[] pixels = null;
    public string url;
    public bool done = false;
    public GameObject g;

    public void Download(string url,GameObject g)
    {
        this.url = url;
        this.g = g;

        Debug.Log("Downloading from url=" + url);

        thread = new Thread(() => DoThread());
        thread.Start();
    }

    public void DoThread()
    {
        Debug.Log("downloading pic on a thread");
        HttpWebRequest lxRequest = (HttpWebRequest)WebRequest.Create(url);
        string lsResponse = string.Empty;
        using (HttpWebResponse lxResponse = (HttpWebResponse)lxRequest.GetResponse()) {
            using (BinaryReader reader = new BinaryReader(lxResponse.GetResponseStream())) {
                pixels = reader.ReadBytes(1 * 1024 * 1024 * 10);
            }
        }
        Debug.Log("Done downloading, creating decoder...");
        JpegDecoder jdec = new JpegDecoder(pixels);
        Debug.Log("decoder created, decompressing...");
        byte[] img = jdec.DecodeScan();
        Debug.Log("Done decompressing");
        done = true;
    }
}

List<ThreadedImageLoader> loaders = new List<ThreadedImageLoader>();
public float delta = 1f;

void Start()
{
    string url = "https://www.gstatic.com/webp/gallery/4.jpg";
    ThreadedImageLoader td = gameObject.AddComponent<ThreadedImageLoader>();
    loaders.Add(td);
    td.Download(url,gameObject);
}

void Update()
{
    float d = delta * Time.deltaTime;
    transform.Rotate(new Vector3(d, d, d));
    if (loaders.Count > 0) {
        ThreadedImageLoader td = (ThreadedImageLoader)loaders[0];
        if (td.done) {
            Debug.Log("Update:pixels lenth:" + td.pixels.Length);
            if (td.pixels.Length > 0) {
                Texture2D t = new Texture2D(1, 1);
                t.LoadRawTextureData(td.pixels);
                t.Apply();
                gameObject.GetComponent<Renderer>().material.mainTexture = t;
            }

            loaders.RemoveAt(0);
            Destroy(td);

            // keep downloading the image again
            string url = "https://www.gstatic.com/webp/gallery/4.jpg";
            ThreadedImageLoader tdd = gameObject.AddComponent<ThreadedImageLoader>();
            loaders.Add(tdd);
            tdd.Download(url,gameObject);
        }
    }
}
 }

As the code runs, the cube starts spinning, the thread gets created, the image is downloaded from the link, but when the jpeg decoder gets created, it crashes inside the decoder with an error reading the image.

The jpeg decoder im using is at that link above. Seems very simple, just one file, but it stops decoding with error while reading the downloaded data.

I know the image data downloaded is correct because if I use LoadImage(pixels) on the same data it the image appears perfectly. Of course i cant use Loadimage in the real code because it freezes the main thread because it decodes the image on the main thread (which causes the freeze).

Does anyone know a better c# jpeg decoder that i can use in this case? one that can run in a thread and doesnt have a lot of dependencies increasing the bloat? I just need it to be able to decode a jpeg within a thread in Unity.

I tried several of the nuget packages, but cant get them to install properly in Unity. The one at that link was the only one file decoder i could find that was easy to use, but of course it crashes!

Thanks for any help.

programmer3
  • 97
  • 1
  • 12
  • 2
    Why are you making this so complicated? Why don't you just use `UnityWebRequest` like everyone else? https://stackoverflow.com/questions/31765518/how-to-load-an-image-from-url-with-unity – Ian Kemp Mar 01 '19 at 21:49
  • WebRequest causes a freeze as well when the image is large because it decodes the image on the main thread. But i till try that async version from that link you posted , thanks – programmer3 Mar 01 '19 at 21:50
  • I tried the async version from that link, i got error that "async" and "await" and "task" feature is not available in .NET 3.5 that im using in Unity, and that i should use version 5 or greater of C# – programmer3 Mar 01 '19 at 21:56
  • Is there a special reason why you an not switch to .NET 4.X ? – derHugo Mar 03 '19 at 20:32
  • @derHugo Many people dont have .Net 4 installed on their computer maybe??? – programmer3 Mar 05 '19 at 17:19
  • .Net 4.6 e.g. is from 2015 .. I'ld expect most poeple to have it installed on their computer by default already. – derHugo Mar 05 '19 at 20:20
  • unity's .net runtime is self contained, users don't need to download anything. – DangerMouse Mar 06 '19 at 01:40
  • Using async/await is not a solution at all. Async/await is a continuation paradigm and not multithreaded code. Whether you use async/await or coroutines in unity it's the same, so the code using async/await with UnityWebRequestTexture in this post "https://stackoverflow.com/questions/31765518/how-to-load-an-image-from-url-with-unity" will still do all the processing on the main thread. – With A SpiRIT Dec 25 '19 at 13:12

0 Answers0