2012-08-25 47 views
4

我有一段代码,我一直在努力为视频提供服务。代码如下:.net MVC流媒体MP4到iDevice问题

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视频,并立即开始播放。

有没有什么特别的我需要做的,我错过了命令使我的方法兼容iDevices?任何帮助,将不胜感激。

回答

2

感谢您的回复,并给出的信息是非常有帮助的。最后,我使用以下solution来实现字节范围请求。

2

要在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> 

如果还可以轻松地应用您的自定义逻辑,例如授权或自定义视频文件源,通过创建您的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处理程序,我不确定它对您的情况有多大影响,但我希望它能帮助您!