WAVE文件头mmio操作实例分析备忘

wave文件头分很多种,参考:

https://blog.csdn.net/xsjm206/article/details/6727023

实际上更多。所以操作起来其实挺麻烦的。但是总的来说只要记住文件头大小即可了。44,58,60,90。

mmio函数操作步骤:

1。HMMIO hmmio = mmioOpen(strFileName, NULL, MMIO_ALLOCBUF | MMIO_READ);

PS:第二个参数需要注意:除非打开内存文件、为缓冲 I / O 指定缓冲区的大小或指定卸载的 I / O 过程以打开文件,否则此参数应为NULL。如果此参数不是NULL,则它引用的MMIOINFO 结构的所有未使用成员都必须设置为零,包括保留的成员。

2。操作文件。wave文件由各种chunk(块)构成,RIFF块,fmt块,fact块,data块。据说还有LIST块,不懂。

齐秦的《不必勉强》的wave文件头。

首先查找的一定是RIFF块。mmiodescend是用来查找子块的。

MMCKINFO ckinfo;

mmioDescend(hmmio, &ckinfo, NULL, 0);

PS:第三个参数是父块,因为是第一个块,所以写NULL。

第二个参数关键:

typedef struct _MMCKINFO
{
        FOURCC          ckid;           /* chunk ID */
        DWORD           cksize;         /* chunk size */
        FOURCC          fccType;        /* form type or list type */
        DWORD           dwDataOffset;   /* offset of data portion of chunk */
        DWORD           dwFlags;        /* flags used by MMIO functions */
} MMCKINFO, *PMMCKINFO, NEAR *NPMMCKINFO, FAR *LPMMCKINFO;

这个结构体设计得很恶心。实际操作中,子块标识符ckid全是数字,让你调试时不知道查到哪里了。

RIFF:52-49-46-46(HEX),1179011410(十进制)。

fmt  : 66-6D-74-20(HEX),544501094(十进制)

fact:  66-61-63-74(HEX),1952670054(十进制)

data:64-61-64-61(HEX),1635017060(十进制)

LIST:4C-49-53-54(HEX),1414744396(十进制)

PS:查十进制值时是倒序放的。01-02-03-04,字符存放都是正序的ABCD,计算数字则是倒着读的,04-03-02-01;

返回值为0时,表示查找成功。

查找子块时其实可以预先设定ckid,然后查找,这样就可以跳过中间块,直奔目标:

ckinfo.ckid = mmioFOURCC('d', 'a', 't', 'a')  ;

MMCKINFO MIKF;

mmioDescend(hmmio, &MIKF, &ckinfo, MMIO_FINDCHUNK);

查找子块后退出mmioAscend(hmmio, &ckinfo, 0);

mmioDescend需要查找的数据:

1.文件大小:RIFF块(12字节)的cksize。不包括RIFF文件头ID和SIZE。即cksize+8。

2.WAVEFORMAT信息填充:fmt[空格]块,一般WAVE文件是44字节,其中的fmt块是24字节,也有26,40字节的。其中去掉开头的fmt标识符和cksize,即是16(18)字节的WAVEFORMAT。这部分内容需要另一个mmio函数,mmioRead

WAVEFORMAT pcmWaveFormat;

mmioRead(hmmio, (HPSTR)&pcmWaveFormat, sizeof(pcmWaveFormat));

3.数据区大小:data块的cksize。需要注意的是,这部分内容不包括8字节的块标识符。

4.数据区后面是音乐文件的标签,作者,唱片集,出版年代等信息。

3。操作音频数据:

 MMIOINFO mminfo;

mmioGetInfo(hmmio, &mminfo, 0);

这个mmioinfo 太重要了。

typedef struct _MMIOINFO
{
        /* general fields */
        DWORD           dwFlags;        /* general status flags */
        FOURCC          fccIOProc;      /* pointer to I/O procedure */
        LPMMIOPROC      pIOProc;        /* pointer to I/O procedure */
        UINT            wErrorRet;      /* place for error to be returned */
        HTASK           htask;          /* alternate local task */

        /* fields maintained by MMIO functions during buffered I/O */
        LONG            cchBuffer;      /* size of I/O buffer (or 0L) */
        HPSTR           pchBuffer;      /* start of I/O buffer (or NULL) */
        HPSTR           pchNext;        /* pointer to next byte to read/write */
        HPSTR           pchEndRead;     /* pointer to last valid byte to read */
        HPSTR           pchEndWrite;    /* pointer to last byte to write */
        LONG            lBufOffset;     /* disk offset of start of buffer */

        /* fields maintained by I/O procedure */
        LONG            lDiskOffset;    /* disk offset of next read or write */
        DWORD           adwInfo[3];     /* data specific to type of MMIOPROC */

        /* other fields maintained by MMIO */
        DWORD           dwReserved1;    /* reserved for MMIO use */
        DWORD           dwReserved2;    /* reserved for MMIO use */
        HMMIO           hmmio;          /* handle to open file */
} MMIOINFO, *PMMIOINFO, NEAR *NPMMIOINFO, FAR *LPMMIOINFO;
typedef const MMIOINFO FAR *LPCMMIOINFO;

其中mmioinfo.next即是读取数据的指针。但这个指针包括标识符,即data的ckid,cksize。由于我的文件50多兆,所以需要缓存输入,当选择数据总大小时,起初是选择了文件大小,最后播放文件到结尾时,程序出错。后来改为数据区大小,显示可以了。照理来说应该是datasize+8才对。

DWORD BufferSize=176400;

inf arraySize=BufferSize;

BYTE *pbWave;

 while (dataSize > 0)

{

dataSize-=BufferSize;

if dataSize<BufferSize)

arraySize=dataSize;

 pbWave = new BYTE[arraySize];

for(int b=0;b<arraySize;b++)

{

 *((BYTE*)pbWave + b) = *((BYTE*)mminfo.pchNext);

}

//这数据已得到,输出到声卡就行了,我用的xaudio,这玩意是真TM不好用,有噪音不说,一旦出错,其他播放器也不能正常播放(我的耳机声卡可能太低档了,会出这问题)

delete pbWave[];

}

 mmioClose(hmmio, 0);

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值