ImageVerifierCode 换一换
格式:DOCX , 页数:19 ,大小:24.18KB ,
资源ID:10579365      下载积分:2 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/10579365.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(使用CODECs压缩Wave音频.docx)为本站会员(b****8)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

使用CODECs压缩Wave音频.docx

1、使用CODECs压缩Wave音频使用CODECs压缩Wave音频概要微软的Win95和WinNT操作系统都包含有能够压缩解压缩Wave音频流的CODECs。将你的wave 音频以压缩形式保存不但能够减少对存储空间的需求,在网络上传送时也能减少数据传输 的时间。本文及其附带的实例代码告诉你怎样使用安装在Windows系统中的CODECs来压缩和解压缩音 频。稍稍改变这些代码就可以用作解压缩经过压缩的数据,执行数据格式转换。 所附实例代码是用Microsoft Visual C+ 5.0版本开发的,并在Win95和WinNT 4.0操作系 统上测试过。简介Win95及最近的WinNT都具有能过安装

2、的CODECs处理压缩的wave格式的音频和视频数据流的 能力。一个CODEC是一小段用于压缩(COmpress)及解压缩(DECompress)数据流的代码(因此, 得名CO-DEC)。许多CODECs即能压缩又能解压缩。而一些CODECs仅能用于解压缩,这样私 有数据可以在系统上播放,但数据格式不能在系统上创建。尽管一个CODEC原则上能够用于压缩解压缩任一种数据流,还是设计有各种各样的CODECs 以实现以高的压缩比率,更好的保真度或实时压缩性能来压缩某种数据类型。例如,获取 高的视频压缩数据压缩率的最好方法应用于音频数据时未必就能得到相同的效果,反之也 然。本文着重于怎样在自己的代码中

3、使用CODEC将音频数据以你的系统中CODECs所支持的方式进 行压缩。压缩音频数据的一个主要原因是降低存储某一声音序列所需数据量。少的数据量 意味着声音所占有的空间更少,并且能够以更快的速度在MODEM和网络上传递。如果数据 以Windows系统所支持的某一通用格式压缩的话,则可以不必手工解压缩就直接播放-系 统将使用它自己的CODECs解压缩数据并播放。我的系统中有什么CODECs?Win95和WinNT本身附带有几种标准的CODECs,也可由系统中所安装的应用程序安装其他的 CODECs。例如,DSP Group,Inc. TrueSpeech CODEC随Win95发送,因此你写的任何

4、应用于 Win95的程序都可应用此CODEC(假如用户没有在控制面板中删除它或禁止它的话)。以后 可能要安装的CODEC的一个例子是微软网络(MSN)软件自已所用的音频数据。所有安装的CODECs由音频压缩管理器(ACM)管理。我们可以从一小程序中查询ACM来查到安 装了哪些CODECs,它们都支持什么格式。你也可双击控制面板中的多媒体选项,选择高级 标签,就能看到系统中所安装的CODECs。介绍应用ACM,得知它所管理每一个CODEC都可以做些什么的一个好方法是写一个简单的 查询ACM的命令行应用程序。本文所附带的CAPS程序完成的就是这个功能-让我们看看它的 代码,我将给你一起分析此程序,

5、解释每一步完成的什么功能。首先从调用ACM编程接口所需的包含的头文件开始 :#include #include #include / 多媒体注册#include / 音频压缩管理器#include mmsystem.h头文件定了Windows支持大部分的多媒体功能,但不包含ACM接口及任何厂商定义。 mmreg.h包含了对不同厂商设计的各种wave数据类型的格式标签的定义。它也包含了用于处理 不同的wave数据类型的结构( 基于WAVEFORAMTEX)的定义。msacm.h包含了ACM所需的API, 标志等等。我们要做的第一件事就是执行一些常见的ACM查询来判断版本号,获取诸如它当前管理了多

