530 lines
12 KiB
C++
530 lines
12 KiB
C++
#include <windows.h>
|
|
#include <atlcomcli.h>
|
|
#include <dshow.h>
|
|
#include <qedit.h>
|
|
|
|
#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<ISampleGrabberCB*> ( 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<ICaptureGraphBuilder2> graphBuilder;
|
|
|
|
CComPtr<IFilterGraph2> filterGraph;
|
|
CComPtr<ISampleGrabber> sampleGrabber;
|
|
CComPtr<IBaseFilter> sourceFilter;
|
|
CComPtr<IBaseFilter> waveRenderer;
|
|
CComPtr<IBaseFilter> grabberFilter;
|
|
CComPtr<IBaseFilter> nullRenderer;
|
|
CComPtr<IBasicAudio> audioConfig;
|
|
|
|
CComPtr<IMediaSeeking> mediaSeeking;
|
|
CComPtr<IMediaPosition> mediaPosition;
|
|
CComPtr<IMediaControl> mediaControl;
|
|
CComPtr<IMediaEvent> 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<void**>(&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<IPin> myPin;
|
|
CComPtr<IBaseFilter> 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<IEnumPins> 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<IPin> inputPin;
|
|
CComPtr<IPin> 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;
|
|
}
|