Asp.net mvc 3 来自MVC3操作的HTML5视频无法正常工作

Asp.net mvc 3 来自MVC3操作的HTML5视频无法正常工作,asp.net-mvc-3,html5-video,mediaelement.js,http-streaming,video.js,Asp.net Mvc 3,Html5 Video,Mediaelement.js,Http Streaming,Video.js,我正在为MVC3站点的视频提供服务,控制器操作返回返回FilePathResult的视频,当尝试在浏览器中播放时,我发现一些令人沮丧的问题,无论我使用的是video.js还是mediaelement.js Chrome不允许您使用progressbar更改位置,也不允许您在视频完成后重播视频 IE9似乎相对较好 Firefox无法正确显示已用/剩余时间 但是,如果我只给出一个被托管文件的相对路径,那么一切都很好。 这些视频需要仅对属于特定角色的用户可用,因此这不是一个真正的选项 行动:

我正在为MVC3站点的视频提供服务,控制器操作返回返回FilePathResult的视频,当尝试在浏览器中播放时,我发现一些令人沮丧的问题,无论我使用的是video.js还是mediaelement.js

  • Chrome不允许您使用progressbar更改位置,也不允许您在视频完成后重播视频
  • IE9似乎相对较好
  • Firefox无法正确显示已用/剩余时间
但是,如果我只给出一个被托管文件的相对路径,那么一切都很好。 这些视频需要仅对属于特定角色的用户可用,因此这不是一个真正的选项

行动:

    [Authorize]
    public ActionResult Video(string fileName)
    {
        var pathBase = Server.MapPath("~/Downloads/Videos/");
        var filePath = pathBase + fileName;
        var contentType = ContentType(fileName);
        return new FilePathResult(filePath, contentType) { FileDownloadName = fileName };
    }
剃刀:

   <!-- @t = the video entity -->
   <video width="640" height="360" id="@t.Id" poster="@Url.Action("Video", "Download", new { fileName = @t.Poster })" controls="controls" preload="none">
        <!-- MP4 source must come first for iOS -->
        <source src="@Url.Action("Video", "Download", new { fileName = @t.Mp4 })" type='video/mp4' />
        <!-- WebM for Firefox 4 and Opera -->
        <source src="@Url.Action("Video", "Download", new { fileName = @t.WebM })" type='video/webm' />
        <!-- OGG for Firefox 3 -->
        <source src="@Url.Action("Video", "Download", new { fileName = @t.Ogv })" type='video/ogg' />
        <!-- Fallback flash player for no-HTML5 browsers with JavaScript turned off -->
        <object width="640" height="360" type="application/x-shockwave-flash" data="@Url.Content("~/Content/flashmediaelement.swf")">       
            <param name="movie" value="@Url.Content("~/Content/flashmediaelement.swf")" /> 
            <param name="flashvars" value="controls=true&poster=@Url.Action("Video", "Download", new { fileName = @t.Poster })&file=@Url.Action("Video", "Download", new { fileName = @t.Mp4 })" />         
            <!-- Image fall back for non-HTML5 browser with JavaScript turned off and no Flash player installed -->
            <img src="@Url.Action("Video", "Download", new { fileName = @t.Poster })" width="640" height="360" alt="@t.Title" 
                title="No video playback capabilities" />
        </object>   
    </video>

我最终编写了一个HTTP处理程序来处理这些扩展,尽管Chrome的问题似乎与我的处理程序不支持范围请求有关

我使用以下博客帖子来帮助我:。解决方案(由我修改为包括内容类型以及一些基本安全性)如下所示:

    public void ProcessRequest(HttpContext context)
    {
        if (!context.Request.RequestContext.HttpContext.User.Identity.IsAuthenticated)
            context.Response.Redirect("~");
        var path =
            context.Request.RequestContext.HttpContext.Server.MapPath(
                context.Request.AppRelativeCurrentExecutionFilePath);
        long size, start, end, length, fp = 0;
        using (StreamReader reader = new StreamReader(path))
        {

            size = reader.BaseStream.Length;
            start = 0;
            end = size - 1;
            length = size;
            // Now that we've gotten so far without errors we send the accept range header
            /* At the moment we only support single ranges.
             * Multiple ranges requires some more work to ensure it works correctly
             * and comply with the spesifications: http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2
             *
             * Multirange support annouces itself with:
             * header('Accept-Ranges: bytes');
             *
             * Multirange content must be sent with multipart/byteranges mediatype,
             * (mediatype = mimetype)
             * as well as a boundry header to indicate the various chunks of data.
             */
            context.Response.AddHeader("Accept-Ranges", "0-" + size);
            context.Response.ContentType = "video/mp4";
            // header('Accept-Ranges: bytes');
            // multipart/byteranges
            // http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2

            if (!String.IsNullOrEmpty(context.Request.ServerVariables["HTTP_RANGE"]))
            {
                long anotherStart = start;
                long anotherEnd = end;
                string[] arr_split =
                    context.Request.ServerVariables["HTTP_RANGE"].Split(new char[] {Convert.ToChar("=")});
                string range = arr_split[1];

                // Make sure the client hasn't sent us a multibyte range
                if (range.IndexOf(",") > -1)
                {
                    // (?) Shoud this be issued here, or should the first
                    // range be used? Or should the header be ignored and
                    // we output the whole content?
                    context.Response.AddHeader("Content-Range", "bytes " + start + "-" + end + "/" + size);
                    throw new HttpException(416, "Requested Range Not Satisfiable");

                }

                // If the range starts with an '-' we start from the beginning
                // If not, we forward the file pointer
                // And make sure to get the end byte if spesified
                if (range.StartsWith("-"))
                {
                    // The n-number of the last bytes is requested
                    anotherStart = size - Convert.ToInt64(range.Substring(1));
                }
                else
                {
                    arr_split = range.Split(new char[] {Convert.ToChar("-")});
                    anotherStart = Convert.ToInt64(arr_split[0]);
                    long temp = 0;
                    anotherEnd = (arr_split.Length > 1 && Int64.TryParse(arr_split[1].ToString(), out temp))
                                     ? Convert.ToInt64(arr_split[1])
                                     : size;
                }
                /* Check the range and make sure it's treated according to the specs.
                 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
                 */
                // End bytes can not be larger than $end.
                anotherEnd = (anotherEnd > end) ? end : anotherEnd;
                // Validate the requested range and return an error if it's not correct.
                if (anotherStart > anotherEnd || anotherStart > size - 1 || anotherEnd >= size)
                {

                    context.Response.AddHeader("Content-Range", "bytes " + start + "-" + end + "/" + size);
                    throw new HttpException(416, "Requested Range Not Satisfiable");
                }
                start = anotherStart;
                end = anotherEnd;

                length = end - start + 1; // Calculate new content length
                fp = reader.BaseStream.Seek(start, SeekOrigin.Begin);
                context.Response.StatusCode = 206;
            }
        }
        // Notify the client the byte range we'll be outputting
        context.Response.AddHeader("Content-Range", "bytes " + start + "-" + end + "/" + size);
        context.Response.AddHeader("Content-Length", length.ToString());
        // Start buffered download
        context.Response.WriteFile(path, fp, length);
        context.Response.Flush();
    }

