FFME: 先进的 WPF MediaElement 替代方案
:star: 如果您喜欢这个项目,请给它加星并通过 PayPal.Me 表示感谢
状态更新
- 如果您想支持这个项目,可以通过 PayPal.Me 表示感谢
- 当前状态:(2024-06-26) - BETA 1 版本 7.0.361.1 现已发布(查看发布页面)
- NuGet 包可在此处获取:https://www.nuget.org/packages/FFME.Windows/
- FFmpeg 版本:7.0 -- 请确保下载的是共享库版本,并适用于您的架构(通常为 x64)
- 重大变更:从 4.1.320 版本开始,
Source
依赖属性已降级为通知属性。请改用异步的Open
和Close
方法。 - 我在编写这个项目时学到了很多。如果您感兴趣,可以在这里找到我最新的视频和渲染实验。
请注意,当前的 NuGet 发布版本可能需要与源代码当前状态不同版本的 FFmpeg 二进制文件。
WPF 应用程序快速使用指南
入门
-
打开 Visual Studio 并创建一个新的 WPF 应用程序。
目标框架必须设置为 .NET 5.0 或更高版本
-
在包管理器控制台中安装 NuGet 包:
PM> Install-Package FFME.Windows
-
获取 FFmpeg 共享二进制文件(64 位或 32 位,取决于您的应用程序目标架构)
可以通过以下方式之一
-
自行构建
我推荐使用 Media Autobuild Suite 请不要在这里询问相关帮助。
或
-
下载兼容的构建版本
对于 x64 构建
- dll 文件位于此处,7.0 x64,
将下载的两个文件夹中
bin
文件夹的内容合并到一个单独的文件夹中,例如c:\ffmpeg\x64
。
最终
c:\ffmpeg\x64
文件夹的内容应如下所示- avcodec-59.dll
- avdevice-59.dll
- avfilter-8.dll
- avformat-59.dll
- avutil-58.dll
- ffmpeg.exe
- ffplay.exe
- ffprobe.exe
- swresample-4.dll
- swscale-6.dll
- dll 文件位于此处,7.0 x64,
将下载的两个文件夹中
-
在应用程序的启动代码(Main 方法)中
将 Unosquare.FFME.Library.FFmpegDirectory 变量设置为 DLL 和 EXE 文件所在文件夹的路径,例如:
Unosquare.FFME.Library.FFmpegDirectory = @"c:\ffmpeg";
然后像使用其他 WPF 控件一样使用 FFME MediaElement 控件。
示例
在主窗口中(例如 MainWindow.xaml)
-
添加命名空间:
xmlns:ffme="clr-namespace:Unosquare.FFME;assembly=ffme.win"
-
添加 FFME 控件:
<ffme:MediaElement x:Name="Media" Background="Gray" LoadedBehavior="Play" UnloadedBehavior="Manual" />
-
通过调用异步方法 Open 来播放文件或流:
await Media.Open(new Uri(@"c:\your-file-here"));
-
通过调用以下方法关闭媒体:
await Media.Close();
其他使用说明
- 请记住:
Unosquare.FFME.Windows.Sample
提供了许多功能的使用示例。请将其作为主要参考。 - 生成的 API 文档可在此处获取
功能概览
FFME 是一个先进的、近乎可直接替代的 微软 WPF MediaElement 控件替代品。标准 MediaElement 使用 DirectX (DirectShow) 进行媒体播放,而 FFME 使用 FFmpeg 来读取和解码音视频。这意味着对于那些想要支持 HLS 播放等功能,或者不想在客户端机器上安装编解码器的人来说,使用 FFME 可能就是答案。
FFME 相比标准 MediaElement 提供了多项改进,如:
- 快速媒体定位和逐帧定位。
- Position、Balance、SpeedRatio、IsMuted 和 Volume 等属性都是依赖属性。
- 额外和扩展的媒体事件。提取(和修改)视频、音频和字幕帧非常容易。
- 轻松应用 FFmpeg 视频和音频滤镜图。
- 提取媒体流的元数据和规格(标题、专辑、比特率、编解码器、FPS 等)。
- 对媒体播放应用音量、平衡和速度比率。
- MediaState 在此控件上实际可用。标准 WPF MediaElement 在这方面严重缺乏。
- 能够选择文件或 URL 中包含的媒体流。
- 指定输入和编解码器参数。
- 可选择通过设备或编解码器进行硬件解码加速。
- 捕获流数据包、音频、视频和字幕帧。
- 在渲染时更改原始视频、音频和字幕数据。
- 执行自定义流读取和流录制。
... 所有这些功能都集成在一个 MediaElement 控件中
FFME 还支持打开捕获设备。请参阅以下示例 URL 和 issue #48
device://dshow/?audio=Microphone (Vengeance 2100):video=MS Webcam 4000
device://gdigrab?title=Command Prompt
device://gdigrab?desktop
如果你希望在更改 SpeedRatio 属性时音频音调不变,你需要在与 FFmpeg 二进制文件相同的目录中放置 SoundTouch.dll
库 v2.1.1。你可以在这里获取 SoundTouch 库。
关于其工作原理
首先,让我们回顾一些概念。数据包
是从输入中读取的一组字节。所有数据包
都属于特定的媒体类型
(音频、视频、字幕、数据),包含一些时间信息,最重要的是压缩数据。数据包被发送到编解码器
,然后编解码器生成帧
。请注意,生成 1 个帧
并不总是恰好需要 1 个数据包
。一个数据包
可能包含多个帧
,但一个帧
也可能需要多个数据包
才能被解码器构建。帧
将包含时间信息和原始的未压缩数据。现在,你可能认为可以使用帧
并在屏幕上显示像素或将样本发送到声卡。我们接近了,但仍需要进行一些额外处理。事实证明,不同的编解码器
会产生不同的未压缩数据格式。例如,一些视频编解码器会以 ARGB 输出像素数据,一些以 RGB 输出,还有一些以 YUV420 输出。因此,我们需要将这些帧``转换
成所有硬件都能原生使用的格式。我将这些转换后的帧称为媒体块
。这些媒体块
将包含标准音频和视频格式的未压缩数据,所有硬件都能接收。
上述过程在 3 个不同层面实现:
MediaContainer
封装了输入流。这一层跟踪MediaComponentSet
,它只是MediaComponent
对象的集合。每个MediaComponent
包含数据包
缓存、帧
解码 和块
转换 逻辑。它提供以下重要功能:- 我们调用
Open
来打开输入流并检测不同的流组件。这也决定了要使用的编解码器。 - 我们调用
Read
来读取下一个可用的数据包,并将其存储在相应的组件中(音频、视频、字幕、数据等)。 - 我们调用
Decode
来从每个组件持有的队列中读取下一个数据包,并返回一组帧。 - 最后,我们调用
Convert
将给定的帧
转换为媒体块
。
- 我们调用
MediaEngine
封装了MediaContainer
,负责执行控制输入流的命令(播放、暂停、停止、定位等),同时保持 3 个后台工作线程。PacketReadingWorker
设计用于持续从MediaContainer
读取数据包。它会在需要时读取数据包,不需要时暂停。这取决于缓存中的数据量。它会尝试始终保持大约 1 秒的媒体数据包。FrameDecodingWorker
获取PacketReadingWorker
写入的数据包并将其解码为帧。然后将这些帧转换为块
并写入MediaBlockBuffer
。这个块缓冲区可以被其他东西(这里描述的下一个工作线程)读取,以便渲染其内容。- 最后,
BlockRenderingWorker
从MediaBlockBuffer
读取块,并将这些块发送到特定平台的IMediaRenderer
。
- 在最高层,我们有一个
MediaElement
。它封装了一个MediaEngine
,并包含平台特定的方法实现,用于执行音频渲染、视频渲染、字幕渲染以及MediaEngine
和自身之间的属性同步等任务。
下面提供了一个高级图表作为额外参考。
一些进行中的工作
欢迎您的帮助!
- 我正在计划这个控件的下一个版本
Floyd
。请查看 Issues 部分。
Windows:编译、运行和测试
请注意,我无法分发 FFmpeg 的二进制文件,因为我不确定是否被允许这样做。请按照以下说明编译、运行和测试 FFME。
- 克隆此存储库并确保已安装.Net Core 3.1或更高版本。
- 下载适用于您目标架构的FFmpeg共享二进制文件:FFmpeg Windows下载。
- 解压刚下载的
zip
文件内容,进入解压出的bin
文件夹。您应该看到3个exe
文件和多个dll
文件。选择并复制所有这些文件。 - 将上一步中的所有文件粘贴到一个容易记住的文件夹中。记下完整路径。(我使用了
c:\ffmpeg\
) - 打开解决方案,将
Unosquare.FFME.Windows.Sample
项目设置为启动项目。您可以通过右键单击项目并选择设为启动项目
来完成此操作。请注意,您需要安装Visual Studio 2019和适用于目标架构的dotnet 5.0 SDK。 - 在
Unosquare.FFME.Windows.Sample
项目下,找到App.xaml.cs
文件,在构造函数下找到Library.FFmpegDirectory = @"c:\ffmpeg";
这一行,将路径替换为您解压FFmpeg二进制文件(dll文件)的文件夹。 - 点击
开始
运行项目。 - 您应该会看到一个示例媒体播放器。点击右下角的
打开
图标,输入媒体文件的URL或路径。 - 文件或URL应立即播放,通过点击
信息
图标,所有属性应显示在媒体显示区右侧。 - 您可以在项目中使用生成的程序集,无需其他依赖项。寻找
ffme.win.dll
。
ffmeplay.exe示例应用程序
该项目的源代码包含一个功能强大的媒体播放器(FFME.Windows.Sample
),涵盖了FFME
控件的大多数用例。如果您只是想快速了解,以下是ffmeplay
接受的快捷键列表。
快捷键 | 功能描述 |
---|---|
G | 切换字幕颜色示例 |
左箭头 | 向左跳转1帧 |
右箭头 | 向右跳转1帧 |
+ / 音量增大 | 增加音频音量 |
- / 音量减小 | 降低音频音量 |
M / 音量静音 | 静音音频 |
上箭头 | 增加播放速度 |
下箭头 | 降低播放速度 |
A | 循环切换音频流 |
S | 循环切换字幕流 |
Q | 循环切换视频流 |
C | 循环切换闭路字幕通道 |
R | 重置更改 |
Y / H | 对比度:增加 / 减少 |
U / J | 亮度:增加 / 减少 |
I / K | 饱和度:增加 / 减少 |
E | 循环切换音频滤镜示例 |
T | 将截图保存到desktop/ffplay 文件夹 |
W | 开始/停止将数据包(无转码)录制为传输流到desktop/ffplay 文件夹 |
双击 | 进入全屏 |
Esc | 退出全屏 |
鼠标滚轮向上 / 向下 | 缩放:放大 / 缩小 |
致谢
排名不分先后
- 感谢FFmpeg团队制作了这把媒体界的瑞士军刀。我鼓励您向他们捐款。
- 感谢NAudio团队制作了.NET平台上最好的音频库 -- 有朝一日我会为他们需要的一些改进做出贡献。
- 感谢Ruslan Balanukhin制作了FFmpeg互操作绑定生成器工具:FFmpeg.AutoGen。
- 感谢Martin Bohme编写的教程,介绍如何使用FFmpeg创建视频播放器。
- 感谢Barry Mieny制作的精美FFmpeg logo
类似项目
许可证
- 请参阅LICENSE文件以获取更多信息。