.net核心中的视频流(使用状态代码206)

时间:2017-09-20 06:57:55

标签: .net asp.net-core video-streaming

我的.NET Core应用程序将从存储流式传输视频。 我找到了这个解决方案https://www.codeproject.com/Articles/820146/HTTP-Partial-Content-In-ASP-NET-Web-API-Video

并尝试像这样重写它

    [AllowAnonymous]
    [HttpGet("{container}/{name}")]
    public IActionResult Get(string container, string name)
    {
        var stream = _fileStorageClient.GetStream(container, name); //Got from storage
        if (stream == null)
            return NotFound();

        Response.Headers["Accept-Ranges"] = "bytes";

        //if there is no range - this is usual request
        var rangeHeaderValue = Request.Headers["Range"].FirstOrDefault();
        if (string.IsNullOrEmpty(rangeHeaderValue))
        {
            var fileStreamResult = new FileStreamResult(stream, "video/mp4");
            Response.ContentLength = stream.Length;
            Response.StatusCode = (int) HttpStatusCode.OK;
            return fileStreamResult;
        }

        if (!TryReadRangeItem(rangeHeaderValue, stream.Length, out long start, out long end))
        {
            return StatusCode((int) HttpStatusCode.RequestedRangeNotSatisfiable);
        }

        Response.Headers["Content-Range"] = $"{start}-{end}/{stream.Length}";
        Response.ContentLength = end - start + 1;
        Response.StatusCode = (int) HttpStatusCode.PartialContent;

        var outStream = new MemoryStream();
        CreatePartialContent(stream, outStream, start, end);
        outStream.Seek(0, SeekOrigin.Begin);
        return new FileStreamResult(outStream, "video/mp4");
    }

    private static void CreatePartialContent(Stream inputStream, Stream outputStream,
        long start, long end)
    {
        var remainingBytes = end - start + 1;
        var buffer = new byte[ReadStreamBufferSize];
        long position;
        inputStream.Position = start;
        do
        {
            try
            {
                var count = remainingBytes > ReadStreamBufferSize ? 
                    inputStream.Read(buffer, 0, ReadStreamBufferSize) : 
                    inputStream.Read(buffer, 0, (int) remainingBytes);
                outputStream.Write(buffer, 0, count);
            }
            catch (Exception error)
            {
                Debug.WriteLine(error);
                break;
            }
            position = inputStream.Position;
            remainingBytes = end - position + 1;
        } while (position <= end);
    }

    private bool TryReadRangeItem(string rangeHeaderValue, long contentLength,
        out long start, out long end)
    {
        if (string.IsNullOrEmpty(rangeHeaderValue))
            throw new ArgumentNullException(nameof(rangeHeaderValue));

        start = 0;
        end = contentLength - 1;

        var rangeHeaderSplitted = rangeHeaderValue.Split('=');
        if (rangeHeaderSplitted.Length == 2)
        {
            var range = rangeHeaderSplitted[1].Split('-');
            if (range.Length == 2)
            {
                if (long.TryParse(range[0], out long startParsed))
                    start = startParsed;
                if (long.TryParse(range[1], out long endParsed))
                    end = endParsed;
            }
        }

        return start < contentLength && end < contentLength;
    }

当我尝试在家中执行操作时,我有两个请求

请求1

GET /api/videoFiles/video-answers/7f72c19b-5a5a-ed17-f87d-e755834a1c92 HTTP/1.1
Host: localhost:65086
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4
Cookie: vc=2; _ga=GA1.1.1273330415.1475670014

回复1

HTTP/1.1 200 OK
Content-Length: 5517780
Content-Type: video/mp4
Accept-Ranges: bytes
Server: Kestrel
X-SourceFiles: =?UTF-8?B?QzpcV29ya1xIZXJ6ZW5cSGVyemVuLldlYlxhcGlcdmlkZW9GaWxlc1x2aWRlby1hbnN3ZXJzXDdmNzJjMTliLTVhNWEtZWQxNy1mODdkLWU3NTU4MzRhMWM5Mg==?=
X-Powered-By: ASP.NET
Date: Wed, 20 Sep 2017 06:37:01 GMT

然后请求2

GET /api/videoFiles/video-answers/7f72c19b-5a5a-ed17-f87d-e755834a1c92 HTTP/1.1
Host: localhost:65086
Connection: keep-alive
Accept-Encoding: identity;q=1, *;q=0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36
Accept: */*
Referer: http://localhost:65086/api/videoFiles/video-answers/7f72c19b-5a5a-ed17-f87d-e755834a1c92
Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4
Cookie: vc=2; _ga=GA1.1.1273330415.1475670014
Range: bytes=0-

回复2

HTTP/1.1 206 Partial Content
Content-Length: 5517780
Content-Type: video/mp4
Content-Range: 0-5517779/5517780
Accept-Ranges: bytes
Server: Kestrel
X-SourceFiles: =?UTF-8?B?QzpcV29ya1xIZXJ6ZW5cSGVyemVuLldlYlxhcGlcdmlkZW9GaWxlc1x2aWRlby1hbnN3ZXJzXDdmNzJjMTliLTVhNWEtZWQxNy1mODdkLWU3NTU4MzRhMWM5Mg==?=
X-Powered-By: ASP.NET
Date: Wed, 20 Sep 2017 06:37:01 GMT

加载后视频控件可立即使用,然后变为灰色

当我返回没有Accept-Ranges的FileStreamResult(如第一个条件中)时,一切正常。

这段代码出了什么问题?

1 个答案:

答案 0 :(得分:0)

在ASP.NET Core 2.1中添加了对范围link的支持。

将文件构造函数与enableRangeProcessing结合使用:

FileStreamResult文件(流fileStream,字符串contentType, bool enableRangeProcessing