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<Stream>(); WriteToStream(); // Первое обращение - запуск видео файла на воспроизведение } [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 } //Класс записи видео файла в поток 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)// Кажому клиенту отдаём видео данные { 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 connectionsPresumption 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/<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); } }
}
On the client's side, he runs a video player via SignalR technology.