从ASP.NET MVC2即成视频文件到iPhone [英] Serve video file to iPhone from ASP.NET MVC2

查看:120
本文介绍了从ASP.NET MVC2即成视频文件到iPhone的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图从ASP.NET MVC视频文件用于iPhone客户端。视频格式正确,如果我有它在可公开访问的web目录下正常工作。

I'm attempting to serve video files from ASP.NET MVC to iPhone clients. The video is formatted properly, and if I have it in a publicly accessible web directory it works fine.

这是我读过的核心问题是,iPhone需要你有一份简历准备下载环境,让您筛选字节通过HTTP头的范围。我认为这是为了让用户可以通过视频快进。

The core issue from what I've read is that the iPhone requires you to have a resume-ready download environment that lets you filter your byte ranges through HTTP headers. I assume this is so that users can skip forward through videos.

在服务与MVC文件,不存在这些头。我试着模拟它,但没有运气。我们这里有IIS6,我无法做很多头操作的。 ASP.NET将在我抱怨说: 此操作需要IIS综合管道模式。

When serving files with MVC, these headers do not exist. I've tried to emulate it, but with no luck. We have IIS6 here and I'm unable to do many header manipulations at all. ASP.NET will complain at me saying "This operation requires IIS integrated pipeline mode."

升级是不是一种选择,而我不能将文件移动到公共网络的份额。我感到我们的环境的限制,但我正在寻找解决方案,不过。

Upgrading isn't an option, and I'm not allowed to move the files to a public web share. I feel limited by our environment but I'm looking for solutions nonetheless.

下面是我想要在短期做一些样品code ...

Here is some sample code of what I'm trying to do in short...

public ActionResult Mobile(string guid = "x")
{
    guid = Path.GetFileNameWithoutExtension(guid);
    apMedia media = DB.apMedia_GetMediaByFilename(guid);
    string mediaPath = Path.Combine(Transcode.Swap_MobileDirectory, guid + ".m4v");

    if (!Directory.Exists(Transcode.Swap_MobileDirectory)) //Make sure it's there...
        Directory.CreateDirectory(Transcode.Swap_MobileDirectory);

    if(System.IO.File.Exists(mediaPath))
        return base.File(mediaPath, "video/x-m4v");

    return Redirect("~/Error/404");
}

我知道我需要做这样的事情,但是我无法做它在.NET MVC。 <一href=\"http://dotnetslackers.com/articles/aspnet/Range-Specific-Requests-in-ASP-NET.aspx\">http://dotnetslackers.com/articles/aspnet/Range-Specific-Requests-in-ASP-NET.aspx

下面是一个HTTP响应头的作品的一个例子:

Here is an example of an HTTP response header that works:

Date    Mon, 08 Nov 2010 17:02:38 GMT
Server  Apache
Last-Modified   Mon, 08 Nov 2010 17:02:13 GMT
Etag    "14e78b2-295eff-4cd82d15"
Accept-Ranges   bytes
Content-Length  2711295
Content-Range   bytes 0-2711294/2711295
Keep-Alive  timeout=15, max=100
Connection  Keep-Alive
Content-Type    text/plain

这是一个不的例子(这是从.NET)

And here is an example of one that doesn't (this is from .NET)

Server  ASP.NET Development Server/10.0.0.0
Date    Mon, 08 Nov 2010 18:26:17 GMT
X-AspNet-Version    4.0.30319
X-AspNetMvc-Version 2.0
Content-Range   bytes 0-2711294/2711295
Cache-Control   private
Content-Type    video/x-m4v
Content-Length  2711295
Connection  Close

任何想法?谢谢你。

Any ideas? Thank you.

推荐答案

更​​新:这是现在的codePLEX <一个项目/ A>

UPDATE: This is now a project on CodePlex.

好吧,我得到它的工作我的本地测试站上,我可以流视频到我的iPad。这是一个有点脏,因为这是一个有点难度比我预期,现在,它的工作,我没有清理干净,此刻的时间。关键零部件:

Okay, I got it working on my local testing station and I can stream videos to my iPad. It's a bit dirty because it was a little more difficult than I expected and now that it's working I don't have the time to clean it up at the moment. Key parts:

操作过滤器:

public class ByteRangeRequest : FilterAttribute, IActionFilter
{
    protected string RangeStart { get; set; }
    protected string RangeEnd { get; set; }

