使用CODECs壓縮Wave音頻_第1頁
使用CODECs壓縮Wave音頻_第2頁
使用CODECs壓縮Wave音頻_第3頁
使用CODECs壓縮Wave音頻_第4頁
使用CODECs壓縮Wave音頻_第5頁
已閱讀5頁,還剩13頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、使用CODECs壓縮Wave音頻 簡介Win95及最近的WinNT都具有能過安裝的CODECs處理壓縮的wave格式的音頻和視頻數(shù)據(jù)流的 能力。一個CODEC是一小段用于壓縮(COmpress)及解壓縮(DECompress)數(shù)據(jù)流的代碼(因此, 得名CO-DEC)。許多CODECs即能壓縮又能解壓縮。而一些CODECs僅能用于解壓縮,這樣私 有數(shù)據(jù)可以在系統(tǒng)上播放,但數(shù)據(jù)格式不能在系統(tǒng)上創(chuàng)建。盡管一個CODEC原則上能夠用于壓縮解壓縮任一種數(shù)據(jù)流,還是設(shè)計有各種各樣的CODECs 以實現(xiàn)以高的壓縮比率,更好的保真度或?qū)崟r壓縮性能來壓縮某種數(shù)據(jù)類型。例如,獲取 高的視頻壓縮數(shù)據(jù)壓縮率的最好方法

2、應(yīng)用于音頻數(shù)據(jù)時未必就能得到相同的效果,反之也 然。本文著重于怎樣在自己的代碼中使用CODEC將音頻數(shù)據(jù)以你的系統(tǒng)中CODECs所支持的方式進 行壓縮。壓縮音頻數(shù)據(jù)的一個主要原因是降低存儲某一聲音序列所需數(shù)據(jù)量。少的數(shù)據(jù)量 意味著聲音所占有的空間更少,并且能夠以更快的速度在MODEM和網(wǎng)絡(luò)上傳遞。如果數(shù)據(jù) 以Windows系統(tǒng)所支持的某一通用格式壓縮的話,則可以不必手工解壓縮就直接播放-系 統(tǒng)將使用它自己的CODECs解壓縮數(shù)據(jù)并播放。我的系統(tǒng)中有什么CODECs?Win95和WinNT本身附帶有幾種標(biāo)準(zhǔn)的CODECs,也可由系統(tǒng)中所安裝的應(yīng)用程序安裝其他的 CODECs。例如,DSP Gro

3、up,Inc. TrueSpeech CODEC隨Win95發(fā)送,因此你寫的任何應(yīng)用于 Win95的程序都可應(yīng)用此CODEC(假如用戶沒有在控制面板中刪除它或禁止它的話)。以后 可能要安裝的CODEC的一個例子是微軟網(wǎng)絡(luò)(MSN)軟件自已所用的音頻數(shù)據(jù)。所有安裝的CODECs由音頻壓縮管理器(ACM)管理。我們可以從一小程序中查詢ACM來查到安 裝了哪些CODECs,它們都支持什么格式。你也可雙擊控制面板中的多媒體選項,選擇高級 標(biāo)簽,就能看到系統(tǒng)中所安裝的CODECs。介紹應(yīng)用ACM,得知它所管理每一個CODEC都可以做些什么的一個好方法是寫一個簡單的 查詢ACM的命令行應(yīng)用程序。本文所附帶

4、的CAPS程序完成的就是這個功能-讓我們看看它的 代碼,我將給你一起分析此程序,解釋每一步完成的什么功能。首先從調(diào)用ACM編程接口所需的包含的頭文件開始 :#include &ltwindows.h>#include &ltmmsystem.h>#include &ltmmreg.h> / 多媒體注冊#include &ltmsacm.h> / 音頻壓縮管理器#include &ltstdio.h>mmsystem.h頭文件定了Windows支持大部分的多媒體功能,但不包含ACM接口及任何廠商定義。 mmreg.h包含了對不

