使用 C# 进行媒体文件转换






4.21/5 (14投票s)
2005年7月27日
5分钟阅读

355316

12286
演示构建 DirectShow 过滤器图以进行文件转换。
引言
GraphEdit 工具来自 DirectShow SDK,是在 Windows 平台上模拟媒体文件处理的流行工具。最近,开源的 DirectShow .NET 包装器 DirectShowLib 发布了。DirectShowLib 1.0 版本封装了最重要的接口,并且比从 Quartz.dll 生成的互操作程序集提供了更多的功能。在本文中,我们将介绍一个使用 C# 构建过滤器图以进行媒体文件转换的应用程序。因此,我们将展示如何使用 C# 创建提供 GraphEdit 部分功能的应用程序。
背景
多媒体应用程序有多种文件格式。最受欢迎的是 MPEG 系列(MPEG-1/2、MPEG 4(第 2 部分或第 10 部分)...)、Microsoft 系列(AVI、ASF、WMV...)、QuickTime 系列(QT、MOV...)和 RealMedia(RM、RAM,...)。每种格式都有其优点和缺点。此外,一些格式受到称为“软件专利”的愚蠢事物的限制(可能由大型公司中那些懒惰的中层经理发明,他们发现将工作交给法律部门比实际开发客户想要的产品更容易 ;-)。
因此,对于这个应用程序,我决定编写一个转换实用程序,可以将许多媒体文件转换为 Windows Media Video(.wmv)格式。此外,由于 Microsoft 拥有 ASF 格式(.wmv 基于此格式)的专利,我编写了代码以转换为称为 Matroska 的开放格式倡议。
使用代码
此网站提供了许多使用 .NET 中 DirectShow 的资源。DirectShowLib 的前身是该网站上的 .netmaster 的一个项目。我研究了他们的代码,您可以参考他们,了解我在本文中尚未解释的内容。
首先,编译应用程序的命令行(在 build.cmd 中提供,并假设 C# 编译器可从当前路径访问)引用 DirectShowLib 程序集。在代码中,我们开始于
using DirectShowLib;
然后,我们使用以下变量来构建过滤器图
// The main com object
FilterGraph fg = null;
// The graphbuilder interface ref
IGraphBuilder gb = null;
// The mediacontrol interface ref
IMediaControl mc = null;
// The mediaevent interface ref
IMediaEventEx me = null;
在进行一些初始步骤(对于所有 C# 中的 DirectShow 应用程序都相同)后,我们使用以下代码将媒体文件转换为 .wmv 文件
// here we use the asf writer to create wmv files
WMAsfWriter asf_filter = new WMAsfWriter();
IFileSinkFilter fs = (IFileSinkFilter)asf_filter;
hr = fs.SetFileName( fileName + ".wmv", null );
DsError.ThrowExceptionForHR( hr );
hr = gb.AddFilter( (IBaseFilter)asf_filter, "WM Asf Writer" );
DsError.ThrowExceptionForHR( hr );
hr = gb.RenderFile( fileName + fExt, null );
DsError.ThrowExceptionForHR( hr );
hr = mc.Run();
DsError.ThrowExceptionForHR( hr );
此代码创建了一个 WMAsfWriter
对象,并访问其 IFileSinkFilter
接口来设置文件名。然后,它使用 GraphBuilder
接口方法 AddFilter
将过滤器添加到图中。在此之后,我们使用“智能连接”(通过调用 RenderFile
实现)让 DirectShow 运行时构建图的其余部分。然后,当我们调用 MediaControl
接口上的 Run
方法时,我们实际上正在写入文件,因为此图中的渲染器过滤器是文件写入器。
关注点
从我之前的评论中,您可能已经猜到我不是软件专利的忠实粉丝。在编写了转换为 .wmv 文件的代码后,我了解到 Microsoft 对其基础文件格式拥有专利。所以我寻找替代方案,我意识到这个领域充斥着这些“愚蠢的小东西”。所以我决定增加对转换为 Matroska 文件格式的支持,该格式在我所知是“无专利”的。
Matroska 支持
用于构建写入 .mkv 文件的过滤器图的代码与写入 .wmv 文件的代码类似。除了我们不创建 WMAsfWriter
而是创建一个 FileWriter
对象(再次,访问其 IFileSinkFilter
接口来设置名称)。然后,我们使用以下代码添加 Matroska Mux 过滤器
// create an instance of the matroska multiplex filter and add it
// Matroska Mux Clsid = {1E1299A2-9D42-4F12-8791-D79E376F4143}
Guid guid = new Guid( "1E1299A2-9D42-4F12-8791-D79E376F4143" );
Type comtype = Type.GetTypeFromCLSID( guid );
IBaseFilter matroska_mux = (IBaseFilter)Activator.CreateInstance( comtype );
如果您已在系统上安装了 Matroska 支持(如果您不认为编解码器包是“邪恶的”,请从 www.matroska.org 下载编解码器包),Matroska Muxer 的 CLSID 将包含在您的注册表中。然后,您可以创建一个类型对象并调用 Activator.CreateInstance
来获取一个可以添加到过滤器图中的 IBaseFilter
对象。
再次使用 GraphBuilder.RenderFile
将尝试从源媒体文件构建图的其余部分。此过程并非总能如预期般工作,您应该将 Matroska 支持视为实验性的,主要用于说明目的。
局限性和已知问题
我最初开发此应用程序是因为我有一些 Real Media 文件想转换为 .wmv。我在 GraphEdit 工具中手动构建了过滤器图,并为每个文件重新构建。所以我决定编写一个执行相同操作的小应用程序会很方便。如果您在系统上安装了 Real Media 分割器(通过 Real Player 或 Real Alternative),可以将 Real Media 文件无缝转换为 Windows Media 文件。
Windows Media 文件到 Matroska 文件的转换似乎进行得相当顺利。但是 MPEG 文件无法通过此应用程序转换为 Matroska 文件(我还没有研究这个问题)。但是您可以将 MPEG 转换为 WMV,然后再转换为 Matroska 文件。(第二次转换在某些文件上似乎会挂起,但文件不会损坏,可以在您喜欢的播放器中播放。GraphEdit 在这些文件上也有类似的困难。)如前所述,Matroska 支持是实验性的,主要用于说明目的。所以我不能保证我会支持应用程序的这项功能。
安装带有外壳扩展功能的 Matroska 编解码器包在我的系统上造成了问题(在其他机器上也似乎存在此问题)。但默认安装脚本不包含此功能。尽管如此,通过 Google 搜索发现,在 XP 上安装 Matroska 编解码器包后,其他人也遇到了问题。
某些 Matroska 文件的时序看起来很奇怪,我打算研究这个问题。
如果文件很大,转换可能需要一些时间。我使用任务管理器应用程序并检查 CPU 使用率来确定转换何时完成。