    public ByteRangeRequest(string RangeStartParameter, string RangeEndParameter)
    {
        RangeStart = RangeStartParameter;
        RangeEnd = RangeEndParameter;
    }

    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (filterContext == null)
            throw new ArgumentNullException("filterContext");

        if (!filterContext.ActionParameters.ContainsKey(RangeStart))
            filterContext.ActionParameters.Add(RangeStart, null);
        if (!filterContext.ActionParameters.ContainsKey(RangeEnd))
            filterContext.ActionParameters.Add(RangeEnd, null);

        var headerKeys = filterContext.RequestContext.HttpContext.Request.Headers.AllKeys.Where(key => key.Equals("Range", StringComparison.InvariantCultureIgnoreCase));
        Regex rangeParser = new Regex(@"(\d+)-(\d+)", RegexOptions.Compiled);

        foreach(string headerKey in headerKeys)
        {
            string value = filterContext.RequestContext.HttpContext.Request.Headers[headerKey];
            if (!string.IsNullOrEmpty(value))
            {
                if (rangeParser.IsMatch(value))
                {
                    Match match = rangeParser.Match(value);

                    filterContext.ActionParameters[RangeStart] = int.Parse(match.Groups[1].ToString());
                    filterContext.ActionParameters[RangeEnd] = int.Parse(match.Groups[2].ToString());
                    break;
                }
            }
        }
    }

    public void OnActionExecuted(ActionExecutedContext filterContext)
    {
    }
}

根据FileStreamResult定制结果:

Custom Result based on FileStreamResult:

public class ContentRangeResult : FileStreamResult
{
    public int StartIndex { get; set; }
    public int EndIndex { get; set; }
    public long TotalSize { get; set; }
    public DateTime LastModified { get; set; }

    public FileStreamResult(int startIndex, int endIndex, long totalSize, DateTime lastModified, string contentType, Stream fileStream)
        : base(fileStream, contentType)
    {
        StartIndex = startIndex;
        EndIndex = endIndex;
        TotalSize = totalSize;
        LastModified = lastModified;
    }

    public override void ExecuteResult(ControllerContext context)
    {
        if (context == null)
            throw new ArgumentNullException("context");

        HttpResponseBase response = context.HttpContext.Response;
        response.ContentType = this.ContentType;
        response.AddHeader(HttpWorkerRequest.GetKnownResponseHeaderName(HttpWorkerRequest.HeaderContentRange), string.Format("bytes {0}-{1}/{2}", StartIndex, EndIndex, TotalSize));
        response.StatusCode = 206;

        WriteFile(response);
    }

    protected override void WriteFile(HttpResponseBase response)
    {
        Stream outputStream = response.OutputStream;
        using (this.FileStream)
        {
            byte[] buffer = new byte[0x1000];
            int totalToSend = EndIndex - StartIndex;
            int bytesRemaining = totalToSend;
            int count = 0;

            FileStream.Seek(StartIndex, SeekOrigin.Begin);

            while (bytesRemaining > 0)
            {
                if (bytesRemaining <= buffer.Length)
                    count = FileStream.Read(buffer, 0, bytesRemaining);
                else
                    count = FileStream.Read(buffer, 0, buffer.Length);

                outputStream.Write(buffer, 0, count);
                bytesRemaining -= count;
            }
        }
    }      
}

我的MVC的行动:

My MVC action:

[ByteRangeRequest("StartByte", "EndByte")]
public FileStreamResult NextSegment(int? StartByte, int? EndByte)
{
    FileStream contentFileStream = System.IO.File.OpenRead(@"C:\temp\Gets.mp4");
    var time = System.IO.File.GetLastWriteTime(@"C:\temp\Gets.mp4");
    if (StartByte.HasValue && EndByte.HasValue)
        return new ContentRangeResult(StartByte.Value, EndByte.Value, contentFileStream.Length, time, "video/x-m4v", contentFileStream);

    return new ContentRangeResult(0, (int)contentFileStream.Length, contentFileStream.Length, time, "video/x-m4v", contentFileStream);
}

我真的希望这会有所帮助。我花了很多时间在这!你可能想尝试的一件事是删除片段,直到它再次打破。这将是很好,看看ETag的东西,修改日期等,都可以删除。我只是没有此刻的时间。

I really hope this helps. I spent a LOT of time on this! One thing you might want to try is removing pieces until it breaks again. It would be nice to see if the ETag stuff, modified date, etc. could be removed. I just don't have the time at the moment.

编程快乐!

这篇关于从ASP.NET MVC2即成视频文件到iPhone的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