科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件VC调用ACM音频编程接口压缩Wave音频

VC调用ACM音频编程接口压缩Wave音频

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

本文介绍了在Microsoft Visual C 6.0下如何调用ACM音频压缩编程接口对原始录入的Wave音频进行数据压缩.

作者:中国电子科技集团公司 来源:天极网 2007年10月19日

关键字:

  • 评论
  • 分享微博
  • 分享邮件
将Wave音频转换为CODEC所支持的PCM格式

  通过CODEC将源Wave音频转换成CODEC所支持的PCM格式,可以使用任何可以做PCM间转换的驱动器。另外还有一点很重要:我们打开转换流时,要指明ACM_STREAMOPENF_NONREALTIME标志。若省略此标志,那么一些驱动程序(例如TrueSpeech CODEC)将会报告发生第512号"不可能发生的"错误。该错误指明所要求的转换不能实时进行,如果在试图播放数据的同时转换大量数据,就必须注意这点。下面是该步转换过程的简要描述:

mmr = acmStreamOpen(&hstr,
NULL, //任意驱动器
&wfSrc, //源格式
pwfPCM, //目标格式
NULL, //无过滤
NULL, //无回调
0, //初始数据
ACM_STREAMOPENF_NONREALTIME);

  根据以字节计的平均速率计算出输出缓冲区的大小,并加上一机动位(bit)如果没有此额外的空间IMA_ADPCM驱动程序将不能转换。中间的转换结果将存放在pDst1Data中:

DWORD dwSrcBytes = dwSrcSamples * wfSrc.wBitsPerSample / 8;
DWORD dwDst1Samples = dwSrcSamples * pwfPCM->nSamplesPerSec / wfSrc.nSamplesPerSec;
DWORD dwDst1Bytes = dwDst1Samples * pwfPCM->wBitsPerSample / 8;
unsigned char * pDst1Data = new unsigned char[dwDst1Bytes];
……
ACMSTREAMHEADER strhdr; //填充转换信息
memset(&strhdr, 0, sizeof(strhdr));
strhdr.cbStruct = sizeof(strhdr);
strhdr.pbSrc = cpBuf; //指定要转换的源Wave音频数据为cpBuf中的数据
strhdr.cbSrcLength = dwSrcBytes;
strhdr.pbDst = pDst1Data;
strhdr.cbDstLength = dwDst1Bytes;
mmr = acmStreamPrepareHeader(hstr, &strhdr, 0);
mmr = acmStreamConvert(hstr, &strhdr, 0); //转换数据
……
acmStreamClose(hstr, 0);

  当流打开时,第二个参数为NULL,表示接受任何驱动程序进行转换。复杂的只是计算需要给输出数据分配多大的缓冲区。PCM格式间的转换不牵扯压缩和解压缩,缓冲区大小直接就计算出来了。至于调用acmStreamPrepareHeader这个ACM API函数,是由于它可以为驱动程序安排好一切并允许驱动程序在转换前锁定内存。

  生成最终的压缩格式

  向最终压缩格式的转换过程与前面的PCM格式间转换非常相似,只不过此次转换我们提供了打开流时想要使用的驱动程序的句柄。实际上,此处仍可使用NULL,因为已预知此驱动程序存在,但提供句柄避免了系统浪费时间为我们查找此驱动程序:

mmr = acmStreamOpen(&hstr,
had, //驱动器句柄
pwfPCM, //源格式
pwfDrv, //目标格式
NULL, //无过滤
NULL, //无回调
0, //实例化数据
ACM_STREAMOPENF_NONREALTIME);

  另外,计算用于压缩数据的缓冲区的尺寸有点难办,需要凭猜测。WAVEFORMATEX结构的nAvgBytesPerSec 域表示回放期间读取字节的平均速率。我们可使用它来估计存储压缩的wave需要多大空间。一 些驱动程序给出的数据确实是平均的,而不是最差场合下的值,因此我选择多增加50%的空间。 此方法在实践中虽然有些浪费但很有效:

DWORD dwDst2Bytes = pwfDrv->nAvgBytesPerSec * dwDst1Samples / pwfPCM->nSamplesPerSec;
dwDst2Bytes = dwDst2Bytes * 3 / 2;
unsigned char * pDst2Data = new unsigned char [dwDst2Bytes];

  其中,无符号字符型指针pDst2Data用于存储压缩的最终Wave音频数据,其大小经上式估算后存到dwDst2Bytes中。一旦转换完成,ACMSTREAMHEADER的结构的cbDstLengthUsed 域指出缓冲区实际用了多少字节。可以通过它来计算出压缩比:

double result= (double) dwSrcBytes / (double) strhdr2.cbDstLengthUsed;

  当源信号为8K采样、16bits PCM编码、单声道、长度为1秒的Wave音频信号, 驱动程序采用Windows 98自带的TrueSpeech 音频CODEC,它能实现大约10:1的压缩,这样高的压缩率还是比较另人满意的。

  小结

  本文以TrueSpeech CODEC为例对使用ACM音频压缩编程接口实现Wave音频压缩的过程作了介绍。如果有自已的压缩格式,也可创建并安装自已的CODEC,实现的方法与之基本类似。在理解了上述编程思想的前提下,对代码稍加改动就可编写出相 应的解压程序。本程序在Windows 2000 Professional下,由Microsoft Visual C++ 6.0编译通过。

查看本文来源

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章