HRESULT AddMP3Filters(IGraphBuilder* pgb, CCString& FileName, IBaseFilter** pSource, IBaseFilter** pSplitter, IBaseFilter** pMP3, IBaseFilter** pOutput) { CCString s; HRESULT hr = E_FAIL; // Set the source! s = L"Source"; if(SUCCEEDED(hr = pgb->AddSourceFilter(FileName.bstr(), s.bstr(), pSource))) { // Create the other filters and add them to the graph. if(SUCCEEDED(CreateFilterAndAdd(pgb, CLSID_MPEGStreamSplitter, L"MPEG Stream Splitter", pSplitter))) { if(SUCCEEDED(CreateFilterAndAdd(pgb, CLSID_MP3Decoder, L"MP3 decoder", pMP3))) { if(SUCCEEDED(CreateFilterAndAdd(pgb, CLSID_DefaultDSoundDevice, L"Output", pOutput))) { hr = S_OK; } } } } if(FAILED(hr)) { // Release all the stuff. SAFE_REMOVE_FILTER(pgb, *pSource); SAFE_REMOVE_FILTER(pgb, *pSplitter); SAFE_REMOVE_FILTER(pgb, *pMP3); SAFE_REMOVE_FILTER(pgb, *pOutput); } return hr; }
HRESULT CreateFilterAndAdd(IGraphBuilder* pgb, const GUID& clsid, PCWSTR wszName, IBaseFilter** ppOut) { CCString Name = wszName; HRESULT hr = 0; *ppOut = 0; if(FAILED(hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)ppOut))) { return E_FAIL; } if(FAILED(pgb->AddFilter(*ppOut, Name.bstr()))) { (*ppOut)->Release(); *ppOut = 0; return E_FAIL; } return S_OK; }
HRESULT AudioPlayer::Open(CCString FileName, CCLog* pLog) { HRESULT hr; this->Close(); if(FAILED(hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IMediaControl, (PVOID*)&this->pControl))) { pLog->AddEntry(L"Error working with DShow objects."); pLog->AddEntry(hr, L"CoCreateInstance"); return E_FAIL; } // Now get IMediaSeeking interface - this is REQUIRED. if(FAILED(hr = this->pControl->QueryInterface(IID_IMediaSeeking, (PVOID*)&this->pSeeking))) { pLog->AddEntry(L"Error working with DShow objects."); pLog->AddEntry(hr, L"QI for IID_IMediaSeeking"); SAFE_RELEASE(this->pControl); return E_FAIL; } // Now get the IBasicAudio interface - this is PREFERRED. if(FAILED(hr = this->pControl->QueryInterface(IID_IBasicAudio, (PVOID*)&this->pAudio))) { pLog->AddEntry(L"DShow player does not support basic audio controls such as volume or balance."); } if(FAILED(this->AttemptMP3Graph(FileName, pLog))) { // Render the file now that we know we're good to go. if(FAILED(hr = this->pControl->RenderFile(FileName.bstr()))) { pLog->AddEntry(L"Error rendering the file. The file may be corrupt."); pLog->AddEntry(hr, L"IMediaControl::RenderFile"); SAFE_RELEASE(this->pControl); SAFE_RELEASE(this->pSeeking); SAFE_RELEASE(this->pAudio); return E_FAIL; } } // Make sure we can use TIME_FORMAT_MEDIA_TIME for seeking... otherwise // We won't know how to seek. if(FAILED(hr = this->pSeeking->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME))) { pLog->AddEntry(L"The audio rendering software does not support seeking using time units. This is unrecoverable."); pLog->AddEntry(hr, L"IMediaSeeking::SetTimeFormat"); SAFE_RELEASE(this->pControl); SAFE_RELEASE(this->pSeeking); SAFE_RELEASE(this->pAudio); return E_FAIL; } // Now set up our notifications and begin our notification thread to handle them. this->hExitEvent = CreateEvent(NULL, FALSE, FALSE, NULL); this->hNotificationThread = (HANDLE)_beginthread(AudioPlayer::NotificationProc, 0, this); //this->hNotificationThread = CreateThread(NULL, 0, AudioPlayer::NotificationProc, // this, 0, &dwId); /* Make sure that our old properties propogate to this file. */ this->SetVolume(this->dwVolume, pLog); if(this->bPlaying == TRUE) this->Play(pLog); // We made it this far! Hooray! return S_OK; }