VC 调 用ACM 音 频 压 缩 编 程 接 口 的 方 法

 

音 频 和 视 频 数 据 是 大 多 数 多 媒 体 应 用 程 序 向 用 户 提 供 信 息 的 主 要 方 式, 这 些 数 据 一 般 具 有较 高 的 采 样 速 率, 如 果 不 经 过 压 缩 的 话, 保 存 它 们 需 要 消 耗 大 量 的 存 贮 空 间, 在 网 络 上 进 行 传 输的 效 率 也 很 低, 因 此 音 频 视 频 数 字 压 缩 编 码 在 多 媒 体 技 术 中 占 有 很 重 要 的 地 位。 就 音 频 数 据 而言, 目 前 常 用 的 压 缩 方 法 有 很 多 种, 不 同 的 方 法 具 有 不 同 的 压 缩 比 和 还 原 音 质, 编 码 的 格 式 和 算法 也 各 不 相 同, 其 中 某 些 压 缩 算 法 相 当 复 杂, 普 通 程 序 不 可 能 去 实 现 其 编 解 码 算 法。 所 幸 的 是,与Windows 3.x 相 比,Windows 95/NT 4.0 为 多 媒 体 应 用 程 序 提 供 了 更 强 的支 持, 引 入 了ACM(Audio Compression Manager, 音 频 压 缩 管 理 器) 和VCM(Video Compression Manager, 视 频 压 缩 管 理 器), 它 们 负 责 管 理 系 统 中 所 有 音 频 和 视 频 编 解 码 器(Coder-Decoder,简 称CODEC, 是 实 现 音 频 视 频 数 据 编 解 码 的 驱 动 程 序), 应 用 程 序 可 以 通 过ACM 或VCM 提 供 的 编 程接 口 调 用 这 些 系 统 中 现 成 的 编 解 码 器 来 实 现 音 频 或 视 频 数 据 的 压 缩 和 解 压 缩。95/NT 4.0 系 统自 带 的 音 频CODECs 支 持 一 些 早 期 的 音 频 数 据 压 缩 标 准, 如ADPCM 等,Internet Explorer 4.0 等应 用 程 序 包 含 的 音 频CODECs 支 持 一 些 比 较 新 的 压 缩 标 准, 如MPEG Layer 3 等。 在 控 制 面 板 的 多媒 体 组 件 中 选 择“ 高 级”, 打 开“ 音 频 压 缩 的 编 码 解 码 器”, 就 可 列 出 系 统 中 安 装 的 所 有 音 频CODECs。本 文 所 要 介 绍 的 就 是ACM 音 频 压 缩 接 口 的 编 程 方 法, 所 用 编 程 工 具 为VC++ 5.0。

获 取CODECs 的 信 息

---- ACM API msacm.h 中, 外, ACM mmsystem.hmmreg.h 构。 ACM ACM 用, acmGetVersion ACM 息。

---- 前 面 提 到, 在控 制 面 板 中 可 以 查 看 系 统 中CODECs 的 信 息, 而 在 应 用 程 序 中 也 常 常 需 要 知 道 某 种 音 频CODECs 是否 存 在, 并 获 取 其 编 解 码 参 数 等 信 息, 这 一 点 可 以 通 过 调 用 下 面 两 个 函 数 来 实 现。

---- MMRESULT mmr=acmMetrics(NULL, ACM_METRIC_COUNT_CODECS, &dwCodecs);

---- mmr = acmDriverEnum(CodecsEnumProc, 0, 0);

---- acmMetrics() 函 数 可 以 获 取 许 多ACM 对 象 的 有 用 信 息, 例 如 向 其 中 传 递ACM_METRIC_COUNT_CODECS 可 以 查 询 系 统 中 安 装 的 音 频CODECs 总 数。 函 数acmDriverEnum() 的 功 能 是 枚 举 所 有 的 音 频CODECs,在acmDriverEnum() 的 参 数 中 指 定 回 调 函 数CodecsEnumProc() 可 以 进 一 步 查 询 每 个CODEC 的 信息。Windows 编 程 中 经 常 要 用 到 回 调 函 数, 下 面 是 枚 举 音 频CODECs 的 一 个 回 调 函 数 的 示 例。

 
  
 
  
