创建用于相互转换音频文件的桌面应用程序
下面的文章将指导您完成创建基于桌面对话框的应用程序的过程,该应用程序可用于相互转换音频文件。包括:
“engine”-一个类库,用于从一种格式到另一种格式的实际转换
枚举给定路径中的文件以及其中的任何子文件夹。
用户界面和用户体验
我开发的程序无需安装即可运行,无需外部DLL,甚至不需要静态库。只需构建并运行即可。
背景
MicrosoftMediaFoundation是一个基于Windows的多媒体平台,使开发人员能够创建各种多媒体软件。
转换音频文件
使用MicrosoftMediaFoundation转换音频文件需要对音频流进行编码和解码,这将在以下教程中进行说明。
第一步是为此类音频处理创建我们自己的类,我们称之为SG_Audio(Convert)。
SG_AudioConvert::SG_AudioConvert() { // Initialize whatever needs to be initialized Init(); } SG_AudioConvert::~SG_AudioConvert() { // Clean up whatever needs to be cleaned up Cleanup(); }1234567891011复制代码类型:[c]
初始化中
我们的Init()功能由构造调用,执行以下操作:
检查它是否已经通过初始化。我们不希望(也不应该)多次这样做。
调用HeapSetInformation()为我们的堆启用某些功能。请注意,我们正在初始化单线程单元,您可以在这篇出色的文章中了解有关该术语的更多信息。
调用MFStartup()以启动WindowsMediaFoundation。
设置m_bInit为true,表示初始化已完成。
int SG_AudioConvert::Init() { HRESULT hr = S_OK; // check already initialized 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; // success } m_bInit = FALSE; return RET_FAIL; // fail }12345678910111213141516171819202122复制代码类型:[c]
打扫干净
在继续之前,我们还介绍一下我们类的Destructor调用的清理过程。
int SG_AudioConvert::Cleanup() { MFShutdown(); CoUninitialize(); return RET_OK; // success }1234567复制代码类型:[c]
在清理过程中,我们执行以下操作:
致电MFShutdown()
呼叫CoUninitialize()
我们的通用音频转换功能
我们开发intSG_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);12345复制代码类型:[c]
转换
我们的通用转换函数如下所示:ConvertProc()
注:WriteLogFile()是在描述我的旧的日志记录功能之一这个文章。
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; // Create a media source for the input file. hr = transcoder.OpenFile(p_szSrc); if (SUCCEEDED(hr)) { //Configure the profile and build a topology. hr = transcoder.ConfigureAudioOutput(TargetFormat); } else { return RET_INPUT_FAIL; // open input file fail } if (SUCCEEDED(hr)) { hr = transcoder.ConfigureContainer(ContainerType); } //Transcode and generate the output file. 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; // encoding failed } return RET_OK; // encoding success }123456789101112131415161718192021222324252627282930313233343536373839404142434445复制代码类型:[c]
我们的转换功能
这是我们的转换函数:
以下六个功能涵盖了以下音频格式的每种组合之间的转换:.mp3,.wav和.m4a。
// Convert to MP3 int SG_AudioConvert::Wav_to_Mp3(const wchar_t* p_szWavFile, const wchar_t* p_szMp3File) { // check initialize if (!m_bInit) return RET_NOT_INIT; // convert 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) { // check initialize if (!m_bInit) return RET_NOT_INIT; // Convert return(ConvertProc(p_szM4AFile, p_szMp3File, MFAudioFormat_MP3, MFTranscodeContainerType_MP3)); } // Convert to M4A int SG_AudioConvert::Wav_to_M4A(const wchar_t* p_szWavFile, const wchar_t* p_szM4AFile) { // check initialize if (!m_bInit) return RET_NOT_INIT; // Convert 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) { // check initialize if (!m_bInit) return RET_NOT_INIT; // Convert return(ConvertProc(p_szMp3File, p_szM4AFile,MFAudioFormat_AAC, MFTranscodeContainerType_MPEG4)); } // Convert to Wav int SG_AudioConvert::MP3_to_Wav(const wchar_t* p_szMp3File, const wchar_t* p_szWavFile) { // check initialize if (!m_bInit) return RET_NOT_INIT; // Convert 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) { // check initialize if (!m_bInit) return RET_NOT_INIT; // Convert return(ConvertProc(p_szM4AFile, p_szWavFile, MFAudioFormat_PCM, MFTranscodeContainerType_WAVE)); }1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768复制代码类型:[c]
我们的文件搜索机制
我最近更新了一些旧代码(感谢LoukaDiagnekov)来支持现代应用程序,包括UNICODE字符串,并且该代码托管在此存储库中。
此类的一个不错的功能是可以在一个搜索中设置多个查询的功能。我们还可以递归地扫描文件夹及其子文件夹,以查找与我们的标准相匹配的文件。
这是struct运行搜索之前填写的主要内容。请注意,当涉及到数百万个文件时,此类有点慢,但是就我们的音频转换器工具而言,它可以正常工作。
// Specifies settings to use for searching for files struct FindFileOptions_t { bool recursive; // Whether to look inside subdirectories bool returnFolders; // Return folder names as results too bool *terminateValue; // Value to check to see whether search should be // terminated wstring location; // Where to search for files wstring filter; // Filter for files to be included wstring excludeFile; // Exclude filter for files wstring excludeDir; // Exclude filter for directories };12345678910111213141516复制代码类型:[c]
我们的运作模式
我们定义了9种操作模式,可以将一种或两种格式秘密转换为第三种。这样,我们可以在给定路径中搜索一种或两种类型的文件,并在找到时将其转换为第三种格式。
typedef enum { M4A_WAV_TO_MP3 = 0, // convert m4a and wav to mp3 MP3_M4A_TO_WAV = 1, // convert mp3 and m4a to wav MP3_WAV_TO_M4A = 2, // convert mp3 and wav to m4a M4A_TO_MP3 = 3, // convert m4a to mp3 WAV_TO_MP3 = 4, // convert wav to mp3 MP3_TO_WAV = 5, // convert mp3 to wav M4A_TO_WAV = 6, // convert m4a to wav WAV_TO_M4A = 7, // convert wav to m4a MP3_TO_M4A = 8, // convert mp3 to m4a LAST_ELEMENT = 9 } OperationMode;1234567891011121314复制代码类型:[c]
让我们采用一种“操作模式”并对其进行详细说明。例如,MP3_WAV_TO_M4A。
在此模式下,我们希望在给定路径中搜索.mp3和.wav文件,并将所有找到的文件转换为m4a。
选择此模式后,我们将执行以下操作:
使用以下查询搜索文件:
#define QUERY_MP3_WAV L"*.mp3;*.wav";1复制代码类型:[cpp]
因此,回到我们的FindFile课程,我们将其设置为:
opts.filter = QUERY_MP3_WAV;1复制代码类型:[cpp]
然后,我们调用:
scanPath(wstring path)1复制代码类型:[cpp]
开始我们的文件搜索。搜索完成后,我们将得到一个数组,其中包含所有找到的文件,然后将这些文件转换为我们的目标音频类型。
用户界面
该软件基于基于Dialog的MFC应用程序。对话框可调整大小,并且每次调整对话框大小时都会调整每个元素。这是使用MarcRicharme的以下文章中的一些非常古老(但坚如磐石)的代码实现的。对话框也有其自己的皮肤,背景颜色,透明元素,因此它看起来比标准MFC应用程序更好。
突破数字边界:科学上网的必要性与实用指南
在当今高度互联的世界中,互联网已成为人们获取信息、交流思想、开展商业活动的重要平台。然而,由于各种原因,全球范围内存在着不同程度的网络限制和审查制度。这些限制不仅阻碍了信息的自由流通,也影响了人们的日常生活和工作效率。科学上网作为一种突破网络限制的有效手段,正变得越来越重要。本文将深入探讨科学上网的必要性,并提供一份实用的技术指南,帮助读者在数字世界中自由穿行。
一、科学上网:数字时代的生存技能
科学上网,简单来说就是通过各种技术手段绕过网络限制,实现自由访问互联网的行为。这种行为并非简单的"翻墙",而是一种在特定环境下维护自身数字权利的必要措施。
1.1 信息自由与知识获取
在知识经济时代,信息就是力量。许多重要的学术资源、技术文档和国际新闻平台在某些地区无法直接访问。科学上网打破了这种信息壁垒,让用户能够平等地获取全球知识资源。例如:
- 访问Google Scholar等学术搜索引擎
- 查阅被屏蔽的维基百科条目
- 获取国际媒体的多元视角报道
1.2 隐私保护与数据安全
在监控日益严密的环境中,科学上网工具提供的加密功能可以有效保护用户的网络隐私。通过VPN等工具,用户的浏览历史、通讯内容和个人数据都能得到更好的保护,防止被不当收集和利用。
1.3 商业需求与全球协作
对于跨国企业、自由职业者和数字游民来说,科学上网是开展业务的必备工具。它允许:
- 访问国际商务平台
- 使用被限制的云服务
- 进行安全的跨境通讯
二、主流科学上网技术详解
2.1 VPN:安全便捷的首选方案
虚拟私人网络(VPN)是目前最流行的科学上网方式。其工作原理是在用户设备和远程服务器之间建立加密隧道,所有网络流量都通过这个隧道传输。
优势分析:
- 端到端加密保障安全
- 隐藏真实IP地址
- 支持多设备同时连接
- 可绕过地理限制访问流媒体
推荐服务:
1. ExpressVPN:速度快,服务器分布广
2. NordVPN:安全性高,双重加密
3. Surfshark:性价比高,无限设备连接
2.2 代理服务器:轻量级解决方案
代理服务器充当用户与目标网站之间的中介,适用于特定场景的科学上网需求。
类型比较:
| 类型 | 协议支持 | 加密性 | 适用场景 |
|------|---------|--------|----------|
| HTTP代理 | HTTP | 弱 | 网页浏览 |
| SOCKS5 | 多种协议 | 中等 | 游戏、P2P |
使用建议:
- 临时访问时使用免费代理
- 重要操作选择付费代理服务
- 避免在不安全网站上输入敏感信息
2.3 SSH隧道:技术向的安全选择
SSH隧道通过安全外壳协议建立加密连接,适合有一定技术基础的用户。
配置步骤:
1. 获取SSH服务器访问权限
2. 本地设置端口转发
3. 配置浏览器使用SOCKS代理
适用场景:
- 企业远程办公
- 开发者访问受限资源
- 需要高度匿名的操作
三、科学上网实用指南
3.1 工具选择标准
在选择科学上网工具时,应考虑以下关键因素:
- 安全性:是否采用AES-256等强加密标准
- 隐私政策:是否保留用户日志
- 服务器分布:是否覆盖所需地区
- 连接速度:是否满足流媒体等高带宽需求
- 客户端支持:是否提供多平台应用
3.2 使用注意事项
- 避免使用来历不明的免费服务
- 定期更换连接节点
- 注意当地法律法规
- 重要操作配合多重加密使用
- 保持软件及时更新
3.3 进阶技巧
- 分流设置:仅对需要科学上网的流量进行路由
- 混淆技术:应对深度包检测(DPI)
- 多重跳板:增强匿名性
- 自建服务器:完全掌控数据安全
四、常见问题解答
Q:科学上网是否合法?
A:合法性因地区而异。在一些国家,使用科学上网工具可能违反当地法律。用户应自行了解并承担相应风险。
Q:免费VPN安全吗?
A:大多数免费VPN通过出售用户数据或投放广告盈利,存在隐私风险。建议选择信誉良好的付费服务。
Q:如何测试VPN是否泄漏DNS?
A:可使用ipleak.net等网站进行检测,确保所有请求都通过VPN隧道传输。
Q:为什么有时连接速度很慢?
A:可能原因包括服务器负载高、网络封锁严重或本地网络问题。尝试切换节点或协议类型。
五、未来展望
随着网络审查技术的不断升级,科学上网工具也在持续进化。未来可能出现:
- 基于区块链的分布式VPN
- AI驱动的智能流量混淆
- 量子加密技术的应用
- 更加用户友好的隐私保护方案
精彩点评
在这个信息即权力的数字时代,科学上网已从技术爱好者的玩具转变为现代数字公民的必备技能。它不仅是突破地理限制的工具,更是维护网络自由、保护数字隐私的盾牌。
本文系统性地梳理了科学上网的技术脉络,既有对必要性的深刻阐述,又提供了极具操作性的实用指南。特别值得一提的是,文章没有停留在简单的工具推荐层面,而是深入探讨了技术原理、选择标准和进阶技巧,使读者能够根据自身需求做出明智选择。
语言表达上,文章在保持专业性的同时做到了通俗易懂,技术术语解释清晰,逻辑结构严谨。从基础概念到前沿展望,构建了一个完整的认知框架,既适合初学者入门,也能给有经验的用户带来新的启发。
在数字权利日益受到挑战的今天,这样一篇兼具知识性和实用性的指南,无疑为追求信息自由的网民提供了宝贵的参考。记住:知识不应有国界,思想不该被禁锢——而这正是科学上网最根本的价值所在。
版权声明:
作者: freeclashnode
链接: https://www.freeclashnode.com/news/article-4042.htm
来源: FreeClashNode
文章版权归作者所有,未经允许请勿转载。
热门文章
- 6月27日|18.9M/S,Shadowrocket(小火箭)/V2ray/Clash(小猫咪)免费节点订阅链接每天更新
- 6月23日|21.1M/S,Clash(小猫咪)/Shadowrocket(小火箭)/V2ray免费节点订阅链接每天更新
- 6月28日|22.2M/S,V2ray/Clash(小猫咪)/Shadowrocket(小火箭)免费节点订阅链接每天更新
- 6月26日|23M/S,Clash(小猫咪)/V2ray/SSR免费节点订阅链接每天更新
- 6月22日|18.4M/S,V2ray/Shadowrocket(小火箭)/Clash(小猫咪)免费节点订阅链接每天更新
- 6月24日|19.8M/S,Shadowrocket(小火箭)/V2ray/Clash(小猫咪)免费节点订阅链接每天更新
- 7月1日|21.7M/S,Clash(小猫咪)/V2ray/Shadowrocket(小火箭)免费节点订阅链接每天更新
- 6月29日|20.9M/S,Shadowrocket(小火箭)/V2ray/Clash(小猫咪)免费节点订阅链接每天更新
- 7月2日|20.9M/S,Clash(小猫咪)/SSR/V2ray免费节点订阅链接每天更新
- 6月30日|22.7M/S,Clash(小猫咪)/Shadowrocket(小火箭)/V2ray免费节点订阅链接每天更新
最新文章
- 7月17日|22M/S,Shadowrocket(小火箭)/Clash(小猫咪)/V2ray免费节点订阅链接每天更新
- 7月16日|20.3M/S,SSR/Clash(小猫咪)/V2ray免费节点订阅链接每天更新
- 7月15日|22.9M/S,Clash(小猫咪)/SSR/V2ray免费节点订阅链接每天更新
- 7月14日|22.8M/S,Clash(小猫咪)/V2ray/SSR免费节点订阅链接每天更新
- 7月13日|19.9M/S,Clash(小猫咪)/Shadowrocket(小火箭)/V2ray免费节点订阅链接每天更新
- 7月12日|22.3M/S,Clash(小猫咪)/V2ray/Shadowrocket(小火箭)免费节点订阅链接每天更新
- 7月11日|21.4M/S,Clash(小猫咪)/V2ray/Shadowrocket(小火箭)免费节点订阅链接每天更新
- 7月10日|21.6M/S,V2ray/Shadowrocket(小火箭)/Clash(小猫咪)免费节点订阅链接每天更新
- 7月9日|19.6M/S,SSR/V2ray/Clash(小猫咪)免费节点订阅链接每天更新
- 7月8日|22.1M/S,Shadowrocket(小火箭)/Clash(小猫咪)/V2ray免费节点订阅链接每天更新