Recently, a client reached out to me that their video streaming wouldn’t allow for seeking (fast-forward & rewind). Not knowing a lot about streaming, I did some google searching and found out that if the API is not setup to support seeking, then it will not work.
I found a great starting point for this:
https://www.codeproject.com/Articles/820146/HTTP-Partial-Content-In-ASP-NET-Web-API-Video
Basically, the browser will request various seek-points in the video and the endpoint must be able to handle this and return the requested chunks of media. The requests will send a range header value that the API must use to return the proper spot in the video. Also, the endpoint must set the status code to “Partial Content”.
I refactored the code a bit and created this Streamer class:
class FileStreamer { public FileInfo FileInfo { get; set; } public long Start { get; set; } public long End { get; set; } public async Task WriteToStream(Stream outputStream, HttpContent content, TransportContext context) { try { var buffer = new byte[65536]; using (var video = FileInfo.OpenRead()) { if (End == -1) { End = video.Length; } var position = Start; var bytesLeft = End - Start + 1; video.Position = Start; while (position <= End) { var bytesRead = video.Read(buffer, 0, (int) Math.Min(bytesLeft, buffer.Length)); await outputStream.WriteAsync(buffer, 0, bytesRead); position += bytesRead; bytesLeft = End - position + 1; } } } catch (Exception ex) { // fail silently } finally { outputStream.Close(); } } }
It takes the file info and the start and end positions, in bytes, to return.
Now, in the controller, we must do a few things:
Sample controller code:
public HttpResponseMessage Get(string filename) { var filePath = GetFilePath(filename); if (!File.Exists(filePath)) return new HttpResponseMessage(HttpStatusCode.NotFound); var response = Request.CreateResponse(); response.Headers.AcceptRanges.Add("bytes"); var streamer = new FileStreamer(); streamer.FileInfo = new FileInfo(filePath); response.Content = new PushStreamContent(streamer.WriteToStream, GetMimeType(filePath)); RangeHeaderValue rangeHeader = Request.Headers.Range; if (rangeHeader != null) { long totalLength = streamer.FileInfo.Length; var range = rangeHeader.Ranges.First(); streamer.Start = range.From ?? 0; streamer.End = range.To ?? totalLength - 1; response.Content.Headers.ContentLength = streamer.End - streamer.Start + 1; response.Content.Headers.ContentRange = new ContentRangeHeaderValue(streamer.Start, streamer.End, totalLength); response.StatusCode = HttpStatusCode.PartialContent; } else { response.StatusCode = HttpStatusCode.OK; } return response; }
the standard way to reference the videos in html is to just use a video tag:
<video style="width:100%;height:100%;" controls autoplay="true" src="https://localhost:9000/api/getFile/testfile1.mp3"> </video>
And now your videos support streaming!
Looking for a new job? We work with some of the biggest names in tech, and we’re hiring! Check out our open jobs!