【问题标题】:.net MVC Streaming MP4 to iDevice issue.net MVC 将 MP4 流式传输到 iDevice 问题
【发布时间】:2012-08-20 22:55:10
【问题描述】:

我一直在编写的一段用于提供视频的代码有点问题。代码如下:

public ResumingFileStreamResult GetMP4Video(string videoID)
    {
        if (User.Identity.IsAuthenticated)
        {
            string clipLocation = string.Format("{0}\\Completed\\{1}.mp4", ConfigurationManager.AppSettings["VideoLocation"].ToString(), videoID);

            FileStream fs = new FileStream(clipLocation, FileMode.Open, FileAccess.Read);

            ResumingFileStreamResult fsr = new ResumingFileStreamResult(fs, "video/mp4");

            return fsr;
        }
        else
        {
            return null;
        }
    }

这是我的 HTML 代码:

<video controls preload poster="@Url.Content(string.Format("~/Videos/{0}_2.jpg", Model.VideoID))">
    <source src="@Url.Action("GetMP4Video", "Video", new { videoID = Model.VideoID })" type="video/mp4" />
    <source src="@Url.Action("GetWebMVideo", "Video", new { videoID = Model.VideoID })" type="video/webm" />

        <object id="flowplayer" data="@Url.Content("~/Scripts/FlowPlayer/flowplayer-3.2.14.swf")" type="application/x-shockwave-flash" width="640" height="360">
            <param name="movie" value="@Url.Content("~/Scripts/FlowPlayer/flowplayer-3.2.14.swf")" />
            <param name="allowfullscreen" value="true" />
            <param name="flashvars" value="config={'playlist':['@Url.Content(string.Format("~/Videos/{0}_2.jpg", Model.VideoID))',{'url':'@Url.Action("GetMP4Video", "Video", new { videoID = Model.VideoID })','autoPlay':false}]}" />
        </object>
</video>

我的问题是这个设置似乎在我桌面上的所有浏览器中都可以正常工作,但是当我尝试使用我的 iPad 或 iPhone 加载页面时,它只会显示播放图标,其中有一条线表示它无法播放。我尝试将 mp4 视频的源更改为指向 mp4 视频的直接链接,然后 iPad 立即开始播放。

为了使我的方法与 iDevices 兼容,我是否需要做一些我错过的特别事情?对此的任何帮助将不胜感激。

【问题讨论】:

    标签: asp.net .net ios asp.net-mvc html


    【解决方案1】:

    要使您的视频可在 iOS 设备上播放,您需要实现对字节范围(或部分)请求的支持。这些类型的请求允许下载不是全部内容,而是逐块下载部分内容(典型的流式传输)。这是 iOS 设备在页面上获取和播放视频的唯一方式。

    部分请求使用Range 标头告诉服务器下一个块的位置和大小。另一端的服务器以206 Partial Content 响应并请求块内容。

    您可以找到几种 ASP.NET 处理程序的实现,它们可以处理 Internet 中的部分请求。我建议为此使用 StaticFileHandler:易于安装,并且还具有开箱即用的缓存功能。它也可以通过 Nuget 交付,但包裹名为Talifun.Web

    要配置 StaticFileHandler,请在 web.config 中为 mp4 文件注册处理程序,并在单独的配置部分进行配置:

    <configuration>
      <configSections>
        <section name="StaticFileHandler" type="Talifun.Web.StaticFile.Config.StaticFileHandlerSection, Talifun.Web" requirePermission="false" allowDefinition="MachineToApplication"/>
      </configSections>
    
      <StaticFileHandler webServerType="NotSet">
        <!-- The defaults to use when an extension is found that does not have a specific rule  -->
        <fileExtensionDefault name="Default" serveFromMemory="true" maxMemorySize="100000" compress="true"/>
        <!-- Specific rules for extension types -->
        <fileExtensions>
            <fileExtension name="VideoStaticContent" extension="3gp, 3g2, asf, avi, dv, flv, mov, mp4, mpg, mpeg, wmv" serveFromMemory="true" maxMemorySize="100000" compress="false"/>
        </fileExtensions>
      </StaticFileHandler>
    
      <system.webServer>
        <handlers>
          <add name="StaticContentHandler" verb="GET,HEAD" path="*.mp4" type="Talifun.Web.StaticFile.StaticFileHandler, Talifun.Web"/>
        </handlers>
      </system.webServer>
    </configuration>
    

    If 还可以通过创建 ASP.NET 处理程序并直接调用 StaticFileManager 来轻松应用您的自定义逻辑,例如授权或自定义视频文件源。

    public class MyOwnVideoHandler : IHttpHandler
    {
        public void ProcessRequest(HttpContext context)
        {
            // Authorization or any other stuff.
            ...
    
            // Get file from your storage.
            FileInfo file = ...;
    
            // Serve the file with StaticFileHandler.
            StaticFileManager.Instance.ProcessRequest(new HttpContextWrapper(context), file);
        }
    }
    

    此外,您可以查看Scott Mitchell's article about partial requests 了解详细信息并使用其作者编写的处理程序:它对我有用,但它没有缓存功能。

    【讨论】:

      【解决方案2】:

      @whyleee 是正确的。我不能说 StaticFileHandler 有多好,但我自己也遇到过同样的问题,这让我发疯。 Range 标头必须包含在 RequestResponse 标头中才能正常工作。例如,使用我自己的处理程序中的一些代码对您的代码进行轻微修改,看起来像这样(请记住,这是使用 .ashx 处理程序):

      //First, accept Range headers.
      context.Response.AddHeader("Accept-Ranges", "bytes")
      
      //Then, read all of the bytes from the file you are requesting.
      Dim file_info As New System.IO.FileInfo(clipLocation)
      Dim bytearr As Byte() = File.ReadAllBytes(file_info.FullName)
      
      //Then, you will need to check for a range header, and then serve up a 206 Partial Content status code in your response.
      Dim startbyte As Integer = 0
      If Not context.Request.Headers("Range") Is Nothing Then
          //Get the actual byte range from the range header string, and set the starting byte.
          Dim range As String() = context.Request.Headers("Range").Split(New Char() {"="c, "-"c})
          startbyte = Convert.ToInt64(range(1))
      
          //Set the status code of the response to 206 (Partial Content) and add a content range header.
          context.Response.StatusCode = 206
          context.Response.AddHeader("Content-Range", String.Format(" bytes {0}-{1}/{2}", startbyte, bytearr.Length - 1, bytearr.Length))
      End If
      
      //Finally, write the video file to the output stream, starting from the specified byte position.
      context.Response.OutputStream.Write(bytearr, startbyte, bytearr.Length - startbyte)
      

      正如我所说,这是 .ashx 处理程序的代码,所以我不确定它在多大程度上适用于您的情况,但我希望它对您有所帮助!

      【讨论】:

        【解决方案3】:

        感谢您的回复,所提供的信息非常有帮助。最后我使用了下面的solution 来实现字节范围请求。

        【讨论】:

        • 更新了链接
        • 太棒了!谢谢。
        猜你喜欢
        • 2016-07-22
        • 1970-01-01
        • 2017-02-16
        • 1970-01-01
        • 1970-01-01
        • 2014-10-29
        • 2011-12-02
        • 1970-01-01
        • 2012-07-02
        相关资源
        最近更新 更多