.net webapi 返回视频流
需求:
- web api返回视频流,可以在浏览器上播放
- 在浏览器上,可以设置播放位置(通过slider设置)
在浏览器端,使用如下方式播放:
<video style="width:100%;height:100%;" controls autoplay="true" src="https://ip:port/api/apiname/testvideo.mp3"> </video>
技术方案1:
如果使用通用的fileStram方式返回,同时MediaTypeHeaderValue设置为 "video/mp4"是可以返回视频流,并进行播放的。但是存在的问题是浏览器端无法修改播放位置。
技术方案2:
为了解决设置播放位置问题,在客户端每次请求时候,需要返回指定位置的buffer给客户端,即根据客户端header传递的start和end位置(Request.Headers.Range)来返回PushStreamContent,如下:
HttpResponseMessage GetVideo(string filePath,string mimeType) { if (!File.Exists(filePath)) return new HttpResponseMessage(HttpStatusCode.NotFound); var response = Request.CreateResponse(); response.Headers.AcceptRanges.Add("bytes"); var streamer = new VideoStreamer(); streamer.FileInfo = new FileInfo(filePath); response.Content = new PushStreamContent(streamer.WriteToStream, mimeType); 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; } }
其中VideoStreamer用于读取指定range的stream,定义如下:
class VideoStreamer { 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) { } finally { outputStream.Close(); } } }