音频文件格式转换桌面应用程序开发

在本文中,将探讨如何创建一个桌面对话框应用程序,该程序可以用于音频文件格式之间的转换。这包括“引擎”——一个用于实际格式转换的类库,以及在给定路径及其子文件夹中枚举文件。用户界面和用户体验也是关注的重点。

开发的程序无需安装,不需要外部DLL,甚至不需要静态库。只需构建并运行即可。

微软媒体基金会是一个基于Windows的多媒体平台,它为开发者提供了创建各种多媒体软件的能力。使用微软媒体基金会转换音频文件需要对音频流进行编码和解码,这在下面的教程中有详细解释。

构建第一个构建块

创建了自己的音频处理类,称为SG_AudioConvert。以下是其构造函数和析构函数的实现:

SG_AudioConvert::SG_AudioConvert() { // 初始化需要初始化的内容 Init(); } SG_AudioConvert::~SG_AudioConvert() { // 清理需要清理的内容 Cleanup(); }

初始化

Init()函数由构造函数调用,执行以下操作:

  • 检查是否已经初始化。不希望(也不应该)多次进行初始化。
  • 调用HeapSetInformation()以启用堆的某些功能。注意,正在初始化一个单线程公寓,可以在这篇文章中了解更多关于这个术语的信息。
  • 调用MFStartup()以启动Windows媒体基金会。
  • 将m_bInit设置为true,以指示初始化已完成。
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; // 失败 }

清理

在继续之前,还需要介绍由类的析构函数调用的清理过程。

  • 调用MFShutdown()
  • 调用CoUninitialize()
int SG_AudioConvert::Cleanup() { MFShutdown(); CoUninitialize(); return RET_OK; // 成功 }

通用音频转换函数

开发了SG_AudioConvert::ConvertProc()来执行所有文件转换,从任何支持的音频类型到任何其他类型。向它传递以下参数:

  • p_szSrc - 源文件
  • p_szDst - 目标文件
  • TargetFormat - 目标格式的GUID - 参见“音频编解码器”
  • ContainerType - 容器类型 - 参见“文件容器”

函数原型如下:

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)

开始文件搜索。搜索完成后,有一个包含所有找到的文件的数组,然后将它们转换为目标音频类型。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485