波形文件數據的讀取 mmio的操作

如果需要從底層來控制和操作波形文件,就需要獲取波形文件的聲音的採樣數據。RIFF格式文件與普通文件不同,不能像打開普通文件一樣打開RIFF文件。幸好,VC爲讀取多媒體文件提供了專門用來操作RIFF格式文件的I/OB函數,這些多媒體I/O函數都以mmio開頭,包括打開,關閉,寫入,創建新數據塊等一系列的操作。

讀取WAV文件的一般流程:
1.讀取文件需要通過mmioOpen打開波形文件,打開的方式很簡單,如下所示:
HMMIO h;
h = mmioOpen(path, NULL, MMIO_READ_WRITE);
mmioOpen函數可以打開一個標準文件,內存文件或用戶存儲系統,該函數返回的指針類型HMMIO是一個多媒體文件句柄,HMMIO句柄不是標準的文件句柄,只能用於多媒體文件I/O函數。函數中的path表示一個波形文件的有效路徑,MMIO_READ_WRITE表示以可讀寫的方式打開文件。NULL對應的參數爲指向特殊參數的MMIOINFO結構指針,通常被設爲NULL。

波形文件數據的讀取 - airmanisvip - 我的博客
WAV文件的格式

偏移量

字節

數據

0000

4

“RIFF”

0004

4

波形塊的大小(文件大小減8)

0008

4

“WAVE”

000c

4

“fmt ”

0010

4

格式塊的大小(18字節)

0014

2

WAVEFORMATEX.wFormatTag

0016

2

WAVEFORMATEX.nChannels

0018

4

WAVEFORMATEX.nSamplePerSec

001c

4

WAVEFORMATEX.nAvgBytesPerSec

0020

2

WAVEFORMATEX.BlockAlign

0022

2

WAVEFORMATEX.wBitsPerSample

0024

2

WAVEFORMATEX.cbsize

0028

4

“data”

002c

4

波形文件大小

0030

波形數據開始

2. 打開文件後,可通過HMMO句柄獲得文件中的波形部份:
MMCKINFO mmckinfo;
mmckinfo.fccType = mmioFOURCC('W','A','V','E');
mmioDescend(h, &mmckinfo, NULL, MMIO_FINDRIFF);
經上述調用,mmioDescend函數在句柄h所指向的文件中搜索構造類型爲"WAVE"的塊的信息,MMCKINFO結構用來接受波形部份信息。該函數調用時會通過檢查MMCKINFO結構的fccType的數據來決定需要獲得什麼構造類型的信息。我們指定函數的wflags參數爲MMIO_FINDRIFF,表示需要搜索"RIFF"塊信息。
RIFF文件的塊信息結構MMCKINFO的定義如下:
typedef struct 
{
    FOURCC ckid;                // 記錄塊的標識
    DWORD cksize;             // 記錄該塊的數據長度,該長度不包含4字節的塊標識長度
    FOURCC fccType;          // 記錄塊的類型
    DWORD dwDataOffset; // 記錄塊數據成員的首地址距文件頭的偏移量
    DOWRD dwFlags;          // 用來指定塊的附加信息,一般爲空或MMIO_DIRTY等標記
}MMCKINFO;

3. 得到波形部分的MMCKINFO結構指針後,下一步就是獲得波形文件的信息部分:
MMCKINFO mmfmtckinfo;
mmfmtckinfo.ckid = mmioFOURCC('F','M','T',' ');
mmioDescend(h, &mmfmtckinfo, &mmckinfo, MMIO_FINDCHUNCK);

4. 同樣採用mmioDescend函數,但調用的結果不同,該函數可以通過把"RIFF"塊mmckinfo作爲"父塊",以塊搜索塊的方式搜索到構造類型爲"fmt "。搜索到的塊信息由mmfmtckinfo對象接受。MMIO_FINDCHUNCK標識表示搜索塊信息,h爲傳入多媒體文件的句柄。
MMCKINFO結構中的fccType成員爲四字節數據,如果類型不滿4個字符,應該往後面添加空格。

5. 得到了fmt部分的MMCKINFO指針後需要通過mmfmtckinfo得到PCMWAVEFORMAT結構:
PCMWAVEROMAT wformat;
mmioRead(h, &wformat, mmfmtckinfo.cksize);
當文件指針指到多媒體文件的mmfmtckinfo部分,函數會自動搜索到需要讀入的PCMWAVEFORMT結構首地址,並按首地址順次向wformat填滿mmfmtckinfo.cksize大小的字符數。函數成功調用後,得到非空的PCMWAVEFORMAT對象wformat,並返回讀出的字節總數,否則mmioRead返回-1,表示讀操作出錯.

6. 如果還需要得到波形文件的數據信息,也就是說,要得到data部分信息,也可以通過調用mmioDescend函數得以實現。實現的第一步使文件的當前位置退回到mmckinfo塊的位置:
mmioAscend(h, &mmfmtckinfo, 0);
然後需要聲明一個對象mmdatainfo,並把該對象的fccType成員設置爲"data"類型。通過mmioDescend函數搜索到data部分的地址:
MMCKINFO mmdatainfo;
mmdatainfo.ckid = mmioFOURCC('d','a', 't', 'a');
mmioDescend(h, &mmdatainfo, &mmckinfo, MMIO_FINDCHUNK);
HGLOBAL hdata;
LPSTR      pdata;
hdata = GlobalAlloc(GMEM_MOVEALBE, mmdatainfo.cksize);
pdata = (LPSTR)GlobalLock(hdata);
mmioRead(h, pdata, mmdatainfo.cksize);

7. GlobalAlloc函數用來得到固定大小數據塊的指針,該指針指向的空間沒有實際含義的對象存在。GlobalLock函數通過鎖定由GlobalAlloc函數得到的數據塊,把hdata句柄轉換成爲內存指針。mmioRead(h, pdata, mmdatainfo,.cksize)語句用來向pdata地址讀入mmdatainfo.cksize大小的數據。
GlobalAlloc函數原型爲:
HGLOBAL GlobalAlloc
(
    UINT uFlags;           // allocation attributes
    DWORD dwBytes; // numbers of bytes to allocate 
)
(1). uFlags爲分配屬性標識。各表示含義如下:
GMEM_FIXED表示分配固定的內在空間;
GMEM_MOVEABLE表示分配可變內存空間
GMEM_SHARE 表示可以使用DDE操作
GMEM_DISCARABLE 只用於和16位Windows相兼容的應用中,表示該內存塊是可被釋放的,採用該標識必須用GlobalDiscard函數來釋放塊;
GMEM_ZEROIIT用於把內在塊的大小初始化爲0。如果uFlags取0,表示分配固定的內在空間。
(2). dwBytes 指定分配內存大小。
GlobalLock函數原型:
LPVOID GlobalLock
(
    HGLOBAL hMem; // handle to the global memory object
)
(3). hMem爲GlobalAlloc函數返回的句柄,GlobalLock函數返回內存指針。

以上7個馬驟後,得到了波形文件的數據信息,並把數據信息讀入到內存中,通過對指針pdata指向內存塊的訪問,我們就可以隨意地訪問該內存塊的任何信息。

發佈了18 篇原創文章 · 獲贊 11 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章