Streaming Video Content to a Browser using Web API

A client recently needed support for video streaming behavior that included seeking (fast-forward and rewind) but discovered that their current setup did not allow it. The root cause: the API serving the videos was not configured to support byte-range requests, which are essential for seeking functionality in browsers.

Research revealed that if an API does not support these requests—typically defined by the Range header and a 206 Partial Content response—browsers will be unable to jump to different points in the video.

This article provided a useful starting point: HTTP Partial Content In ASP.NET Web API Video - CodeProject

The browser sends requests for specific byte ranges in a video, and the endpoint must return only those requested chunks. To do so correctly, the API must read the Range header and set the HTTP status code to "Partial Content".

The code was refactored slightly to create 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:

1. Set the FileInfo Object on the Streamer object

2. If the range is set in the header, then we must do the following:

  1. Retrieve the start & end indices from the header
  2. Set the corresponding properties in the Streamer object
  3.  Set Content Length and the Content Range to the correct values in the response header
  4. Set the status code to "Partial Content"

3. If the range is not set, then we must:

  1. Return the media file as normal, which just entails returning the media file
  1. Set the status code to "Ok"

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="http://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 and make your next career move with Planet.

Let’s Partner Together
Contact us today for expert talent solutions or career-defining opportunities.