使用MVC FileStream播放视频文件的问题

时间:2012-08-09 09:07:24

标签: asp.net-mvc video-streaming html5-video mediaelement.js

我正在尝试使用以下代码检索要播放给用户的视频文件:

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

            using (FileStream stream = new FileStream(clipLocation, FileMode.Open))
            {
                FileStreamResult fsResult = new FileStreamResult(stream, "video/mp4");
                VideoResult result = new VideoResult(ReadFully(fsResult.FileStream), "video/mp4");

                return result;
            }
        }
        else
        {
            return null;
        }
    }

    private static byte[] ReadFully(Stream input)
    {
        byte[] buffer = new byte[32 * 1024];
        using (MemoryStream ms = new MemoryStream())
        {
            int read;
            while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
            {
                ms.Write(buffer, 0, read);
            }
            return ms.ToArray();
        }
    }
}

为了向客户端显示我正在使用媒体元素:

<!-- Video Player Here -->
<video width="640" height="360" poster="@Url.Content(string.Format("~/Videos/{0}_2.jpg", Model.VideoID))" controls="controls" preload="none">
<!-- MP4 for Safari, IE9, iPhone, iPad, Android, and Windows Phone 7 -->
<source type="video/mp4" src="@Url.Action("GetMP4Video", "Video", new { videoID = Model.VideoID })" />
<!-- Flash fallback for non-HTML5 browsers without JavaScript -->
    <object width="320" height="240" type="application/x-shockwave-flash" data="@Url.Content("~/Scripts/ME/flashmediaelement.swf")">
        <param name="movie" value="@Url.Content("~/Scripts/ME/flashmediaelement.swf")" />
        <param name="flashvars" value="controls=true&file=@Url.Action("GetMP4Video", "Video", new { videoID = Model.VideoID })" />
        <!-- Image as a last resort -->
        <img src="myvideo.jpg" width="320" height="240" title="No video playback capabilities" />
    </object>
</video>

问题是该文件似乎没有播放或至少不一致。在视频中寻找也似乎不能正常工作。我想我的问题是这是一种向用户提供视频的可接受方式吗?如果是这样,我错了什么?我认为重要的是我对视频非常陌生,而且我正在学习。任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:1)

这对我有用。改编自here

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

    }

答案 1 :(得分:0)

是的,您正在尝试将网络服务器提供的mp4文件放入嵌入HTML文件的播放器中,并且无法正常播放(除非文件非常小或者您的互联网速度非常快)连接,以便文件快速下载到浏览器的临时文件夹。

要正确播放视频文件,请按照以下任何步骤操作。

  1. 使用Windows Media Server / Flash媒体服务器。通过Windows Media Encoder或Flash媒体编码器将您的网络摄像头推送到服务器,并使用服务器实时链接通过任何合适的播放器(如jwplayer)链接到您的网站。

  2. 使用Windows Media Encoder将网络摄像头流式传输给任何不涉及服务器的人。当您的编码器启动时,您将获得一个URL来查看您的流,您可以使用该网址在您的网站上发布。

  3. 使用第三方流媒体服务,他们为您提供发布点来发布您的网络摄像头流,并使用他们提供的链接在您的网站上显示。 (通过LiveStream查看brighcove或Mogulus

  4. 希望这有帮助。