/*-------------------------------------------------------------*/ BOOL MPEGHeader::ReadHeader(BYTE *pData, int nSize, int* pnOffset) { unsigned int i=0; BOOL bValidHeader=FALSE; while (i<(nSize-sizeof(m_RawMPEGHeader))) { // Copy header bytes memcpy(&m_RawMPEGHeader,&pData[i],sizeof(m_RawMPEGHeader)); // Check Header if (m_RawMPEGHeader.FrameSyncH==0xFF && m_RawMPEGHeader.FrameSyncL==0x0F) { // we found it bValidHeader=TRUE; break; } i++; } // check if we have found a valid header if (bValidHeader==FALSE) { ASSERT(FALSE); return FALSE; } pData+=i; // set the offset if possible if (pnOffset) { *pnOffset=i; } // get Xing header data m_nFlags = 0; // clear to null incase fail // Set SampleRate m_nSampleRate= MPEGSamplerates[1-m_RawMPEGHeader.Version][m_RawMPEGHeader.SampleRateIndex]; // Set BitRate m_nBitRate= MPEGBitrates[1-m_RawMPEGHeader.Version][3-m_RawMPEGHeader.Layer][m_RawMPEGHeader.BitRateIndex]; // Set Frame Size CalcFrameSize(); // Determine offset of header if( m_RawMPEGHeader.Version==MPEG_I ) { // MPEG-I if( m_RawMPEGHeader.ChannelMode != 3 ) { // MONO pData+=(32+4); } else { // STEREO, DUAL-CHANNEL or JOINT-STEREO pData+=(17+4); } } else { // MPEG-II if( m_RawMPEGHeader.ChannelMode != 3 ) { // MONO pData+=(17+4); } else { // STEREO, DUAL-CHANNEL or JOINT-STEREO pData+=(9+4); } } // Check for Xing Tag if( pData[0] != 'X' ) return TRUE; if( pData[1] != 'i' ) return TRUE; if( pData[2] != 'n' ) return TRUE; if( pData[3] != 'g' ) return TRUE; pData+=4; m_nFlags= ExtractI4(pData); pData+=4; if( m_nFlags & FRAMES_FLAG ) { m_nFrames= ExtractI4(pData); pData+=4; } if( m_nFlags & BYTES_FLAG ) { m_nBytes= ExtractI4(pData); pData+=4; } if( m_nFlags & TOC_FLAG ) { // Get the first 100 bytes for(i=0;i<100;i++) m_btToc[i] = pData[i]; // Increase buffer pData+=100; } if( m_nFlags & VBR_SCALE_FLAG ) { m_nVbrScale = ExtractI4(pData); pData+=4; } #ifdef DEBUG_SHOW_TOC for(i=0;i<100;i++) { if( (i%10) == 0 ) printf("\n"); { LTRACE( _T( " %3d" ), m_btToc[ i ] ); } } #endif // This is a valid Xing Header m_bIsXingHeader=TRUE; return TRUE; }
BOOL CMp3Info::Load(const TCHAR *szFileName,BOOL bVbrScan) { DWORD dwBeginPtr; unsigned char hbuf[4]; static unsigned long head; unsigned char xingTag[4+12+100]; unsigned char id3tag[128]; //XING VBR ヘッダで使用 const unsigned long FRAMES_FLAG = 0x0001; const unsigned long BYTES_FLAG = 0x0002; const unsigned long TOC_FLAG = 0x0004; const unsigned long VBR_SCALE_FLAG = 0x0008; Release(); long lDataPtr = 0; //mp3ストリームの開始位置 ULONG dataSize = 0; //RMP形式のストリームサイズを取得する========================== CFile f; f.Open(szFileName,CFile::modeCreate|CFile::modeNoTruncate|CFile::modeReadWrite|CFile::shareDenyNone,NULL); // HMMIO hmmio = mmioOpen((char*)szFileName,NULL,MMIO_COMPAT); // if(hmmio) { //RMP3ファイルの確認 char hdr[4]; // LONG ret = mmioRead(hmmio,hdr,sizeof(hdr)); LONG ret = f.Read(hdr,sizeof(hdr)); if((ret == 4) && (hdr[0] == 'R') && (hdr[1] == 'I') && (hdr[2] == 'F') && (hdr[3] == 'F')) { // mmioSeek(hmmio,0,SEEK_SET); //RMP3チャンクへ移動 // MMCKINFO mmckOutinfoParent; // memset(&mmckOutinfoParent,0,sizeof(mmckOutinfoParent)); // mmckOutinfoParent.fccType = mmioFOURCC('R','M','P','3'); char buf[256]; f.SeekToBegin(); f.Read(buf,256); int i; for(i=0; i<250; i++) { if(buf[i]=='R' || buf[i+1]=='M' || buf[i+2]=='P' || buf[i+3]=='3') break; } if(i!=250) // if(mmioDescend(hmmio,&mmckOutinfoParent,NULL,MMIO_FINDRIFF) == MMSYSERR_NOERROR) { //dataチャンクへ移動 // MMCKINFO mmckOutinfoSubchunk; // memset(&mmckOutinfoSubchunk,0,sizeof(mmckOutinfoSubchunk)); // mmckOutinfoSubchunk.fccType = mmioFOURCC('d','a','t','a'); for(i=0; i<250; i++) { if(buf[i]=='d' || buf[i+1]=='a' || buf[i+2]=='t' || buf[i+3]=='a') break; } if(i!=250) // if(mmioDescend(hmmio,&mmckOutinfoSubchunk,&mmckOutinfoParent,MMIO_FINDCHUNK) == MMSYSERR_NOERROR) { // lDataPtr = mmioSeek(hmmio,0,SEEK_CUR); lDataPtr = i+4; i+=4; // dataSize = mmckOutinfoSubchunk.cksize; //ストリームサイズを取得 dataSize = (int)(BYTE)buf[i]+(int)(BYTE)buf[i+1]*256+(int)(BYTE)buf[i+2]*65536+(int)(BYTE)buf[i+3]*256*65536; } } } // mmioClose(hmmio,0); } f.Close(); DWORD dwRet; HANDLE hFile = CreateFile( szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, //指定したファイルが存在していない場合、この関数は失敗します。 FILE_ATTRIBUTE_NORMAL, NULL); if(hFile == INVALID_HANDLE_VALUE) { return FALSE; } if(dataSize == 0) { filesize=dataSize = GetFileSize(hFile,NULL); //id3tagヘッダを読み込む SetFilePointer(hFile,-128,NULL,FILE_END); if(!ReadFile(hFile,&id3tag,sizeof(id3tag),&dwRet,NULL)) { CloseHandle(hFile); return FALSE; } if((dwRet == sizeof(id3tag)) && (memcmp(id3tag,"TAG",3) == 0)) { //ID3TAGのサイズ分を差し引く dataSize -= 128; } } //ID3V2ヘッダを読み込む char id3v2head[10]; SetFilePointer(hFile,0,NULL,FILE_BEGIN); if(ReadFile(hFile,&id3v2head,sizeof(id3v2head),&dwRet,NULL) && (dwRet == sizeof(id3v2head)) && (memcmp(id3v2head,"ID3",3) == 0) ) { lDataPtr = (((long )(id3v2head[6]&0x7f)<<21) | ((long )(id3v2head[7]&0x7f)<<14) | ((long )(id3v2head[8]&0x7f)<<7) | (long )(id3v2head[9]&0x7f)); lDataPtr += 10; } SetFilePointer(hFile,lDataPtr,NULL,FILE_BEGIN); if(ReadFile(hFile,&id3v2head,sizeof(id3v2head),&dwRet,NULL) && (dwRet == sizeof(id3v2head)) && (memcmp(id3v2head,"ID3",3) == 0) ) { lDataPtr += (((long )(id3v2head[6]&0x7f)<<21) | ((long )(id3v2head[7]&0x7f)<<14) | ((long )(id3v2head[8]&0x7f)<<7) | (long )(id3v2head[9]&0x7f)); lDataPtr += 10; } SetFilePointer(hFile,lDataPtr,NULL,FILE_BEGIN); if(ReadFile(hFile,&id3v2head,sizeof(id3v2head),&dwRet,NULL) && (dwRet == sizeof(id3v2head)) && (memcmp(id3v2head,"ID3",3) == 0) ) { lDataPtr += (((long )(id3v2head[6]&0x7f)<<21) | ((long )(id3v2head[7]&0x7f)<<14) | ((long )(id3v2head[8]&0x7f)<<7) | (long )(id3v2head[9]&0x7f)); lDataPtr += 10; } SetFilePointer(hFile,lDataPtr,NULL,FILE_BEGIN); if(ReadFile(hFile,&id3v2head,sizeof(id3v2head),&dwRet,NULL) && (dwRet == sizeof(id3v2head)) && (memcmp(id3v2head,"ID3",3) == 0) ) { lDataPtr += (((long )(id3v2head[6]&0x7f)<<21) | ((long )(id3v2head[7]&0x7f)<<14) | ((long )(id3v2head[8]&0x7f)<<7) | (long )(id3v2head[9]&0x7f)); lDataPtr += 10; } SetFilePointer(hFile,lDataPtr,NULL,FILE_BEGIN); if(ReadFile(hFile,&id3v2head,sizeof(id3v2head),&dwRet,NULL) && (dwRet == sizeof(id3v2head)) && (memcmp(id3v2head,"ID3",3) == 0) ) { lDataPtr += (((long )(id3v2head[6]&0x7f)<<21) | ((long )(id3v2head[7]&0x7f)<<14) | ((long )(id3v2head[8]&0x7f)<<7) | (long )(id3v2head[9]&0x7f)); lDataPtr += 10; } SetFilePointer(hFile,lDataPtr,NULL,FILE_BEGIN); if(ReadFile(hFile,&id3v2head,sizeof(id3v2head),&dwRet,NULL) && (dwRet == sizeof(id3v2head)) && (memcmp(id3v2head,"ID3",3) == 0) ) { lDataPtr += (((long )(id3v2head[6]&0x7f)<<21) | ((long )(id3v2head[7]&0x7f)<<14) | ((long )(id3v2head[8]&0x7f)<<7) | (long )(id3v2head[9]&0x7f)); lDataPtr += 10; } //Mp3ヘッダ情報の読み取り DWORD dwFrameCount = 0; MPEGINFO mpegHead; MPEGINFO *pMpegHead = &m_mpegInfo; SetFilePointer(hFile,lDataPtr,NULL,FILE_BEGIN); while(ReadFile(hFile,&hbuf,sizeof(hbuf),&dwRet,NULL) && (dwRet == sizeof(hbuf))) { head=((unsigned long )hbuf[0] << 24) | ((unsigned long) hbuf[1] << 16) | ((unsigned long) hbuf[2] << 8) | (unsigned long) hbuf[3]; //mp3ヘッダとしての妥当性をチェック if(!mp3head_check(head)) { //+1 if(SetFilePointer(hFile,-3,NULL,FILE_CURRENT) > (DWORD)(lDataPtr + 10 * 1024)) { //先頭の10Kだけを調べる break; } continue;//1バイトずらしてもう一度 } //pMpegHeadに戻すのは最初の1フレームだけ if(dwFrameCount > 0) { pMpegHead = &mpegHead; } else { dwBeginPtr = SetFilePointer(hFile,0,NULL,FILE_CURRENT) - 4; //最初のMP3ヘッダまでの余分なデータ分をサイズから差し引く dataSize -= dwBeginPtr; } if(head & (1<<20)) { pMpegHead->lsf = (head & (1<<19)) ? 0x0 : 0x1; pMpegHead->mpeg25 = 0; } else { pMpegHead->lsf = 1; pMpegHead->mpeg25 = 1; } pMpegHead->lay = 4-((head>>17)&3); if(pMpegHead->mpeg25) pMpegHead->sampling_frequency = 6 + ((head>>10)&0x3); else pMpegHead->sampling_frequency = ((head>>10)&0x3) + (pMpegHead->lsf*3); if(pMpegHead->sampling_frequency > 8) pMpegHead->sampling_frequency = 8; pMpegHead->sampling_frequency = freqs[pMpegHead->sampling_frequency]; pMpegHead->error_protection = ((head>>16)&0x1)^0x1; pMpegHead->bitrate_index = ((head>>12)&0xf); pMpegHead->padding = ((head>>9)&0x1); pMpegHead->extension = ((head>>8)&0x1); pMpegHead->mode = ((head>>6)&0x3); pMpegHead->mode_ext = ((head>>4)&0x3); pMpegHead->copyright = ((head>>3)&0x1); pMpegHead->original = ((head>>2)&0x1); pMpegHead->emphasis = head & 0x3; pMpegHead->stereo = (pMpegHead->mode == 3) ? 1 : 2; pMpegHead->bps = tabsel_123[pMpegHead->lsf][pMpegHead->lay-1][pMpegHead->bitrate_index]; switch(pMpegHead->lay) { case 1: pMpegHead->framesize = (long) tabsel_123[pMpegHead->lsf][0][pMpegHead->bitrate_index] * 12000; pMpegHead->framesize /= pMpegHead->sampling_frequency; pMpegHead->framesize = ((pMpegHead->framesize+pMpegHead->padding)<<2)-4; break; case 2: pMpegHead->framesize = (long) tabsel_123[pMpegHead->lsf][1][pMpegHead->bitrate_index] * 144000; pMpegHead->framesize /= pMpegHead->sampling_frequency; pMpegHead->framesize += pMpegHead->padding - 4; break; case 3: pMpegHead->framesize = (long) tabsel_123[pMpegHead->lsf][2][pMpegHead->bitrate_index] * 144000; pMpegHead->framesize /= pMpegHead->sampling_frequency<<(pMpegHead->lsf); pMpegHead->framesize += pMpegHead->padding - 4; break; } //フレーム数と録音時間を計算 if(dwFrameCount == 0) { pMpegHead->size = dataSize; pMpegHead->msec=0; if(!(pMpegHead->framesize+4)) { CloseHandle(hFile); return FALSE;//0除算防止 } _int64 i64Msec; pMpegHead->flmnum = pMpegHead->size/(pMpegHead->framesize+4); //i64Msec = (_int64 )pMpegHead->flmnum * 576 * (pMpegHead->lsf?1:2) * 1000 / pMpegHead->sampling_frequency; //pMpegHead->msec = (ULONG )i64Msec; if(pMpegHead->bps == 0) { CloseHandle(hFile); return FALSE;// 2004-02-19 0除算防止 } pMpegHead->msec = pMpegHead->size * 8 / (pMpegHead->bps*((pMpegHead->stereo==1)?2:1)) ; if(pMpegHead->mpeg25) { //mpeg2 if(pMpegHead->stereo == 2) { //+17+4 SetFilePointer(hFile,17,NULL,FILE_CURRENT); } else { //+9+4 SetFilePointer(hFile,9,NULL,FILE_CURRENT); } } else { //mpeg1 if(pMpegHead->stereo == 2) { //+32+4 SetFilePointer(hFile,32,NULL,FILE_CURRENT); } else { //+17+4 SetFilePointer(hFile,17,NULL,FILE_CURRENT); } } //VBRタグを読み取る if(!ReadFile(hFile,&xingTag,sizeof(xingTag),&dwRet,NULL)) { CloseHandle(hFile); return FALSE; } if((dwRet == sizeof(xingTag)) && (memcmp(xingTag,"Xing",4) == 0)) { int iOffset = 4; ULONG flag = ExtractI4(&xingTag[iOffset]); if(flag & FRAMES_FLAG) { iOffset += 4; pMpegHead->flmnum = ExtractI4(&xingTag[iOffset])+1; pMpegHead->msec = (ULONG )((_int64 )pMpegHead->flmnum * 576 * (pMpegHead->lsf?1:2) * 1000 / pMpegHead->sampling_frequency); } if(flag & BYTES_FLAG) { iOffset += 4; pMpegHead->size = ExtractI4(&xingTag[iOffset]); } if( flag & TOC_FLAG ) { for(int i=0; i<100; i++) toc[i]=xingTag[i]; } pMpegHead->bps = (ULONG)(_int64 )(pMpegHead->size*8)/(pMpegHead->msec); pMpegHead->bVbr = TRUE; } // 2004-10-04 追加 // VBRI 形式タグを読み取る SetFilePointer(hFile,dwBeginPtr+sizeof(DWORD)*9,NULL,FILE_BEGIN); VBRI vbri; if(!ReadFile(hFile,&vbri,sizeof(vbri),&dwRet,NULL)) { CloseHandle(hFile); return FALSE; } if(memcmp(vbri.magic,"VBRI",4) == 0) { vbri.version = ExtractI2((unsigned char *)&vbri.version); vbri.delay = ExtractI2((unsigned char *)&vbri.delay); vbri.quality = ExtractI2((unsigned char *)&vbri.quality); vbri.streamBytes = ExtractI4((unsigned char *)&vbri.streamBytes); vbri.streamFrames = ExtractI4((unsigned char *)&vbri.streamFrames); vbri.tableSize = ExtractI2((unsigned char *)&vbri.tableSize); vbri.tableScale = ExtractI2((unsigned char *)&vbri.tableScale); vbri.entryBytes = ExtractI2((unsigned char *)&vbri.entryBytes); vbri.entryFrames = ExtractI2((unsigned char *)&vbri.entryFrames); pMpegHead->flmnum = vbri.streamFrames; pMpegHead->msec = (ULONG )((_int64 )pMpegHead->flmnum * 576 * (pMpegHead->lsf?1:2) * 1000 / pMpegHead->sampling_frequency); pMpegHead->size = vbri.streamBytes; pMpegHead->bps = (ULONG)(_int64 )(pMpegHead->size*8)/(pMpegHead->msec); pMpegHead->bVbr = TRUE; } SetFilePointer(hFile,dwBeginPtr+4,NULL,FILE_BEGIN); } dwFrameCount++; if(!m_mpegInfo.bVbr) //VBRのときはすべてのフレームをスキャン break; if(!bVbrScan) break; FRAMEINFO frameInfo; frameInfo.dwPtr = SetFilePointer(hFile,0,NULL,FILE_CURRENT)-4; frameInfo.dwSize = pMpegHead->framesize; //m_listFrame.push_back(frameInfo); if(!pMpegHead->framesize) break;//無限ループを防止 SetFilePointer(hFile,pMpegHead->framesize,NULL,FILE_CURRENT); }