在幾年以前IP電話被炒的沸沸揚揚,但用過的人都覺得這個技術非常不成熟,語音質量很差,時斷時續,還經常有延遲,結果這項技術的應用沒有普及開來。但隨著Internet應用的越來越廣泛以及相關技術發展的日新月異,聲音質量不斷提高,通過Internet打電話早已不再是夢想,已經成為了我們生活中的一部分。今天我使用IP電話打長途,每分鐘只需要3毛錢,使用OICQ的語音聊天,網友仿佛就在你的身邊。如果我們的帶寬足夠的,我們甚至還可以在網上收看Quicktime視頻直播,用RealAudio收聽電台廣播,也可以點播好聽的MP3歌曲。不過對於程序員來說,更好的消息是我們對於這些媒體流的編程也也變得越來越容易。為什麼這麼說呢,下面讓我們先來了解一下Codec。
Codecs
什麼是Codecs?其實它就是音頻壓縮的解碼編碼器,實際上有點類似ActiveX控件。ActiveX控件使程序員可以調用一些他人實現好的功能而無需從頭做起。Codecs提供了類似的功能,只不過它集中在提供如何對媒體格式進行轉換的功能。例如,如果想寫一個把CD轉MP3的應用程序,我們只需要做下列工作:
l 從CD音軌中讀取數據。
l 生成一個有效的MP3文件頭。
l 調用相應的codec把音軌數據編碼為MP3。
Windows本身已經帶了很多的codec。下面是其中幾個的說明:
名稱
說明
GSM
好像用於某些移動電話網絡。
DSP TrueSpeech
可以生成一種一位的聲音格式用於語音通話-聲音非常清楚。
Fraunhoffer IIS MP3
這種可以用來生成MP3格式。
PCM
用於生成Windows標准聲音格式。大多數Codec支持的聲音格式都可以和它相互轉化。
當前安裝的codec的完整列表可以通過察看控制面板中多媒體的部分來獲得。
ACM API
ACM是"Audio Compression Manager"縮寫,翻譯過來就是聲音壓縮管理器。它是微軟編寫的用於調用Codec功能的接口函數庫。它本來應該聲明在MMSystem.pas單元中,但是由於某些原因Borland把它給省略了。所以我們要作的第一件事是找到它的API聲明單元MSACM.pas。必須要感謝Francois PIEtte,他共享了他轉換的單元文件,我們可以從www.Delphi-Jedi.org下載它。
使用ACM轉換媒體格式包括以下幾步:
l 首先必須指定輸入輸出格式,我們需要設定TWaveFormatEX記錄, 但是這個結構記錄太小無法容納大多數Codec所需要的信息。為了解決這個問題,我們使用一個自定義的 TACMFormat記錄,這個記錄在TWaveFormatEX的基礎上增加了128字節。
l 打開一個ACM流。首先調用acmStreamOpen函數,把輸入輸出格式作為參數傳遞過去。然後ACM或者返回一個有效的句柄或者返回一個錯誤代碼(比如ACMERR_NotPossible)來表明轉換的請求無法完成。
l 接下來要確定輸出緩沖區的大小。調用acmStreamSize函數會通知ACM每次我們將生成多少字節的數據,然後函數會返回請求大小的緩沖區(我們總是應該高估一下大小,保證提供一個足夠大的緩沖區)。
l 然後,我們要生成一個轉換頭。需要調用acmStreamPrepareHeader函數,把先前調用acmStreamOpen函數返回的流句柄作為參數。生成的轉換頭會告訴ACM源緩沖區和目的緩沖區的地址。ACM不會自動分配內存,我們必須自己來申請內存。
l 所有的准備工作基本上完成了,只剩下如何轉換數據了。這是非常簡單的,只需要調用acmStreamConvert函數。AcmStreamConvert函數的參數包括流句柄和轉換頭句柄。這個函數通過設定轉換頭中的cbDstLengthUsed表明轉換過程中真正被使用的字節數。
l 一旦完成了ACM的會話,我們必須釋放使用的全部資源。轉換頭用acmStreamUnprepareHeader函數來釋放,流用acmStreamClose來關閉。
選擇格式
正如前面提到的,在開始轉換以前必須先設定輸入輸出格式。TWaveFormatEX記錄(聲明在MMSystem.pas單元中),它僅僅指定了比特率,頻率等等。除非我們只打算在不同的PCM格式間進行轉換,否則TWaveFormatEX是不夠用的。下面是它的替代格式:
TACMWaveFormat = packed record
case integer of
0 : (Format : TWaveFormatEx);
1 : (RawData : Array[0..128] of byte);
end;
這個變體記錄使我們仍然可以讀取TWaveFormatEX結構數據,同時RawData提供了足夠的空間來容納其它Codec需要的額外信息。
雖然我們不知道額外信息的大小,但我們可以使用acmFormatChoose函數來獲得。
AcmFormatChoose函數只需要一個TACMFormatChooseA類型的參數。這個參數是一個簡單的結構可以包括下列信息:
成員
說明