使用Asp.Net WebForms + WebApi + HTML5

时间:2015-12-05 09:37:21

标签: asp.net html5 video asp.net-web-api broadcast

问题在于:

    服务器上的
  1. 有一个视频文件;
  2. 管理员在播放时运行它(视频广播开始);
  3. 用户已连接到服务器 - 必须提供给当前正在播放的视频流。实时网络直播。
  4. 为了实现这项任务,我作为文章的基础: http://www.strathweb.com/2013/01/asynchronously-streaming-video-with-asp-net-web-api/
    有效。独立地并行地为流提供视频文件。 我正在寻找。

    接下来有必要解决向多个客户广播的问题(工作中的第3段)。我读了这篇文章: http://gigi.nullneuron.net/gigilabs/streaming-data-with-asp-net-web-api-and-pushcontentstream/

    由于我必须在视频字节中提供证据 - 我将StreamWriter类替换为Stream 它适用于第一个客户端之一。

    我创建了一个网站Asp.Net WebForms + WebApi + HTML5。 网页 - 运行视频管理器并由用户查看。 WebApi为播放器提供<video>(HTML5)视频流。

    HTML5:

    <video>
        <source src="http://localhost:8080/SiteVideoStreaming/api/live/?filename=nameFile" />
    </video>
    

    WebApi控制器:

    //Controllers
    public class LiveController : ApiController
    {
        private static ConcurrentBag<Stream> clients; // List of clients who need to simultaneously deliver video data
        static string fileName = "";
    
        static LiveController()
        {
            clients = new ConcurrentBag<Stream>();
            WriteToStream(); // The first call - start to play a video file
        }
    
        [HttpGet]
        public HttpResponseMessage Subscribe(string filename)
        {
            fileName = HostingEnvironment.MapPath("~/Videos/") + filename;
    
            var response = Request.CreateResponse();
            response.Content = new PushStreamContent((a, b, c) => { OnStreamAvailable(a, b, c); }, "video/mp4");
            return response;
        }
    
    
        private void OnStreamAvailable(Stream stream, HttpContent content, TransportContext context)
        {
            clients.Add(stream); // Add new client
        }
    
        //Class record a video file into a streams
        public async static void WriteToStream()
        {
            var buffer = new byte[65536];
    
            using (var video = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                var length = (int)video.Length;
                var bytesRead = 1;
    
                while (length > 0 && bytesRead > 0)
                {
                    bytesRead = video.Read(buffer, 0, Math.Min(length, buffer.Length));
    
                    foreach (var client in clients)// Each client in turn we return video data
                    {
                        try
                        {
                            await client.WriteAsync(buffer, 0, bytesRead); // ERROR - here !!! when you connect a second client
                            await client.FlushAsync();
                        }
                        catch (Exception ex)
                        {
                            Stream ignore;
                            clients.TryTake(out ignore);
                        }
                    }
    
                    length -= bytesRead;
                }
            }
        }
    }
    

    如果请求首先来自一个客户端 - 则是视频。工作。 如果来自第二个客户端的请求 - 当你尝试开始给他一个流错误时会发生。 在这个连接drop和第一个客户端。

    错误如下:

      

    [System.Web.HttpException] = {“远程主机关闭了连接。   错误代码是0x800704CD。“}

    据我所知,在互联网上搜索后:

      

    0x800704CD“在不存在的网络上尝试了一项操作   连接“。

    告诉我,我做得不对? 谢谢。

1 个答案:

答案 0 :(得分:0)

我这样做了。 我用这个控制器:

public class VideoController : ApiController
{

    // GET api/<controller>
    public HttpResponseMessage Get(string filename)
    {
        if (filename == null)
            return new HttpResponseMessage(HttpStatusCode.BadRequest);

        string filePath = HostingEnvironment.MapPath("~/Videos/") + filename;

        if (Request.Headers.Range != null)
        {
            //Range Specifc request: Stream video on wanted range.
            try
            {
                //NOTE: ETag calculation only with file name is one approach (Not the best one though - GUIDs or DateTime is may required in live applications.).
                Encoder stringEncoder = Encoding.UTF8.GetEncoder();
                byte[] stringBytes = new byte[stringEncoder.GetByteCount(filePath.ToCharArray(), 0, filePath.Length, true)];
                stringEncoder.GetBytes(filePath.ToCharArray(), 0, filePath.Length, stringBytes, 0, true);
                MD5CryptoServiceProvider MD5Enc = new MD5CryptoServiceProvider();
                string hash = BitConverter.ToString(MD5Enc.ComputeHash(stringBytes)).Replace("-", string.Empty);

                HttpResponseMessage partialResponse = Request.CreateResponse(HttpStatusCode.PartialContent);
                partialResponse.Headers.AcceptRanges.Add("bytes");
                partialResponse.Headers.ETag = new EntityTagHeaderValue("\"" + hash + "\"");

                var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
                partialResponse.Content = new ByteRangeStreamContent(stream, Request.Headers.Range, new MediaTypeHeaderValue("video/mp4"));
                return partialResponse;
            }
            catch (Exception ex)
            {
                return new HttpResponseMessage(HttpStatusCode.InternalServerError);
            }
        }
        else
        {
            return new HttpResponseMessage(HttpStatusCode.RequestedRangeNotSatisfiable);
        }
    }
}

在客户端 - 我通过SignalR技术运行<video>视频播放器。