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

问题描述

概述

我目前正在使用 ASP.net Core REST Server 开发媒体流服务器。我目前正在使用 .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;
}

尝试过的框架

  • Xabe.FFmpeg
  • FFMpegSharp

解决方法

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

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

命令行实用程序

命令行实用程序非常易于使用且文档齐全。文档是 here。您的基本方法是将 ffmpeg.exe 包含在您的网络项目中(确保您有适用于每个平台的版本),并使用 Process.Start 调用它,使用命令行参数将其指向您的视频文件和配置输出。输出完成后,您可以像示例中那样返回 File 来提供它。还有一些像 this one 这样的开源 .NET 包装器可以为您节省一些工作。不幸的是,命令行实用程序在启动后并没有提供太多(任何)控制,也没有提供确定进度的编程方式。但是,如果您在最后遵循我的建议,这些问题应该不会成为问题。

Libav

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

还要知道,您不能只为每个平台找到干净整洁、始终保持最新状态的可下载二进制文件(至少有一个原因是担心专利诉讼)。相反,您必须为您的代码可能运行的每个平台自己构建它。在 here 上找到您的平台,然后按照字面意思的说明进行操作。如果你有一个偏差,无论多么小,你都无法构建它,你会想知道为什么。

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

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

事实上,我将推荐使用命令行实用程序路线,因为 -

无论如何都不应该尝试即时转码

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

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

并且不要忘记支持内容范围请求

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

希望至少有一些帮助!