#include #include #include #include #include "TRACK.h" #include "MEDIA.h" #include "SCENE.h" #include "CODEC.h" #include "process.h" typedef struct SndFadeType_ { int started; // -1: No Fade, 0: Fade not begin, 1: Fade begins u32 type; // 1: Fade In, 2: Fade Out DWORD BeginTime; int Duration; } SndFadeType; unsigned __stdcall VolumeSoundThread(void *params); HRESULT AddToGraphEdit(IUnknown *pUnkGraph, DWORD *pdwRegister); void RemoveFromGraphEdit(DWORD pdwRegister); class CSampleGrabberCBSound : public ISampleGrabberCB { public: IMediaControl *mediaControl; u32 Locked; u32 FrameNum; STDMETHODIMP_(ULONG) AddRef() { return 2; } STDMETHODIMP_(ULONG) Release() { return 1; } STDMETHODIMP QueryInterface(REFIID riid, void ** ppv) { if( riid == IID_ISampleGrabberCB || riid == IID_IUnknown ) { *ppv = (void *) static_cast ( this ); return NOERROR; } return E_NOINTERFACE; } STDMETHODIMP SampleCB( double SampleTime, IMediaSample * pSample ) { return 0; } STDMETHODIMP BufferCB( double dblSampleTime, BYTE * pBuffer, long lBufferSize ) { // add effects here ... // ex: memset(pBuffer, 127, lBufferSize); FrameNum++; return 0; } }; class SoundWrapper { public : CComPtr graphBuilder; CComPtr filterGraph; CComPtr sampleGrabber; CComPtr sourceFilter; CComPtr waveRenderer; CComPtr grabberFilter; CComPtr nullRenderer; CComPtr audioConfig; CComPtr mediaSeeking; CComPtr mediaPosition; CComPtr mediaControl; CComPtr mediaEvent; CSampleGrabberCBSound CB; bool soundInitialized; WAVEFORMATEX soundFormat; DWORD grabberNum; SoundWrapper() { // This must be callled before // interfaces can be accessed CoInitialize(NULL); soundInitialized = false; grabberNum = 0; } ~SoundWrapper() { // Technically, uninit ever init CoUninitialize(); } void FindPin(IBaseFilter* baseFilter, PIN_DIRECTION direction, int pinNumber, IPin** destPin); bool ConnectPins(IBaseFilter* outputFilter, unsigned int outputNum, IBaseFilter* inputFilter, unsigned int inputNum); bool loadSoundFile(char *MN, bool grabMode); long *grabSound(); void uninitSound(); }; class SOUND_Grabber:public INPUT_IO { WORLD * pScn; HRESULT hrinit; public: DWORD sTimer; double lastTime; SoundWrapper *sw; SndFadeType sndFadeType; float volume; float rate; int INIT (WORLD *pScene); int FRAME (); int END (); IOTYPE GetType() {return IOtype_SOUND;}; void SetData(int dataIdx, void *data); void * GetData(int dataIdx); }; bool SoundWrapper::loadSoundFile(char *TheFile, bool grabMode) { HRESULT result; if (soundInitialized) { uninitSound(); } // Create the main object that runs the graph graphBuilder.CoCreateInstance(CLSID_CaptureGraphBuilder2); filterGraph.CoCreateInstance(CLSID_FilterGraph); CB.Locked = 0; graphBuilder->SetFiltergraph(filterGraph); // This takes the absolute filename path and // Loads the appropriate file reader and splitter // Depending in the file type. WCHAR filename[ 1024 ]; MultiByteToWideChar(CP_ACP,0,TheFile,-1,filename,1024); filterGraph->AddSourceFilter(filename, L"Sound Source", &sourceFilter); grabberFilter.CoCreateInstance(CLSID_SampleGrabber); grabberFilter->QueryInterface(IID_ISampleGrabber, reinterpret_cast(&sampleGrabber)); // We have to set the 24-bit RGB desire here // So that the proper conversion filters // Are added automatically. AM_MEDIA_TYPE desiredType; memset(&desiredType, 0, sizeof(desiredType)); desiredType.majortype = MEDIATYPE_Audio; desiredType.subtype = MEDIASUBTYPE_PCM; desiredType.formattype = FORMAT_WaveFormatEx; //desiredType.bFixedSizeSamples = true; sampleGrabber->SetMediaType(&desiredType); sampleGrabber->SetBufferSamples(TRUE); filterGraph->AddFilter(grabberFilter, L"Sample Grabber"); // direct render CComPtr myPin; CComPtr renderFilter; FindPin(sourceFilter, PINDIR_OUTPUT, 0, &myPin); result = filterGraph->Render(myPin); myPin.Release(); AddToGraphEdit(filterGraph, &grabberNum); if (result != S_OK) { uninitSound(); return false; } filterGraph->QueryInterface(IID_IMediaEvent, (void **)&mediaEvent); AM_MEDIA_TYPE connectedType; if (grabMode) { if (SUCCEEDED(sampleGrabber->GetConnectedMediaType(&connectedType))) { if (connectedType.formattype == FORMAT_WaveFormatEx) { soundFormat = *((WAVEFORMATEX *)connectedType.pbFormat); } CoTaskMemFree(connectedType.pbFormat); sampleGrabber->SetCallback(&CB,1); } else { uninitSound(); return false; } } filterGraph->QueryInterface(IID_IBasicAudio, (void **)&audioConfig); filterGraph->QueryInterface(IID_IMediaSeeking, (void **)&mediaSeeking); filterGraph->QueryInterface(IID_IMediaPosition, (void **)&mediaPosition); GUID format; const GUID timeFormat = TIME_FORMAT_MEDIA_TIME ; mediaSeeking->GetTimeFormat(&format); if (S_OK == mediaSeeking->IsFormatSupported(&timeFormat)) { mediaSeeking->SetTimeFormat(&timeFormat); } filterGraph->QueryInterface(IID_IMediaControl, (void **)&mediaControl); CB.mediaControl = mediaControl; CB.FrameNum = 0; if (SUCCEEDED(mediaControl->Run())) { soundInitialized = true; return true; } else { uninitSound(); return false; } grabSound(); } long *SoundWrapper::grabSound() { // to Do return NULL; } void SoundWrapper::FindPin(IBaseFilter* baseFilter, PIN_DIRECTION direction, int pinNumber, IPin** destPin) { CComPtr enumPins; *destPin = NULL; if (SUCCEEDED(baseFilter->EnumPins(&enumPins))) { ULONG numFound; IPin* tmpPin; while (SUCCEEDED(enumPins->Next(1, &tmpPin, &numFound)) && numFound > 0) { PIN_DIRECTION pinDirection; tmpPin->QueryDirection(&pinDirection); if (pinDirection == direction) { if (pinNumber == 0) { // Return the pin's interface *destPin = tmpPin; break; } pinNumber--; } tmpPin->Release(); } } } bool SoundWrapper::ConnectPins(IBaseFilter* outputFilter, unsigned int outputNum, IBaseFilter* inputFilter, unsigned int inputNum) { CComPtr inputPin; CComPtr outputPin; if (!outputFilter || !inputFilter) { return false; } FindPin(outputFilter, PINDIR_OUTPUT, outputNum, &outputPin); FindPin(inputFilter, PINDIR_INPUT, inputNum, &inputPin); if (inputPin && outputPin) { return SUCCEEDED(filterGraph->Connect(outputPin, inputPin)); } else { return false; } } void SoundWrapper::uninitSound() { if (soundInitialized) { if (mediaControl) mediaControl->Stop(); if (grabberNum) RemoveFromGraphEdit(grabberNum); grabberNum = 0; audioConfig.Release(); mediaControl.Release(); mediaSeeking.Release(); mediaPosition.Release(); grabberFilter.Release(); sourceFilter.Release(); nullRenderer.Release(); sampleGrabber.Release(); filterGraph.Release(); graphBuilder.Release(); CB.mediaControl = NULL; } soundInitialized = false; } int SOUND_Grabber::INIT(WORLD *pScene) { lastTime = dCurrentTime = 0.0f; dTotalTime = 0.0f; ulCurrentFrame = 0; ulMediaParams = 0; lTimeState = 0; sndFadeType.started = -1; volume = 1.0f; sw = new SoundWrapper(); if (!sw->loadSoundFile((char*)MediaName, false)) { delete sw; sw = NULL; } else { LONGLONG time; sw->mediaSeeking->GetDuration(&time); dTotalTime = (double)time / 10000000; dAvgFramePerSecond = 30.0; sw->mediaControl->Pause(); } pScn = pScene; return sw != NULL; } int SOUND_Grabber::FRAME() { float prevTime; if (sw) { if (dCurrentTime != lastTime) { sw->mediaPosition->put_CurrentPosition(dCurrentTime); } if (lTimeState) sw->grabSound(); if (sndFadeType.started == -1) { switch (lTimeState) { case 0: sw->mediaControl->Pause(); break; case 255: sw->mediaPosition->put_CurrentPosition(0); sw->mediaControl->Stop(); break; case 1: sw->mediaControl->Run(); break; } } if (lTimeState != 1) lTimeState = 0; if (sndFadeType.started == 0) { sw->mediaControl->Run(); u32 threadID; _beginthreadex(NULL, 256, &VolumeSoundThread, (void *)this, 0, &threadID); } prevTime = dCurrentTime; sw->mediaPosition->get_CurrentPosition(&dCurrentTime); BOOL bEnd = false; long lEventCode, lParam1, lParam2; while (E_ABORT != sw->mediaEvent->GetEvent(&lEventCode, &lParam1, &lParam2, 0)) { if (lEventCode == EC_COMPLETE) bEnd = true; sw->mediaEvent->FreeEventParams(lEventCode, lParam1, lParam2); } if (ulMediaParams & 2) sw->audioConfig->put_Volume(-10000); else sw->audioConfig->put_Volume(-10000*(1-volume)); if (bEnd) { if (ulMediaParams & 1) { dCurrentTime = 0.0f; sw->mediaPosition->put_CurrentPosition(dCurrentTime); sw->mediaControl->Stop(); if (lTimeState == 1) sw->mediaControl->Run(); } else { lTimeState = 0; } } ulCurrentFrame = TIME_TO_FRAME(dCurrentTime, dAvgFramePerSecond); lastTime = dCurrentTime; } return 0; } void SOUND_Grabber::SetData(int dataIdx, void *data) { static float log10over20 = log(10.0f)/log(20.0f); switch (dataIdx) { case 0: sndFadeType.type = *(int *)data; sndFadeType.BeginTime = timeGetTime(); sndFadeType.started = 0; break; case 1: sndFadeType.Duration = *(int *)data; sndFadeType.BeginTime = timeGetTime(); sndFadeType.started = 0; break; case 3: volume = *(float *)data; volume = log(volume+1.0f)/log(2.0f); sw->audioConfig->put_Volume(-10000*(1-volume)); sndFadeType.started = -1; break; case 4: rate = *(float *)data; sw->mediaSeeking->SetRate(rate); break; } } void *SOUND_Grabber::GetData(int dataIdx) { switch (dataIdx) { case 0: return &sndFadeType.type; case 1: return &sndFadeType.Duration; case 3: return &volume; case 4: return &rate; case 5: sw->mediaPosition->get_CurrentPosition(&dCurrentTime); return &dCurrentTime; } return NULL; } int SOUND_Grabber::END() { sw->uninitSound(); delete sw; return 0; } INPUT_IO *SOUND_CREATE(WORLD *pScene,char *Filename) { INPUT_IO *Ret; if (!IsExist(Filename)) { Ret = ERROR_CREATE("Sound file not\nexist"); return Ret; } Ret = (INPUT_IO *)new(SOUND_Grabber); strcpy((char*)Ret->MediaName,Filename); if (!Ret->INIT(pScene)) { delete Ret; return NULL; } return Ret; } unsigned __stdcall VolumeSoundThread(void *params) { SOUND_Grabber *sndPtr = (SOUND_Grabber *)params; int newVolume; double ratio; DWORD curTime; sndPtr->sndFadeType.started = 1; while ((curTime = timeGetTime()) < sndPtr->sndFadeType.BeginTime + sndPtr->sndFadeType.Duration) { switch (sndPtr->sndFadeType.type) { case 1: ratio = ((double)curTime - sndPtr->sndFadeType.BeginTime)/sndPtr->sndFadeType.Duration; break; case 2: ratio = ((double)sndPtr->sndFadeType.Duration - curTime + sndPtr->sndFadeType.BeginTime)/sndPtr->sndFadeType.Duration; break; default: return 0; } ratio = sqrt(ratio); newVolume = -10000*(1-ratio); sndPtr->sw->audioConfig->put_Volume(newVolume); Sleep(5); } sndPtr->sndFadeType.started = -1; return 0; }