ASP.NET MVC视频分片响应及转码相关技术问题咨询
Hey there, let's tackle each of your questions one by one to get your video playback working smoothly:
1. Implementing the LoadVideo Action for Remote Video Streaming
To serve a remote video to your HTML5 <video> tag with chunked support, you need to handle HTTP Range requests—this is what allows browsers to request only parts of the video at a time, enabling smooth playback without loading the entire file upfront. Here's a complete implementation:
public async Task<ActionResult> LoadVideo() { var remoteVideoUrl = "http://another-server.com/123.mp4"; using var httpClient = new HttpClient(); // Check if the browser sent a Range header for chunked requests var rangeHeader = Request.Headers["Range"]; if (!string.IsNullOrEmpty(rangeHeader)) { // Parse the range format: bytes=start-end var rangeParts = rangeHeader.Replace("bytes=", "").Split('-'); if (long.TryParse(rangeParts[0], out var start)) { // Get total length of the remote video first var headResponse = await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, remoteVideoUrl)); var contentLength = long.Parse(headResponse.Content.Headers.ContentLength.ToString()); var end = rangeParts.Length > 1 && long.TryParse(rangeParts[1], out var parsedEnd) ? Math.Min(parsedEnd, contentLength - 1) : contentLength - 1; // Request only the needed byte range from the remote server var request = new HttpRequestMessage(HttpMethod.Get, remoteVideoUrl); request.Headers.Range = new System.Net.Http.Headers.RangeHeaderValue(start, end); var response = await httpClient.SendAsync(request); var stream = await response.Content.ReadAsStreamAsync(); // Set headers required for partial content response Response.StatusCode = (int)HttpStatusCode.PartialContent; Response.Headers.Add("Accept-Ranges", "bytes"); Response.Headers.Add("Content-Range", $"bytes {start}-{end}/{contentLength}"); return new FileStreamResult(stream, "video/mp4") { FileDownloadName = "video.mp4" }; } } // Fallback: send the entire video if no range header is present var fullStream = await httpClient.GetStreamAsync(remoteVideoUrl); return new FileStreamResult(fullStream, "video/mp4"); }
This code:
- Avoids downloading the entire remote video to your server by fetching only requested chunks
- Returns the
206 Partial Contentstatus code required for HTML5 video streaming - Supports breakpoint resuming if the user pauses and resumes playback
2. Using the HTML5 Video Tag
The HTML code you provided will work perfectly once your LoadVideo action supports range requests. Just double-check the src points to your controller and action path (e.g., /Home/LoadVideo if your controller is HomeController).
3. Streaming Large Videos in Chunks
The core solution is supporting HTTP Range requests, as shown in the first example. Browsers automatically send these headers when loading large videos, so your action just needs to:
- Parse the requested byte range from the
Rangeheader - Fetch only that specific range from the remote server
- Return the partial content with the correct status code and headers
This approach keeps memory usage low on your server and lets the browser load chunks incrementally as needed.
4. Transcoding 720P Video to 480P
To transcode video, you'll need a video processing tool—FFmpeg is the industry standard. You can call it via command line or use a .NET wrapper like FFmpeg.AutoGen. Here's a simplified implementation:
private async Task<string> TranscodeTo480P(string inputUrl) { var tempInputPath = Path.GetTempFileName() + ".mp4"; var tempOutputPath = Path.GetTempFileName() + ".mp4"; // Download remote 720P video to a temporary file using var httpClient = new HttpClient(); using var inputStream = await httpClient.GetStreamAsync(inputUrl); using var fileStream = new FileStream(tempInputPath, FileMode.Create); await inputStream.CopyToAsync(fileStream); // FFmpeg command to transcode to 480P (adjust parameters for quality/speed) var ffmpegPath = Path.Combine(HttpContext.Server.MapPath("~/Bin"), "ffmpeg.exe"); var arguments = $"-i \"{tempInputPath}\" -vf scale=-2:480 -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 128k \"{tempOutputPath}\""; // Execute FFmpeg process var process = new ProcessStartInfo { FileName = ffmpegPath, Arguments = arguments, RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true }; using var ffmpegProcess = Process.Start(process); await ffmpegProcess.WaitForExitAsync(); // Clean up temporary input file System.IO.File.Delete(tempInputPath); return tempOutputPath; } // Updated LoadVideo action to serve transcoded 480P video public async Task<ActionResult> LoadVideo() { var remoteVideoUrl = "http://another-server.com/123.mp4"; var transcodedPath = await TranscodeTo480P(remoteVideoUrl); var fileInfo = new FileInfo(transcodedPath); // Handle range requests for the transcoded file var rangeHeader = Request.Headers["Range"]; if (!string.IsNullOrEmpty(rangeHeader)) { var rangeParts = rangeHeader.Replace("bytes=", "").Split('-'); if (long.TryParse(rangeParts[0], out var start)) { var end = rangeParts.Length > 1 && long.TryParse(rangeParts[1], out var parsedEnd) ? Math.Min(parsedEnd, fileInfo.Length - 1) : fileInfo.Length - 1; var stream = new FileStream(transcodedPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); stream.Seek(start, SeekOrigin.Begin); var contentLength = end - start + 1; Response.StatusCode = (int)HttpStatusCode.PartialContent; Response.Headers.Add("Accept-Ranges", "bytes"); Response.Headers.Add("Content-Range", $"bytes {start}-{end}/{fileInfo.Length}"); return new FileStreamResult(stream, "video/mp4") { FileDownloadName = "video_480p.mp4" }; } } // Serve full transcoded file if no range request return File(transcodedPath, "video/mp4", "video_480p.mp4"); }
Pro Tip: Add a background service to clean up old temporary transcoded files to avoid disk space bloat.
5. Transcoding to .m3u8 (HLS Format)
Absolutely! HLS (HTTP Live Streaming) uses a .m3u8 playlist file that points to small .ts video chunks, which is great for adaptive bitrate streaming. Here's how to implement it with FFmpeg:
Step 1: Generate HLS Playlist & Chunks
Use this FFmpeg command to convert your video to HLS format:
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 128k -hls_time 10 -hls_list_size 0 -hls_segment_filename "chunk_%03d.ts" output.m3u8
-hls_time 10: Creates 10-second video chunks-hls_list_size 0: Keeps all chunks in the playlist
Step 2: ASP.NET MVC Actions for HLS
public async Task<ActionResult> LoadHlsVideo() { var remoteVideoUrl = "http://another-server.com/123.mp4"; var tempDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); Directory.CreateDirectory(tempDir); var inputPath = Path.Combine(tempDir, "input.mp4"); var outputM3u8Path = Path.Combine(tempDir, "output.m3u8"); // Download remote video using var httpClient = new HttpClient(); using var inputStream = await httpClient.GetStreamAsync(remoteVideoUrl); using var fileStream = new FileStream(inputPath, FileMode.Create); await inputStream.CopyToAsync(fileStream); // Run FFmpeg to generate HLS var ffmpegPath = Path.Combine(HttpContext.Server.MapPath("~/Bin"), "ffmpeg.exe"); var arguments = $"-i \"{inputPath}\" -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 128k -hls_time 10 -hls_list_size 0 -hls_segment_filename \"{tempDir}/chunk_%03d.ts\" \"{outputM3u8Path}\""; var process = new ProcessStartInfo { FileName = ffmpegPath, Arguments = arguments, RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true }; using var ffmpegProcess = Process.Start(process); await ffmpegProcess.WaitForExitAsync(); // Update chunk URLs in the playlist to point to our chunk-serving action var m3u8Content = await System.IO.File.ReadAllTextAsync(outputM3u8Path); var updatedM3u8 = m3u8Content.Replace("chunk_", $"/Home/GetHlsChunk?dir={tempDir}&chunk="); return Content(updatedM3u8, "application/vnd.apple.mpegurl"); } // Action to serve individual HLS chunks public ActionResult GetHlsChunk(string dir, string chunk) { var chunkPath = Path.Combine(dir, chunk); return File(chunkPath, "video/MP2T"); }
Step 3: Frontend for HLS
Most modern browsers support HLS natively, but add hls.js for broader compatibility:
<video width="400" controls> <source src="/Home/LoadHlsVideo" type="application/vnd.apple.mpegurl"> Your browser does not support HTML5 video. </video> <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script> <script> var video = document.querySelector('video'); if (Hls.isSupported()) { var hls = new Hls(); hls.loadSource('/Home/LoadHlsVideo'); hls.attachMedia(video); } </script>
内容的提问来源于stack exchange,提问作者eslamirad




