//------------------------------------------------------------------------------------------------- // Author: Ivo Herzeg // // Purpose: // - A DivX-Video Control // // History: // - [19/2/2004] created the file // //------------------------------------------------------------------------------------------------- #define STRICT #include "StdAfx.h" #if !defined(LINUX) && !defined(NOT_USE_DIVX_SDK) #include #include #include "UIDivX_Video.h" #include "UIVideoPanel.h" //----------------------------------------------------------------------------- // Defines, constants, and global variables //----------------------------------------------------------------------------- CDivXPlayer g_DivXPlayer; bool CDivXPlayer::Load_DivX( CUIVideoPanel* pPanel, const string &szFileName ) { //stop playing pPanel->m_bPaused = 0; pPanel->m_bPlaying = 0; if (szFileName.empty()) { return 0; } //convert ".bik" to ".avi" string FileName=szFileName; size_t size=FileName.size(); FileName[size-4]=(char)'.'; FileName[size-3]=(char)'a'; FileName[size-2]=(char)'v'; FileName[size-1]=(char)'i'; //just in case there is already an AVI playing Stop_DivX(); //-------------------------------------------------------- //video init //-------------------------------------------------------- divxFile = OpenDivxFile( FileName.c_str() ); if (divxFile==0) { pPanel->GetUISystem()->GetISystem()->GetILog()->Log("DivX: failed to load: %s", FileName.c_str() ); pPanel->OnError("AVI not found"); return 0; } else { pPanel->GetUISystem()->GetISystem()->GetILog()->Log("DivX: loading file: %s", FileName.c_str() ); } retVal = DivxGetContentInfo( divxFile, &divxFileInfo ); //learn details about the file assert(!retVal); //allocate a frame buffer uint32 fbsize=(divxFileInfo.height * divxFileInfo.width * 4 * 2); m_pFrameBuffer = new unsigned char [fbsize]; assert(m_pFrameBuffer); uint64* fb=(uint64*)m_pFrameBuffer; for(uint32 x=0; x<(fbsize/8); x++) fb[x]=0; //set output to openGL 32 bit aligned data retVal = DivxSetOutputVideoFormat( divxFile, eARGB_32BIT ); assert(!retVal); //set up the callback function retVal = DivxSetCallBackFn( divxFile, 0 ); //you have to work out some way to let this guy know about the frame buffer. assert(!retVal); //give the codec the output buffers retVal = DivxSetVideoBuffer( divxFile, (void*)m_pFrameBuffer ); assert(!retVal); retVal = DivxModeSet( divxFile, eFRAME ); assert(!retVal); //----------------------------------------------------------------- //audio init //----------------------------------------------------------------- if (divxFileInfo.audio_bytes) { HWND hwnd = (HWND)pPanel->GetUISystem()->GetISystem()->GetIRenderer()->GetHWND(); if (m_pAudioBuffer==0) m_pAudioBuffer = new unsigned char [MAX_AUD_BUFFER_SIZE]; //allocate the audio buffer for(uint32 x=0; xGetIRenderer()->UpdateTextureInVideoMemory(m_iTextureID, (uint8*)m_pFrameBuffer, 0, 0, divxFileInfo.width, divxFileInfo.height, eTF_8888); if (pPanel->m_iTextureID > -1) { pPanel->GetUISystem()->GetIRenderer()->RemoveTexture(pPanel->m_iTextureID); pPanel->m_iTextureID = -1; } if (divxFileInfo.width==640 && divxFileInfo.height==480) pPanel->m_iTextureID = pPanel->GetUISystem()->GetIRenderer()->DownLoadToVideoMemory((uint8*)m_pFrameBuffer, divxFileInfo.width, divxFileInfo.height, eTF_0888, eTF_0888, 0, 0, FILTER_LINEAR, 0, "$VideoPanel", FT_DYNAMIC); else pPanel->m_iTextureID = pPanel->GetUISystem()->GetIRenderer()->DownLoadToVideoMemory((uint8*)m_pFrameBuffer, divxFileInfo.width, divxFileInfo.height, eTF_0888, eTF_0888, 0, 0, FILTER_LINEAR, 0, NULL, FT_DYNAMIC); if (pPanel->m_iTextureID == -1) { assert(!"Failed to create video memory surface for blitting video!"); delete[] pPanel->m_pSwapBuffer; pPanel->m_pSwapBuffer = 0; //BinkClose(m_hBink); //m_hBink = 0; Stop_DivX(); pPanel->OnError(""); return 0; } m_LastFramer =0xffffffff; return 1; } //----------------------------------------------------------------------------- // Name: UpdateVideo() // Desc: Handles video-playback //----------------------------------------------------------------------------- bool CDivXPlayer::Update_DivX( CUIVideoPanel* pPanel ) { if (divxFile && pPanel->m_bPlaying) { f64 frequency = GetQPF(); static f64 OldTime = GetQPC()/frequency; //--------------------------------------------------- f64 sec = GetQPC()/frequency; f64 delta = sec-OldTime; OldTime = GetQPC()/frequency; m_VideoTime+=(f32)delta; if (m_FrameCounter==0) { OldTime = GetQPC()/frequency; m_VideoTime=0.0f; } bool EndOfFile=1; uint32 FrameNo=(uint32)(m_VideoTime*divxFileInfo.videoFrameRate); if (FrameNo0; y--) { u64* fbuf=fb1+((y-1)*w/2); for(uint32 x=0; xm_iTextureID!=-1) pPanel->GetUISystem()->GetIRenderer()->UpdateTextureInVideoMemory(pPanel->m_iTextureID, m_pFrameBuffer, 0, 0, divxFileInfo.width, divxFileInfo.height, eTF_8888); //pPanel->GetUISystem()->GetIRenderer()->UpdateTextureInVideoMemory(pPanel->m_iTextureID, (uint8*)(fb1+h*w/2), 0, 0, w, h, eTF_8888); //uint32* ptr=(uint32*)m_pFrameBuffer; //for(uint32 x=0; x<(divxFileInfo.width*divxFileInfo.height); x++) ptr[x]=0; if (m_FrameCounter==0) { if (divxFileInfo.audio_bytes) { PlaySound(); } else { StopSound(); } } m_FrameCounter++; m_LastFramer=FrameNo; } } //------------------------------------------------------------------- if (EndOfFile) { StopSound(); m_LastFramer=0xffffffff; pPanel->m_bPaused = 0; pPanel->m_bPlaying = 0; pPanel->OnFinished(); } } return 1; } //----------------------------------------------------------------------------- // Name: Stop_DivX() // Desc: stops video and releases all resources //----------------------------------------------------------------------------- void CDivXPlayer::Stop_DivX() { m_AudioCounter=0; m_FrameCounter=0; m_VideoTime=0.0f; if (divxFile) { if (divxFileInfo.audio_bytes) { StopSound(); if (m_pAudioBuffer) delete m_pAudioBuffer; m_pAudioBuffer=0; g_DivXPlayer.m_StreamingSound.Release(); g_DivXPlayer.m_StreamingSound.m_SoundEnabled=0; SAFE_RELEASE( g_DivXPlayer.m_SoundManager.m_pDS ); CloseHandle( m_hNotificationEvent ); } CloseDivxFile(divxFile); divxFile=0; } else { //setup the buffers uint32 q0=MAX_NUM_VID_BUFFERS; uint32 q1=MAX_NUM_AUD_BUFFERS; uint32 q2=MAXSBUF; int retVal = DivxSetNumAudVidBuffers( MAX_NUM_VID_BUFFERS, MAX_NUM_AUD_BUFFERS, q2 ); assert(!retVal); } if (m_pFrameBuffer) delete m_pFrameBuffer; m_pFrameBuffer=0; } /* void CDivXPlayer::Release_DivX() { }*/ //----------------------------------------------------------------------------- // Name: PlayBuffer() // Desc: Reset the buffer, fill it with sound, and starting it playing //----------------------------------------------------------------------------- HRESULT CDivXPlayer::PlaySound( ) { BOOL bLooped=0; HRESULT hr; if( NULL == g_DivXPlayer.m_StreamingSound.m_SoundEnabled ) return E_FAIL; // Sanity check hr = g_DivXPlayer.m_StreamingSound.Reset(); assert(hr==S_OK); // Fill the entire buffer with wave data, and if the wav file is small then // repeat the wav file if the user wants to loop the file, otherwise fill in silence LPDIRECTSOUNDBUFFER pDSB = g_DivXPlayer.m_StreamingSound.GetBuffer( 0 ); hr = g_DivXPlayer.m_StreamingSound.FillBufferWithSound( pDSB, bLooped ); assert(hr==S_OK); // Always play with the LOOPING flag since the streaming buffer // wraps around before the entire WAV is played if( FAILED( hr = g_DivXPlayer.m_StreamingSound.Play( 0, DSBPLAY_LOOPING ) ) ) assert(hr==S_OK); return S_OK; } //----------------------------------------------------------------------------- // Name: PlayBuffer() // Desc: Reset the buffer, fill it with sound, and starting it playing //----------------------------------------------------------------------------- HRESULT CDivXPlayer::StopSound( ) { HRESULT hr; if( NULL == g_DivXPlayer.m_StreamingSound.m_SoundEnabled ) return E_FAIL; // Sanity check hr = g_DivXPlayer.m_StreamingSound.Stop(); assert(hr==S_OK); hr = g_DivXPlayer.m_StreamingSound.Reset(); assert(hr==S_OK); return S_OK; } //----------------------------------------------------------------------------- // Name: CSoundManager::Initialize() // Desc: Initializes the IDirectSound object and also sets the primary buffer // format. This function must be called before any others. //----------------------------------------------------------------------------- HRESULT CSoundManager::Initialize( HWND hWnd, DWORD dwCoopLevel ) { HRESULT hr; SAFE_RELEASE( m_pDS ); HRESULT hr00=DSERR_ALLOCATED; HRESULT hr01=DSERR_INVALIDPARAM; HRESULT hr02=DSERR_NOAGGREGATION; HRESULT hr03=DSERR_NODRIVER; HRESULT hr04=DSERR_OUTOFMEMORY; // Create IDirectSound using the primary sound device hr = DirectSoundCreate8( NULL, &m_pDS, NULL ); if (hr) return hr; assert(hr==S_OK); // Set DirectSound coop level hr = m_pDS->SetCooperativeLevel( hWnd, dwCoopLevel ); if (hr) return hr; assert(hr==S_OK); return S_OK; } //----------------------------------------------------------------------------- // Name: CSoundManager::SetPrimaryBufferFormat() // Desc: Set primary buffer to a specified format // !WARNING! - Setting the primary buffer format and then using this // same dsound object for DirectMusic messes up DirectMusic! // For example, to set the primary buffer format to 22kHz stereo, 16-bit // then: dwPrimaryChannels = 2 // dwPrimaryFreq = 22050, // dwPrimaryBitRate = 16 //----------------------------------------------------------------------------- HRESULT CSoundManager::SetPrimaryBufferFormat( DWORD dwPrimaryChannels, DWORD dwPrimaryFreq, DWORD dwPrimaryBitRate ) { HRESULT hr; LPDIRECTSOUNDBUFFER pDSBPrimary = NULL; if( m_pDS == NULL ) return CO_E_NOTINITIALIZED; // Get the primary buffer DSBUFFERDESC dsbd; ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) ); dsbd.dwSize = sizeof(DSBUFFERDESC); dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER; dsbd.dwBufferBytes = 0; dsbd.lpwfxFormat = NULL; hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBPrimary, NULL ); assert(hr==S_OK); WAVEFORMATEX wfx; ZeroMemory( &wfx, sizeof(WAVEFORMATEX) ); wfx.wFormatTag = (WORD) WAVE_FORMAT_PCM; wfx.nChannels = (WORD) dwPrimaryChannels; wfx.nSamplesPerSec = (DWORD) dwPrimaryFreq; wfx.wBitsPerSample = (WORD) dwPrimaryBitRate; wfx.nBlockAlign = (WORD) (wfx.wBitsPerSample / 8 * wfx.nChannels); wfx.nAvgBytesPerSec = (DWORD) (wfx.nSamplesPerSec * wfx.nBlockAlign); hr = pDSBPrimary->SetFormat(&wfx); assert(hr==S_OK); SAFE_RELEASE( pDSBPrimary ); return S_OK; } //----------------------------------------------------------------------------- // Name: CSoundManager::CreateStreaming() // Desc: //----------------------------------------------------------------------------- HRESULT CSoundManager::CreateStreaming( DWORD dwCreationFlags, GUID guid3DAlgorithm, DWORD dwNotifyCount, DWORD dwNotifySize, HANDLE hNotifyEvent ) { HRESULT hr; if( m_pDS == NULL ) return CO_E_NOTINITIALIZED; if( hNotifyEvent == NULL ) return E_INVALIDARG; LPDIRECTSOUNDBUFFER pDSBuffer = NULL; DWORD dwDSBufferSize = NULL; DSBPOSITIONNOTIFY* aPosNotify = NULL; LPDIRECTSOUNDNOTIFY pDSNotify = NULL; uint32 frequency=44100/1; m_WaveFile.m_wfx.wFormatTag =1; m_WaveFile.m_wfx.nChannels =2; m_WaveFile.m_wfx.nSamplesPerSec =frequency; m_WaveFile.m_wfx.nAvgBytesPerSec=m_WaveFile.m_wfx.nSamplesPerSec*4; m_WaveFile.m_wfx.nBlockAlign =0x04; m_WaveFile.m_wfx.wBitsPerSample =0x10; m_WaveFile.m_wfx.cbSize =0; //pWaveFile->m_hmmio->unused=0x10000; m_WaveFile.m_ck.ckid =0;// 0x61746164; m_WaveFile.m_ck.cksize =0; //0x0077a100; m_WaveFile.m_ck.dwDataOffset=0; //0x2c; m_WaveFile.m_ck.dwFlags =0; m_WaveFile.m_ck.fccType =0; m_WaveFile.m_ckRiff.ckid =0;//0x46464952; m_WaveFile.m_ckRiff.cksize =0;//0x0077a124; m_WaveFile.m_ckRiff.fccType =0;//0x45564157; m_WaveFile.m_ckRiff.dwDataOffset =0;//0x00000008; m_WaveFile.m_ckRiff.dwFlags =0;//0x00000000; m_WaveFile.m_dwSize=0;//0x77a100; // Figure out how big the DSound buffer should be dwDSBufferSize = dwNotifySize * dwNotifyCount; // Set up the direct sound buffer. Request the NOTIFY flag, so // that we are notified as the sound buffer plays. Note, that using this flag // may limit the amount of hardware acceleration that can occur. DSBUFFERDESC dsbd; ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) ); dsbd.dwSize = sizeof(DSBUFFERDESC); dsbd.dwFlags = dwCreationFlags | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GETCURRENTPOSITION2; dsbd.dwBufferBytes = dwDSBufferSize; dsbd.guid3DAlgorithm = guid3DAlgorithm; dsbd.lpwfxFormat = &m_WaveFile.m_wfx; hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBuffer, NULL ); assert(hr==S_OK); // Create the notification events, so that we know when to fill // the buffer as the sound plays. hr = pDSBuffer->QueryInterface( IID_IDirectSoundNotify, (VOID**)&pDSNotify ); assert(hr==S_OK); aPosNotify = new DSBPOSITIONNOTIFY[ dwNotifyCount ]; if( aPosNotify == NULL ) return E_OUTOFMEMORY; for( DWORD i = 0; i < dwNotifyCount; i++ ) { aPosNotify[i].dwOffset = (dwNotifySize * i) + dwNotifySize - 1; aPosNotify[i].hEventNotify = hNotifyEvent; } // Tell DirectSound when to notify us. The notification will come in the from // of signaled events that are handled in WinMain() hr = pDSNotify->SetNotificationPositions( dwNotifyCount, aPosNotify ); assert(hr==S_OK); SAFE_RELEASE( pDSNotify ); SAFE_DELETE_ARRAY( aPosNotify ); // Create the sound g_DivXPlayer.m_StreamingSound.Init( pDSBuffer, dwDSBufferSize, &m_WaveFile, dwNotifySize ); g_DivXPlayer.m_StreamingSound.m_SoundEnabled=1; return S_OK; } //----------------------------------------------------------------------------- // Name: CSound::FillBufferWithSound() // Desc: Fills a DirectSound buffer with a sound file //----------------------------------------------------------------------------- HRESULT CStreamingSound::FillBufferWithSound( LPDIRECTSOUNDBUFFER pDSB, BOOL bRepeatWavIfBufferLarger ) { HRESULT hr; VOID* pDSLockedBuffer = NULL; // Pointer to locked buffer memory DWORD dwDSLockedBufferSize = 0; // Size of the locked DirectSound buffer DWORD dwWavDataRead = 0; // Amount of data read from the wav file if( pDSB == NULL ) return CO_E_NOTINITIALIZED; // Make sure we have focus, and we didn't just switch in from // an app which had a DirectSound device // hr = RestoreBuffer( pDSB, NULL ); //assert(hr==S_OK); hr = RestoreBuffer( pDSB, NULL ); // Lock the buffer down hr = pDSB->Lock( 0, m_dwDSBufferSize,&pDSLockedBuffer, &dwDSLockedBufferSize, NULL, NULL, 0L ); assert(hr==S_OK); assert(dwDSLockedBufferSize==0x00081330); // Reset the wave file to the beginning //m_pWaveFile->ResetFile(); //11111111111111111 int retVal; uint32 a0=DIVX_OK; //The function was successful. uint32 a1=DIVX_FAIL;//The function failed. uint32 a2=INVALID_HANDLE; //Retuned when handle value is invalid. int BytesReturned; retVal = DivxNextAudioChunk(g_DivXPlayer.divxFile,&BytesReturned); assert(!retVal); // assert (BytesReturned==MAXSBUF); g_DivXPlayer.m_AudioCounter=0; uint8* p=g_DivXPlayer.m_pAudioBuffer; uint8* sbuf=(uint8*)pDSLockedBuffer; uint32 t=0; for (uint32 x=g_DivXPlayer.m_AudioCounter; x<(g_DivXPlayer.m_AudioCounter+dwDSLockedBufferSize); x++) { sbuf[t]=p[x]; t++; } g_DivXPlayer.m_AudioCounter+=dwDSLockedBufferSize; dwWavDataRead=dwDSLockedBufferSize; if( dwWavDataRead == 0 ) { // Wav is blank, so just fill with silence FillMemory( (BYTE*) pDSLockedBuffer,dwDSLockedBufferSize, (BYTE)(g_DivXPlayer.m_SoundManager.m_WaveFile.m_wfx.wBitsPerSample == 8 ? 128 : 0 ) ); } else if( dwWavDataRead < dwDSLockedBufferSize ) { // If the wav file was smaller than the DirectSound buffer, // we need to fill the remainder of the buffer with data if( bRepeatWavIfBufferLarger ) { // Reset the file and fill the buffer with wav data DWORD dwReadSoFar = dwWavDataRead; // From previous call above. while( dwReadSoFar < dwDSLockedBufferSize ) { assert(0); // This will keep reading in until the buffer is full for very short files //hr = m_pWaveFile->ResetFile(); //assert(hr==S_OK); // hr = m_pWaveFile->Read( (BYTE*)pDSLockedBuffer + dwReadSoFar, dwDSLockedBufferSize - dwReadSoFar,&dwWavDataRead ); // assert(hr==S_OK); dwReadSoFar += dwWavDataRead; } } else { // Don't repeat the wav file, just fill in silence FillMemory( (BYTE*) pDSLockedBuffer + dwWavDataRead, dwDSLockedBufferSize - dwWavDataRead, (BYTE)(g_DivXPlayer.m_SoundManager.m_WaveFile.m_wfx.wBitsPerSample == 8 ? 128 : 0 ) ); } } // Unlock the buffer, we don't need it anymore. pDSB->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0 ); return S_OK; } //----------------------------------------------------------------------------- // Name: CSound::RestoreBuffer() // Desc: Restores the lost buffer. *pbWasRestored returns TRUE if the buffer was // restored. It can also NULL if the information is not needed. //----------------------------------------------------------------------------- HRESULT CStreamingSound::RestoreBuffer( LPDIRECTSOUNDBUFFER pDSB, BOOL* pbWasRestored ) { HRESULT hr; if( pDSB == NULL ) return CO_E_NOTINITIALIZED; if( pbWasRestored ) *pbWasRestored = FALSE; DWORD dwStatus; hr = pDSB->GetStatus( &dwStatus ); assert(hr==S_OK); if( dwStatus & DSBSTATUS_BUFFERLOST ) { // Since the app could have just been activated, then // DirectSound may not be giving us control yet, so // the restoring the buffer may fail. // If it does, sleep until DirectSound gives us control. do { hr = pDSB->Restore(); #if !defined(LINUX) && !defined(NOT_USE_DIVX_SDK) if( hr == DSERR_BUFFERLOST ) Sleep( 10 ); #endif } while( ( hr = pDSB->Restore() ) == DSERR_BUFFERLOST ); if( pbWasRestored != NULL ) *pbWasRestored = TRUE; return S_OK; } else { return S_FALSE; } } //----------------------------------------------------------------------------- // Name: CSound::GetFreeBuffer() // Desc: Finding the first buffer that is not playing and return a pointer to // it, or if all are playing return a pointer to a randomly selected buffer. //----------------------------------------------------------------------------- LPDIRECTSOUNDBUFFER CStreamingSound::GetFreeBuffer() { if( m_apDSBuffer == NULL ) return FALSE; for( DWORD i=0; iGetStatus( &dwStatus ); if ( ( dwStatus & DSBSTATUS_PLAYING ) == 0 ) break; } } if( i != m_dwNumBuffers ) return m_apDSBuffer[ i ]; else return m_apDSBuffer[ rand() % m_dwNumBuffers ]; } //----------------------------------------------------------------------------- // Name: CSound::GetBuffer() // Desc: //----------------------------------------------------------------------------- LPDIRECTSOUNDBUFFER CStreamingSound::GetBuffer( DWORD dwIndex ) { if( m_apDSBuffer == NULL ) return NULL; if( dwIndex >= m_dwNumBuffers ) return NULL; return m_apDSBuffer[dwIndex]; } //----------------------------------------------------------------------------- // Name: CSound::Play() // Desc: Plays the sound using voice management flags. Pass in DSBPLAY_LOOPING // in the dwFlags to loop the sound //----------------------------------------------------------------------------- HRESULT CStreamingSound::Play( DWORD dwPriority, DWORD dwFlags, LONG lVolume, LONG lFrequency, LONG lPan ) { HRESULT hr; BOOL bRestored; if( m_apDSBuffer == NULL ) return CO_E_NOTINITIALIZED; LPDIRECTSOUNDBUFFER pDSB = GetFreeBuffer(); assert(pDSB); // Restore the buffer if it was lost hr = RestoreBuffer( pDSB, &bRestored ); // assert(hr==S_OK); if( bRestored ) { // The buffer was restored, so we need to fill it with new data hr = FillBufferWithSound( pDSB, FALSE ); assert(hr==S_OK); } if( m_dwCreationFlags & DSBCAPS_CTRLVOLUME ) { pDSB->SetVolume( lVolume ); } if( lFrequency != -1 && (m_dwCreationFlags & DSBCAPS_CTRLFREQUENCY) ) { pDSB->SetFrequency( lFrequency ); } if( m_dwCreationFlags & DSBCAPS_CTRLPAN ) { pDSB->SetPan( lPan ); } return pDSB->Play( 0, dwPriority, dwFlags ); } //----------------------------------------------------------------------------- // Name: CSound::Stop() // Desc: Stops the sound from playing //----------------------------------------------------------------------------- HRESULT CStreamingSound::Stop() { if( m_apDSBuffer == NULL ) return CO_E_NOTINITIALIZED; HRESULT hr = 0; for( DWORD i=0; iStop(); return hr; } //----------------------------------------------------------------------------- // Name: CStreamingSound::HandleWaveStreamNotification() // Desc: Handle the notification that tells us to put more wav data in the // circular buffer //----------------------------------------------------------------------------- HRESULT CStreamingSound::HandleWaveStreamNotification( BOOL bLoopedPlay ) { HRESULT hr; DWORD dwCurrentPlayPos; DWORD dwPlayDelta; DWORD dwBytesWrittenToBuffer; VOID* pDSLockedBuffer = NULL; VOID* pDSLockedBuffer2 = NULL; DWORD dwDSLockedBufferSize; DWORD dwDSLockedBufferSize2; if( m_apDSBuffer == NULL ) return CO_E_NOTINITIALIZED; // Restore the buffer if it was lost BOOL bRestored; hr = RestoreBuffer( m_apDSBuffer[0], &bRestored ); // assert(hr==S_OK); if( bRestored ) { // The buffer was restored, so we need to fill it with new data hr = FillBufferWithSound( m_apDSBuffer[0], FALSE ); assert(hr==S_OK); return S_OK; } // Lock the DirectSound buffer hr = m_apDSBuffer[0]->Lock( m_dwNextWriteOffset, m_dwNotifySize, &pDSLockedBuffer, &dwDSLockedBufferSize, &pDSLockedBuffer2, &dwDSLockedBufferSize2, 0L ); assert(hr==S_OK); assert(dwDSLockedBufferSize==0x000204cc); // m_dwDSBufferSize and m_dwNextWriteOffset are both multiples of m_dwNotifySize, // it should the second buffer, so it should never be valid if( pDSLockedBuffer2 != NULL ) return E_UNEXPECTED; if( !m_bFillNextNotificationWithSilence ) { uint32 BufferEnd = (g_DivXPlayer.m_AudioCounter&(MAXSBUF-1))+dwDSLockedBufferSize; if (BufferEnd>MAXSBUF){ uint32 ToBig = BufferEnd-MAXSBUF; uint32 BytesLeft = dwDSLockedBufferSize-ToBig; uint8* p=g_DivXPlayer.m_pAudioBuffer; uint8* sbuf=(uint8*)pDSLockedBuffer; uint32 t=0; for (uint32 x=(g_DivXPlayer.m_AudioCounter&(MAXSBUF-1)); x<((g_DivXPlayer.m_AudioCounter&(MAXSBUF-1))+BytesLeft); x++) { sbuf[t]=p[x]; t++; } g_DivXPlayer.m_AudioCounter+=BytesLeft; int BytesReturned; DivxNextAudioChunk(g_DivXPlayer.divxFile,&BytesReturned); for (uint32 x=(g_DivXPlayer.m_AudioCounter&(MAXSBUF-1)); x<((g_DivXPlayer.m_AudioCounter&(MAXSBUF-1))+ToBig); x++) { sbuf[t]=p[x]; t++; } g_DivXPlayer.m_AudioCounter+=ToBig; dwBytesWrittenToBuffer=dwDSLockedBufferSize; } else { //streaming hr = 0; uint8* p=g_DivXPlayer.m_pAudioBuffer; uint8* sbuf=(uint8*)pDSLockedBuffer; uint32 t=0; for (uint32 x=(g_DivXPlayer.m_AudioCounter&(MAXSBUF-1)); x<((g_DivXPlayer.m_AudioCounter&(MAXSBUF-1))+dwDSLockedBufferSize); x++) { sbuf[t]=p[x]; t++; } g_DivXPlayer.m_AudioCounter+=dwDSLockedBufferSize; dwBytesWrittenToBuffer=dwDSLockedBufferSize; } //if( FAILED(hr) ) // return DXTRACE_ERR( TEXT("Read"), hr ); } else { // Fill the DirectSound buffer with silence FillMemory( pDSLockedBuffer, dwDSLockedBufferSize, (BYTE)( g_DivXPlayer.m_SoundManager.m_WaveFile.m_wfx.wBitsPerSample == 8 ? 128 : 0 ) ); dwBytesWrittenToBuffer = dwDSLockedBufferSize; } // If the number of bytes written is less than the // amount we requested, we have a short file. if( dwBytesWrittenToBuffer < dwDSLockedBufferSize ) { if( !bLoopedPlay ) { // Fill in silence for the rest of the buffer. FillMemory( (BYTE*) pDSLockedBuffer + dwBytesWrittenToBuffer, dwDSLockedBufferSize - dwBytesWrittenToBuffer, (BYTE)(g_DivXPlayer.m_SoundManager.m_WaveFile.m_wfx.wBitsPerSample == 8 ? 128 : 0 ) ); // Any future notifications should just fill the buffer with silence m_bFillNextNotificationWithSilence = TRUE; } else { // We are looping, so reset the file and fill the buffer with wav data DWORD dwReadSoFar = dwBytesWrittenToBuffer; // From previous call above. while( dwReadSoFar < dwDSLockedBufferSize ) { // This will keep reading in until the buffer is full (for very short files). assert(0); //hr = m_pWaveFile->ResetFile(); //if( FAILED(hr) ) // return DXTRACE_ERR( TEXT("ResetFile"), hr ); assert(0); dwReadSoFar += dwBytesWrittenToBuffer; } } } // Unlock the DirectSound buffer m_apDSBuffer[0]->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0 ); // Figure out how much data has been played so far. When we have played // past the end of the file, we will either need to start filling the // buffer with silence or starting reading from the beginning of the file, // depending if the user wants to loop the sound hr = m_apDSBuffer[0]->GetCurrentPosition( &dwCurrentPlayPos, NULL ); assert(hr==S_OK); // Check to see if the position counter looped if( dwCurrentPlayPos < m_dwLastPlayPos ) dwPlayDelta = ( m_dwDSBufferSize - m_dwLastPlayPos ) + dwCurrentPlayPos; else dwPlayDelta = dwCurrentPlayPos - m_dwLastPlayPos; m_dwPlayProgress += dwPlayDelta; m_dwLastPlayPos = dwCurrentPlayPos; // If we are now filling the buffer with silence, then we have found the end so // check to see if the entire sound has played, if it has then stop the buffer. if( m_bFillNextNotificationWithSilence ) { // We don't want to cut off the sound before it's done playing. if( m_dwPlayProgress >= g_DivXPlayer.m_SoundManager.m_WaveFile.GetSize() ) { m_apDSBuffer[0]->Stop(); } } // Update where the buffer will lock (for next time) m_dwNextWriteOffset += dwDSLockedBufferSize; m_dwNextWriteOffset %= m_dwDSBufferSize; // Circular buffer return S_OK; } //----------------------------------------------------------------------------- // Name: CStreamingSound::Reset() // Desc: Resets the sound so it will begin playing at the beginning //----------------------------------------------------------------------------- HRESULT CStreamingSound::Reset() { HRESULT hr; if( m_apDSBuffer[0] == NULL ) return CO_E_NOTINITIALIZED; m_dwLastPlayPos = 0; m_dwPlayProgress = 0; m_dwNextWriteOffset = 0; m_bFillNextNotificationWithSilence = FALSE; // Restore the buffer if it was lost BOOL bRestored; hr = RestoreBuffer( m_apDSBuffer[0], &bRestored ); // assert(hr==S_OK); if( bRestored ) { // The buffer was restored, so we need to fill it with new data hr = FillBufferWithSound( m_apDSBuffer[0], FALSE ); assert(hr==S_OK); } return m_apDSBuffer[0]->SetCurrentPosition( 0L ); } //----------------------------------------------------------------------------- // Name: NotificationProc() // Desc: Handles dsound notifcation events //----------------------------------------------------------------------------- DWORD WINAPI NotificationProc( LPVOID lpParameter ) { HRESULT hr; HWND hDlg = (HWND) lpParameter; MSG msg; DWORD dwResult; BOOL bDone = FALSE; BOOL bLooped; while( !bDone ) { dwResult = MsgWaitForMultipleObjects( 1, &g_DivXPlayer.m_hNotificationEvent,FALSE, INFINITE, QS_ALLEVENTS ); switch( dwResult ) { case WAIT_OBJECT_0 + 0: // g_hNotificationEvent is signaled // This means that DirectSound just finished playing // a piece of the buffer, so we need to fill the circular // buffer with new sound from the wav file bLooped = 0;//( IsDlgButtonChecked( hDlg, IDC_LOOP_CHECK ) == BST_CHECKED ); hr = g_DivXPlayer.m_StreamingSound.HandleWaveStreamNotification( bLooped ); assert(hr==S_OK); break; case WAIT_OBJECT_0 + 1: // Messages are available while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) { if( msg.message == WM_QUIT ) bDone = TRUE; } break; } } return 0; } #endif