.net MVCstreamMP4到iDevice问题

对于我一直在为video服务的一段代码,我遇到了一些问题。 代码如下:

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加载页面时,它只是显示带有一行的播放图标,表示它无法播放。 我尝试将mp4video的源代码更改为直接链接到mp4video,并立即开始播放。

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

要使您的video在iOS设备上可以播放,您需要实现对字节范围 (或部分 )请求的支持。 这些types的请求不允许下载整个内容,但部分地按块(典型的stream式传输 )进行分块。 这是iOS设备如何在页面上播放video的唯一方式。

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

您可以find几个ASP.NET处理程序的实现,它们可以处理Internet上的部分请求。 我build议为此使用StaticFileHandler :易于安装,并具有开箱即用的cachingfunction。 它也可以通过Nuget交付,但是这个包叫做Talifun.Web 。

要configurationStaticFileHandler,请在web.config中为mp4文件注册处理程序,并将其configuration在单独的configuration部分中:

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

如果还可以通过创buildASP.NET处理程序并直接调用StaticFileManager来轻松应用自定义逻辑,例如授权或自定义video文件源。

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

此外,你可以看看斯科特·米切尔关于部分请求细节的文章 ,并使用它的作者编写的处理程序:它为我工作,但它没有cachingfunction。

@whyleee是正确的。 我不能说StaticFileHandler有多好,但是我自己也一直在面对同样的问题,这让我疯狂。 RequestResponse头文件中必须包含Range头才能正常工作。 例如,稍微修改一下你的代码,用我自己的Handler的一些代码,看起来像这样(记住,这是使用.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处理程序的代码,所以我不知道它是多less适用于您的情况,但我希望它可以帮助你!

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