For more on preallocated data buffers, see the following subsection.
Avoiding GC Overhead: DownloadHandlerScripts with pre-allocated buffers
Many of Unity’s power users are constantly concerned with reducing CPU spikes due to garbage collection. For these users, the UnityWebRequest system permits the pre-allocation of a managed-code byte array which will be used to deliver downloaded data to DownloadHandlerScript’s
ReceiveData
callback.
Using this method completely eliminates managed-code memory allocation when using DownloadHandlerScript-derived classes to capture downloaded data.
To make a
DownloadHandlerScript
operate with a pre-allocated managed buffer, simply supply a byte array to the constructor of DownloadHandlerScript
.
Note: The size of the byte array limits the amount of data delivered to the ReceiveData callback each frame. Do not provide too small of a byte array or your data will arrive slowly, over many frames.
https://stackoverflow.com/questions/49524324/obtain-data-from-unitywebrequest-while-still-downloading
https://stackoverflow.com/questions/49524324/obtain-data-from-unitywebrequest-while-still-downloading
It is possible to do it with
UnityWebRequest
but you have to perform extra work. The secret is to use DownloadHandlerScript
with UnityWebRequest
.
Create a separate class and make it derive from
DownloadHandlerScript
instead of MonoBehaviour
. In the example below, I will call it CustomWebRequest
. Override the bool ReceiveData(byte[] data, int dataLength)
, void CompleteContent()
and the void ReceiveContentLength(int contentLength)
functions inside it.
Here is an example of the
CustomWebRequest
class:public class CustomWebRequest : DownloadHandlerScript
{
// Standard scripted download handler - will allocate memory on each ReceiveData callback
public CustomWebRequest()
: base()
{
}
// Pre-allocated scripted download handler
// Will reuse the supplied byte array to deliver data.
// Eliminates memory allocation.
public CustomWebRequest(byte[] buffer)
: base(buffer)
{
}
// Required by DownloadHandler base class. Called when you address the 'bytes' property.
protected override byte[] GetData() { return null; }
// Called once per frame when data has been received from the network.
protected override bool ReceiveData(byte[] byteFromServer, int dataLength)
{
if (byteFromServer == null || byteFromServer.Length < 1)
{
Debug.Log("CustomWebRequest :: ReceiveData - received a null/empty buffer");
return false;
}
//Do something with or Process byteFromServer here
return true;
}
// Called when all data has been received from the server and delivered via ReceiveData
protected override void CompleteContent()
{
Debug.Log("CustomWebRequest :: CompleteContent - DOWNLOAD COMPLETE!");
}
// Called when a Content-Length header is received from the server.
protected override void ReceiveContentLength(int contentLength)
{
Debug.Log(string.Format("CustomWebRequest :: ReceiveContentLength - length {0}", contentLength));
}
}
And to use it to start the download, just create new instance of
UnityWebRequest
and use CustomWebRequest
as the downloadHandler
before calling the SendWebRequest
function. No coroutine required for this and you don't even have to yield anything. This is how to do it:UnityWebRequest webRequest;
//Pre-allocate memory so that this is not done each time data is received
byte[] bytes = new byte[2000];
void Start()
{
string url = "http://yourUrl/mjpg/video.mjpg";
webRequest = new UnityWebRequest(url);
webRequest.downloadHandler = new CustomWebRequest(bytes);
webRequest.SendWebRequest();
}
That's it.
- When Unity first makes the request,
ReceiveContentLength(int contentLength)
is called. You can use thecontentLength
parameter to determine the total number of bytes you will receive from that request. - The
ReceiveData
function is called each time new data is received and from that function, you can access that current data from thebyteFromServer
parameter and the length of it from thedataLength
parameter. - When Unity is done receiving data, the
CompleteContent
function is called.
No comments:
Post a Comment