如何通过互联网将视频从 PC 流式传输到 Windows Phone 8 手机

问题描述:

我开始创建一个应用程序,其中很大一部分依赖于从 PC 到 WP8 手机的流式视频(少数视频流).

I am starting to create an application of which large part relies on streaming Video(few video streams) from a PC to a WP8 mobile phone.

  • 我必须从以下视频格式中选择一种:Motion JPEGMPEG-4H.264.

应该以某种方式保护流,这样未经授权的人就很难接收或解码它.

The stream should be somehow protected so unauthorized person would have hard time to receive or maybe decode it.

问题是:(1.)如何将上述格式的视频从 PC 流式传输到 WP8 手机以及 (2) 如何合理保护这种传输?

The question is: (1.)How to stream video of above named formats from a PC to WP8 phone and (2)how to reasonably secure this transmission?

PC-server 部分将使用 C# 编写.

The PC-server part will be written in C#.

基础设施

由于这是一个小项目,您可以使用 IIS 设置您的家用 PC,并直接从您自己的家用服务器流式传输内容.

Infrastructure

Since it's a small project you can set up your home PC with IIS and stream the content directly from your own home server.

在 MP4 文件中使用 H.264 编码的视频很重要,因为几乎所有设备都支持这种格式.

It's important that you use H.264-encoded videos in MP4 files because it's THE format which is supported on almost every device out there.

内容将通过 HTTP 流式传输,并可在应用或浏览器中查看.

Content will be streamed over HTTP and can be viewed in app or in browser.

由于这只是一个您将要实施的小规模系统,因此您可以忽略很多安全部分而专注于首先获取视频流...您仍然需要一个关于您存储的视频及其位置的数据库位于您的硬盘上,我的建议是将所有视频存储在一个位置,例如 C:\MP4\

Since it's just a small scale system you will be implementing, you can disregard a lot of the security part and concentrate on getting the video streaming first... You will still need a database concerning what videos you have stored and where they are located on your hard drive, my suggestion would be to store all the videos in one location such as C:\MP4\

接下来是设置 IIS,您可以使用您的 IP 地址,也可以购买一个域并将其 A 记录更改为指向您的 IP.

Next part would be to setup IIS, you can either use your IP Address, or buy a domain and change its A Records to point to your IP.

然后,您可以创建一个带有名为 Videos 的表的小型数据库,列标记为 VideoID 和 FilePath,并用您的视频填充数据库.

You can then create a small database with a table named Videos, have columns labeled VideoID and FilePath and fill the database with your videos.

数据库完成后,您可以继续编写一个通用处理程序来处理视频流.

After the database is done, you can proceed to writing a generic handler which will handle the streaming of the video.

创建一个名为 Watch.ashx 的新 .ashx 文件,现在无论您想观看哪个视频,您都可以通过像这样将 videoid 参数传递给 Watch.ashx 来实现...

Create a new .ashx file called Watch.ashx, now whichever video you wish to watch, you'll soon be able to do so by passing the videoid parameter to Watch.ashx like this...

http://127.0.0.1/Watch.ashx?v=VIDEOID

为了让您入门,我在下面列出了整个课程.

I've included the entire class below to get you started.

<%@ WebHandler Language="C#" Class="Watch" %>

using System;
using System.Globalization;
using System.IO;
using System.Web;

public class Watch : IHttpHandler {

    public void ProcessRequest(HttpContext context)
    {
        // Get the VideoID from the requests `v` parameters.
        var videoId = context.Request.QueryString["v"];
        
        /* With the videoId you'll need to retrieve the filepath 
        /  from the database. You'll need to replace the method 
        /  below with your own depending on whichever
        /  DBMS you decide to work with.
        *////////////////////////////////////////////////////////
        var videoPath = DataBase.GetVideoPath(videoId);
        
        // This method will stream the video.
        this.RangeDownload(videoPath, context);
    }

    
    private void RangeDownload(string fullpath, HttpContext context)
    {
        long size;
        long start;
        long theend;
        long length;
        long fp = 0;
        using (StreamReader reader = new StreamReader(fullpath))
        {
            size = reader.BaseStream.Length;
            start = 0;
            theend = size - 1;
            length = size;

            context.Response.AddHeader("Accept-Ranges", "0-" + size);

            if (!string.IsNullOrEmpty(context.Request.ServerVariables["HTTP_RANGE"]))
            {
                long anotherStart;
                long anotherEnd = theend;
                string[] arrSplit = context.Request.ServerVariables["HTTP_RANGE"].Split('=');
                string range = arrSplit[1];

                if ((range.IndexOf(",", StringComparison.Ordinal) > -1))
                {
                    context.Response.AddHeader("Content-Range", "bytes " + start + "-" + theend + "/" + size);
                    throw new HttpException(416, "Requested Range Not Satisfiable");
                }

                if ((range.StartsWith("-")))
                {
                    anotherStart = size - Convert.ToInt64(range.Substring(1));
                }
                else
                {
                    arrSplit = range.Split('-');
                    anotherStart = Convert.ToInt64(arrSplit[0]);
                    long temp;
                    if ((arrSplit.Length > 1 && Int64.TryParse(arrSplit[1], out temp)))
                    {
                        anotherEnd = Convert.ToInt64(arrSplit[1]);
                    }
                    else
                    {
                        anotherEnd = size;
                    }
                }

                anotherEnd = (anotherEnd > theend) ? theend : anotherEnd;

                if ((anotherStart > anotherEnd | anotherStart > size - 1 | anotherEnd >= size))
                {
                    context.Response.AddHeader("Content-Range", "bytes " + start + "-" + theend + "/" + size);
                    throw new HttpException(416, "Requested Range Not Satisfiable");
                }

                start = anotherStart;
                theend = anotherEnd;

                length = theend - start + 1;

                fp = reader.BaseStream.Seek(start, SeekOrigin.Begin);
                context.Response.StatusCode = 206;
            }
        }

        context.Response.ContentType = "video/mp4";
        context.Response.AddHeader("Content-Range", "bytes " + start + "-" + theend + "/" + size);
        context.Response.AddHeader("Content-Length", length.ToString(CultureInfo.InvariantCulture));

        context.Response.TransmitFile(fullpath, fp, length);
        context.Response.End();
    }
    
    public bool IsReusable
    {
        get
        {
            return false;
        }
    }

}

我根据cipto0382的工作改编了上面的类,原始可以在这里找到:

I adapted the class above from cipto0382's work, the original can be found here:

http://blogs.visigo.com/chriscoulson/easy-handling-of-http-range-requests-in-asp-net/

在离别笔记中,为了节省带宽,我强烈建议您从 IIS 应用程序库下载媒体服务,您可以限制视频传输的比特率,以免它占用您的整个带宽.

On parting notes, to save on bandwidth, I highly recommend that you download Media Services from the IIS Appplication Gallery, you can throttle the bitrate that videos are transmitted so that it doesn't eat up your entire bandwidth.