📄 mfm.c
字号:
{ 11025,12000,8000,0 },
};
#define MP3_GETFORMAT_BUFLEN 0x1000
/*BOOL __Mpeg1GetFmt(UINT8 *pbData, MPEG1WAVEFORMAT *pFormat)
{
UINT32 Layer;
pFormat->wfx.wFormatTag = WAVE_FORMAT_MPEG; // Get number of channels from Mode
switch (pbData[3] >> 6)
{
case 0x00:
pFormat->fwHeadMode = ACM_MPEG_STEREO;
break;
case 0x01:
pFormat->fwHeadMode = ACM_MPEG_JOINTSTEREO;
break;
case 0x02:
pFormat->fwHeadMode = ACM_MPEG_DUALCHANNEL;
break;
case 0x03:
pFormat->fwHeadMode = ACM_MPEG_SINGLECHANNEL;
break;
}
pFormat->wfx.nChannels = (WORD)(pFormat->fwHeadMode == ACM_MPEG_SINGLECHANNEL ? 1 : 2);
pFormat->fwHeadModeExt = (WORD)(1 << (pbData[3] >> 4));
pFormat->wHeadEmphasis = (WORD)((pbData[3] & 0x03) + 1);
pFormat->fwHeadFlags = (WORD)(((pbData[2] & 1) ? ACM_MPEG_PRIVATEBIT : 0) +
((pbData[3] & 8) ? ACM_MPEG_COPYRIGHT : 0) +
((pbData[3] & 4) ? ACM_MPEG_ORIGINALHOME : 0) +
((pbData[1] & 1) ? ACM_MPEG_PROTECTIONBIT : 0) +
((pbData[1] & 0x08) ? ACM_MPEG_ID_MPEG1 : 0));
switch ((pbData[1] >> 1) & 3)
{
case 3:
pFormat->fwHeadLayer = ACM_MPEG_LAYER1;
Layer = 1;
break;
case 2:
pFormat->fwHeadLayer = ACM_MPEG_LAYER2;
Layer = 2;
break;
case 1:
pFormat->fwHeadLayer = ACM_MPEG_LAYER3;
Layer = 3;
break;
case 0:
return (FALSE);
}
// Get samples per second from sampling frequency
pFormat->wfx.nSamplesPerSec = FreqTable[0][(pbData[2] >> 2) & 3];
pFormat->dwHeadBitrate = BitrateTable[0][Layer-1][pbData[2] >>4] * 1000;
pFormat->wfx.nAvgBytesPerSec = pFormat->dwHeadBitrate / 8; // Deal with free format (!)
if (pFormat->wfx.nSamplesPerSec != 44100 &&
// Layer 3 can sometimes switch bitrates
!(Layer == 3 && // !m_pStreamList->AudioLock() &&
(pbData[2] >> 4) == 0))
{
if (Layer == 1)
{
pFormat->wfx.nBlockAlign = (WORD)(4 * ((pFormat->dwHeadBitrate * 12) / pFormat->wfx.nSamplesPerSec));
}
else
{
pFormat->wfx.nBlockAlign = (WORD)((144 * pFormat->dwHeadBitrate) / pFormat->wfx.nSamplesPerSec);
}
}
else
{
pFormat->wfx.nBlockAlign = 1;
}
pFormat->wfx.wBitsPerSample = 0;
pFormat->wfx.cbSize = sizeof(MPEG1WAVEFORMAT) - sizeof(WAVEFORMATEX);
pFormat->dwPTSLow = 0;
pFormat->dwPTSHigh = 0;
return TRUE;
}
*/
UINT MediaFileGetMP3Format(HMEDIAFILE hmmio, MPEGLAYER3WAVEFORMAT *lpInfo)
{
MpegFrameHeader mpegFrameHeader, mpegFrameHeaderNew;
enum MpegVersion mpegVersion;
UINT16 mpegLayer;
UINT16 wFrameLen;
UINT32 dwBitRate, dwFreq;
UINT32 dwMaxSearchTimes, dwLoop, i, j;
UINT8 *pGetFormatBuf;
UINT dwRet;
if (hmmio == NULL || lpInfo == NULL){
return MMIOERR_CHUNKNOTFOUND;
}
pGetFormatBuf = (UINT8 *)MemAlloc(MP3_GETFORMAT_BUFLEN);
if(!pGetFormatBuf)
return MMIOERR_OUTOFMEMORY;
dwRet = MMIOERR_CHUNKNOTFOUND;
dwLoop = 0;
MediaFileSeek(hmmio, 0, 0);
while(dwRet == MMIOERR_CHUNKNOTFOUND)
{
dwMaxSearchTimes = MediaFileRead(hmmio, pGetFormatBuf, MP3_GETFORMAT_BUFLEN);
if((dwMaxSearchTimes < 4) || (dwMaxSearchTimes > MP3_GETFORMAT_BUFLEN))
break;
dwMaxSearchTimes -= (4 - 1);
for(i = 0; i < dwMaxSearchTimes; i ++)
{
memcpy(&mpegFrameHeader, pGetFormatBuf + i, 4);
// if(mpegFrameHeader.framesync != 0x7FF
if(mpegFrameHeader.framesync1 != 0xFF
|| mpegFrameHeader.framesync2 != 0x7
|| mpegFrameHeader.mpegver == 1
|| mpegFrameHeader.mpeglayer == 0
|| mpegFrameHeader.bitrate == 0xF
|| mpegFrameHeader.bitrate == 0x0
|| mpegFrameHeader.samplerate == 0x3)
continue;
switch (mpegFrameHeader.mpegver)
{
case 0: mpegVersion = MPEGVER_25; break;
// case 1: mpegVersion = MPEGVER_NA; break;
case 2: mpegVersion = MPEGVER_2; break;
case 3: mpegVersion = MPEGVER_1; break;
}
mpegLayer = 4 - mpegFrameHeader.mpeglayer;
if(mpegVersion == MPEGVER_1)
dwBitRate = BitrateTable[0][mpegLayer-1][mpegFrameHeader.bitrate];
else
dwBitRate = BitrateTable[1][mpegLayer-1][mpegFrameHeader.bitrate];
if(mpegVersion == MPEGVER_1)
dwFreq = FreqTable[0][mpegFrameHeader.samplerate];
else if(mpegVersion == MPEGVER_2)
dwFreq = FreqTable[1][mpegFrameHeader.samplerate];
else if(mpegVersion == MPEGVER_25)
dwFreq = FreqTable[2][mpegFrameHeader.samplerate];
if(mpegLayer == 1)
wFrameLen = (12000 * dwBitRate / dwFreq + mpegFrameHeader.padding) * 4;
else if(mpegLayer == 2)
wFrameLen = 144000 * dwBitRate / dwFreq + mpegFrameHeader.padding;
else if(mpegLayer == 3)
{
if(mpegVersion == MPEGVER_1)
wFrameLen = 144000 * dwBitRate / dwFreq + mpegFrameHeader.padding;
else
wFrameLen = 144000 * dwBitRate / dwFreq / 2 + mpegFrameHeader.padding;
}
/* if(mpegFrameHeader.hascrc == 0)
{
UINT16 wFrameCrc;
wFrameCrc = *(UINT16 *)(pGetFormatBuf + i + 4);
if(wFrameCrc != Crc16(pGetFormatBuf + i + 4 + 2, wFrameLen, 0))
continue;
}*/
if(dwBitRate == 0)
{
//固定比特率要计算实际比特率
for(j = i + 4; j < dwMaxSearchTimes; j ++)
{
memcpy(&mpegFrameHeaderNew, pGetFormatBuf + j, 4);
if(mpegFrameHeaderNew.framesync1 != 0xFF
|| mpegFrameHeaderNew.framesync2 != 0x7
|| mpegFrameHeaderNew.mpegver == 1
|| mpegFrameHeaderNew.mpeglayer == 0
|| mpegFrameHeaderNew.bitrate == 0xF
|| mpegFrameHeaderNew.bitrate == 0x0
|| mpegFrameHeaderNew.samplerate == 0x3)
continue;
if(mpegFrameHeaderNew.mpegver == mpegFrameHeader.mpegver
&& mpegFrameHeaderNew.mpeglayer == mpegFrameHeader.mpeglayer
&& mpegFrameHeaderNew.samplerate == mpegFrameHeader.samplerate)
break;
}
if(j >= dwMaxSearchTimes)
continue;
if(mpegVersion == MPEGVER_1)
dwBitRate = mpegFrameHeader.samplerate * (j - i) / 144000;
else
dwBitRate = mpegFrameHeader.samplerate * (j - i) / 72000;
}
else
{
//查找是否紧跟一个新的桢头
memcpy(&mpegFrameHeaderNew, pGetFormatBuf + i + wFrameLen, 4);
if(mpegFrameHeaderNew.framesync1 != 0xFF
|| mpegFrameHeaderNew.framesync2 != 0x7
|| mpegFrameHeaderNew.mpegver == 1
|| mpegFrameHeaderNew.mpeglayer == 0
|| mpegFrameHeaderNew.bitrate == 0xF
|| mpegFrameHeaderNew.bitrate == 0x0
|| mpegFrameHeaderNew.samplerate == 0x3
|| mpegFrameHeaderNew.mpegver != mpegFrameHeader.mpegver
|| mpegFrameHeaderNew.mpeglayer != mpegFrameHeader.mpeglayer
|| mpegFrameHeaderNew.samplerate != mpegFrameHeader.samplerate
|| mpegFrameHeaderNew.chanmode != mpegFrameHeader.chanmode)
continue;
}
if(mpegLayer != 3)
{
// if(mpegVersion == MPEG_VER_1)
// __Mpeg1GetFmt(ch, (MPEG1WAVEFORMAT *)lpInfo);
dwRet = MMIOERR_ACCESSDENIED;
break;
}
lpInfo->wfx.cbSize = MPEGLAYER3_WFX_EXTRA_BYTES;
lpInfo->wfx.wFormatTag = WAVE_FORMAT_MPEGLAYER3;
lpInfo->wfx.nChannels = (mpegFrameHeader.chanmode == 3) ? 1 : 2;
lpInfo->wfx.nAvgBytesPerSec = dwBitRate * (1000 / 8); // not really used but must be one of 64, 96, 112, 128, 160kbps
lpInfo->wfx.wBitsPerSample = 0; // MUST BE ZERO
lpInfo->wfx.nBlockAlign = 1; // MUST BE ONE
lpInfo->wfx.nSamplesPerSec = dwFreq;
lpInfo->fdwFlags = MPEGLAYER3_FLAG_PADDING_OFF;
lpInfo->nBlockSize = MP3_BLOCK_SIZE; // voodoo value #1
lpInfo->nFramesPerBlock = 1; // MUST BE ONE
lpInfo->nCodecDelay = 1393; // voodoo value #2
#ifdef _WIN32
lpInfo->wID = MPEGLAYER3_ID_MPEG;
#else
lpInfo->wID = *(UINT16 *)&mpegFrameHeader;
#endif
// MediaFileSeek(hmmio, -4, SEEK_CUR);
MediaFileSeek(hmmio, dwLoop * MP3_GETFORMAT_BUFLEN + i, 0);
dwRet = MMSYSERR_NOERROR;
break;
}
dwLoop ++;
}
MemFree(pGetFormatBuf);
return dwRet;
}
//pFormat要定义为长度WAVEFORMATEX_MAXLEN
//文件指针会移动到数据开始位置
UINT MediaFileGetFormat(HMEDIAFILE hmmio, UINT8 voiceType, WAVEFORMATEX *pFormat,
UINT32 *pdwFileLength, UINT32 *pdwTimeLength)
{
MMCKINFO mmckinfoParent; // parent chunk information
MMCKINFO mmckinfoSubchunk; // subchunk information structure
DWORD dwFmtSize; // size of "FMT" chunk
UINT dwError;
UINT32 dwPos, dwEnd;
if(voiceType == VOICE_TYPE_MP3)
{
// 直接定位 MP3 文件信息
dwError = MediaFileGetMP3Format(hmmio, (MPEGLAYER3WAVEFORMAT *)pFormat);
if(dwError != MMSYSERR_NOERROR)
return dwError;
dwPos = MediaFileSeek(hmmio, 0, SEEK_CUR);
dwEnd = MediaFileLength(hmmio);
// dwEnd = MediaFileSeek(hmmio, 0, SEEK_END);
// MediaFileSeek(hmmio, dwPos, SEEK_SET);
*pdwFileLength = (dwEnd - dwPos);
*pdwTimeLength = *pdwFileLength / pFormat->nAvgBytesPerSec;
return MMSYSERR_NOERROR;
}
else if(voiceType == VOICE_TYPE_WMA)
{
dwError = MediaFileGetWMAFormat(hmmio, (WAVEFORMATEX *)pFormat, pdwTimeLength);
if(dwError != MMSYSERR_NOERROR)
return dwError;
dwPos = MediaFileSeek(hmmio, 0, SEEK_CUR);
dwEnd = MediaFileLength(hmmio);
// dwEnd = MediaFileSeek(hmmio, 0, SEEK_END);
// MediaFileSeek(hmmio, dwPos, SEEK_SET);
*pdwFileLength = (dwEnd - dwPos);
return MMSYSERR_NOERROR;
}
else
{
// 寻找“WAVE”信息块,以确定文件是一个波形声音文件
mmckinfoParent.fccType = MediaFileStrToFourCC("WAVE", 0);
if (MediaFileDescend(hmmio, &mmckinfoParent, NULL, MMIO_FINDRIFF) != MMSYSERR_NOERROR)
return MMIOERR_CHUNKNOTFOUND;
// 寻找信息块中的“FMT”子块
mmckinfoSubchunk.ckid = MediaFileStrToFourCC("fmt ", 0);
if (MediaFileDescend(hmmio, &mmckinfoSubchunk, &mmckinfoParent, MMIO_FINDCHUNK) != MMSYSERR_NOERROR)
return MMIOERR_CHUNKNOTFOUND;
// 读取“FMT”子块数据
dwFmtSize = mmckinfoSubchunk.cksize;
pFormat->cbSize = 0;
if (MediaFileRead(hmmio,(BYTE *)pFormat, dwFmtSize) != (int)dwFmtSize)
return MMIOERR_CHUNKNOTFOUND;
//mocodifed by ju 2006-06-21 begin
{
INT nBps; //播放波特率
nBps = pFormat->nSamplesPerSec*pFormat->nChannels*pFormat->wBitsPerSample;
if( nBps > 176000 ) //大于176kbps,不播放
return MMIOERR_CHUNKNOTFOUND;
}
//mocodifed by ju 2006-06-21 end
// 退出“FMT”子块
MediaFileAscend(hmmio, &mmckinfoSubchunk, 0);
// 定位到“DATA”子块i
mmckinfoSubchunk.ckid = MediaFileStrToFourCC("data", 0);
if (MediaFileDescend(hmmio, &mmckinfoSubchunk, &mmckinfoParent, MMIO_FINDCHUNK) != MMSYSERR_NOERROR)
return MMIOERR_CHUNKNOTFOUND;
if(pdwFileLength != NULL)
*pdwFileLength = mmckinfoSubchunk.cksize;
*pdwTimeLength = *pdwFileLength / pFormat->nAvgBytesPerSec;
return MMSYSERR_NOERROR;
}
return MMSYSERR_NOERROR;
}
/**************************************************************************************
WMA 文件头格式信息
**************************************************************************************/
/* for debugging */
#define WMAERR_OK 0
#define WMAERR_FAIL 1
#define WMAERR_INVALIDARG 2
#define WMAERR_BUFFERTOOSMALL 3
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -