微软使用此方法来加快多媒体文件的 I/O 操作.
如果不适用该类API转而直接使用系统函数fread等将降低效率
并且分配更多的内存: App
→ AppBuf
→ FileIOBuffer
→ MultimediaFile
使用 mmio 将省去AppBuf这一环节,直接读取操作系统的文件输入输出缓冲
#include <STDIO.H>
#include <mmsystem.h>
#pragma comment(lib, "winmm.lib")
-----------------
typedef struct tagMMIOINFO{
DWORD dwFlags; // 打开文件方式标志,取值见表12-11
FOURCC fccIOProc; // 标识文件IO过程的四字符代码,无IO过程时为NULL
LPMMIOPROC pIOProc;// 文件IO过程的指针
UINT wErrorRet; // 扩展的错误值,只用于打开函数
HTASK hTask; // 局部IO过程的句柄
LONG cchBuffer; // 文件缓冲区的字节大小,对非缓冲文件为0
HPSTR pchBuffer; // 指向文件缓冲区的指针,对非缓冲文件为NULL
HPSTR pchNext; // 指向缓冲区的下一读/写位置的指针
HPSTR pchEndRead; // 指向缓冲区内的可读位置尾
HPSTR pchEndWrite; // 指向缓冲区内的可写位置尾
LONG lBufOffset; // 保留
LONG lDiskOffset; // 当前文件位置(从文件头的偏移字节数)
DWORD adwInfo[4]; // IO过程维护的状态信息
DWORD dwReserved1; // 保留
DWORD dwReserved2; // 保留
HMMIO hmmio; // 由打开函数返回的文件句柄
} MMIOINFO;
// dwFlags:
// MMIO_ALLOCBUF 打开缓冲文件
// MMIO_CREATE 创建新文件
// MMIO_READ 打开只读文件
// MMIO_WRITE 打开只写文件
// MMIO_READWRITE 打开读写文件
HMMIO mmioOpen( //return: 返回被打开文件的句柄,出错时返回 NULL;
char* fileName,
MMIOINFO*, // 额外参数的指针定义见杂项,一般为 NULL
DWORD dwFlags // 标识,见上
);
LONG mmioRead( // return:返回实际写入的字节数
HMMIO, // 文件的句柄
HPSTR pOutData, // 读取数据后用来存放读取到数据的指针,一般是WAVEFORMATEX对象的地址再强制转换
LONG // 存放读取数据的缓冲区的大小
);
LONG mmioWrite(
HMMIO, // 文件的句柄
HPSTR pSrcData, // 待写入数据的指针,可以为char*
LONG // 待写入数据的字节数
);
MMRESULT mmioClose(HMMIO, UINT wFlags/*关闭标识,可取0*/);
MMRESULT mmioDescend( // 进入块,成功返回MMSYSERR_NOERROR(= 0)
HMMIO hmmio, // 文件句柄
LPMMCKINFO lpck, // 指向接收MMCKINFO结构的缓冲区指针
LPMMCKINFO lpckParent, // 指向指定父块之MMCKINFO结构的指针,无父块时取为NULL
// MMIO_FINDLIST:列表块内的指定标识符块、MMIO_FINDRIFF:RIFF块内的指定标识符块
// 搜索标志,可取值有:0:当前位置、MMIO_FINDCHUNK:指定块标识符
UINT wFlags
);
MMRESULT mmioAscend( // 离开块,成功返回MMSYSERR_NOERROR(= 0)
HMMIO hmmio, // 文件句柄
LPMMCKINFO lpck, // 指向(已被mmioDescend填充的)MMCKINFO结构的指针
UINT wFlags // 保留,必须为0
);
// lpstrCommand大小写无关
MCIERROR WINAPI mciSendString(LPCSTR lpstrCommand, LPSTR lpstrReturnString, UINT uReturnLength, HWND hwndCallback);
// 执行效率高
MCIERROR WINAPI mciSendCommand(MCIDEVICEID mciId, UINT uMsg, DWORD dwParam1, DWORD dwParam2);
// mciSendString() 打开cd播放器(cdaudio)或者放音设备(waveaudio)
char buf[50];
MCIERROR mciError;
mciError = mciSendString("open cdaudio", buf, strlen(buf), NULL);
if (mciError) {mciGetErrorString((mciError, buf, strlen(buf)));}
// 也可以简单的这样:
mciSendString("open cdaudio", NULL, 0, NULL);
mciSendString("play cdaudio", NULL, 0, NULL);
mciSendString("pause cdaudio", NULL, 0, NULL);
mciSendString("resume cdaudio", NULL, 0, NULL);
mciSendString("stop cdaudio", NULL, 0, NULL);
mciSendString("close cdaudio", NULL, 0, NULL);
// 播放一个 wav,mid,avi 文件
mciSendString("open myfolder\\tada.wav alias aa", NULL, 0, NULL);
mciSendString("play aa wait", NULL, 0, NULL);
mciSendString("close aa", NULL, 0, NULL);
// 录制声音
mciSendString("open new type waveaudio alias aa", NULL, 0, NULL);
mciSendString("record aa", NULL, 0, NULL);
mciSendString("save aa 'c:\\program files\\aaa.wav' wait", NULL, 0, NULL);
mciSendString("close aa", NULL, 0, NULL);
// 打开 放音设备
MCI_OPEN_PARMS mciOpen;
UINT m_wDeviceID;
mciOpen.lpstrDeviceType = "avivideo"; // NULL:表示由MCI自动判断文件类型
mciOpen.lpstrElementName = "myfolder\\clock.avi";
mciSendCommand(0, MCI_OPEN, MCI_OPEN_ELEMENT, (DWORD)&mciOpen);
m_wDeviceID = mciOpen.wDeviceID;
// param
// MCI_WAIT :会等到 函数所指定的操作完成后才返回
// MCI_NOTIFY :设备完成一次操作后 post 一个 MM_MCINOTIFY
// MCI_OPEN_SHAREABLE :将设备或文件以共享的方式打开
// 播放
MCI_PLAY_PARMS mciPlay;
mciSendCommand(m_wDeviceID, MCI_PLAY, MCI_WAIT, (DWORD)&mciPlay);
// 暂停
MCI_PLAY_PARMS PlayParms;
mciSendCommand(m_wDeviceID, MCI_PAUSE, 0, (DWORD)(LPVOID)&PlayParms);
// 停止
mciSendCommand(m_wDeviceID, MCI_STOP, NULL, NULL);
// 跳跃, 跳转的目标时间单位为毫秒
MCI_SEEK_PARMS SeekParms;
SeekParms.dwTo = 4 * 1000;
mciSendCommand(m_wDeviceID, MCI_SEEK, MCI_TO | MCI_WAIT, (DWORD)(LPVOID)&SeekParms);
// 跳到文件头
mciSendCommand(m_wDeviceID, MCI_SEEK, MCI_SEEK_TO_START, NULL);
// 跳到文件尾
mciSendCommand(m_wDeviceID, MCI_SEEK, MCI_SEEK_TO_END, NULL);
// 录音
MCI_RECORD_PARMS RecordParms;
mciSendCommand(m_wDeviceID, MCI_RECORD, NULL, (DWORD)(LPVOID)&RecordParms);
// 保存录音
MCI_SAVE_PARMS saveParms;
saveParms.lpfilename = "c:\\wavefile.wav";
mciSendCommand(m_wDeviceID, MCI_SAVE, MCI_SAVE_FILE | MCI_WAIT, (DWORD)(LPVOID)&saveParms);