Search Unity

Question 401 Exception constantly popping up. URL or HTTP authentication issue?

Discussion in 'Multiplayer' started by diogomiguelmm, Sep 9, 2020.

  1. diogomiguelmm

    diogomiguelmm

    Joined:
    Sep 9, 2020
    Posts:
    6
    Hello

    I'm doing this experiment of mine where the Unity project uses the AR/XR (ARFoundation) Kit. I was hesitant if I were to create this thread on this section or on the AR/VR one but my struggle is a connection issue.

    I had no problem setting everything up in Unity itself, as the documentation provided was pretty clear.

    My goal is to stream whatever my IP Camera is capturing to a 3D plane in Unity, that will later be exported as a mobile app.




    Now to the IP Camera connection part. I've searched through various pages around the internet, from here on Stackoverflow to several Unity forum threads and managed to have the code below, that is supposed to fetch the video stream via URL while also processing the image.

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Networking;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5. using System;
    6. using System.Net;
    7. using System.IO;
    8.  
    9. public class IPCamConfig : MonoBehaviour
    10. {
    11.  
    12.    public MeshRenderer frame;  
    13.    [SerializeField]
    14.    private string sourceURL = "http://192.168.1.107/main.html?id=1&playtype=fv";
    15.    private Texture2D texture;
    16.    private Stream stream;
    17.  
    18.    public string username;
    19.    public string password;
    20.  
    21.    CustomWebRequest camImage;
    22.    UnityWebRequest webRequest;
    23.    byte[] bytes = new byte[90000];
    24.  
    25.    private void Start()
    26.    {
    27.        webRequest = new UnityWebRequest(sourceURL);
    28.        webRequest.downloadHandler = new CustomWebRequest(bytes);
    29.        webRequest.Send();
    30.  
    31.        GetVideo();
    32.        StartCoroutine(GetFrame());
    33.        FindLength(stream);
    34.    }
    35.  
    36.    private void GetVideo()
    37.    {
    38.        Debug.Log("fetching mesh texture...");
    39.        texture = new Texture2D(2, 2);
    40.        Debug.Log("mesh texture identified!");
    41.        // create HTTP request
    42.        Debug.Log("fetching video URL...");
    43.        HttpWebRequest req = (HttpWebRequest)WebRequest.Create(sourceURL)
    44.            as HttpWebRequest;
    45.        req.Method = "GET";
    46.        Debug.Log("URL identified!");
    47.        //Optional (if authorization is Digest)
    48.        Debug.Log("getting response...");
    49.        req.Credentials = new NetworkCredential("username", "password");
    50.  
    51.        // get response
    52.        Debug.Log("Getting response...");
    53.        WebResponse resp = req.GetResponse();
    54.  
    55.  
    56.        // get response stream
    57.        stream = resp.GetResponseStream();
    58.        StartCoroutine(GetFrame());
    59.    }
    60.  
    61.    IEnumerator GetFrame()
    62.    {
    63.        Byte[] JpegData = new Byte[65536];
    64.  
    65.        while (true)
    66.        {
    67.            int bytesToRead = FindLength(stream);
    68.            print(bytesToRead);
    69.            if (bytesToRead == -1)
    70.            {
    71.                print("End of stream");
    72.                yield break;
    73.            }
    74.  
    75.            int leftToRead = bytesToRead;
    76.  
    77.            while (leftToRead > 0)
    78.            {
    79.                leftToRead -= stream.Read(JpegData, bytesToRead - leftToRead, leftToRead);
    80.                yield return null;
    81.            }
    82.  
    83.            MemoryStream ms = new MemoryStream(JpegData, 0, bytesToRead, false, true);
    84.  
    85.            texture.LoadImage(ms.GetBuffer());
    86.            frame.material.mainTexture = texture;
    87.            stream.ReadByte(); // CR after bytes
    88.            stream.ReadByte(); // LF after bytes
    89.        }
    90.    }
    91.  
    92.    int FindLength(Stream stream)
    93.    {
    94.        int b;
    95.        string line = "";
    96.        int result = -1;
    97.        bool atEOL = false;
    98.  
    99.        while ((b = stream.ReadByte()) != -1)
    100.        {
    101.            if (b == 10) continue; // ignore LF char
    102.            if (b == 13)
    103.            { // CR
    104.                if (atEOL)
    105.                {  // two blank lines means end of header
    106.                    stream.ReadByte(); // eat last LF
    107.                    return result;
    108.                }
    109.                if (line.StartsWith("Content-Length:"))
    110.                {
    111.                    result = Convert.ToInt32(line.Substring("Content-Length:".Length).Trim());
    112.                }
    113.                else
    114.                {
    115.                    line = "";
    116.                }
    117.                atEOL = true;
    118.            }
    119.            else
    120.            {
    121.                atEOL = false;
    122.                line += (char)b;
    123.            }
    124.        }
    125.        return -1;
    126.    }
    127. }
    Problem is, every time I try to run the Unity scene it always gives a 401 exception error.



    It could also be from the URL itself, as it was the only one that had a video source, although it's being played by a Flash player. And yes, it's the IP camera's website. The camera I'm using is a Conceptronic CIPCAM720S.

    I've heard that successful cases have URLs ending in .MJPEG, yet I couldn't find a way to "convert" my URL like this. Is there any other way to do this? Or does this have to do with an HTTP connection?
    It's the first time I'm working with IP cameras and HTTP connections.
     
  2. FakeByte

    FakeByte

    Joined:
    Dec 8, 2015
    Posts:
    147
    It gives a 401 error which means your user credentials were rejected, check if the username and password you entered are correct
     
    Joe-Censored likes this.
  3. diogomiguelmm

    diogomiguelmm

    Joined:
    Sep 9, 2020
    Posts:
    6
    Hi. Sorry for the late reply.

    Yes, the user credentials are the same as it says on my IP camera's user manual. I input these in the IPCamConfig script component at the bottom right corner of my first screenshot. I'm not sure if this is a good practice or if I should define the user credentials as private variables in IPCamConfig.cs
     
  4. FakeByte

    FakeByte

    Joined:
    Dec 8, 2015
    Posts:
    147
    According to this website your specific model doesn't use HTTP, but instead RTSP protocol, the connection got refused sincec unity web requests uses HTTP.
    https://www.ispyconnect.com/man.aspx?n=Conceptronic
     
    diogomiguelmm likes this.
  5. diogomiguelmm

    diogomiguelmm

    Joined:
    Sep 9, 2020
    Posts:
    6
    Alright, I can now view the stream in a more seamless way with iSpy. As for the C# script, I have to use new code or some sort of plug-in, right?

    I've looked around and found these two plug-ins:

    https://mfkl.github.io/libvlc/unity/2019/12/18/Introducing-LibVLCSharp-for-Unity.html
    https://github.com/gujadot/RTSP_Unity_Plugin

    I'm not sure if using these is the best way to establish a connection via RTSP.
     
  6. diogomiguelmm

    diogomiguelmm

    Joined:
    Sep 9, 2020
    Posts:
    6
    I just got another IP camera which happens to use HTTP protocol. I went on and used the iSpy software, got the corresponding link and it fixed the 401 error but Unity still shows a plain white screen instead of the footage (no errors on the console either) .
    It may have not helped me ultimately with the project but at least the 401 exception is solved.
    Thank you very much @FakeByte !