BOOL CALLBACK CodecsEnumProc(HACMDRIVERID 
  
 
  
hadid, DWORD dwInstance, DWORD fdwSupport) {
  
 
  
DWORD dwSize = 0;
  
 
  
if (fdwSupport & ACMDRIVERDETAILS_SUPPORTF_CODEC)
  
 
  
 printf("多格式转换/n");
  
 
  
ACMDRIVERDETAILS add;
  
 
  
acmdd.cbStruct = sizeof(acmdd);
  
 
  
MMRESULT mmr = acmDriverDetails(hadid, &acmdd, 0);
  
 
  
if (mmr)  error_msg(mmr);
  
 
  
else {
  
 
  
printf(" 全称:  %s/n", acmdd.szLongName);
  
 
  
printf(" 描述:   %s/n", acmdd.szFeatures);
  
 
  
}
  
 
  
HACMDRIVER had = NULL;
  
 
  
mmr = acmDriverOpen(&had, hadid, 0);      //打开驱动程序
  
 
  
if (mmr)  error_msg(mmr);
  
 
  
else {
  
 
  
mmr = acmMetrics(had, ACM_METRIC_
  
 
  
MAX_SIZE_FORMAT, &dwSize);
  
 
  
WAVEFORMATEX* pwf = (WAVEFORMATEX*) malloc(dwSize);
  
 
  
memset(pwf, 0, dwSize);
  
 
  
pwf->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 = acmFormatEnum(had, &fd, FormatEnumProc, 0, 0);  
  
 
  
if (mmr)  error_msg(mmr);
  
 
  
free(pwf);
  
 
  
acmDriverClose(had, 0);
  
 
  
}
  
 
  
return TRUE; 
  
 
  
}
  
 
  

---- CodecsEnumProc() 共 有 三 个 参 数。 第 一 个 参 数 是 驱 动 程 序 的ID 值; 第 二 个 参 数 是 实 例 数 据, 本文 例 子 中 未 使 用; 第 三 个 参 数 描 述 该 驱 动 程 序 所 支 持 的 功 能, 它 由 一 组 标 识 进 行 或 运 算 构 成, 例如, 如 果 设 置 了 标 识ACMDRIVERDETAILS_SUPPORTF_CODEC, 则 说 明 该 驱 动 程 序 可 以 将 一 种 编 码 格式 的 音 频 信 号 转 换 成 另 一 种 编 码 格 式。 通 过acmDriverDetails() 函 数 可 以 获 得 对 该 驱 动 程 序 进一 步 的 信 息, 如CODEC 的 名 称、 简 单 描 述 等。 以 上 信 息 实 际 上 是 由ACM 收 集, 并 保 存 在ACM 内 部, 所以 查 询 以 上 信 息 时 并 未 真 正 将 驱 动 程 序 加 载 至 内 存。 而 要 获 得 每 一 种 驱 动 程 序 支 持 的 音 频 格 式信 息, 则 必 须 将 驱 动 程 序 加 载 至 内 存, 这 是 通 过acmDriverOpen() 完 成 的, 在 退 出CodecsEnumProc() 前, 还 要 用acmDriverClose() 来 关 闭 已 打 开 的 驱 动 程 序。 在 使 用 音 频 格 式 枚 举 函 数 前, 需 要 先 分配 一 块 缓 冲 区 存 置 格 式 信 息, 缓 冲 区 的 大 小 可 通 过 调 用acmMetrics() 查 询ACM_METRIC_MAX_SIZE_FORMAT 获 得, 格 式 信 息 中 的 音 频 格 式 标 识 设 为WAVE_FORMAT_UNKNOWN。 在 音 频 格 式 枚 举 中 同 样 使 用 了 回调 函 数, 此 回 调 函 数 只 是 列 出 了 该 音 频 格 式 的 名 称 和 标 识 值。

BOOL CALLBACK FormatEnumProc
  
 
  
(HACMDRIVERID hadid, LPACMFORMATDETAILS
  
 
  
 pafd, DWORD dwInstance, DWORD fdwSupport) {
  
 
  
printf("%4.4lXH, %s/n", pafd- >dwFormatTag, pafd- >szFormat);
  
 
  
return TRUE; 
  
 
  
}
  
 
  

---- 上 面 介 绍 了 浏览 系 统 中 所 有 音 频CODECs 及 每 种CODEC 所 支 持 的 音 频 格 式 的 方 法, 某 些 典 型 的 应 用 程 序 可 能 需要 列 出 系 统 中 所 有 可 以 选 用 的CODECs, 并 由 用 户 来 选 择 使 用 哪 一 种CODEC 进 行 压 缩, 此 时 就 需 要利 用 上 面 的 编 程 方 法 来 获 取CODECs 的 信 息。

