Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Async video streaming in ASP.Net Core Web Api is not working

I have used http://www.strathweb.com/2013/01/asynchronously-streaming-video-with-asp-net-web-api/ this technique before and worked perfect for async video streaming.

But for ASP.NET Core this way is not working as expected.

By Video streaming class is:

public class VideoStream
{
    private readonly string _filename;
    public VideoStream(string filename)
    {
        _filename = filename;
    }

    public async Task WriteToStream(Stream outputStream, HttpContent content, TransportContext context)
    {
        try
        {
            var buffer = new byte[65536];
            using (var video = File.Open(_filename, FileMode.Open, FileAccess.Read))
            {
                var length = (int)video.Length;
                var bytesRead = 1;
                while (length > 0 && bytesRead > 0)
                {
                    bytesRead = video.Read(buffer, 0, Math.Min(length, buffer.Length));
                    await outputStream.WriteAsync(buffer, 0, bytesRead);
                    length -= bytesRead;
                }
            }
        }
        catch (Exception)
        { return; }
        finally
        {
            outputStream.Flush();
            outputStream.Dispose();
        }
    }
}

and I have the following Action for video streaming requests:

    [HttpGet]
    [Route("[action]")]
    public IActionResult GetVideo(int id)
    {
        var fileName = GetVideoFileName(id);
        var video = new VideoStream(fileName);
        var response = new HttpResponseMessage
        {
            Content = new PushStreamContent(video.WriteToStream, new MediaTypeHeaderValue("video/mp4"))
        };
        var objectResult = new ObjectResult(response);
        objectResult.ContentTypes.Add(new Microsoft.Net.Http.Headers.MediaTypeHeaderValue("video/mp4"));
        return objectResult;
    }

Since by default Asp.Net Core doesn't have built-in Media Formatter for video/mp4 I have created the following custom Media Formatter

 public class VideoOutputFormatter : IOutputFormatter
{
    public bool CanWriteResult(OutputFormatterCanWriteContext context)
    {
        if (context == null)
            throw new ArgumentNullException(nameof(context));
            return true;
    }
    public async Task WriteAsync(OutputFormatterWriteContext context)
    {
        if (context == null)
            throw new ArgumentNullException(nameof(context));
        var response = context.HttpContext.Response;
        response.ContentType = "video/mp4";

       How to impelemnt  ???
    }
}

and added the following line to Startup.cs

 services.AddMvc(options =>
        {
              options.OutputFormatters.Add(new VideoOutputFormatter());
        });

It actually calls my custom formatter. I doesn't know how to implement this custom media formatter for video/mp4. Anyone can help me ?

like image 611
Nurlan Valizada Avatar asked Jan 17 '17 13:01

Nurlan Valizada


1 Answers

Looking at the source code for Asp.NET Core really helped me find the answer to this one. They have a StreamOutputFormatter class that's really close to what you want to use. I only had to modify it to look for PushStreamContent and it worked like a charm.

Here's my complete VideoOutputFormatter:

public class VideoOutputFormatter : IOutputFormatter
{
    public bool CanWriteResult(OutputFormatterCanWriteContext context)
    {
        if (context == null)
            throw new ArgumentNullException(nameof(context));

        if (context.Object is PushStreamContent)
            return true;

        return false;
    }

    public async Task WriteAsync(OutputFormatterWriteContext context)
    {
        if (context == null)
            throw new ArgumentNullException(nameof(context));

        using (var stream = ((PushStreamContent)context.Object))
        {
            var response = context.HttpContext.Response;
            if (context.ContentType != null)
            {
                response.ContentType = context.ContentType.ToString();
            }

            await stream.CopyToAsync(response.Body);
        }
    }
}

Instead of wrapping the HttpResponseMessage in the ObjectResult in your controller, you'll want to just shove the PushStreamContent object into the ObjectResult instead. You still need to set the MediaTypeHeaderValue on the ObjectResult.

like image 135
villecoder Avatar answered Sep 19 '22 19:09

villecoder