JD2022-TU1/main/extern/Camcam/LIBS/Input/SOUND.cpp

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;
}