2

我正在从MVC3网站提供视频,控制器操作返回视频返回FilePathResult,并且当试图在浏览器中播放时,我看到一些令人沮丧的问题,无论我使用video.js还是mediaelement.js。来自MVC3操作的HTML5视频无法正常工作

  • 铬不会让你使用进度条改变位置,也不允许你可以重播视频一旦完成
  • 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&[email protected]("Video", "Download", new { fileName = @t.Poster })&[email protected]("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> 
+0

做的网址是什么样子时,他们完全解析? – heff 2012-08-08 01:09:01

+0

Download/Video?fileName = file.ext – damienc88 2012-08-08 05:52:51

回答

3

我最后写一个HTTP处理程序来处理这些扩展,但它似乎Chrome的问题是与我的处理程序不支持这样做范围请求。

我用以下博文来帮助我:http://blogs.visigo.com/chriscoulson/easy-handling-of-http-range-requests-in-asp-net/。解决方案(由我修改以包含内容类型以及一些基本安全性)如下:

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(); 
    } 
+0

你好,我在我的Asp.Net mvc应用程序中使用了上面的代码,它似乎不适用于那些位于网络位置的非常大的视频。即大约2GB的视频。我正在使用IIS7服务器,它似乎是从浏览器发送到IIS的第一个请求发送延迟的响应。然后视频播放顺利。但如果我确实寻求,那么它会再次延迟。如果我的视频位于IIS内部或位于IIS托管的计算机中,我看不到此问题。 – lsc 2016-03-03 09:57:51

0

感谢您的回答!

我用类似的东西:

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(); 

    } 
相关问题