在本文中,将探讨如何创建一个桌面对话框应用程序,该程序可以用于音频文件格式之间的转换。这包括“引擎”——一个用于实际格式转换的类库,以及在给定路径及其子文件夹中枚举文件。用户界面和用户体验也是关注的重点。
开发的程序无需安装,不需要外部DLL,甚至不需要静态库。只需构建并运行即可。
微软媒体基金会是一个基于Windows的多媒体平台,它为开发者提供了创建各种多媒体软件的能力。使用微软媒体基金会转换音频文件需要对音频流进行编码和解码,这在下面的教程中有详细解释。
创建了自己的音频处理类,称为SG_AudioConvert。以下是其构造函数和析构函数的实现:
SG_AudioConvert::SG_AudioConvert() {
// 初始化需要初始化的内容
Init();
}
SG_AudioConvert::~SG_AudioConvert() {
// 清理需要清理的内容
Cleanup();
}
Init()函数由构造函数调用,执行以下操作:
int SG_AudioConvert::Init() {
HRESULT hr = S_OK;
// 检查是否已经初始化
if (m_bInit)
return RET_OK;
(void)HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
if (SUCCEEDED(hr)) {
hr = MFStartup(MF_VERSION);
m_bInit = TRUE;
return RET_OK; // 成功
}
m_bInit = FALSE;
return RET_FAIL; // 失败
}
在继续之前,还需要介绍由类的析构函数调用的清理过程。
int SG_AudioConvert::Cleanup() {
MFShutdown();
CoUninitialize();
return RET_OK; // 成功
}
开发了SG_AudioConvert::ConvertProc()来执行所有文件转换,从任何支持的音频类型到任何其他类型。向它传递以下参数:
函数原型如下:
int SG_AudioConvert::ConvertProc(
const wchar_t* p_szSrc,
const wchar_t* p_szDst,
const GUID TargetFormat,
const GUID ContainerType);
通用转换函数ConvertProc()如下所示:
int SG_AudioConvert::ConvertProc(
const wchar_t* p_szSrc,
const wchar_t* p_szDst,
const GUID TargetFormat,
const GUID ContainerType) {
CTranscoder transcoder;
HRESULT hr = S_OK;
// 为输入文件创建媒体源。
hr = transcoder.OpenFile(p_szSrc);
if (SUCCEEDED(hr)) {
// 配置配置文件并构建拓扑。
hr = transcoder.ConfigureAudioOutput(TargetFormat);
} else {
return RET_INPUT_FAIL; // 打开输入文件失败
}
if (SUCCEEDED(hr)) {
hr = transcoder.ConfigureContainer(ContainerType);
}
// 转码并生成输出文件。
if (SUCCEEDED(hr)) {
hr = transcoder.EncodeToFile(p_szDst);
}
if (SUCCEEDED(hr)) {
WriteLogFile(L"Output file created: %s\n", p_szDst);
} else {
WriteLogFile(L"Output file was not created due to error: %s\n", p_szDst);
}
if (!SUCCEEDED(hr)) {
return RET_ENC_FAIL; // 编码失败
}
return RET_OK; // 编码成功
}
以下是转换函数,涵盖了以下音频格式之间的所有转换组合:.mp3、.wav和.m4a。
// 转换为MP3
int SG_AudioConvert::Wav_to_Mp3(
const wchar_t* p_szWavFile,
const wchar_t* p_szMp3File) {
// 检查初始化
if (!m_bInit)
return RET_NOT_INIT;
// 转换
return (ConvertProc(p_szWavFile, p_szMp3File,
MFAudioFormat_MP3, MFTranscodeContainerType_MP3));
}
int SG_AudioConvert::M4A_to_Mp3(
const wchar_t* p_szM4AFile,
const wchar_t* p_szMp3File) {
// 检查初始化
if (!m_bInit)
return RET_NOT_INIT;
// 转换
return (ConvertProc(p_szM4AFile, p_szMp3File,
MFAudioFormat_MP3, MFTranscodeContainerType_MP3));
}
// 转换为M4A
int SG_AudioConvert::Wav_to_M4A(
const wchar_t* p_szWavFile,
const wchar_t* p_szM4AFile) {
// 检查初始化
if (!m_bInit)
return RET_NOT_INIT;
// 转换
return (ConvertProc(p_szWavFile, p_szM4AFile, MFAudioFormat_AAC,
MFTranscodeContainerType_MPEG4));
}
int SG_AudioConvert::MP3_to_M4A(
const wchar_t* p_szMp3File,
const wchar_t* p_szM4AFile) {
// 检查初始化
if (!m_bInit)
return RET_NOT_INIT;
// 转换
return (ConvertProc(p_szMp3File, p_szM4AFile,MFAudioFormat_AAC,
MFTranscodeContainerType_MPEG4));
}
// 转换为Wav
int SG_AudioConvert::MP3_to_Wav(
const wchar_t* p_szMp3File,
const wchar_t* p_szWavFile) {
// 检查初始化
if (!m_bInit)
return RET_NOT_INIT;
// 转换
return (ConvertProc(p_szMp3File, p_szWavFile, MFAudioFormat_PCM,
MFTranscodeContainerType_WAVE));
}
int SG_AudioConvert::M4A_to_Wav(
const wchar_t* p_szM4AFile,
const wchar_t* p_szWavFile) {
// 检查初始化
if (!m_bInit)
return RET_NOT_INIT;
// 转换
return (ConvertProc(p_szM4AFile, p_szWavFile, MFAudioFormat_PCM,
MFTranscodeContainerType_WAVE));
}
最近更新了一些旧代码(感谢Louka Diagnekov),以支持现代应用程序,包括UNICODE字符串,它托管在这个仓库中。这个类的一个不错的功能是可以设置多个查询进行一次搜索。还可以递归扫描文件夹及其子文件夹,以找到符合标准的文件。
在运行搜索之前,这是填充的主要结构。请注意,当涉及到数百万文件时,这个类有点慢,但对于音频转换工具来说,它工作得很好。
// 指定用于搜索文件的设置
struct FindFileOptions_t {
bool recursive; // 是否查看子目录
bool returnFolders; // 返回文件夹名称作为结果
bool *terminateValue; // 检查是否应该终止搜索的值
wstring location; // 搜索文件的位置
wstring filter; // 要包含的文件的过滤器
wstring excludeFile; // 排除文件的过滤器
wstring excludeDir; // 排除目录的过滤器
};
定义了九种操作模式,将一种或两种格式之间的转换转换为第三种格式。这样,就可以搜索给定路径中的一种或两种类型的文件,找到后,将其转换为目标音频类型。
typedef enum {
M4A_WAV_TO_MP3 = 0, // 将m4a和wav转换为mp3
MP3_M4A_TO_WAV = 1, // 将mp3和m4a转换为wav
MP3_WAV_TO_M4A = 2, // 将mp3和wav转换为m4a
M4A_TO_MP3 = 3, // 将m4a转换为mp3
WAV_TO_MP3 = 4, // 将wav转换为mp3
MP3_TO_WAV = 5, // 将mp3转换为wav
M4A_TO_WAV = 6, // 将m4a转换为wav
WAV_TO_M4A = 7, // 将wav转换为m4a
MP3_TO_M4A = 8, // 将mp3转换为m4a
LAST_ELEMENT = 9
} OperationMode;
让详细解释一个操作模式。例如,MP3_WAV_TO_M4A。在这种模式下,希望在给定路径中搜索.mp3和.wav文件,并将所有找到的文件转换为m4a。当选择这种模式时,会执行以下操作:
#define QUERY_MP3_WAV L"*.mp3;*.wav";
回到FindFile类,这样设置:
opts.filter = QUERY_MP3_WAV;
然后调用:
scanPath(wstring path)
开始文件搜索。搜索完成后,有一个包含所有找到的文件的数组,然后将它们转换为目标音频类型。