(三)音 頻 數(shù) 據(jù) 的 壓 縮
下 面 說(shuō) 明 使 用 CODEC 實(shí) 現(xiàn) 音 頻 壓 縮 的 過(guò) 程;假 設(shè) 源 信 號(hào) 為8K 采 樣、16bits PCM 編 碼、 單 聲 道、 長(zhǎng) 度 為1 秒 的 音 頻 信 號(hào)。 驅(qū) 動(dòng) 程 序 采 用Windows 95 自 帶 的TrueSpeech 音 頻CODEC, 它 能 實(shí) 現(xiàn) 大 約10:1 的 壓 縮。 在 此 例 中,TrueSpeech CODEC 支 持 從 源 音 頻 格 式 到 目 標(biāo) 格 式 的 轉(zhuǎn) 換, 而 在 實(shí) 際 應(yīng) 用 中, 可 能 某 種CODEC 不 支 持 直 接 將 源 音 頻 格 式 轉(zhuǎn) 換 成 目 標(biāo) 格 式, 這 時(shí) 可 以 采 取 兩 步 轉(zhuǎn) 換 法, 即 先 將 源 格 式 轉(zhuǎn) 換 成 一 種 中 間 格 式, 再 將 此 中 間 格 式 轉(zhuǎn) 換 成 目 標(biāo) 格 式, 因 為 線 性PCM 編 碼 最 為 簡(jiǎn) 單, 且 為 絕 大 多 數(shù)CODEC 所 支 持, 所 以 一 般 中 間 格 式 都 選 為 線 性PCM 格 式 的 一 種。
1.在 進(jìn) 行 壓 縮 之 前 首 先 需 要 確 定TrueSpeech 驅(qū) 動(dòng) 程 序 的ID 值: 為 此 需 要 用 到acmDriverEnum() 函 數(shù), 對(duì) 枚 舉 到 的 每 一 個(gè) 驅(qū) 動(dòng) 程 序, 由acmDriverEnum() 指 定 的 回 調(diào) 函 數(shù) 將 檢 查 其 支 持 的 所 有 音 頻 格 式, 若 其 中 包 括wFormatTag 值 為WAVE_FORMAT_DSPGROUP_TRUESPEECH 的 音 頻 格 式, 則 此 驅(qū) 動(dòng) 程 序 就 是 要 尋 找 的TrueSpeech CODEC, 它 所 支 持 的 第 一 種WAVE_FORMAT_DSPGROUP_TRUESPEECH 音 頻 格 式 即 為 目 標(biāo) 音 頻 壓 縮 格 式。
2.打 開(kāi) 驅(qū) 動(dòng) 程 序:
根 據(jù) 查 詢 的 結(jié) 果, 設(shè) hadID 為 TrueSpeech CODEC 的 ID 值,pwfDrv 為 指 向 目 標(biāo) WAVEFORMATEX 結(jié) 構(gòu) 的 指 針, 接 下 來(lái) 利 用 獲 得 的ID 值 打 開(kāi) 相 應(yīng) 的 驅(qū) 動(dòng) 程 序
HACMDRIVER had = NULL;
mmr = acmDriverOpen(&had, hadID, 0);
if(mmr) { printf(" 打開(kāi)驅(qū)動(dòng)程序失敗\n"); exit(1); }
3.壓 縮: 和 解 壓 縮 一 樣, 都 是 將 音 頻 信 號(hào) 從 一 種 音 頻 格 式 轉(zhuǎn) 換 成 另 一 種 格 式, 要 完 成 這 一 過(guò) 程, 首 先 要 打 開(kāi) 轉(zhuǎn) 換 流; 在 用acmStreamOpen 打 開(kāi) 轉(zhuǎn) 換 流 時(shí), 我 們 指 定 了ACM_STREAMOPENF_NONREALTIME 標(biāo) 志, 它 表 示 轉(zhuǎn) 換 無(wú) 需 實(shí) 時(shí) 進(jìn) 行, 因 為 很 多 壓 縮 算 法 的 計(jì) 算 量 是 相 當(dāng) 大 的, 實(shí) 時(shí) 完 成 幾 乎 是 不 可 能 的, 例 如 在 本 例 中, 如 果 不 指 定 此 標(biāo) 志,TrueSpeech CODEC 就 會(huì) 返 回“ 無(wú) 法 完 成” 的 錯(cuò) 誤。
HACMSTREAM hstr = NULL;
DWORD dwSrcBytes = dwSrcSamples * wfSrc.wBitsPerSample / 8;
mmr = acmStreamOpen(&hstr,had, //驅(qū)動(dòng)程序句柄 pwfSrc, //指向源音頻格式的指針 pwfDrv, //指向目標(biāo)音頻格式的指針 NULL, //無(wú)過(guò)濾器 NULL, //無(wú)回調(diào)函數(shù) 0,ACM_STREAMOPENF_NONREALTIME);
在 真 正 進(jìn) 行 轉(zhuǎn) 換 之 前, 還 必 須 準(zhǔn) 備 轉(zhuǎn) 換 流 的 信 息 頭。 下 面 一 段 代 碼 中, 先 利 用 源 數(shù) 據(jù) 的 大 小 以 及 目 標(biāo) 格 式 的 平 均 數(shù) 據(jù) 率 估 算 目 標(biāo) 數(shù) 據(jù) 的 緩 存 區(qū) 大 小, 然 后 調(diào) 用acmStreamPrepareHeader 為 轉(zhuǎn) 換 準(zhǔn) 備 信 息 頭。
DWORD dwDstBytes=pwfDrv->nAvgBytesPerSec*dwSrcSamples/wfSrc.nSamplesPerSec;
dwDstBytes = dwDstBytes*3/2; // 計(jì) 算 壓 縮 后 音 頻 數(shù) 據(jù) 大 小, 并 依 此 適 當(dāng) 增 加 輸 出 緩 沖 區(qū) 的 大 小。
BYTE* pDstData = new BYTE [dwDstBytes];
ACMSTREAMHEADER shdr;
memset(&strhdr, 0, sizeof(shdr));
shdr.cbStruct = sizeof(shdr);
shdr.pbSrc = pSrcData; //源音頻數(shù)據(jù)區(qū)
shdr.cbSrcLength = dwSrcBytes;
shdr.pbDst = pDstData; //壓縮后音頻數(shù)據(jù)緩沖區(qū)
shdr.cbDstLength = dwDstBytes;
mmr = acmStreamPrepareHeader(hstr, &shdr, 0);
語(yǔ) 音 數(shù) 據(jù) 真 正 的 壓 縮 過(guò) 程 是 由 函 數(shù)acmStreamConvert() 完 成 的。 在 調(diào) 用acmStreamConvert() 時(shí) 可 以 指 定 回 調(diào) 函 數(shù), 以 便 在 轉(zhuǎn) 換 過(guò) 程 中 顯 示 進(jìn) 度 信 息 等。 在 本 例 中, 未 指 定 回 調(diào) 函 數(shù), 只 是 簡(jiǎn) 單 地 等 待 壓 縮 的 結(jié) 束。
—- mmr = acmStreamConvert(hstr, &shdr, 0);
數(shù) 據(jù) 壓 縮 完 畢 后, 應(yīng) 用 程 序 就 可 以 把 緩 沖 區(qū) 中 的 數(shù) 據(jù) 寫(xiě) 入 目 標(biāo) 文 件 中。
最 后, 必 須 關(guān) 閉 轉(zhuǎn) 換 流 和 驅(qū) 動(dòng) 程 序。
mmr = acmStreamClose(hstr, 0); mmr = acmDriverClose(had, 0);
版權(quán)申明:本站文章均來(lái)自網(wǎng)絡(luò),如有侵權(quán),請(qǐng)?jiān)u論 ,收到后立即刪除,謝謝!
浙公網(wǎng)安備 33010602011771號(hào)