首页 > 解决方案 > ASP.NET Core 5.0 MVC HLS Transcoding using FFMPEG

问题描述

Overview

I'm currently working on a media streaming server using ASP.net Core REST Server. I'm currently using .net 5.0 and ASP.net Core MVC

What I need

I need to be able to dynamically down-res the original video file. from 1080p to 720p for example. Also I need to be able to make the media file able to be transcoded to a different encoding based on client capabilities.

What I've Tried

I've been looking for a library that can manage this feat, but I can't seem to find one. I thought FFMpeg would be able to do this. I know this is possible because applications like plex and emby seem to manage this.'

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

ERROR 416: Range Not Satisfiable "http://127.0.0.1:3208/api/get/movies/299687/dcman58/video/transcoded?resolution=480&bitrate=4800"

标签: javascriptc#asp.netffmpeg

解决方案


Your problem is with this line:

Response.Headers.Add("Content-Range", $"bytes {0}-{fileSize}/{fileSize}");

This is the error description: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/416

I suspect you're approaching the problem wrong. The FFMPEG encoding needs to run to completion before you can start serving any data back to the client. You cant retrieve the output from FFMPEG on the fly.

I can't tell from your code whether the files are already converted and on disk at the point that you're trying to return them; if so, just return the file itself without specifying ranges, the "application/x-mpegURL" part in your return will do the magic for you


推荐阅读