Форма Windows vs Unity3D HttpWebRequest Performace
Я работаю над простой программой, которая захватывает изображение с удаленной IP-камеры. После нескольких дней исследований я смог извлечь JPEG- изображения из прямой трансляции MJPEG с помощью полученных образцов кодов.
Я сделал прототип с использованием Windows Form. С Windows Form я получаю соответственно 80 изображений каждые 10 секунд с IP-камеры.
Теперь я перенес код на Unity3D и получаю около 2 кадров каждые 10 секунд.
Так что в основном около 78 изображений не получены. Это похоже на средневековое слайд-шоу PowerPoint.
Я запускаю функцию в новом потоке так же, как я делал в форме Windows. Сначала я подумал, что проблема в Unity заключается в том, что я отображал изображение, но это не так.
Я удалил код, который отображает изображение в качестве текстуры и использовал целое число для подсчета количества полученных изображений. Тем не менее, я получаю от 2 до 4 изображений каждые 10 секунд. То есть в приложении Windows Form я получаю от 80 до 100 изображений каждые 10 секунд.
Получение 2 изображений за 10 секунд в Unity неприемлемо для того, что я делаю. Код, который я написал, похоже, не является проблемой, потому что он прекрасно работает в Windows Form.
Вещи, которые я пробовал:
Я думал, что проблема в среде Unity3D Editor, поэтому я вызвал Windows 10 64bit и запустил ее, но это не решило проблему.
Изменен сервер сценариев с Mono2x на IL2CPP, но проблема все еще остается.
Уровень совместимости Api изменен с .NET 2.0 на .NET 2.0 Subset и ничего не изменилось.
Ниже приведена простая функция I, которая имеет эту проблему. На Unity он работает слишком медленно, хотя я звонил из другого потока.
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. Точно сказать не могу....
В чем дело? Почему это происходит? Как я могу это исправить?
2 ответа
Возможно, это тот случай, когда нужно использовать Read[a lot]
вместо Read
??
Read[a lot]
:
https://msdn.microsoft.com/en-us/library/system.io.stream.read(v=vs.110).aspx
Возвращаемое значение Тип: System.Int32 Общее количество байтов, считанных в буфер. Это может быть меньше количества запрошенных байтов, если столько байтов в данный момент недоступно
Предположительно, ReadAsync
может помочь, руководство, хотя это приводит к совершенно другому коду.
Я немного озадачен тем, какая часть вашего кода, о которой вы говорите, имеет проблему с производительностью - она отображает MPG или это фрагмент кода, который вы опубликовали здесь? Предполагая, что HttpRequest не является вашей проблемой (которую вы можете легко протестировать в Fiddler, чтобы увидеть, сколько времени на самом деле занимают вызов и выборка), тогда я предполагаю, что ваша проблема заключается в отображении MPG, а не кода, который вы опубликовали (который не будет отличаться между WinForms и Unity)
Я думаю, если проблема в Unity, вы передаете созданный MemoryStream в Unity для создания графического ресурса? Ваш код выглядит так, как будто он читает поток, и когда он достигает символа конца изображения, он создает новый MemoryStream, который содержит все содержимое буфера данных. Это может быть проблемой для Unity, которая не является проблемой в WinForms - поток памяти, кажется, содержит весь созданный вами буфер, но это больше, чем фактический контент, который вы прочитали - возможно, Unity видит это как поврежденный Jpg?
Попробуйте использовать конструктор MemoryStream, который берет диапазон байтов от вашего байта [] и передает только те данные, которые, как вы знаете, составляют ваш поток изображений.
Другие проблемы в коде могут быть (но вряд ли связаны с производительностью); Фрагментация кучи больших объектов при создании и отбрасывании большого байта []; нединамическое хранение входящего потока (фиксированный размер буфера назначения); нет проверки размера входящего потока или индикаторов окончания потока (если поток ответа не содержит весь поток изображения, кажется, что стратегии для этого нет).