ASP.NET 使用 FFMPEG 的 Core 5.0 MVC HLS 转码
ASP.NET Core 5.0 MVC HLS Transcoding using FFMPEG
概览
我目前正在使用 ASP.net 核心 REST 服务器开发媒体流服务器。我目前正在使用 .net 5.0 和 ASP.net Core MVC
我需要什么
我需要能够动态降低原始视频文件的分辨率。例如从 1080p 到 720p。我还需要能够根据客户端功能将媒体文件转码为不同的编码。
我试过的
我一直在寻找可以实现这一壮举的图书馆,但我似乎找不到。我认为 FFMpeg 可以做到这一点。我知道这是可能的,因为像 plex 和 emby 这样的应用程序似乎可以解决这个问题。'
C#
public static FileStream GetTranscodedStream(string requestedUser, string path, int targetResolution, int targetBitRate)
{
string directoryOutput = Directory.CreateDirectory(Path.Combine(Paths.TempData, $"stream_{requestedUser}")).FullName;
string fileOutput = Path.Combine(directoryOutput, $"v_t{path}-r{targetResolution}.m3u8");
string exe = Directory.GetFiles(Paths.FFMpeg, "ffmpeg*", SearchOption.AllDirectories)[0];
string arguments = $"-i \"{media.PATH}\" -bitrate {targetBitRate}k -f hls -hls_time 2 -hls_playlist_type vod -hls_flags independent_segments -hls_segment_type mpegts -hls_segment_filename \"{Path.Combine(directoryOutput, $"stream_t{path}-r{targetResolution}%02d.ts")}\" \"{fileOutput}\"";
Process process = new()
{
StartInfo = new()
{
FileName = exe,
Arguments = arguments,
UseShellExecute = true,
},
EnableRaisingEvents = true,
};
process.Start();
return new(fileOutput, FileMode.Open);
}
[HttpGet("{tmdb}/{user}/video/transcoded")]
public IActionResult GetMovieStream(string tmdb, string user, int resolution, int bitrate)
{
MediaBase movie = MovieLibraryModel.Instance.GetMovieByTMDB(tmdb);
var transcoded = GetTranscodedStream(user, movie.PATH, resolution, bitrate);
long fileSize = new FileInfo(movie.PATH).Length;
Response.Headers.Clear();
Response.ContentLength = fileSize;
Response.Headers.Add("Accept-Ranges", $"bytes");
Response.Headers.Add("Content-Range", $"bytes {0}-{fileSize}/{fileSize}");
activeStreams.Add(Users.Instance.Get(user), timer);
return File(transcoded, "application/x-mpegURL", true);
}
HTML
<link rel="stylesheet" href="/assets/lib/video.js/video-js.css">
<video id="vid1" class="videojs vjs-default-skin" controls data-setup="{}" preload="auto">
<source src="http://127.0.0.1:3208/api/get/movies/299687/dcman58/video/transcoded?resolution=480&bitrate=4800" type="application/x-mpegURL">
</video>
Javascript
var player = videojs('vid1');
player.play();
错误
ERROR 416: Range Not Satisfiable "http://127.0.0.1:3208/api/get/movies/299687/dcman58/video/transcoded?resolution=480&bitrate=4800"
你的问题出在这一行:
Response.Headers.Add("Content-Range", $"bytes {0}-{fileSize}/{fileSize}");
这是错误描述:https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/416
我怀疑您处理问题的方式有误。 FFMPEG 编码需要 运行 完成,然后才能开始将任何数据返回给客户端。您无法即时检索 FFMPEG 的输出。
我无法从您的代码中判断文件是否已经转换并在您尝试 return 时位于磁盘上;如果是这样,只需 return 文件本身而不指定范围,return 中的 "application/x-mpegURL"
部分将为您施展魔法
概览
我目前正在使用 ASP.net 核心 REST 服务器开发媒体流服务器。我目前正在使用 .net 5.0 和 ASP.net Core MVC
我需要什么
我需要能够动态降低原始视频文件的分辨率。例如从 1080p 到 720p。我还需要能够根据客户端功能将媒体文件转码为不同的编码。
我试过的
我一直在寻找可以实现这一壮举的图书馆,但我似乎找不到。我认为 FFMpeg 可以做到这一点。我知道这是可能的,因为像 plex 和 emby 这样的应用程序似乎可以解决这个问题。'
C#
public static FileStream GetTranscodedStream(string requestedUser, string path, int targetResolution, int targetBitRate)
{
string directoryOutput = Directory.CreateDirectory(Path.Combine(Paths.TempData, $"stream_{requestedUser}")).FullName;
string fileOutput = Path.Combine(directoryOutput, $"v_t{path}-r{targetResolution}.m3u8");
string exe = Directory.GetFiles(Paths.FFMpeg, "ffmpeg*", SearchOption.AllDirectories)[0];
string arguments = $"-i \"{media.PATH}\" -bitrate {targetBitRate}k -f hls -hls_time 2 -hls_playlist_type vod -hls_flags independent_segments -hls_segment_type mpegts -hls_segment_filename \"{Path.Combine(directoryOutput, $"stream_t{path}-r{targetResolution}%02d.ts")}\" \"{fileOutput}\"";
Process process = new()
{
StartInfo = new()
{
FileName = exe,
Arguments = arguments,
UseShellExecute = true,
},
EnableRaisingEvents = true,
};
process.Start();
return new(fileOutput, FileMode.Open);
}
[HttpGet("{tmdb}/{user}/video/transcoded")]
public IActionResult GetMovieStream(string tmdb, string user, int resolution, int bitrate)
{
MediaBase movie = MovieLibraryModel.Instance.GetMovieByTMDB(tmdb);
var transcoded = GetTranscodedStream(user, movie.PATH, resolution, bitrate);
long fileSize = new FileInfo(movie.PATH).Length;
Response.Headers.Clear();
Response.ContentLength = fileSize;
Response.Headers.Add("Accept-Ranges", $"bytes");
Response.Headers.Add("Content-Range", $"bytes {0}-{fileSize}/{fileSize}");
activeStreams.Add(Users.Instance.Get(user), timer);
return File(transcoded, "application/x-mpegURL", true);
}
HTML
<link rel="stylesheet" href="/assets/lib/video.js/video-js.css">
<video id="vid1" class="videojs vjs-default-skin" controls data-setup="{}" preload="auto">
<source src="http://127.0.0.1:3208/api/get/movies/299687/dcman58/video/transcoded?resolution=480&bitrate=4800" type="application/x-mpegURL">
</video>
Javascript
var player = videojs('vid1');
player.play();
错误
ERROR 416: Range Not Satisfiable "http://127.0.0.1:3208/api/get/movies/299687/dcman58/video/transcoded?resolution=480&bitrate=4800"
你的问题出在这一行:
Response.Headers.Add("Content-Range", $"bytes {0}-{fileSize}/{fileSize}");
这是错误描述:https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/416
我怀疑您处理问题的方式有误。 FFMPEG 编码需要 运行 完成,然后才能开始将任何数据返回给客户端。您无法即时检索 FFMPEG 的输出。
我无法从您的代码中判断文件是否已经转换并在您尝试 return 时位于磁盘上;如果是这样,只需 return 文件本身而不指定范围,return 中的 "application/x-mpegURL"
部分将为您施展魔法