5、同廠商設(shè)計的各種wave數(shù)據(jù)類型的格式標(biāo)簽的定義。它也包含了用于處理 不同的wave數(shù)據(jù)類型的結(jié)構(gòu)( 基于WAVEFORAMTEX)的定義。msacm.h包含了ACM所需的API, 標(biāo)志等等。我們要做的第一件事就是執(zhí)行一些常見的ACM查詢來判斷版本號,獲取諸如它當(dāng)前管理了多少 個驅(qū)動程序的的信息。下面是查詢ACM的部分代碼: / 取得ACM版本號 DWORD dwACMVer = acmGetVersion(); printf("ACM version %u.%.02u build %u", HIWORD(dwACMVer) >> 8, HIWORD(dwACM

6、Ver) & 0x00FF, LOWORD(dwACMVer); if (LOWORD(dwACMVer) = 0) printf(" (Retail)"); printf("n"); / 顯示一些ACM的信息 printf("ACM metrics:n"); DWORD dwCodecs = 0; MMRESULT mmr = acmMetrics(NULL, ACM_METRIC_COUNT_CODECS, &dwCodecs); if (mmr) show_error(mmr); else printf(&quo

7、t;%lu codecs installedn", dwCodecs); CAPS實例查詢了更多的ACM信息。你可以仔細查看它的代碼,運行程序得知結(jié)果。對ACM有了簡單了解后,現(xiàn)在可以要求它枚舉出系統(tǒng)中當(dāng)前所有的驅(qū)動程序。我們在程序中所 調(diào)用的枚舉函數(shù)使用回調(diào)函數(shù)來匯報每個設(shè)備的數(shù)據(jù),這在Windows編程是一種很普遍的方法。 下面的調(diào)用就是枚舉當(dāng)前ACM所管理的所有設(shè)備: / 枚舉所有允許的驅(qū)動程序 printf("Enabled drivers:n"); mmr = acmDriverEnum(DriverEnumProc, 0, 0); if (mmr) s

8、how_error(mmr);如同其它多媒體函數(shù),許多ACM函數(shù)調(diào)用返回一MMRESULT值,指出了可能發(fā)生的錯誤。此值為0 表示函數(shù)成功執(zhí)行?,F(xiàn)在,讓我們看看枚舉回調(diào)函數(shù)DriverEnumProc,它由系統(tǒng)中的每一個驅(qū) 動程序調(diào)用:BOOL CALLBACK DriverEnumProc(HACMDRIVERID hadid, DWORD dwInstance, DWORD fdwSupport) printf(" id: %8.8lxH", hadid); printf(" supports:n"); if (fdwSupport & AC

9、MDRIVERDETAILS_SUPPORTF_ASYNC) printf(" async conversionsn"); if (fdwSupport & ACMDRIVERDETAILS_SUPPORTF_CODEC) printf(" different format conversionsn"); if (fdwSupport & ACMDRIVERDETAILS_SUPPORTF_CONVERTER) printf(" same format conversionsn"); if (fdwSupport &a

10、mp; ACMDRIVERDETAILS_SUPPORTF_FILTER) printf(" filteringn"); / 獲得一些具體信息 ACMDRIVERDETAILS dd; dd.cbStruct = sizeof(dd); MMRESULT mmr = acmDriverDetails(hadid, &dd, 0); if (mmr) printf(" "); show_error(mmr); else printf(" Short name: %sn", dd.szShortName); printf(&quo

11、t; Long name: %sn", dd.szLongName); printf(" Copyright: %sn", dd.szCopyright); printf(" Licensing: %sn", dd.szLicensing); printf(" Features: %sn", dd.szFeatures); printf(" Supports %u formatsn", dd.cFormatTags); printf(" Supports %u filter formatsn&q

12、uot;, dd.cFilterTags); / 打開驅(qū)動程序 HACMDRIVER had = NULL; mmr = acmDriverOpen(&had, hadid, 0); if (mmr) printf(" "); show_error(mmr); else DWORD dwSize = 0; mmr = acmMetrics(had, ACM_METRIC_MAX_SIZE_FORMAT, &dwSize); if (dwSize cbSize = LOWORD(dwSize) - sizeof(WAVEFORMATEX); pwf->w

13、FormatTag = 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) printf(" "); show_error(mmr); free(pwf);

14、acmDriverClose(had, 0); return TRUE; / 繼續(xù)枚舉驅(qū)動程序向回調(diào)函數(shù)傳遞了描述驅(qū)動程序所支持類型的一組標(biāo)志。一些驅(qū)動程序可以異步 操作,而另一些驅(qū)動程序則不能。一些驅(qū)動程序能夠?qū)⒁环Nwave數(shù)據(jù)格式轉(zhuǎn)換成另一種格 式(稱作CODECs),而另一些驅(qū)動程序僅能完成過濾操作,其輸入輸出格式是一樣的。注 意ACM維護著這類數(shù)據(jù)及驅(qū)動程序的名字,版權(quán)信息等等,這樣我們可以不必裝載或打開 指定的驅(qū)動程序就可以得到這些數(shù)據(jù)。這樣很方便,譬如當(dāng)需將數(shù)據(jù)放在列表框中由用戶 選擇時。要獲得有關(guān)某一驅(qū)動程序能力更多的詳細信息,必須裝載驅(qū)動程序并打開它,可通過調(diào)用 acmOpen

15、Driver實現(xiàn)。一旦驅(qū)動程序打開,可請求枚舉它所支持的wave數(shù)據(jù)格式。同時有一 個小問題-盡管所有wave格式描述結(jié)構(gòu)基于WAVEFORAMTEX,許多格式使用此結(jié)構(gòu)的擴展形 式來保存其特定的信息。如果我們想枚舉所有格式,需要知道為此結(jié)構(gòu)分配多少供驅(qū)動 程序填寫詳細信息的空間。可通過向acmMetrics函數(shù)傳遞ACM_METRIC_MAX_SIZE_FORMAT標(biāo) 志得到所需的最大的結(jié)構(gòu)的尺寸。如果你讀過上面的代碼,你會發(fā)現(xiàn)我只是簡單的將分配的空間強制轉(zhuǎn)換為WAVEFORMATEX指針。 我只對通用信息而不是任一特定類型的數(shù)據(jù)感興趣,因此這個指針符合我的要求。為結(jié)構(gòu)分配了空間后,現(xiàn)在我可

16、以acmFormatEnum來枚舉所支持的格式。這次又用到一個回 調(diào)函數(shù)來取得枚舉出的格式的相關(guān)數(shù)據(jù):BOOL CALLBACK FormatEnumProc(HACMDRIVERID hadid, LPACMFORMATDETAILS pafd, DWORD dwInstance, DWORD fdwSupport) printf(" %4.4lXH, %sn", pafd->dwFormatTag, pafd->szFormat); return TRUE; / 繼續(xù)枚舉如你所看到的,這是一次嘗試并僅打印出格式的某些信息。這樣,通過上面的代碼,你能夠查詢AC

17、M所有的驅(qū)動程序,查找每一個驅(qū)動程序所支持的 格式。我建議你現(xiàn)在運行CAPS程序,看看你的系統(tǒng)上安裝了些什么。 使用特定的CODEC好了,我們已得知你的系統(tǒng)上安裝了什么CODECs-現(xiàn)在來看看怎樣查找某一特定的CODEC并 使用它壓縮音頻數(shù)據(jù)。讓我們看看CONV實例,它使用一種有效的CODEC壓縮一個簡單的wave 數(shù)據(jù)包。為了使代碼更趨簡單,我以控制臺應(yīng)用程序的形式的實現(xiàn)它,也沒有嘗試去 播放壓縮過的數(shù)據(jù)或?qū)⑵浯嫒胛募?。這個實例的代碼僅向你展示怎樣找到你所需要的驅(qū) 動程序并使用它將數(shù)據(jù)轉(zhuǎn)換為壓縮格式。剩下的就靠你了。兩步實現(xiàn)壓縮在理想的情況下,壓縮一些數(shù)據(jù)可能只不過是向系統(tǒng)說:“這有一些數(shù)據(jù)

