Windows 表单与 Unity3D HttpWebRequest 性能对比
Windows Form vs Unity3D HttpWebRequest Performance
我正在开发一个从远程 IP 摄像机抓取图像的简单程序。经过几天的研究,我能够使用我得到的示例代码从 MJPEG 直播流中提取 JPEG 图像。
我用 Windows 表格做了一个原型。使用 Windows 表格,我每 10 秒从网络摄像机接收到大约 80 张图像。
现在我将代码移植到 Unity3D,我每 10 秒得到大约 2 帧。
所以基本上 78 图片 未收到 。
这东西看起来像 中世纪的 PowerPoint 幻灯片放映。
我 运行 在新线程中使用函数,就像我在 Windows 表单中所做的那样。我首先想到的是 Unity 中的问题是因为我正在显示图像,但它 不是 。
我删除了将图像显示为纹理的代码,并使用整数来计算接收到的图像数量。不过,我每 10 秒 得到大约 2 到 4 张图像。在 Windows Form 应用程序中,我得到大约 80 到 100 个图像 10秒。
在 10 秒内接收 2 图像 Unity 不可接受 因为我在做什么。我写的代码似乎不是问题,因为它在 Windows Form.
中运行良好
我尝试过的事情:
我虽然问题出在 Unity3D 编辑器 运行 时间,所以我要求 Windows 10 64 位和 运行 它但没有解决问题。
将 脚本后端 从 Mono2x 更改为 IL2CPP 但是问题依旧。
将 Api 兼容性级别 从 .NET 2.0 更改为 。 NET 2.0 子集,没有任何改变。
下面是一个存在该问题的简单函数。它 运行 在 Unity 上也 慢 即使我从另一个 thread.
调用它
bool keepRunning = true;
private void Decode_MJPEG_Images(string streamTestURL = null)
{
keepRunning = true;
streamTestURL = "http://64.122.208.241:8000/axis-cgi/mjpg/video.cgi?resolution=320x240"; //For Testing purposes only
// create HTTP request
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(streamTestURL);
// get response
WebResponse resp = req.GetResponse();
System.IO.Stream imagestream = resp.GetResponseStream();
const int BufferSize = 5000000;
byte[] imagebuffer = new byte[BufferSize];
int a = 2;
int framecounter = 0;
int startreading = 0;
byte[] start_checker = new byte[2];
byte[] end_checker = new byte[2];
while (keepRunning)
{
start_checker[1] = (byte)imagestream.ReadByte();
end_checker[1] = start_checker[1];
//This if statement searches for the JPEG header, and performs the relevant operations
if (start_checker[0] == 0xff && start_checker[1] == 0xd8)// && Reset ==0)
{
Array.Clear(imagebuffer, 0, imagebuffer.Length);
//Rebuild jpeg header into imagebuffer
imagebuffer[0] = 0xff;
imagebuffer[1] = 0xd8;
a = 2;
framecounter++;
startreading = 1;
}
//This if statement searches for the JPEG footer, and performs the relevant operations
if (end_checker[0] == 0xff && end_checker[1] == 0xd9)
{
startreading = 0;
//Write final part of JPEG header into imagebuffer
imagebuffer[a] = start_checker[1];
System.IO.MemoryStream jpegstream = new System.IO.MemoryStream(imagebuffer);
Debug.Log("Received Full Image");
Debug.Log(framecounter.ToString());
//Display Image
}
//This if statement fills the imagebuffer, if the relevant flags are set
if (startreading == 1 && a < BufferSize)
{
imagebuffer[a] = start_checker[1];
a++;
}
//Catches error condition where a = buffer size - this should not happen in normal operation
if (a == BufferSize)
{
a = 2;
startreading = 0;
}
start_checker[0] = start_checker[1];
end_checker[0] = end_checker[1];
}
resp.Close();
}
现在我把这个问题归咎于 HttpWebRequest。也许它在 Unity 中实现不佳。不确定....
这是怎么回事?为什么会这样?我该如何解决?
是否可能必须使用 Read[a lot]
而不是 Read
??
Read[a lot]
:
https://msdn.microsoft.com/en-us/library/system.io.stream.read(v=vs.110).aspx
Return Value Type: System.Int32 The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available
可以想象,ReadAsync
可以提供帮助,manual,尽管它会产生截然不同的代码。
我对您所说的代码的哪一部分存在性能问题感到有点困惑 - 它显示 MPG 还是您在此处发布的代码片段?假设 HttpRequest 不是您的问题(您可以在 Fiddler 中轻松测试以查看调用和提取实际花费了多长时间)那么我猜您的问题出在 MPG 的显示上而不是您发布的代码(哪个WinForms 和 Unity 之间没有区别)
我的猜测是,如果问题出在 Unity 中,您是将创建的 MemoryStream 传递给 unity 以创建图形资源吗?您的代码看起来像是在读取流,当它遇到图像结束字符时,它会创建一个新的 MemoryStream,其中包含整个数据缓冲区内容。这可能是 Unity 的问题,而在 WinForms 中不是问题 - 内存流似乎包含您创建的整个缓冲区,但这比您读取的实际内容更大 - Unity 是否可能将其视为损坏的 Jpg?
尝试使用 MemoryStream 构造函数,它从您的 byte[] 中获取一个字节范围,并仅传递您知道的构成图像流的数据。
代码中的其他问题可能是(但不太可能与性能相关); Large Object Heap 碎片来自 large byte[] 的创建和丢弃;输入流的非动态存储(固定目标缓冲区大小);不检查传入流大小或流结束指示符(如果响应流不包含整个图像流,似乎没有处理它的策略)。
我正在开发一个从远程 IP 摄像机抓取图像的简单程序。经过几天的研究,我能够使用我得到的示例代码从 MJPEG 直播流中提取 JPEG 图像。
我用 Windows 表格做了一个原型。使用 Windows 表格,我每 10 秒从网络摄像机接收到大约 80 张图像。
现在我将代码移植到 Unity3D,我每 10 秒得到大约 2 帧。
所以基本上 78 图片 未收到 。 这东西看起来像 中世纪的 PowerPoint 幻灯片放映。
我 运行 在新线程中使用函数,就像我在 Windows 表单中所做的那样。我首先想到的是 Unity 中的问题是因为我正在显示图像,但它 不是 。
我删除了将图像显示为纹理的代码,并使用整数来计算接收到的图像数量。不过,我每 10 秒 得到大约 2 到 4 张图像。在 Windows Form 应用程序中,我得到大约 80 到 100 个图像 10秒。
在 10 秒内接收 2 图像 Unity 不可接受 因为我在做什么。我写的代码似乎不是问题,因为它在 Windows Form.
中运行良好我尝试过的事情:
我虽然问题出在 Unity3D 编辑器 运行 时间,所以我要求 Windows 10 64 位和 运行 它但没有解决问题。
将 脚本后端 从 Mono2x 更改为 IL2CPP 但是问题依旧。
将 Api 兼容性级别 从 .NET 2.0 更改为 。 NET 2.0 子集,没有任何改变。
下面是一个存在该问题的简单函数。它 运行 在 Unity 上也 慢 即使我从另一个 thread.
调用它bool keepRunning = true;
private void Decode_MJPEG_Images(string streamTestURL = null)
{
keepRunning = true;
streamTestURL = "http://64.122.208.241:8000/axis-cgi/mjpg/video.cgi?resolution=320x240"; //For Testing purposes only
// create HTTP request
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(streamTestURL);
// get response
WebResponse resp = req.GetResponse();
System.IO.Stream imagestream = resp.GetResponseStream();
const int BufferSize = 5000000;
byte[] imagebuffer = new byte[BufferSize];
int a = 2;
int framecounter = 0;
int startreading = 0;
byte[] start_checker = new byte[2];
byte[] end_checker = new byte[2];
while (keepRunning)
{
start_checker[1] = (byte)imagestream.ReadByte();
end_checker[1] = start_checker[1];
//This if statement searches for the JPEG header, and performs the relevant operations
if (start_checker[0] == 0xff && start_checker[1] == 0xd8)// && Reset ==0)
{
Array.Clear(imagebuffer, 0, imagebuffer.Length);
//Rebuild jpeg header into imagebuffer
imagebuffer[0] = 0xff;
imagebuffer[1] = 0xd8;
a = 2;
framecounter++;
startreading = 1;
}
//This if statement searches for the JPEG footer, and performs the relevant operations
if (end_checker[0] == 0xff && end_checker[1] == 0xd9)
{
startreading = 0;
//Write final part of JPEG header into imagebuffer
imagebuffer[a] = start_checker[1];
System.IO.MemoryStream jpegstream = new System.IO.MemoryStream(imagebuffer);
Debug.Log("Received Full Image");
Debug.Log(framecounter.ToString());
//Display Image
}
//This if statement fills the imagebuffer, if the relevant flags are set
if (startreading == 1 && a < BufferSize)
{
imagebuffer[a] = start_checker[1];
a++;
}
//Catches error condition where a = buffer size - this should not happen in normal operation
if (a == BufferSize)
{
a = 2;
startreading = 0;
}
start_checker[0] = start_checker[1];
end_checker[0] = end_checker[1];
}
resp.Close();
}
现在我把这个问题归咎于 HttpWebRequest。也许它在 Unity 中实现不佳。不确定....
这是怎么回事?为什么会这样?我该如何解决?
是否可能必须使用 Read[a lot]
而不是 Read
??
Read[a lot]
:
https://msdn.microsoft.com/en-us/library/system.io.stream.read(v=vs.110).aspx
Return Value Type: System.Int32 The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available
可以想象,ReadAsync
可以提供帮助,manual,尽管它会产生截然不同的代码。
我对您所说的代码的哪一部分存在性能问题感到有点困惑 - 它显示 MPG 还是您在此处发布的代码片段?假设 HttpRequest 不是您的问题(您可以在 Fiddler 中轻松测试以查看调用和提取实际花费了多长时间)那么我猜您的问题出在 MPG 的显示上而不是您发布的代码(哪个WinForms 和 Unity 之间没有区别)
我的猜测是,如果问题出在 Unity 中,您是将创建的 MemoryStream 传递给 unity 以创建图形资源吗?您的代码看起来像是在读取流,当它遇到图像结束字符时,它会创建一个新的 MemoryStream,其中包含整个数据缓冲区内容。这可能是 Unity 的问题,而在 WinForms 中不是问题 - 内存流似乎包含您创建的整个缓冲区,但这比您读取的实际内容更大 - Unity 是否可能将其视为损坏的 Jpg?
尝试使用 MemoryStream 构造函数,它从您的 byte[] 中获取一个字节范围,并仅传递您知道的构成图像流的数据。
代码中的其他问题可能是(但不太可能与性能相关); Large Object Heap 碎片来自 large byte[] 的创建和丢弃;输入流的非动态存储(固定目标缓冲区大小);不检查传入流大小或流结束指示符(如果响应流不包含整个图像流,似乎没有处理它的策略)。