VC 調 用ACM 音 頻 壓 縮 編 程 接 口 的 方 法 (轉)
音 頻 和 視 頻 數 據 是 大 多 數 多 媒 體 應 用 程 序 向 用 戶 提 供 信 息 的 主 要 方 式, 這 些 數 據 一 般 具 有較 高 的 採 樣 速 率, 如 果 不 經 過 壓 縮 的 話, 保 存 它 們 需 要 消 耗 大 量 的 存 貯 空 間, 在 網 絡 上 進 行 傳 輸的 效 率 也 很 低, 因 此 音 頻 視 頻 數 字 壓 縮 編 碼 在 多 媒 體 技 術 中 佔 有 很 重 要 的 地 位。 就 音 頻 數 據 而言, 目 前 常 用 的 壓 縮 方 法 有 很 多 種, 不 同 的 方 法 具 有 不 同 的 壓 縮 比 和 還 原 音 質, 編 碼 的 格 式 和 演算法 也 各 不 相 同, 其 中 某 些 壓 縮 算 法 相 當 復 雜, 普 通 程 序 不 可 能 去 實 現 其 編 解 碼 算 法。 所 幸 的 是,與 3.x 相 比,Windows 95/NT 4.0 為 多 媒 體 應 用 程 序 提 供 了 更 強 的支 持, 引 入 了ACM(Audio Compression Manager, 音 頻 壓 縮 管 理 器) 和VCM(Vo Compression Manager, 視 頻 壓 縮 管 理 器), 它 們 負 責 管 理 系 統 中 所 有 音 頻 和 視 頻 編 解 碼 器(Coder-Decoder,簡 稱CODEC, 是 實 現 音 頻 視 頻 數 據 編 解 碼 的 驅 動 程 序), 應 用 程 序 可 以 通 過ACM 或VCM 提 供 的 編 程接 口 調 用 這 些 系 統 中 現 成 的 編 解 碼 器 來 實 現 音 頻 或 視 頻 數 據 的 壓 縮 和 解 壓 縮。95/NT 4.0 系 統自 帶 的 音 頻CODECs 支 持 一 些 早 期 的 音 頻 數 據 壓 縮 標 準, 如ADPCM 等,Inte Explorer 4.0 等應 用 程 序 包 含 的 音 頻CODECs 支 持 一 些 比 較 新 的 壓 縮 標 準, 如MPEG Layer 3 等。 在 控 制 面 板 的 多媒 體 組 件 中 選 擇“ 高 級”, 打 開“ 音 頻 壓 縮 的 編 碼 解 碼 器”, 就 可 列 出 系 統 中 安 裝 的 所 有 音 頻CODECs。本 文 所 要 介 紹 的 就 是ACM 音 頻 壓 縮 接 口 的 編 程 方 法, 所 用 編 程 工 具 為VC++ 5.0。 :namespace prefix = o ns = "urn:schemas--com::office" />
獲 取CODECs 的 信 息
---- ACM 的 函 數 定 義 在 頭 文 件msacm.h 中, 除 此 之 外, 對ACM 編 程 還 必 須 包 含 頭 文 件mmsystem.h,mmreg.h, 這 兩 個 頭 文 件 定 義 了 多 媒 體 編 程 中 最 基 本 的 常 量 和 數 據 結 構。 為 了 避 免 有 些 高 版 本ACM 才 提 供 的 函 數 和 功 能 在 較 低 版 本 的ACM 中 上 不 可 用, 程 序 中 應 調 用acmGetVersion 函 數 查 詢 用 戶 機 器 中ACM 的 版 本 信 息。
---- 前 面 提 到, 在控 制 面 板 中 可 以 查 看 系 統 中CODECs 的 信 息, 而 在 應 用 程 序 中 也 常 常 需 要 知 道 某 種 音 頻CODECs 是否 存 在, 並 獲 取 其 編 解 碼 參 數 等 信 息, 這 一 點 可 以 通 過 調 用 下 面 兩 個 函 數 來 實 現。
---- MMRESULT mmr=acmMetrics(NULL, ACM_METRIC_COUNT_CODECS, &dwCodecs);
---- mmr = acmEnum(CodecsEnumProc, 0, 0);
---- acmMetrics() 函 數 可 以 獲 取 許 多ACM 對 象 的 有 用 信 息, 例 如 向 其 中 傳 遞ACM_METRIC_COUNT_CODECS 可 以 查 詢 系 統 中 安 裝 的 音 頻CODECs 總 數。 函 數acmDriverEnum() 的 功 能 是 枚 舉 所 有 的 音 頻CODECs,在acmDriverEnum() 的 參 數 中 指 定 回 調 函 數CodecsEnumProc() 可 以 進 一 步 查 詢 每 個CODEC 的 資訊。Windows 編 程 中 經 常 要 用 到 回 調 函 數, 下 面 是 枚 舉 音 頻CODECs 的 一 個 回 調 函 數 的 示 例。
BOOL CALLBACK CodecsEnumProc(HACMDRIVERID
hadid, D 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(" 全稱: %sn", acmdd.szLoame);
printf(" 描述: %sn", 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, %sn", pafd- >dwFormatTag, pafd- >szFormat);
return TRUE;
}
---- 上 面 介 紹 了 瀏覽 系 統 中 所 有 音 頻CODECs 及 每 種CODEC 所 支 持 的 音 頻 格 式 的 方 法, 某 些 典 型 的 應 用 程 序 可 能 需要 列 出 系 統 中 所 有 可 以 選 用 的CODECs, 並 由 用 戶 來 選 擇 使 用 哪 一 種CODEC 進 行 壓 縮, 此 時 就 需 要利 用 上 面 的 編 程 方 法 來 獲 取CODECs 的 信 息。
音 頻 數 據 的 壓 縮
---- 下 面 說 明 使 用 某 一CODEC 實 現 音 頻 壓 縮 的 過 程, 讀 者 朋 友 只 需 稍 加 改 動 就 可 編 寫 出 相 應 的 解 壓 程 序。 假 設 源 信 號 為8K 採 樣、16bits PCM 編 碼、 單 聲 道、 長 度 為1 秒 的 音 頻 信 號。 驅 動 程 序 採 用Windows 95 自 帶 的TrueSpeech 音 頻CODEC, 它 能 實 現 大 約10:1 的 壓 縮。 在 此 例 中,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 的 信 息。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-988754/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- iOS 音訊壓縮(caf與amr互轉)iOS音訊
- AU音訊剪輯設定廣播多頻段壓縮效果的方法音訊
- WIN95 界 面 下 的VC++ 串 口 通 訊 程 序 (轉)C++
- 用VC++編寫CGI程式 (轉)C++
- 解包 bzip2 壓縮的壓縮文件(轉)
- 空壓機變頻改造|空氣壓縮機變頻改造原理
- 過濾器應用【編碼、敏感詞、壓縮、轉義過濾器】過濾器
- Linux下常用壓縮格式的壓縮與解壓方法---轉載Linux
- linux壓縮(解壓縮)命令詳解-轉Linux
- 利用Java實現zip壓縮/解壓縮 (轉)Java
- Linux下壓縮,解壓縮RAR包(轉)Linux
- 用VC++6.0編寫撥號程式 (轉)C++
- Linux中檔案的壓縮與解壓縮(轉貼)Linux
- unix和linux下常用壓縮格式的壓縮與解壓方法(轉)Linux
- 字串的壓縮和解壓縮字串
- 調 用API 函 數 設 計ABOUT 窗 口 (轉)API
- 實用的壓縮解壓工具:WinZip for MacMac
- Tips:壓縮記賬法
- 計算機演算法:資料壓縮之遊程編碼計算機演算法
- 關於VC的編譯模式 (轉)編譯模式
- 基 於Win95 TAPI 的 調 制 解 調 器 編 程 (轉)API
- 給Tomcat,Apache配置gzip壓縮(HTTP壓縮)功能 (轉)TomcatApacheHTTP
- 高效的資料壓縮編碼方式 Protobuf
- 怎麼把影片壓縮?實用又簡單的壓縮影片方法
- VC在windows下編寫用於序列通訊的程式 (轉)Windows
- 簡單的zip壓縮和解壓縮
- Nginx網路壓縮 CSS壓縮 圖片壓縮 JSON壓縮NginxCSSJSON
- JAVA基礎:利用Java實現zip壓縮解壓縮(轉)Java
- JAVA壓縮和解壓縮Java
- zip壓縮和解壓縮
- 用ASP實現線上壓縮與解壓縮功能程式碼
- aix 檔案的壓縮與解壓縮AI
- 資料壓縮簡史 (轉)
- 【轉載】Rocksdb壓縮詳解
- linux壓縮解壓縮Linux
- 檔案壓縮和解壓縮
- 用VC6編寫登錄檔管理程式(三) (轉)
- 用VC6編寫登錄檔管理程式(二) (轉)