谢谢你的回答

我用了类似的方法:

 internal static void StreamVideo(string fullpath, HttpContextBase context)
    {
        long size, start, end, length, fp = 0;
        using (StreamReader reader = new StreamReader(fullpath))
        {

            size = reader.BaseStream.Length;
            start = 0;
            end = size - 1;
            length = size;
            // Now that we've gotten so far without errors we send the accept range header
            /* At the moment we only support single ranges.
             * Multiple ranges requires some more work to ensure it works correctly
             * and comply with the spesifications: http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2
             *
             * Multirange support annouces itself with:
             * header('Accept-Ranges: bytes');
             *
             * Multirange content must be sent with multipart/byteranges mediatype,
             * (mediatype = mimetype)
             * as well as a boundry header to indicate the various chunks of data.
             */
            context.Response.AddHeader("Accept-Ranges", "0-" + size);
            // header('Accept-Ranges: bytes');
            // multipart/byteranges
            // http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html#sec19.2

            if (!String.IsNullOrEmpty(context.Request.ServerVariables["HTTP_RANGE"]))
            {
                long anotherStart = start;
                long anotherEnd = end;
                string[] arr_split = context.Request.ServerVariables["HTTP_RANGE"].Split(new char[] { Convert.ToChar("=") });
                string range = arr_split[1];

                // Make sure the client hasn't sent us a multibyte range
                if (range.IndexOf(",") > -1)
                {
                    // (?) Shoud this be issued here, or should the first
                    // range be used? Or should the header be ignored and
                    // we output the whole content?
                    context.Response.AddHeader("Content-Range", "bytes " + start + "-" + end + "/" + size);
                    throw new HttpException(416, "Requested Range Not Satisfiable");

                }

                // If the range starts with an '-' we start from the beginning
                // If not, we forward the file pointer
                // And make sure to get the end byte if spesified
                if (range.StartsWith("-"))
                {
                    // The n-number of the last bytes is requested
                    anotherStart = size - Convert.ToInt64(range.Substring(1));
                }
                else
                {
                    arr_split = range.Split(new char[] { Convert.ToChar("-") });
                    anotherStart = Convert.ToInt64(arr_split[0]);
                    long temp = 0;
                    anotherEnd = (arr_split.Length > 1 && Int64.TryParse(arr_split[1].ToString(), out temp)) ? Convert.ToInt64(arr_split[1]) : size;
                }
                /* Check the range and make sure it's treated according to the specs.
                 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
                 */
                // End bytes can not be larger than $end.
                anotherEnd = (anotherEnd > end) ? end : anotherEnd;
                // Validate the requested range and return an error if it's not correct.
                if (anotherStart > anotherEnd || anotherStart > size - 1 || anotherEnd >= size)
                {
                    context.Response.ContentType = MimeMapping.GetMimeMapping(fullpath);
                    context.Response.AddHeader("Content-Range", "bytes " + start + "-" + end + "/" + size);
                    throw new HttpException(416, "Requested Range Not Satisfiable");
                }
                start = anotherStart;
                end = anotherEnd;

                length = end - start + 1; // Calculate new content length
                fp = reader.BaseStream.Seek(start, SeekOrigin.Begin);
                context.Response.StatusCode = 206;
            }
        }
        // Notify the client the byte range we'll be outputting
        context.Response.AddHeader("Content-Range", "bytes " + start + "-" + end + "/" + size);
        context.Response.AddHeader("Content-Length", length.ToString());
        // Start buffered download
        context.Response.WriteFile(fullpath, fp, length);
        context.Response.End();

    }

当URL被完全解析时是什么样子的?下载/Video?fileName=file.extHello,我在我的Asp.Net mvc应用程序中使用了上述代码,它似乎不适用于位于网络位置的非常大的视频。i、 e大约2GB的视频。我使用的是IIS7服务器,它似乎是从浏览器发送到IIS的第一个请求的响应得到延迟。然后视频播放后流畅。但是,如果我真的寻求,那么它将再次推迟。如果我的视频在IIS中或在IIS托管的计算机中,我看不到此问题。