- Home /
Unity 5 (C#) live HTML MJPG-streamer viewer?
Hello community,
I have a webpage which shows MJPG-streamer images from a Raspberry Pi webcam which I want to display inside Unity using a texture. Here's the "/stream" page html code:
<p id="streamwrap" class="xform-p">
<img id="streamimage" class="xform" src="http://192.168.1.2:8080/?action=stream">
</p>
I can't use standard 'get' WWW.texture with this because a stream of images can't be pointed to with a "/stream/image.jpg". I can only access the stream via a "/stream" or "/?action=stream" URI. I have tried the code below, but no luck:
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class GET_Stream : MonoBehaviour {
public string url = "http://192.168.1.2:8080/?action=stream";
IEnumerator Start() {
WWW www = new WWW(url);
yield return www;
RawImage renderer = GetComponent<RawImage>();
renderer.texture = www.texture;
}
void Update () {
Start ();
}
}
Another alternative to WWW I know is HttpWebRequest. It may contain something I could use (I'm currently researching this), because when I get the stream grab to work, I'll make it work over SSL (using a similar code to this).
Then I began looking for Unity HTML viewers, but the best one I found was for Unity 3.4 - Awesomium. I did try to install it on Unity 5.4 64-bit (where I got DllNotFoundException) and 32-bit (where I got EntryPointNotFoundException). (I'm surprised that App Inventor has a WebViewer, but Unity doesn't). I'm looking for free options. Any suggestions?
Awesomium error on Unity 5 32-bit:
EntryPointNotFoundException: awe_string_create_from_utf16
AwesomiumMono.StringHelper..ctor (System.String val)
AwesomiumMono.WebCore.Start ()
AwesomiumMono.WebCore.Initialize (AwesomiumMono.WebCoreConfig config, Boolean start)
WebTexture.Start () (at Assets/WebTexture.cs:32)
Thank you.
Answer by Bunny83 · Aug 12, 2016 at 11:07 PM
Using an HTML renderer just for displaying some images seems to be total overkill.
You basically have two options:
Use a TCPClient and send the request manually and parse the response manually. There might be a way with "HttpWebRequest" but it's most likely more complicated.
Don't use the stream at all. The mjpg streamer also allows you to request a single image. Instead of
?action=stream
you can use?action=snapshot
which will return a single image. You just need to re-issue the request when you want a new image. Requesting a single snapshot should be possible with Unity's WWW class.
Do you think re-requesting images one at a time at 30fps would use more bandwidth?
You will have a hard time getting 30fps that way ^^. If you really want such a high framerate you have to use the stream variant. The additional bandwidth isn't the real issue but the latency that each request-response pair has,
If you want to manually parse the stream you might want to have a look at the actual sending code which you can find here (line). It's basically just a multipart body where each part is a seperate JPEG frame.
Though it could still be tough to keep up that rate since you still have to load the jpg image as texture which could take a while.
I currently got this to work, but it overloads and crashes after a short while:
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class GET_Stream : $$anonymous$$onoBehaviour {
public InputField urlInput;
private string url;
IEnumerator GetImage() {
url = urlInput.text;
WWW www = new WWW ("http://" + url + ":8080/?action=snapshot");
yield return www;
Renderer renderer = GetComponent<Renderer>();
renderer.material.mainTexture = www.texture;
}
void Update() {
StartCoroutine(GetImage());
}
}
Can't have an IEnumerator Update()
- can not be a coroutine.
Can't have yield return www;
in void Update()
- cannot be an iterator block.
Won't use sleep or wait functions - will create unnecessary lag, or won't wait long enough.
Can't have if (isDone)
- it will read false, and move on, won't wait.
Can't have a while (isDone)
- freezes game every frame except when broken.
Thanks for help above. Here's what worked for me:
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Networking;
using System.Collections;
public class GET_Stream : $$anonymous$$onoBehaviour {
public InputField urlInput;
private string url;
public float GetRate = 0.15f;
private float nextGet = 0;
IEnumerator GetTexture() {
url = urlInput.text;
Renderer renderer = GetComponent<Renderer>();
UnityWebRequest www = UnityWebRequest.GetTexture("http://" + url + ":8080/?action=snapshot");
yield return www.Send();
renderer.material.mainTexture = ((DownloadHandlerTexture)www.downloadHandler).texture;
}
void Update() {
if (Time.time > nextGet) {
StartCoroutine (GetTexture ());
nextGet = Time.time + GetRate;
}
}
}
Your answer
