使用 DirectShow 将 Wav 文件转换为 MP3 或其他格式
一个简单的类,用于将立体声 44 kHz、16 位 wav 文件转换为其他格式,包括 MP3。该类展示了如何使用 DirectShow API 进行音频转换。
引言
本文介绍如何使用 DirectShow API 进行简单的音频转换,特别是 Wav 到 MP3 的转换。DirectShow API 中的音频编解码器分为三种类型:原生编解码器、ACM 编解码器和 DMO(DirectX 媒体对象)编解码器。
用于音频压缩的原生音频编解码器很少。对于 MP3 编码,我找到的唯一一个是Elecard 的 LAME DirectShow 包装器。大多数 MP3 编码器都采用 ACM(音频压缩管理器)格式,该格式随 Windows 多媒体 API 一起推出。CDSEncoder
类及其相关的类 CDSCodec
和 CDSCodecFormat
枚举 ACM 编解码器及其各自的压缩参数,构建图并进行编码。
GraphBuilder 和其他过滤器
该图由五个过滤器组成
- 文件源(异步)用于读取输入 wav 文件,
- WAV 解析器用于 wav 解析,
- ACM 编解码器用于音频压缩(在本例中:MP3 ACM,由 ACM 包装器过滤器包装),
- WAV 目标,用于 wav 输出多路复用,
- 文件写入器用于写入输出文件。
重要提示
WAV Dest 过滤器不包含在标准过滤器中,但需要从 DirectX SDK(SDK_root\Samples\Multimedia\DirectShow\Filters\WavDest)编译。为了方便起见,已编译的 WAV Dest 过滤器包含在演示 zip 文件中,但您必须通过RegSrv32 wavdest.ax注册它。
ACM 编解码器和 ACM 包装器过滤器
所有 ACM 编解码器都列在 DirectShow 的音频压缩器过滤器类别(CLSID_AudioCompressorCategory
)中,并且不能直接实例化。我们必须使用设备枚举器来使用它们。
注意:根据您的配置,您的计算机上可能安装了针对同一格式的多个 ACM 编解码器。对于 MP3 编解码器,情况可能如此。您可以通过控制面板设置优先级或停用其中一些编解码器,如下面的图片所示。
设备枚举器或如何浏览 ACM 编解码器
必须使用设备枚举器来检索 ACM 编解码器的实例。它通过IEnumMoniker
接口返回编解码器列表,因此我们可以通过调用IMoniker::BindToObject()
获得过滤器接口(IBaseFilter
),并通过调用IMoniker::BindToStorage()
获得过滤器名称。
使用 IAMStreamConfig 接口配置 ACM 编解码器
一旦实例化了所需的编解码器,我们就可以获得用于过滤器配置的IBaseFilter
接口。由于每个IBaseFilter
都有一个或多个 Pin,我们必须使用IEnumPins
接口和IPin::QueryDirection()
调用来搜索输出 Pin。
使用输出 Pin,我们可以查询IAMStreamConfig
接口来配置以下属性
- 声道数,
- 每秒样本数,
- 每秒平均字节数,
- 每个样本的位数。
注意:对于某些编解码器(包括 MP3),必须在图形渲染后调用IAMStreamConfig::SetFormat()
。
类
CDSEncoder
CDSEncoder
承担以下任务
- 枚举音频编解码器(
CLSID_AudioCompressorCategory
), - 构建、渲染和运行图形。
class CDSEncoder : public CArray<CDSCodec*, CDSCodec*> { public: void BuildGraph(CString szSrcFileName, CString szDestFileName, int nCodec, int nFormat); CDSEncoder(); virtual ~CDSEncoder(); protected: void BuildCodecArray(); HRESULT AddFilterByClsid(IGraphBuilder *pGraph, LPCWSTR wszName, const GUID& clsid, IBaseFilter **ppF); BOOL SetFilterFormat(AM_MEDIA_TYPE* pStreamFormat, IBaseFilter* pBaseFilter); IGraphBuilder *m_pGraphBuilder; };
由于CDSEncoder
继承自CArray
,因此编解码器集合通过CArray
方法公开,每个编解码器都作为CDSCodec
对象返回。
CDSCodec
CDSCodec
承担以下任务
- 枚举编解码器支持的参数,
- 公开编解码器名称。
class CDSCodec : public CArray<CDSCodecFormat*, CDSCodecFormat*> { public: CDSCodec(); virtual ~CDSCodec(); CString m_szCodecName; IMoniker *m_pMoniker; void BuildCodecFormatArray(); };
由于CDSCodec
继承自CArray
,因此编解码器支持的参数集合通过CArray
方法公开,每个参数都作为CDSCodecFormat
对象返回。
CDSCodecFormat
CDSCodecFormat
公开了一个编解码器参数的属性
- 声道数,
- 每秒样本数,
- 每秒字节数,
- 每个样本的位数。
class CDSCodecFormat { public: WORD BitsPerSample(); DWORD BytesPerSec(); DWORD SamplesPerSecond(); WORD NumberOfChannels(); CDSCodecFormat(); virtual ~CDSCodecFormat(); public: AM_MEDIA_TYPE* m_pMediaType; };
已知问题
错误检查
本文的目标是演示如何使用 DirectShow 进行简单的音频转换。这些类不如它们应该的那样安全。如果您计划在生产环境中使用它,请记住这一点。
源 Wav 格式
没有采样转换,因此如果您使用 44 kHz Wav,则只能生成 44 kHz 输出文件。
Windows Media
Windows Media 格式只能与证书一起使用,该证书可从微软的Windows Media SDK获得。