如何使用 C# 和 .NET Core 制作转码视频文件流

How can I make a Transcoded Video Filestream using C# and .NET Core

概览

我目前正在使用 ASP.net 核心 REST 服务器开发媒体流服务器。我目前正在使用 .net 5.0 和 ASP.net Core MVC

我需要的

我需要能够动态降低原始视频文件的分辨率。 例如从 1080p720p 我还需要能够根据客户端功能将媒体文件转码为不同的编码。

我试过的

我一直在寻找可以实现这一壮举的图书馆,但我似乎找不到。我认为 FFMpeg 可以做到这一点。我知道这是可能的,因为像 plex 和 emby 这样的应用程序似乎可以解决这个问题。

我做了什么

[HttpGet("/api/streaming/video")]
public IActionResult GetFile()
{
    string path = "C:\Path\To\Video\FILE.mp4";
    System.IO.FileStream stream = new(path, System.IO.FileMode.Open, System.IO.FileAccess.Read);
    Microsoft.AspNetCore.Mvc.FileStreamResult file = File(stream, "video/mp4", true);
    return file;
}

尝试过的框架

鉴于您需要跨平台工作,正如@Andy 所说,最好的解决方案是 ffmpeg。您有两个选择:

  1. 从您的 Web 进程调用 ffmpeg 命令行实用程序;或
  2. 将 libav 库套件(它是 ffmpeg 的基础)编译到每个本机平台,您的代码可能 运行 - Windows、Linux 等 - 制作本机 DLL 包装器,并在您的 ASP.NET 项目中使用 P/Invoke 来访问它。

命令行实用程序

命令行实用程序非常易于使用且文档齐全。文档 here. Your basic approach would be to include ffmpeg.exe in your web project (make sure you have a version for each platform), and use Process.Start to invoke it, using the command line arguments to point it to your video file and configure the output. Once the output is finished, you can serve it by returning with File like in your example. There are also some open source .NET wrappers like this one 可以为您节省一些工作。不幸的是,命令行实用程序在启动后并没有提供太多(任何)控制,也没有提供确定进度的编程方式。不过,如果你按照我最后的建议,这些问题应该都不是问题。

Libav

但是,如果您确实需要或想要完全控制 - 包括逐帧转码、进度报告等 - 那么您将需要使用 libav。在继续之前,请注意您至少需要使用一些 C/C++ 才能使用 libav。这意味着您的服务器代码将必须 运行 完全信任,并且您将容易受到 运行 宁本机代码的安全风险的影响。 (尽管如果您使用 ffmpeg.exe 也是如此,但至少在那种情况下您不会 运行 通过您自己的代码引入新的安全风险的风险)。

还知道,您不能只为每个平台找到干净整洁、总是 up-to-date 可下载的二进制文件(至少一个原因是担心专利诉讼)。相反,您必须自己为您的代码可能 运行 所在的每个平台构建它。在 here 上找到您的平台,然后按照 中的说明进行操作 。哪怕有一点偏差,再小的偏差,你也造不出来,你会绞尽脑汁想出为什么。

构建完成后,下一个主要任务就是向 C# 代码公开所需的 API。 libav APIs 的文档不是一个清晰的模型。他们或多或少假设您将查看 ffmpeg 命令行实用程序的代码以了解如何使用 libav,而这正是您应该做的。但是,如果您投入时间(几天甚至几周)来构建构建并学习 APIs,您将成为媒体大师。使用 libav 几乎没有什么是您做不到的。

现在您终于可以将其集成到您的应用程序中了。同样,您可以采用两种方法。如果你对 C/C++ 很满意,你应该创建一个新的 C/C++ DLL 项目,link libav DLLs,并在那里完成大部分繁重的工作只需导出几个可以从 C# 调用的入口点函数。或者,您可以 P/Invoke 直接访问 libav DLL,但是您需要在 C# 中做大量的数据结构和函数脚手架。除非您对编组非常满意,否则我不会尝试这样做。

事实上,我建议使用命令行实用程序路径,因为 -

无论如何你都不应该尝试在运行中转码

话虽如此,让我们来谈谈您的实际游戏计划吧。您说您需要根据客户端 wants/can 收到的内容“动态”转换视频。没有人这样做。他们所做的是提前创建多个版本的视频并将每个版本保存在服务器上,例如 1080p、720p、480p,甚至可能是 240p 版本。然后,客户端应用程序监控连接质量,同时考虑用户的偏好,将媒体播放器定向到所需的版本。服务器始终提供请求的版本,不会即时转换。除非你在谈论流媒体直播活动——如果是的话那超出了我的专业范围——这就是你应该做的。

因此,我建议使用 ffmpeg 实用程序提前创建不同版本的视频 - 例如作为导入或上传过程的一部分。跟踪数据库中的视频,包括每个视频的可用版本。为客户提供获取此信息的方法。然后,当需要提供视频时,您只需提供客户端在查询参数中请求的视频即可。将确定所需版本的逻辑放在客户端上 - 连接速度 and/or 用户偏好。

别忘了支持 Content-Range 请求

最后,您可能不想只使用 File 来提供媒体服务,除非用户只是要下载文件以供离线观看。假设人们要在浏览器中播放视频,您需要 API 接受 content-range 请求 headers。 Here's 如何做到这一点的一个很好的例子。如果您正确实施,Web 浏览器媒体播放器将能够透明地播放、搜索等。如果出于某种原因需要更改格式,只需重定向 m 的 URLdia播放器切换到合适的版本,保持位置不变,继续播放,用户几乎不会注意到跳过。

希望至少有一些帮助!