音 频 数 据 的 压 缩

---- 使 CODEC 程, 序。 8K 样、16bits PCM 码、 道、 1 号。 Windows 95 TrueSpeech CODEC 101 缩。 中,TrueSpeech CODEC 换, 中, CODEC 式, 法, 式, 式, 线 PCM 单, CODEC 持, 线 PCM 种。

---- 在 进 行 压 缩 之前 首 先 需 要 确 定TrueSpeech 驱 动 程 序 的ID 值。 为 此 需 要 用 到acmDriverEnum() 函 数, 对 枚 举 到 的每 一 个 驱 动 程 序, 由acmDriverEnum() 指 定 的 回 调 函 数 将 检 查 其 支 持 的 所 有 音 频 格 式, 若 其 中 包括wFormatTag 值 为WAVE_FORMAT_DSPGROUP_TRUESPEECH 的 音 频 格 式, 则 此 驱 动 程 序 就 是 要 寻 找的TrueSpeech CODEC, 它 所 支 持 的 第 一 种WAVE_FORMAT_DSPGROUP_TRUESPEECH 音 频 格 式 即 为 目标 音 频 压 缩 格 式。 查 询 所 需 的CODEC 及 其 支 持 的 音 频 格 式 的 方 法 见 前 一 小 节 的 介 绍。

---- 根 据 查 询 的 结果, 设hadID 为TrueSpeech CODEC 的ID 值,pwfDrv 为 指 向 目 标WAVEFORMATEX 结 构 的 指 针, 接 下 来利 用 获 得 的ID 值 打 开 相 应 的 驱 动 程 序。

HACMDRIVER had = NULL;
  
 
  
mmr = acmDriverOpen(&had, hadID, 0);
  
 
  
if(mmr) {  printf(" 打开驱动程序失败/n"); exit(1);  }
  
 
  

---- 压 缩 和 解 压 缩一 样, 都 是 将 音 频 信 号 从 一 种 音 频 格 式 转 换 成 另 一 种 格 式, 要 完 成 这 一 过 程, 首 先 要 打 开 转 换 流。在 用acmStreamOpen 打 开 转 换 流 时, 我 们 指 定 了ACM_STREAMOPENF_NONREALTIME 标 志, 它 表 示 转换 无 需 实 时 进 行。 因 为 很 多 压 缩 算 法 的 计 算 量 是 相 当 大 的, 实 时 完 成 几 乎 是 不 可 能 的, 例 如 在 本例 中, 如 果 不 指 定 此 标 志,TrueSpeech CODEC 就 会 返 回“ 无 法 完 成” 的 错 误。

HACMSTREAM hstr = NULL;
  
 
  
DWORD dwSrcBytes = dwSrcSamples * wfSrc.wBitsPerSample / 8;
  
 
  
mmr = acmStreamOpen(&hstr,had, //驱动程序句柄
  
 
  
pwfSrc, //指向源音频格式的指针
  
 
  
pwfDrv, //指向目标音频格式的指针
  
 
  
NULL, //无过滤器
  
 
  
NULL, //无回调函数
  
 
  
0,ACM_STREAMOPENF_NONREALTIME);
  
 
  

---- 在 真 正 进 行 转换 之 前, 还 必 须 准 备 转 换 流 的 信 息 头。 下 面 一 段 代 码 中, 先 利 用 源 数 据 的 大 小 以 及 目 标 格 式 的 平均 数 据 率 估 算 目 标 数 据 的 缓 存 区 大 小, 然 后 调 用acmStreamPrepareHeader 为 转 换 准 备 信 息 头。

---- DWORD dwDstBytes=pwfDrv->nAvgBytesPerSec*dwSrcSamples/wfSrc.nSamplesPerSec;

---- dwDstBytes = dwDstBytes*3/2; // 计 算 压 缩 后 音 频 数 据 大 小, 并 依 此 适 当 增 加 输 出 缓 冲 区 的 大 小。

BYTE* pDstData = new BYTE [dwDstBytes];
  
 
  
ACMSTREAMHEADER shdr;
  
 
  
memset(&strhdr, 0, sizeof(shdr));
  
 
  
shdr.cbStruct = sizeof(shdr);
  
 
  
shdr.pbSrc = pSrcData;          //源音频数据区
  
 
  
shdr.cbSrcLength = dwSrcBytes;
  
 
  
shdr.pbDst = pDstData; //压缩后音频数据缓冲区
  
 
  
