Search code examples
c#.netiisvideo-streamingkestrel

Mjpeg streaming using .NET 8 on IIS 10


I'm building an API in .NET 8 that when called, will connect to an IP camera in the backend and stream the content (mjpeg) to the client's browser.

I'm not sure how to properly do this, but I got my code below to work on Kestrel/Visual Studio.

However, when I host my app on IIS 10, things get weird. The client will connect to the server, but the video will not show.

Using DevTools I can see that the request will freeze in the "Downloading from Server" state. If I manually kill the connection to the IP Camera in the backend, the browser will quickly show a few frames from the stream and the request will complete.

In addition to this code, I've tried reading the IP Camera stream into a buffer and then writing it out to the response body. However, it only works on Kestrel and not on IIS. I'm wondering if I need to configure something on IIS? I've been working on this for a couple weeks and I'm out of ideas.

Server Side

    public async Task<Stream> Video()
    {
        AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);
        string baseAddress = "http://192.168.1.100";
        string clientId = "Username";
        string clientSecret = "Password";

        var credCache = new CredentialCache
        {
            { new Uri(baseAddress), "Digest", new NetworkCredential(clientId, clientSecret) }
        };

        HttpClient httpClient = new HttpClient(new HttpClientHandler { Credentials = credCache });
        httpClient.BaseAddress = new Uri(baseAddress);

        var response = await httpClient.GetStreamAsync("/cgi-bin/mjpg/video.cgi?channel=1&subtype=1");

        HttpContext.Response.Headers.ContentType = "multipart/x-mixed-replace; boundary=--myboundary";

        return response;
    }

HTML

    <div class="col-md-4">
        <img height="480" width="640" src="/Video">
    </div>

Solution

  • I faced the same issue and it was fixed when I disabled the response body buffering:

    var responseBodyFeature = context.Features.Get<IHttpResponseBodyFeature>();
    if (responseBodyFeature != null) responseBodyFeature.DisableBuffering();
    

    Also note that your boundary value should not start with double hyphens when you define it in your header, so it should look like this:

    "multipart/x-mixed-replace; boundary=myboundary"