18、,請壓縮成這種格式?!?不幸的是,Windows編程與理想相去甚遠,象通常一樣,我們得自已做許多瑣碎的工作。 要解決的第一個也是最重要的問題是給定的CODEC可能不能壓縮你所使用的數(shù)據(jù)格式。例 如,我們錄入了一些11025Hz,8位,單聲道的PCM數(shù)據(jù)(或許是用戶向麥克風(fēng)說的話),此 種格式幾乎所有的多媒體PC都能錄制。我們可能要將數(shù)據(jù)通過MODEM傳遞,因此我們想盡可能 的壓縮數(shù)據(jù),使數(shù)據(jù)量減少。我們選擇了TrucSpeech CODEC,它安裝在Windows中,能夠 獲得大約10:1的壓縮率。我們所要碰到的問題就是TrueSpeech CODEC不能處理11025Hz, 8位,單聲道的P

19、CM數(shù)據(jù)。它只能處理8000Hz,16位,單聲道的數(shù)據(jù)(某些情況下是8位)。 因此我們必須先將源數(shù)據(jù)轉(zhuǎn)換為TrueSpeech CODEC所支持的中間PCM格式,然后在使用它 將中間數(shù)據(jù)轉(zhuǎn)換為最終所需的格式??墒褂秒SWindows分發(fā)的某種不同的CODEC將一種PCM格式轉(zhuǎn)換為另一種格式,因此你需使用 某種CODEC將數(shù)據(jù)轉(zhuǎn)換為其它CODEC能夠處理的格式。我們已知道怎樣去枚舉CODECs及其所 支持的格式,因此這樣做是可以實現(xiàn)的。但還有一個問題,我在實例代碼中忽略了,留給你們解決。如果某一CODEC能夠創(chuàng)建我們所 想要的壓縮格式,但支持幾種不同的輸入格式,我們怎樣選擇最佳的中間格式呢?按照