6、少 个驱动程序的的信息。下面是查询ACM的部分代码:/ 取得ACM版本号DWORD dwACMVer = acmGetVersion();printf(ACM version %u.%.02u build %u,HIWORD(dwACMVer) 8,HIWORD(dwACMVer) & 0x00FF,LOWORD(dwACMVer);if (LOWORD(dwACMVer) = 0) printf( (Retail);printf(n);/ 显示一些ACM的信息printf(ACM metrics:n);DWORD dwCodecs = 0;MMRESULT mmr = acmMetrics(

7、NULL, ACM_METRIC_COUNT_CODECS, &dwCodecs);if (mmr) show_error(mmr); else printf(%lu codecs installedn, dwCodecs);CAPS实例查询了更多的ACM信息。你可以仔细查看它的代码,运行程序得知结果。对ACM有了简单了解后,现在可以要求它枚举出系统中当前所有的驱动程序。我们在程序中所 调用的枚举函数使用回调函数来汇报每个设备的数据,这在Windows编程是一种很普遍的方法。 下面的调用就是枚举当前ACM所管理的所有设备:/ 枚举所有允许的驱动程序printf(Enabled drivers:

8、n);mmr = acmDriverEnum(DriverEnumProc, 0, 0); if (mmr) show_error(mmr);如同其它多媒体函数,许多ACM函数调用返回一MMRESULT值,指出了可能发生的错误。此值为0 表示函数成功执行。现在,让我们看看枚举回调函数DriverEnumProc,它由系统中的每一个驱 动程序调用:BOOL CALLBACK DriverEnumProc(HACMDRIVERID hadid, DWORD dwInstance, DWORD fdwSupport)printf( id: %8.8lxH, hadid);printf( suppor

9、ts:n);if (fdwSupport & ACMDRIVERDETAILS_SUPPORTF_ASYNC) printf( async conversionsn);if (fdwSupport & ACMDRIVERDETAILS_SUPPORTF_CODEC) printf( different format conversionsn);if (fdwSupport & ACMDRIVERDETAILS_SUPPORTF_CONVERTER) printf( same format conversionsn);if (fdwSupport & ACMDRIVERDETAILS_SUPPO

10、RTF_FILTER) printf( filteringn);/ 获得一些具体信息ACMDRIVERDETAILS dd;dd.cbStruct = sizeof(dd);MMRESULT mmr = acmDriverDetails(hadid, &dd, 0);if (mmr) printf( ); show_error(mmr); else printf( Short name: %sn, dd.szShortName);printf( Long name: %sn, dd.szLongName);printf( Copyright: %sn, dd.szCopyright);prin

11、tf( Licensing: %sn, dd.szLicensing);printf( Features: %sn, dd.szFeatures);printf( Supports %u formatsn, dd.cFormatTags);printf( Supports %u filter formatsn, dd.cFilterTags);/ 打开驱动程序HACMDRIVER had = NULL;mmr = acmDriverOpen(&had, hadid, 0);if (mmr) printf( ); show_error(mmr); else DWORD dwSize = 0;mm

12、r = acmMetrics(had, ACM_METRIC_MAX_SIZE_FORMAT, &dwSize);if (dwSize cbSize = LOWORD(dwSize) - sizeof(WAVEFORMATEX);pwf-wFormatTag = WAVE_FORMAT_UNKNOWN;ACMFORMATDETAILS fd;memset(&fd, 0, sizeof(fd);fd.cbStruct = sizeof(fd);fd.pwfx = pwf;fd.cbwfx = dwSize;fd.dwFormatTag = WAVE_FORMAT_UNKNOWN;mmr = ac

13、mFormatEnum(had, &fd, FormatEnumProc, 0, 0); if (mmr) printf( );show_error(mmr);free(pwf);acmDriverClose(had, 0);return TRUE; / 继续枚举驱动程序向回调函数传递了描述驱动程序所支持类型的一组标志。一些驱动程序可以异步 操作,而另一些驱动程序则不能。一些驱动程序能够将一种wave数据格式转换成另一种格 式(称作CODECs),而另一些驱动程序仅能完成过滤操作,其输入输出格式是一样的。注 意ACM维护着这类数据及驱动程序的名字,版权信息等等,这样我们可以不必装载或打开 指定

14、的驱动程序就可以得到这些数据。这样很方便,譬如当需将数据放在列表框中由用户 选择时。要获得有关某一驱动程序能力更多的详细信息,必须装载驱动程序并打开它,可通过调用 acmOpenDriver实现。一旦驱动程序打开,可请求枚举它所支持的wave数据格式。同时有一 个小问题-尽管所有wave格式描述结构基于WAVEFORAMTEX,许多格式使用此结构的扩展形 式来保存其特定的信息。如果我们想枚举所有格式,需要知道为此结构分配多少供驱动 程序填写详细信息的空间。可通过向acmMetrics函数传递ACM_METRIC_MAX_SIZE_FORMAT标 志得到所需的最大的结构的尺寸。如果你读过上面的代

15、码,你会发现我只是简单的将分配的空间强制转换为WAVEFORMATEX指针。 我只对通用信息而不是任一特定类型的数据感兴趣,因此这个指针符合我的要求。为结构分配了空间后,现在我可以acmFormatEnum来枚举所支持的格式。这次又用到一个回 调函数来取得枚举出的格式的相关数据:BOOL CALLBACK FormatEnumProc(HACMDRIVERID hadid, LPACMFORMATDETAILS pafd,DWORD dwInstance, DWORD fdwSupport)printf( %4.4lXH, %sn, pafd-dwFormatTag, pafd-szForma

16、t);return TRUE; / 继续枚举如你所看到的,这是一次尝试并仅打印出格式的某些信息。这样,通过上面的代码,你能够查询ACM所有的驱动程序,查找每一个驱动程序所支持的 格式。我建议你现在运行CAPS程序,看看你的系统上安装了些什么。 使用特定的CODEC好了,我们已得知你的系统上安装了什么CODECs-现在来看看怎样查找某一特定的CODEC并 使用它压缩音频数据。让我们看看CONV实例,它使用一种有效的CODEC压缩一个简单的wave 数据包。为了使代码更趋简单,我以控制台应用程序的形式的实现它,也没有尝试去 播放压缩过的数据或将其存入文件。这个实例的代码仅向你展示怎样找到你所需要的

17、驱 动程序并使用它将数据转换为压缩格式。剩下的就靠你了。两步实现压缩在理想的情况下,压缩一些数据可能只不过是向系统说:“这有一些数据,请压缩成这种格式。” 不幸的是,Windows编程与理想相去甚远,象通常一样,我们得自已做许多琐碎的工作。 要解决的第一个也是最重要的问题是给定的CODEC可能不能压缩你所使用的数据格式。例 如,我们录入了一些11025Hz,8位,单声道的PCM数据(或许是用户向麦克风说的话),此 种格式几乎所有的多媒体PC都能录制。我们可能要将数据通过MODEM传递,因此我们想尽可能的压缩数据,使数据量减少。我们选择了TrucSpeech CODEC,它安装在Windows中

18、,能够 获得大约10:1的压缩率。我们所要碰到的问题就是TrueSpeech CODEC不能处理11025Hz, 8位,单声道的PCM数据。它只能处理8000Hz,16位,单声道的数据(某些情况下是8位)。 因此我们必须先将源数据转换为TrueSpeech CODEC所支持的中间PCM格式,然后在使用它 将中间数据转换为最终所需的格式。可使用随Windows分发的某种不同的CODEC将一种PCM格式转换为另一种格式,因此你需使用 某种CODEC将数据转换为其它CODEC能够处理的格式。我们已知道怎样去枚举CODECs及其所 支持的格式,因此这样做是可以实现的。但还有一个问题,我在实例代码中忽略

19、了,留给你们解决。如果某一CODEC能够创建我们所 想要的压缩格式,但支持几种不同的输入格式,我们怎样选择最佳的中间格式呢?按照 Nigel的准则,那就是“总是做最少量的工作”,我选择使用CODEC所支持的枚举出的第一 种PCM格式。由于很容易实现,可能会导致数据失真。假设我们要使用的某一CODEC有一些 近乎无失真的压缩算法,能够接收8位或16位的11025Hz或22050Hz的PCM数据。我们要转换 以441000Hz,16位立体声录制的高保真的样本。我们试图降低数据量,而不在乎损失质量。如果我们枚举此CODEC所支持的格式,第一个得到的可能是11025Hz,8位单声道的格式。我 们先将数

20、据转换为此格式,然后进行压缩,这其间肯定要损失一些质量,因为这种中间格 式不够好。如果使用16位22050Hz的话会好一些。已告诉过你这种缺憾啦,让我们瞧瞧CONV 实例,看它是怎样工作的。CONV实例程序CONV实例分四个阶段:它创建一些wave格式数据的样本,找到一个合适的CODEC,将数据转 换为此CODEC可处理的中间格式,最后将数据转换成所需的格式。为了简单其间,源数据用 程序创建而不是录入或是从wave文件中读取:/ 首先我们创建一个可能是刚刚才录制的wave 其格式为11.025kHz,/ 8位单声道PCM,这是一个所有机器上都可用的录入格式,我们的例/ 子是1秒长的1kHz的正

21、弦波wave,刚好1000个周期WAVEFORMATEX wfSrc;memset(&wfSrc, 0, sizeof(wfSrc); wfSrc.cbSize = 0;wfSrc.wFormatTag = WAVE_FORMAT_PCM; / PCM wfSrc.nChannels = 1; / MonowfSrc.nSamplesPerSec = 11025; / 11.025 kHzwfSrc.wBitsPerSample = 8; / 8 bitwfSrc.nBlockAlign = wfSrc.nChannels * wfSrc.wBitsPerSample / 8;wfSrc.nA

22、vgBytesPerSec = wfSrc.nSamplesPerSec * wfSrc.nBlockAlign;DWORD dwSrcSamples = wfSrc.nSamplesPerSec;BYTE* pSrcData = new BYTE dwSrcSamples; / 1秒种的长度BYTE* pData = pSrcData; double f = 1000.0;double pi = 4.0 * atan(1.0); double w = 2.0 * pi * f;for (DWORD dw = 0; dw 上面的代码创建了一个WAVEFORMATEX结构用来描述源数据格式,并用

23、简单的数学方法生成了1秒钟长的11.025kHz,8位单声道的PCM的wave数据。下一步就是选择要将数据转换成什么格式及选定一个合适的CODEC。WORD wFormatTag = WAVE_FORMAT_DSPGROUP_TRUESPEECH;/ 现在我们选定一个支持目标格式标签的CODECHACMDRIVERID hadid = find_driver(wFormatTag);if (hadid = NULL) printf(No driver foundn);exit(1);printf(Driver found (hadid: %4.4lXH)n, hadid);find_drive

24、r函数枚举所有的驱动程序直到找到一个支持给定标签值的驱动程序(本例为WAVE_FORMAT_DSPGROUP_TRUESPEECH)。我没有在此给出代码是因为它与前面的枚举代码非常相象。随后你可以查看它是怎样工作的。选定了驱动程序,现在要为最终驱动程序将产生的压缩数据格式创建一个WAVEFORMATEX结构,并为驱动程序用于输入的中间PCM格式产生一个WAVEFORMATEX结构。/ 获得格式的详情/ 注意:这只是一个给定格式签的第一种或是最可能的格式WAVEFORMATEX* pwfDrv = get_driver_format(hadid, wFormatTag);if (pwfDrv =

25、 NULL) printf(Error getting format infon);exit(1); printf(Driver format: %u bits, %lu samples per secondn,pwfDrv-wBitsPerSample, pwfDrv-nSamplesPerSec);/ 获取驱动程序所支持的PCM格式标签/ 注意:我们只是选取第一支持的PCM格式但不一定是最好的选择WAVEFORMATEX* pwfPCM = get_driver_format(hadid, WAVE_FORMAT_PCM);if (pwfPCM = NULL) printf(Error g

26、etting PCM format infon);exit(1); printf(PCM format: %u bits, %lu samples per secondn,pwfPCM-wBitsPerSample, pwfPCM-nSamplesPerSec);有点重复了,要注意的是get_driver_format函数仅仅枚举出第一种匹配的格式-也许不能获得可能的最好的质量。现在我们有了WAVEFORMATEX结构描述源格式,中间PCM格式,以及最终的压缩格式。可以开始转换数据了。转换由被ACM称作流的对象来实现。我们可以打开流,将源格式、目标格式传递给它,要求它进行转换。在此要注意如果C

27、ODEC的算法复杂的话同步转换是很耗时的。一些CODEC可以异步工作,通过向窗口发送一个消息,或调用一个回调函数,或设置一个事件告知你转换进程。下面的代码是以最少麻烦准则完成任务的-你必须等待它直到完成。还有另外一点,很重要。如你所知,我们打开转换流,指明ACM_STREAMOPENF_NONREALTIME标志。这非常重要。若省略此标志,那么一些驱动程序(例如TrueSpeech驱动程序)将会报告错误512(意思是不可能)。此错误告诉你所要求的转换不能实时进行。我的实例代码中没有这个问题,但如果你试图在播放数据的同时转换大量数据,就要注意这点了。让我们看看第一步的转换,它完成的是将源数据转换

28、为中间格式:/ 将源wave转换为CODEC所支持的PCM格式/ 我们使用任一种能实现PCM格式间转换驱动程序HACMSTREAM hstr = NULL; mmr = acmStreamOpen(&hstr,NULL, / 任一驱动程序&wfSrc, / 源格式pwfPCM, / 目标格式NULL, / 无过滤NULL, / 没回调0, / 实例数据(未使用)ACM_STREAMOPENF_NONREALTIME); / 标志if (mmr) printf(Failed to open a stream to do PCM to PCM conversionn);exit(1); / 为转换

29、结果开辟一个缓冲区DWORD dwSrcBytes = dwSrcSamples * wfSrc.wBitsPerSample / 8;DWORD dwDst1Samples = dwSrcSamples * pwfPCM-nSamplesPerSec / wfSrc.nSamplesPerSec;DWORD dwDst1Bytes = dwDst1Samples * pwfPCM-wBitsPerSample / 8;BYTE* pDst1Data = new BYTE dwDst1Bytes; / 填写转换信息ACMSTREAMHEADER strhdr; memset(&strhdr,

30、0, sizeof(strhdr);strhdr.cbStruct = sizeof(strhdr);strhdr.pbSrc = pSrcData; / 要转换的源数据strhdr.cbSrcLength = dwSrcBytes; strhdr.pbDst = pDst1Data;strhdr.cbDstLength = dwDst1Bytes; / 准备好头mmr = acmStreamPrepareHeader(hstr, &strhdr, 0); / 转换数据printf(Converting to intermediate PCM format.n);mmr = acmStreamConvert(hstr, &strhdr, 0); if (mmr) printf(Failed to do PCM to PCM conversionn); exit(1); printf(Conver

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1