在统一的C#线程中解码Jpeg图像

在统一的C#线程中解码Jpeg图像,c#,unity3d,C#,Unity3d,我有一个Unity应用程序,当我使用LoadImage加载大图像时,引擎会一直冻结主线程 所以我决定尝试在一个独立于主线程的线程上解码图像。我在这里使用C#jpeg解码器 我写了一个测试代码来测试它。测试代码在主线程上旋转一个立方体。当立方体旋转时,我创建了一个单独的线程,其中JPG图像从网站下载并解码。解码后,主线程获取这些解码位,并使用LoadRawImageData将其应用于多维数据集 使用旋转立方体的想法是,由于立方体将停止旋转一段时间,因此图像处理引起的任何引擎冻结都将很容易被看到

我有一个Unity应用程序,当我使用LoadImage加载大图像时,引擎会一直冻结主线程

所以我决定尝试在一个独立于主线程的线程上解码图像。我在这里使用C#jpeg解码器

我写了一个测试代码来测试它。测试代码在主线程上旋转一个立方体。当立方体旋转时,我创建了一个单独的线程,其中JPG图像从网站下载并解码。解码后,主线程获取这些解码位,并使用LoadRawImageData将其应用于多维数据集

使用旋转立方体的想法是,由于立方体将停止旋转一段时间,因此图像处理引起的任何引擎冻结都将很容易被看到

这是密码

 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);
        }
    }
}
 }
使用系统集合;
使用System.Collections.Generic;
使用UnityEngine;
使用系统线程;
Net系统;
使用UnityEngine.UI;
使用System.IO;
使用统一。集合;
使用UnityEngine。联网;
使用Jpeg;
公共阶层的自旋:单一行为
{
类ThreadedImageLoader:MonoBehavior
{
公共线程线程=null;
公共字节[]像素=空;
公共字符串url;
公共布尔完成=错误;
公共游戏对象g;
公共无效下载(字符串url,游戏对象g)
{
this.url=url;
这个.g=g;
Debug.Log(“从url=“+url”下载);
线程=新线程(()=>DoThread());
thread.Start();
}
public void DoThread()
{
Log(“在线程上下载pic”);
HttpWebRequest lxRequest=(HttpWebRequest)WebRequest.Create(url);
string lsResponse=string.Empty;
使用(HttpWebResponse lxResponse=(HttpWebResponse)lxRequest.GetResponse()){
使用(BinaryReader=newBinaryReader(lxResponse.GetResponseStream())){
像素=reader.ReadBytes(1*1024*1024*10);
}
}
Log(“完成下载,创建解码器…”);
JPEG解码器jdec=新的JPEG解码器(像素);
Log(“解码器创建,解压缩…”);
字节[]img=jdec.DecodeScan();
Log(“完成解压缩”);
完成=正确;
}
}
列表加载器=新列表();
公共浮动增量=1f;
void Start()
{
字符串url=”https://www.gstatic.com/webp/gallery/4.jpg";
ThreadedImageLoader td=gameObject.AddComponent();
装载机。添加(td);
下载(网址,游戏对象);
}
无效更新()
{
float d=delta*Time.deltaTime;
旋转(新向量3(d,d,d));
如果(loaders.Count>0){
ThreadedImageLoader td=(ThreadedImageLoader)加载程序[0];
如果(td.done){
Log(“更新:像素长度:“+td.pixels.Length”);
如果(td.pixels.Length>0){
纹理2d t=新纹理2d(1,1);
t、 LoadRawTextureData(td.像素);
t、 应用();
gameObject.GetComponent().material.mainTexture=t;
}
装载机。移除(0);
销毁(td);
//继续下载图像
字符串url=”https://www.gstatic.com/webp/gallery/4.jpg";
ThreadedImageLoader tdd=gameObject.AddComponent();
装载机。添加(tdd);
下载(网址,游戏对象);
}
}
}
}
当代码运行时,立方体开始旋转,创建线程,从链接下载图像,但是当创建jpeg解码器时,它在解码器内崩溃,读取图像时出错

im使用的jpeg解码器位于上面的链接处。看起来很简单,只有一个文件,但在读取下载的数据时,它会错误地停止解码

我知道下载的图像数据是正确的,因为如果我在相同的数据上使用LoadImage(像素),图像就会完美地显示出来。当然,我不能在实际代码中使用Loadimage,因为它会冻结主线程,因为它会解码主线程上的图像(这会导致冻结)

有谁知道我可以在这种情况下使用更好的c#jpeg解码器吗?一个可以在一个线程中运行并且没有太多依赖项的线程会增加膨胀吗? 我只需要它能够在统一的线程中解码jpeg

我尝试了几个nuget软件包,但无法在Unity中正确安装它们。那个链接上的那个是我能找到的唯一一个易于使用的文件解码器,但它当然崩溃了


谢谢你的帮助。

你为什么把事情弄得这么复杂?你为什么不像其他人一样使用UnityWebRequest呢?当图像较大时,WebRequest也会导致冻结,因为它在主线程上解码图像。但直到我尝试了你发布的那个链接的异步版本,谢谢我尝试了那个链接的异步版本,我得到了一个错误,我在Unity中使用的.NET 3.5中没有“异步”、“等待”和“任务”功能,我应该使用5版或更高版本的C#你不切换到.NET 4.X有什么特别的原因吗?@derHugo很多人的电脑上可能没有安装.NET 4???为什么你把这个弄得这么复杂?你为什么不像其他人一样使用UnityWebRequest呢?当图像较大时,WebRequest也会导致冻结,因为它在主线程上解码图像。但直到我尝试了你发布的那个链接的异步版本,谢谢我尝试了那个链接的异步版本,我得到了一个错误,我在Unity中使用的.NET 3.5中没有“异步”、“等待”和“任务”功能,我应该使用5版或更高版本的C#你不切换到.NET 4.X有什么特别的原因吗?@derHugo很多人的电脑上可能没有安装.NET 4???