shdr.cbDstLength = dwDstBytes;
  
 
  
mmr = acmStreamPrepareHeader(hstr, &shdr, 0); 
  
 
  

---- 语 音 数 据 真 正的 压 缩 过 程 是 由 函 数acmStreamConvert() 完 成 的。 在 调 用acmStreamConvert() 时 可 以 指 定 回 调函 数, 以 便 在 转 换 过 程 中 显 示 进 度 信 息 等。 在 本 例 中, 未 指 定 回 调 函 数, 只 是 简 单 地 等 待 压 缩 的结 束。

---- mmr = acmStreamConvert(hstr, &shdr, 0);

---- 数 据 压 缩 完 毕后, 应 用 程 序 就 可 以 把 缓 冲 区 中 的 数 据 写 入 目 标 文 件 中。

---- 最 后, 必 须 关闭 转 换 流 和 驱 动 程 序。

mmr = acmStreamClose(hstr, 0);
  
 
  
mmr = acmDriverClose(had, 0);
  
 
  
---- ACM CODEC 程, ACM VC++ 5 ACM 息。
  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
<p> <span style="font-size:14px;color:#337FE5;">【为什么学爬虫?】</span> </p> <p> <span style="font-size:14px;">       1、爬虫入手容易,但是深入较难,如何写出高效率爬虫,如何写出灵活性高可扩展爬虫都是一项技术活。另外在爬虫过中,经常容易遇到被反爬虫,比如字体反爬、IP识别、验证码等,如何层层攻克难点拿到想要数据,这门课,你都能学到!</span> </p> <p> <span style="font-size:14px;">       2、如果是作为一个其他行业开发者,比如app开发,web开发,学习爬虫能让你加强对技术认知,能够开发出更加安全软件和网站</span> </p> <p> <br /> </p> <span style="font-size:14px;color:#337FE5;">【课设计】</span> <p class="ql-long-10663260"> <span> </span> </p> <p class="ql-long-26664262" style="font-size:11pt;color:#494949;"> 一个完整爬虫序,无论大小,总体来说可以分成三个步骤,分别是: </p> <ol> <li class="" style="font-size:11pt;color:#494949;"> 网络请求:模拟浏览器行为从网上抓取数据。 </li> <li class="" style="font-size:11pt;color:#494949;"> 数据解析:将请求下来数据进行过滤,提取我们想要数据。 </li> <li class="" style="font-size:11pt;color:#494949;"> 数据存储:将提取到数据存储到硬盘或者内存中。比如mysql数据库或者redis等。 </li> </ol> <p class="ql-long-26664262" style="font-size:11pt;color:#494949;"> 那么本课也是按照这几个步骤循序渐进进行讲解,带领学生完整掌握每个步骤技术。另外,因为爬虫多样性,在爬取中可能会发生被反爬、效率低下等。因此我们又增加了两个章节来提高爬虫灵活性,分别是: </p> <ol> <li class="" style="font-size:11pt;color:#494949;"> 爬虫进阶:包括IP代理,多线爬虫,图形验证码识别、JS加密解密、动态网页爬虫、字体反爬识别等。 </li> <li class="" style="font-size:11pt;color:#494949;"> Scrapy和分布式爬虫:Scrapy框架、Scrapy-redis组件、分布式爬虫等。 </li> </ol> <p class="ql-long-26664262" style="font-size:11pt;color:#494949;"> 通过爬虫进阶知识点我们能应付大量反爬网站,而Scrapy框架作为一个专业爬虫框架,使他可以快速提高我们写爬虫效率和速度。另外如果一台机器不能满足你需求,我们可以分布式爬虫让多台机器帮助你快速爬取数据。 </p> <p style="font-size:11pt;color:#494949;">   </p> <p class="ql-long-26664262" style="font-size:11pt;color:#494949;"> 从基础爬虫到商业化应爬虫,本套课满足您所有需求! </p> <p class="ql-long-26664262" style="font-size:11pt;color:#494949;"> <br /> </p> <p> <br /> </p> <p> <span style="font-size:14px;background-color:#FFFFFF;color:#337FE5;">【课服务】</span> </p> <p> <span style="font-size:14px;">专属付费社群+定期答疑</span> </p> <p> <br /> </p> <p class="ql-long-24357476"> <span style="font-size:16px;"><br /> </span> </p> <p> <br /> </p> <p class="ql-long-24357476"> <span style="font-size:16px;"></span> </p>
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值