Direct video from Asp.Net site



  • Hey!

    The challenge is:

    • 1 - There's a video file on the server;
    • 2 - the administrator starts it to lose. Video coverage;
    • 3 - Users connected to the server - flow The video that is now being reproduced. Direct broadcast Real time.

    To accomplish this task, I've tried a variant: http://www.strathweb.com/2013/01/asynchronously-streaming-video-with-asp-net-web-api/ It worked. Slipped the video file independently and parallelly. I looked further.

    The problem of multi-customer transmission (para. 3 in the mission) was further addressed. Took this article: http://gigi.nullneuron.net/gigilabs/streaming-data-with-asp-net-web-api-and-pushcontentstream/

    Since I have to give this video byte, I replaced StreamWriter's class on Stream. It works for one first client.

    I made the Asp.Net WebForms + WebApi + HTML5. The website is for the video administrator to launch and search users. WebApi provides a video flow for the player (HTML5).

    HTML5:

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

    WebApi:

    public class LiveController : ApiController
    {
        private static ConcurrentBag<Stream> clients; // Список клиентов, которым надо одновременно отдавать видео данные
        static string fileName = "";
    
    static LiveController()
    {
        clients = new ConcurrentBag&lt;Stream&gt;();
        WriteToStream(); // Первое обращение - запуск видео файла на воспроизведение
    }
    
    [HttpGet]
    public HttpResponseMessage Subscribe(string filename)
    {
        fileName = HostingEnvironment.MapPath("~/Videos/") + filename;
    
        var response = Request.CreateResponse();
        response.Content = new PushStreamContent((a, b, c) =&gt; { OnStreamAvailable(a, b, c); }, "video/mp4");
        return response;
    }
    
    
    private void OnStreamAvailable(Stream stream, HttpContent content, TransportContext context)
    {
        clients.Add(stream); // Add new client
    }
    
    //Класс записи видео файла в поток
    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 &gt; 0 &amp;&amp; bytesRead &gt; 0)
            {
                bytesRead = video.Read(buffer, 0, Math.Min(length, buffer.Length));
    
                foreach (var client in clients)// Кажому клиенту отдаём видео данные
                {
                    try
                    {
                        await client.WriteAsync(buffer, 0, bytesRead);// ERROR - здесь ошибка!!! 
                        await client.FlushAsync();
                    }
                    catch (Exception ex)
                    {
                        Stream ignore;
                        clients.TryTake(out ignore);
                    }
                }
    
                length -= bytesRead;
            }
        }
    }
    

    }

    If the first request came from one client, the video is given, it works.
    If a second client is involved, a mistake is made in trying to start giving up the flow.
    The first client's connection is also falling.

    Mistake:

    [System.Web.HtpException] = {The remote host has broken the connection. Code
    mistakes: 0x800704CD."

    As I realized after searching the Internet, it's:

    0x800704CD "An operation was attempted on a nonexistent network
    connection." Attempted to perform an operation for a non-existent
    network connections

    Presumption of a browser or a diaper blows the connection or the PushStreamContent class itself does not serve more than one compound?

    What am I doing wrong?
    Thank you.



  • I did it. Used such a controller:

    public class VideoController : ApiController
    {
    
    // GET api/&lt;controller&gt;
    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);
        }
    }
    

    }

    On the client's side, he runs a video player via SignalR technology.




Suggested Topics

  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2