20、Nigel的準(zhǔn)則,那就是“總是做最少量的工作”,我選擇使用CODEC所支持的枚舉出的第一 種PCM格式。由于很容易實現(xiàn),可能會導(dǎo)致數(shù)據(jù)失真。假設(shè)我們要使用的某一CODEC有一些 近乎無失真的壓縮算法,能夠接收8位或16位的11025Hz或22050Hz的PCM數(shù)據(jù)。我們要轉(zhuǎn)換 以441000Hz,16位立體聲錄制的高保真的樣本。我們試圖降低數(shù)據(jù)量,而不在乎損失質(zhì)量。 如果我們枚舉此CODEC所支持的格式,第一個得到的可能是11025Hz,8位單聲道的格式。我 們先將數(shù)據(jù)轉(zhuǎn)換為此格式,然后進行壓縮,這其間肯定要損失一些質(zhì)量,因為這種中間格 式不夠好。如果使用16位22050Hz的話會好一些。已告

21、訴過你這種缺憾啦,讓我們瞧瞧CONV 實例,看它是怎樣工作的。CONV實例程序CONV實例分四個階段:它創(chuàng)建一些wave格式數(shù)據(jù)的樣本,找到一個合適的CODEC,將數(shù)據(jù)轉(zhuǎn) 換為此CODEC可處理的中間格式,最后將數(shù)據(jù)轉(zhuǎn)換成所需的格式。為了簡單其間,源數(shù)據(jù)用 程序創(chuàng)建而不是錄入或是從wave文件中讀取: / 首先我們創(chuàng)建一個可能是剛剛才錄制的wave 其格式為11.025kHz, / 8位單聲道PCM,這是一個所有機器上都可用的錄入格式,我們的例 / 子是1秒長的1kHz的正弦波wave,剛好1000個周期 WAVEFORMATEX wfSrc; memset(&wfSrc, 0, si

22、zeof(wfSrc); wfSrc.cbSize = 0; wfSrc.wFormatTag = WAVE_FORMAT_PCM; / PCM wfSrc.nChannels = 1; / Mono wfSrc.nSamplesPerSec = 11025; / 11.025 kHz wfSrc.wBitsPerSample = 8; / 8 bit wfSrc.nBlockAlign = wfSrc.nChannels * wfSrc.wBitsPerSample / 8; wfSrc.nAvgBytesPerSec = wfSrc.nSamplesPerSec * wfSrc.nBloc

23、kAlign; DWORD dwSrcSamples = wfSrc.nSamplesPerSec; BYTE* pSrcData = new BYTE dwSrcSamples; / 1秒種的長度 BYTE* pData = pSrcData; double f = 1000.0; double pi = 4.0 * atan(1.0); double w = 2.0 * pi * f; for (DWORD dw = 0; dw 上面的代碼創(chuàng)建了一個WAVEFORMATEX結(jié)構(gòu)用來描述源數(shù)據(jù)格式,并用簡單的數(shù)學(xué)方法生成了1秒鐘長的11.025kHz,8位單聲道的PCM的wave數(shù)據(jù)。下一步

24、就是選擇要將數(shù)據(jù)轉(zhuǎn)換成什么格式及選定一個合適的CODEC。 WORD wFormatTag = WAVE_FORMAT_DSPGROUP_TRUESPEECH; / 現(xiàn)在我們選定一個支持目標(biāo)格式標(biāo)簽的CODEC HACMDRIVERID hadid = find_driver(wFormatTag); if (hadid = NULL) printf("No driver foundn"); exit(1); printf("Driver found (hadid: %4.4lXH)n", hadid);find_driver函數(shù)枚舉所有的驅(qū)動程序直到找

25、到一個支持給定標(biāo)簽值的驅(qū)動程序(本例為WAVE_FORMAT_DSPGROUP_TRUESPEECH)。我沒有在此給出代碼是因為它與前面的枚舉代碼非常相象。隨后你可以查看它是怎樣工作的。選定了驅(qū)動程序,現(xiàn)在要為最終驅(qū)動程序?qū)a(chǎn)生的壓縮數(shù)據(jù)格式創(chuàng)建一個WAVEFORMATEX結(jié)構(gòu),并為驅(qū)動程序用于輸入的中間PCM格式產(chǎn)生一個WAVEFORMATEX結(jié)構(gòu)。 / 獲得格式的詳情 / 注意:這只是一個給定格式簽的第一種或是最可能的格式 WAVEFORMATEX* pwfDrv = get_driver_format(hadid, wFormatTag); if (pwfDrv = NULL) prin

26、tf("Error getting format infon"); exit(1); printf("Driver format: %u bits, %lu samples per secondn", pwfDrv->wBitsPerSample, pwfDrv->nSamplesPerSec); / 獲取驅(qū)動程序所支持的PCM格式標(biāo)簽 / 注意:我們只是選取第一支持的PCM格式但不一定是最好的選擇 WAVEFORMATEX* pwfPCM = get_driver_format(hadid, WAVE_FORMAT_PCM); if (pw

27、fPCM = NULL) printf("Error getting PCM format infon"); exit(1); printf("PCM format: %u bits, %lu samples per secondn", pwfPCM->wBitsPerSample, pwfPCM->nSamplesPerSec);有點重復(fù)了,要注意的是get_driver_format函數(shù)僅僅枚舉出第一種匹配的格式-也許不能獲得可能的最好的質(zhì)量。現(xiàn)在我們有了WAVEFORMATEX結(jié)構(gòu)描述源格式,中間PCM格式,以及最終的壓縮格式。可以開始

28、轉(zhuǎn)換數(shù)據(jù)了。轉(zhuǎn)換由被ACM稱作流的對象來實現(xiàn)。我們可以打開流,將源格式、目標(biāo)格式傳遞給它,要求它進行轉(zhuǎn)換。在此要注意如果CODEC的算法復(fù)雜的話同步轉(zhuǎn)換是很耗時的。一些CODEC可以異步工作,通過向窗口發(fā)送一個消息,或調(diào)用一個回調(diào)函數(shù),或設(shè)置一個事件告知你轉(zhuǎn)換進程。下面的代碼是以最少麻煩準(zhǔn)則完成任務(wù)的-你必須等待它直到完成。還有另外一點,很重要。如你所知,我們打開轉(zhuǎn)換流,指明ACM_STREAMOPENF_NONREALTIME標(biāo)志。這非常重要。若省略此標(biāo)志,那么一些驅(qū)動程序(例如TrueSpeech驅(qū)動程序)將會報告錯誤512(意思是不可能)。此錯誤告訴你所要求的轉(zhuǎn)換不能實時進行。我的實例代

29、碼中沒有這個問題,但如果你試圖在播放數(shù)據(jù)的同時轉(zhuǎn)換大量數(shù)據(jù),就要注意這點了。讓我們看看第一步的轉(zhuǎn)換,它完成的是將源數(shù)據(jù)轉(zhuǎn)換為中間格式: / / 將源wave轉(zhuǎn)換為CODEC所支持的PCM格式 / 我們使用任一種能實現(xiàn)PCM格式間轉(zhuǎn)換驅(qū)動程序 HACMSTREAM hstr = NULL; mmr = acmStreamOpen(&hstr, NULL, / 任一驅(qū)動程序 &wfSrc, / 源格式 pwfPCM, / 目標(biāo)格式 NULL, / 無過濾 NULL, / 沒回調(diào) 0, / 實例數(shù)據(jù)(未使用) ACM_STREAMOPENF_NONREALTIME); / 標(biāo)志 if

30、 (mmr) printf("Failed to open a stream to do PCM to PCM conversionn"); exit(1); / 為轉(zhuǎn)換結(jié)果開辟一個緩沖區(qū) DWORD dwSrcBytes = dwSrcSamples * wfSrc.wBitsPerSample / 8; DWORD dwDst1Samples = dwSrcSamples * pwfPCM->nSamplesPerSec / wfSrc.nSamplesPerSec; DWORD dwDst1Bytes = dwDst1Samples * pwfPCM->w

31、BitsPerSample / 8; BYTE* pDst1Data = new BYTE dwDst1Bytes; / 填寫轉(zhuǎn)換信息 ACMSTREAMHEADER strhdr; memset(&strhdr, 0, sizeof(strhdr); strhdr.cbStruct = sizeof(strhdr); strhdr.pbSrc = pSrcData; / 要轉(zhuǎn)換的源數(shù)據(jù) strhdr.cbSrcLength = dwSrcBytes; strhdr.pbDst = pDst1Data; strhdr.cbDstLength = dwDst1Bytes; / 準(zhǔn)備好頭

32、mmr = acmStreamPrepareHeader(hstr, &strhdr, 0); / 轉(zhuǎn)換數(shù)據(jù) printf("Converting to intermediate PCM format.n"); mmr = acmStreamConvert(hstr, &strhdr, 0); if (mmr) printf("Failed to do PCM to PCM conversionn"); exit(1); printf("Converted OKn"); / 關(guān)閉流 acmStreamClose(hst

33、r, 0);當(dāng)流打開時,第二個參數(shù)為NULL,表示接受任何驅(qū)動程序進行轉(zhuǎn)換。復(fù)雜的只是計算需要給輸出數(shù)據(jù)分配多大的緩沖區(qū)。由于PCM格式間的轉(zhuǎn)換不牽扯壓縮和解壓縮,直接就計算出來了。你可能注意到調(diào)用了acmStreamPrepareHeader,它為驅(qū)動程序安排好一切并允許驅(qū)動程序在轉(zhuǎn)換前鎖定內(nèi)存。最后一步是將中間格式轉(zhuǎn)換為最終的壓縮格式:/ / 將中間格式轉(zhuǎn)換為最終的壓縮格式 / 打開驅(qū)動程序 HACMDRIVER had = NULL; mmr = acmDriverOpen(&had, hadid, 0); if (mmr) printf("Failed to open

34、 drivern"); exit(1); / 打開轉(zhuǎn)換流 / 注意使用了ACM_STREAMOPENF_NONREALTIME標(biāo)志. / 沒有此標(biāo)志一些軟件壓縮程序會報告512號錯誤-即不可能 mmr = acmStreamOpen(&hstr, had, / 驅(qū)動程序句柄 pwfPCM, / 源格式 pwfDrv, / 目標(biāo)格式 NULL, / 不過濾 NULL, / 無回調(diào)函數(shù) 0, / 實例數(shù)據(jù)(未使用) ACM_STREAMOPENF_NONREALTIME); / 標(biāo)志 if (mmr) printf("Failed to open a stream to

35、 do PCM to driver format conversionn"); exit(1); / 為轉(zhuǎn)換結(jié)果分配一個緩沖區(qū) / 根據(jù)以字節(jié)計的平均速率計算輸出緩沖區(qū)的尺寸 / 并加上一機動位(bit) / 沒有此額外的空間IMA_ADPCM驅(qū)動程序?qū)⒉荒苻D(zhuǎn)換 DWORD dwDst2Bytes = pwfDrv->nAvgBytesPerSec * dwDst1Samples / pwfPCM->nSamplesPerSec; dwDst2Bytes = dwDst2Bytes * 3 / 2; / 增加一點空間 BYTE* pDst2Data = new BYTE dwDst2Bytes; / 填寫轉(zhuǎn)換信息 ACMSTREAMHEADER strhdr2; memset(&strhdr2, 0, sizeof(strhdr2); strhdr2.cbStruct =

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論