.net webapi 返回视频流
需求:
- web api返回视频流,可以在浏览器上播放
- 在浏览器上,可以设置播放位置(通过slider设置)
在浏览器端,使用如下方式播放:
1 2 3 4 5 | < 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(); } } }
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 字符编码:从基础到乱码解决