// WAVReader.cpp: implementation of the WAVReader class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "URLMon.h" #include #include #include #include "..\Header\WavReader.h" ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// WAVReader::WAVReader() { // Init data members m_pwfmt = NULL; m_hmmio = NULL; m_nBlockAlign= 0; m_nAvgDataRate = 0; m_InDataSize = 0; m_OutDataSize = 0; m_nBytesPlayed = 0; memset (&m_mmckiRiff, 0, sizeof (MMCKINFO)); memset (&m_mmckiFmt, 0, sizeof (MMCKINFO)); memset (&m_mmckiData, 0, sizeof (MMCKINFO)); m_Buffer = NULL; m_BufferSize = 0; m_BufferDataRead = 0; m_InDataCursor = 0; m_IsPcm = FALSE; m_pHas = NULL; ZeroMemory(&m_Ash,sizeof(m_Ash)); m_SubFileMem = NULL; } WAVReader::~WAVReader() { // Close file if (m_hmmio) mmioClose (m_hmmio, 0); if (!m_IsPcm) { if(m_pHas) acmStreamUnprepareHeader(m_pHas, &m_Ash, 0); delete [] m_Ash.pbDst; delete [] m_Ash.pbSrc; if(m_pHas) acmStreamClose( m_pHas, 0); } else delete [] m_Buffer; if (m_pwfmt) GlobalFree (m_pwfmt); } CKERROR WAVReader::ReadMemory(void* memory, int size) { if(!memory || !size) return -1; BOOL fRtn = CK_OK; // assume success MMIOINFO mminfo; memset(&mminfo,0,sizeof(MMIOINFO)); mminfo.pchBuffer = (char*) memory; mminfo.cchBuffer = size; mminfo.fccIOProc = FOURCC_MEM; // Open the requested file if ((m_hmmio = mmioOpen(NULL, &mminfo, MMIO_ALLOCBUF | MMIO_READ)) == NULL) { m_mmr = MMIOERR_CANNOTOPEN; goto OPEN_ERROR; } return DoMMio(); OPEN_ERROR: // Handle all errors here fRtn = -1; if (m_hmmio) { // Close file mmioClose (m_hmmio, 0); m_hmmio = NULL; } if (m_pwfmt) { // UNDONE: Change here if using malloc // Free memory GlobalFree (m_pwfmt); m_pwfmt = NULL; } return -1; } // Opens a file CKERROR WAVReader::OpenFile(char *file) { WORD cbExtra = 0; BOOL fRtn = CK_OK; // assume success char* CacheName= file; /* [MAX_PATH]; if(VxURLDownloadToCacheFile(NULL,file,CacheName,_MAX_PATH,0,&wavbsc) != S_OK) return -1; */ if (!CacheName) return -1; if(strlen(CacheName) == 0) return -1; // Open the requested file if ((m_hmmio = mmioOpen (CacheName, NULL, MMIO_ALLOCBUF | MMIO_READ)) == NULL) { m_mmr = MMIOERR_CANNOTOPEN; goto OPEN_ERROR; } return DoMMio(); OPEN_ERROR: // Handle all errors here fRtn = -1; if (m_hmmio) { // Close file mmioClose (m_hmmio, 0); m_hmmio = NULL; } if (m_pwfmt) { // UNDONE: Change here if using malloc // Free memory GlobalFree (m_pwfmt); m_pwfmt = NULL; } return -1; } CKERROR WAVReader::DoMMio(){ WORD cbExtra = 0; BOOL fRtn = CK_OK; // assume success // Descend into initial chunk ('RIFF') if (m_mmr = mmioDescend (m_hmmio, &m_mmckiRiff, NULL, 0)) { goto OPEN_ERROR; } // Validate that it's a WAVE file if ((m_mmckiRiff.ckid != FOURCC_RIFF) || (m_mmckiRiff.fccType != mmioFOURCC('W', 'A', 'V', 'E'))) { m_mmr = MMIOERR_INVALIDFILE; goto OPEN_ERROR; } // Find format chunk ('fmt '), allocate and fill WAVEFORMATEX structure m_mmckiFmt.ckid = mmioFOURCC('f', 'm', 't', ' '); if (m_mmr = mmioDescend (m_hmmio, &m_mmckiFmt, &m_mmckiRiff, MMIO_FINDCHUNK)) { goto OPEN_ERROR; } // Read the format chunk into temporary structure PCMWAVEFORMAT pcmwf; if (mmioRead (m_hmmio, (CHAR *) &pcmwf, sizeof(PCMWAVEFORMAT)) != sizeof(PCMWAVEFORMAT)) { m_mmr = MMIOERR_CANNOTREAD; goto OPEN_ERROR; } // If format is not PCM, then there are extra bytes appended to WAVEFORMATEX if (pcmwf.wf.wFormatTag != WAVE_FORMAT_PCM) { // Read WORD specifying number of extra bytes if (mmioRead (m_hmmio, (LPSTR) &cbExtra, sizeof (cbExtra)) != sizeof(cbExtra)) { m_mmr = MMIOERR_CANNOTREAD; goto OPEN_ERROR; } } // Allocate memory for WAVEFORMATEX structure + extra bytes // UNDONE: GMEM_FIXED???? use malloc? if (m_pwfmt = (WAVEFORMATEX *) GlobalAlloc (GMEM_FIXED, sizeof(WAVEFORMATEX)+cbExtra)) { // Copy bytes from temporary format structure memcpy (m_pwfmt, &pcmwf, sizeof(pcmwf)); m_pwfmt->cbSize = cbExtra; // Read those extra bytes, append to WAVEFORMATEX structure if (cbExtra != 0) { if ((m_mmr = mmioRead (m_hmmio, (LPSTR) ((BYTE *)(m_pwfmt) + sizeof (WAVEFORMATEX)), cbExtra)) != cbExtra) { // Error reading extra bytes m_mmr = MMIOERR_CANNOTREAD; goto OPEN_ERROR; } } } else { // Error allocating memory m_mmr = MMIOERR_OUTOFMEMORY; goto OPEN_ERROR; } // Init some member data from format chunk m_nBlockAlign = m_pwfmt->nBlockAlign; m_nAvgDataRate = m_pwfmt->nAvgBytesPerSec; // Ascend out of format chunk if (m_mmr = mmioAscend (m_hmmio, &m_mmckiFmt, 0)) { goto OPEN_ERROR; } // Cue for streaming Cue(); // Init some member data from data chunk m_InDataSize = m_mmckiData.cksize; // Successful open! goto OPEN_DONE; OPEN_ERROR: // Handle all errors here fRtn = -1; if (m_hmmio) { // Close file mmioClose (m_hmmio, 0); m_hmmio = NULL; } if (m_pwfmt) { // UNDONE: Change here if using malloc // Free memory GlobalFree (m_pwfmt); m_pwfmt = NULL; } return -1; OPEN_DONE: // Create Decode Buffer m_IsPcm = (m_pwfmt->wFormatTag == WAVE_FORMAT_PCM); if(m_IsPcm) { m_BufferSize = min(m_pwfmt->nAvgBytesPerSec / 8, m_InDataSize); m_Buffer = new BYTE[m_BufferSize ]; m_Wfe = *m_pwfmt; m_OutDataSize = m_InDataSize; // Equal if PCM } else { m_Wfe.cbSize = 0; m_Wfe.wFormatTag = WAVE_FORMAT_PCM; m_Wfe.nChannels = m_pwfmt->nChannels; m_Wfe.nSamplesPerSec = m_pwfmt->nSamplesPerSec; m_Wfe.wBitsPerSample = 16; m_Wfe.nBlockAlign = m_Wfe.nChannels * m_Wfe.wBitsPerSample / 8; m_Wfe.nAvgBytesPerSec = m_Wfe.nSamplesPerSec * m_Wfe.nBlockAlign; HRESULT res = acmStreamOpen( &m_pHas, NULL, m_pwfmt, &m_Wfe, NULL, NULL, NULL,ACM_STREAMOPENF_NONREALTIME); if (!res) { unsigned long outsize,insize = m_pwfmt->nAvgBytesPerSec; acmStreamSize(m_pHas, insize, &outsize, ACM_STREAMSIZEF_SOURCE); LPBYTE inbuf=new BYTE[insize]; LPBYTE outbuf=new BYTE[outsize]; m_Ash.cbStruct= sizeof(ACMSTREAMHEADER); m_Ash.fdwStatus= 0; m_Ash.dwUser= 0; m_Ash.pbSrc= inbuf; m_Ash.cbSrcLength= insize; m_Ash.cbSrcLengthUsed= 0; m_Ash.dwSrcUser= insize; m_Ash.pbDst= outbuf; m_Ash.cbDstLength= outsize; m_Ash.cbDstLengthUsed= 0; m_Ash.dwDstUser= outsize; res=acmStreamPrepareHeader( m_pHas, &m_Ash, 0); if (res==0) acmStreamSize(m_pHas, m_InDataSize, &m_OutDataSize, ACM_STREAMSIZEF_SOURCE); else return -1; } else return -1; } return CK_OK; } // Decodes next chunk of data, use get data buffer to get decoded data CKERROR WAVReader::Decode() { if(m_IsPcm) { m_BufferDataRead = ReadPCM(m_Buffer,m_BufferSize); if(m_BufferDataRead > 0) return CK_OK; else return CKSOUND_READER_EOF; } else { MMRESULT res = -1; if(m_InDataCursor >= m_InDataSize) return CKSOUND_READER_EOF; if(m_InDataCursor == 0) { m_Ash.cbSrcLength = DataRead(0, m_Ash.dwSrcUser, (char*)m_Ash.pbSrc); m_Ash.cbDstLengthUsed = 0; res = acmStreamConvert( m_pHas, &m_Ash, ACM_STREAMCONVERTF_START|ACM_STREAMCONVERTF_BLOCKALIGN); if(!m_Ash.cbSrcLengthUsed) res = acmStreamConvert( m_pHas, &m_Ash, ACM_STREAMCONVERTF_START); } else { m_Ash.cbSrcLength = DataRead(m_InDataCursor, m_Ash.dwSrcUser, (char*)m_Ash.pbSrc);; m_Ash.cbDstLengthUsed = 0; res = acmStreamConvert( m_pHas, &m_Ash,ACM_STREAMCONVERTF_BLOCKALIGN ); if(!m_Ash.cbSrcLengthUsed) res = acmStreamConvert( m_pHas, &m_Ash,ACM_STREAMCONVERTF_END); } switch(res) { case 0: { m_InDataCursor += m_Ash.cbSrcLengthUsed;// ? m_Ash.cbSrcLengthUsed : m_Ash.cbSrcLength; return CK_OK; } break; } } return CKSOUND_READER_GENERICERR; } int WAVReader::DataRead(int count, char* buf) { int r=mmioRead(m_hmmio,(HPSTR) buf, count); return r; } int WAVReader::DataRead(long pos, int count, char* buf) { return (DataSeek(pos)!=-1) ? DataRead(count, buf) : -1; } int WAVReader::DataSeek(long pos) { int p=-1; MMRESULT error = mmioAscend(m_hmmio, &m_mmckiFmt,0); if (error!=0) return -1; m_mmckiData.ckid = mmioFOURCC('d','a','t','a'); error=mmioDescend(m_hmmio, &m_mmckiData, &m_mmckiRiff, MMIO_FINDCHUNK); if (error!=0) return -1; p=mmioSeek(m_hmmio,pos,SEEK_CUR); if (p==-1) return -1; return p; } // Gets the last decoded buffer CKERROR WAVReader::GetDataBuffer(BYTE **buf, int *size) { if(m_IsPcm) { *buf = m_Buffer; *size = (int) m_BufferDataRead; } else { *buf = m_Ash.pbDst; *size = m_Ash.cbDstLengthUsed; } return CK_OK; } // Gets the wave format of decoded datas CKERROR WAVReader::GetWaveFormat(CKWaveFormat *wfe) { memcpy(wfe,&m_Wfe,sizeof(CKWaveFormat)); return CK_OK; } // Gets whole decoded data size int WAVReader::GetDataSize() { return (int) m_OutDataSize; } // Gets the play time length int WAVReader::GetDuration() { return (int)(((float)m_OutDataSize * 1000.0f ) / (float)m_Wfe.nAvgBytesPerSec); } CKERROR WAVReader::Seek(int pos) { int p=-1; MMRESULT error = mmioAscend(m_hmmio, &m_mmckiFmt,0); if (error!=0) return -1; m_mmckiData.ckid = mmioFOURCC('d','a','t','a'); error=mmioDescend(m_hmmio, &m_mmckiData, &m_mmckiRiff, MMIO_FINDCHUNK); if (error!=0) return -1; p=mmioSeek(m_hmmio,pos,SEEK_CUR); if (p==-1) return CKSOUND_READER_GENERICERR; if(pos == 0) m_InDataCursor = 0; else m_InDataCursor = p; return CK_OK; } // Play CKERROR WAVReader::Play() { return CK_OK; } // Stop CKERROR WAVReader::Stop() { return CK_OK; } // Cue // BOOL WAVReader::Cue (void) { BOOL fRtn = CK_OK; // assume success // Seek to 'data' chunk from beginning of file if (mmioSeek (m_hmmio, m_mmckiRiff.dwDataOffset + sizeof(FOURCC), SEEK_SET) != -1) { // Descend into 'data' chunk m_mmckiData.ckid = mmioFOURCC('d', 'a', 't', 'a'); if ((m_mmr = mmioDescend (m_hmmio, &m_mmckiData, &m_mmckiRiff, MMIO_FINDCHUNK)) == MMSYSERR_NOERROR) { // Reset byte counter m_nBytesPlayed = 0; } else { // UNDONE: set m_mmr fRtn = -1; } } else { // mmioSeek error m_mmr = MMIOERR_CANNOTSEEK; fRtn = -1; } return fRtn; } // Read // // Returns number of bytes actually read. // On error, returns 0, MMIO error code in m_mmr. // UINT WAVReader::ReadPCM(BYTE * pbDest, UINT cbSize) { MMIOINFO mmioinfo; UINT cb; // Use direct buffer access for reads to maximize performance if (m_mmr = mmioGetInfo (m_hmmio, &mmioinfo, 0)) { goto READ_ERROR; } // Limit read size to chunk size cbSize = (cbSize > m_mmckiData.cksize) ? m_mmckiData.cksize : cbSize; // Adjust chunk size m_mmckiData.cksize -= cbSize; // Copy bytes from MMIO buffer for (cb = 0; cb < cbSize; cb++) { // Advance buffer if necessary if (mmioinfo.pchNext == mmioinfo.pchEndRead) { if (m_mmr = mmioAdvance (m_hmmio, &mmioinfo, MMIO_READ)) { goto READ_ERROR; } if (mmioinfo.pchNext == mmioinfo.pchEndRead) { m_mmr = MMIOERR_CANNOTREAD; goto READ_ERROR; } } // Actual copy // *((BYTE*)pbDest+cb) = *((BYTE*)mmioinfo.pchNext)++; *(pbDest+cb) = *(mmioinfo.pchNext)++; } // End direct buffer access if (m_mmr = mmioSetInfo (m_hmmio, &mmioinfo, 0)) { goto READ_ERROR; } // Successful read, keep running total of number of data bytes read m_nBytesPlayed += cbSize; goto READ_DONE; READ_ERROR: cbSize = 0; READ_DONE: return (cbSize); } void WAVReader::Release() { delete this; }