581 lines
13 KiB
C++
581 lines
13 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"
|
|
|
|
#include <streams.h>
|
|
#include <initguid.h>
|
|
|
|
|
|
#include "CDct.h"
|
|
|
|
// {66086FD4-E1B1-46e0-BB44-A10203A28EED}
|
|
DEFINE_GUID(CLSID_CamCamAudioFilter,
|
|
0x66086fd4, 0xe1b1, 0x46e0, 0xbb, 0x44, 0xa1, 0x2, 0x3, 0xa2, 0x8e, 0xed);
|
|
|
|
class CAudioFilter : public CTransInPlaceFilter
|
|
{
|
|
WAVEFORMATEX waveFormat;
|
|
CDct waveDCT;
|
|
float waveFloatBuffer[SND_DCT_SIZE_MATRIX_COEFS];
|
|
|
|
private:
|
|
// Constructor is private because you have to use CreateInstance
|
|
CAudioFilter(IUnknown *pUnk, HRESULT *phr);
|
|
~CAudioFilter();
|
|
|
|
public:
|
|
static CUnknown * WINAPI CreateInstance(IUnknown *pUnk, HRESULT *phr);
|
|
|
|
HRESULT CheckInputType(const CMediaType *mtIn);
|
|
HRESULT GetMediaType(int iPosition, CMediaType *pMediaType);
|
|
HRESULT Transform(IMediaSample *pSample);
|
|
};
|
|
|
|
|
|
CAudioFilter::CAudioFilter(IUnknown *pUnk, HRESULT *phr) :
|
|
CTransInPlaceFilter(NAME("CamCam Audio Filter"), pUnk, CLSID_CamCamAudioFilter, phr)
|
|
{
|
|
memset(&waveFormat, 0, sizeof(WAVEFORMATEX));
|
|
waveDCT.Initialisation();
|
|
|
|
// add effects ?
|
|
//for (int i=1; i<SND_DCT_SIZE_MATRIX_COEFS; i++)
|
|
//{
|
|
// waveDCT.EffectMatrixXYSet(i>>1, i, 0.5);
|
|
//}
|
|
waveDCT.EffectAddStretch(1.8);
|
|
//for (int i=1; i<SND_DCT_SIZE_MATRIX_COEFS; i++)
|
|
//{
|
|
// waveDCT.EffectMatrixXYSet(i, i, 1.0);
|
|
//}
|
|
waveDCT.EffectEnd();
|
|
}
|
|
|
|
CAudioFilter::~CAudioFilter()
|
|
{
|
|
waveDCT.Liberations();
|
|
}
|
|
|
|
HRESULT CAudioFilter::CheckInputType(const CMediaType *mtIn)
|
|
{
|
|
if ((mtIn->majortype != MEDIATYPE_Audio) ||
|
|
(mtIn->subtype != MEDIASUBTYPE_PCM) ||
|
|
(mtIn->formattype != FORMAT_WaveFormatEx) ||
|
|
(mtIn->cbFormat < sizeof(WAVEFORMATEX)))
|
|
return VFW_E_TYPE_NOT_ACCEPTED;
|
|
|
|
WAVEFORMATEX *pWih = reinterpret_cast<WAVEFORMATEX *>(mtIn->pbFormat);
|
|
//if (pWih->wBitsPerSample != 8)
|
|
// return VFW_E_TYPE_NOT_ACCEPTED;
|
|
if (pWih->nChannels != 1)
|
|
return VFW_E_TYPE_NOT_ACCEPTED;
|
|
memcpy(&waveFormat, pWih, sizeof(WAVEFORMATEX));
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CAudioFilter::GetMediaType( int iPosition, CMediaType *pMediaType)
|
|
{
|
|
ASSERT(m_pInput->IsConnected());
|
|
if (iPosition < 0)
|
|
return E_INVALIDARG;
|
|
|
|
if (iPosition == 0)
|
|
{
|
|
HRESULT hr = m_pInput->ConnectionMediaType(pMediaType);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
pMediaType->SetTemporalCompression(false);
|
|
ASSERT(pMediaType->formattype == FORMAT_WaveFormatEx);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT CAudioFilter::Transform(IMediaSample *pSample)
|
|
{
|
|
BYTE *pBufferInOut, *pBufferInOutInit, *pBufferInOutBegin;
|
|
short *pShortBufferInOut, *pShortBufferInOutInit, *pShortBufferInOutBegin;
|
|
int curChannel = 0;
|
|
HRESULT hr = pSample->GetPointer((BYTE **)&pBufferInOutInit);
|
|
long size = pSample->GetSize();
|
|
float valMin, valMax, valCenter;
|
|
|
|
if (FAILED(hr))
|
|
return hr;
|
|
|
|
//return S_OK;
|
|
switch (waveFormat.wBitsPerSample)
|
|
{
|
|
case 4:
|
|
break;
|
|
case 8:
|
|
valMin = 0.0f;
|
|
valMax = 255.0f;
|
|
valCenter = 128.0f;
|
|
for (curChannel = 0; curChannel < waveFormat.nChannels; curChannel++)
|
|
{
|
|
pBufferInOut = pBufferInOutInit + curChannel;
|
|
for (int i=0; i<size; )
|
|
{
|
|
pBufferInOutBegin = pBufferInOut;
|
|
float *pWaveFloatBuffer = waveFloatBuffer;
|
|
int j;
|
|
|
|
for (j=0; j<SND_DCT_SIZE_MATRIX_COEFS && i < size;
|
|
j++, pWaveFloatBuffer++, i+=waveFormat.nChannels, pBufferInOut+=waveFormat.nChannels)
|
|
*pWaveFloatBuffer = (float)*pBufferInOut;
|
|
|
|
for (;j<SND_DCT_SIZE_MATRIX_COEFS;j++)
|
|
*pWaveFloatBuffer = valCenter;
|
|
|
|
double total1 = 0, total2 = 0;
|
|
for (int i=0; i<SND_DCT_SIZE_MATRIX_COEFS; i++)
|
|
{
|
|
total1 += waveFloatBuffer[i];
|
|
}
|
|
total1 /= SND_DCT_SIZE_MATRIX_COEFS;
|
|
|
|
//u32 uResult = waveDCT.ComputeDCT(waveFloatBuffer, SND_DCT_SIZE_MATRIX_COEFS);
|
|
waveDCT.AlterSample(waveFloatBuffer, SND_DCT_SIZE_MATRIX_COEFS, valCenter);
|
|
//waveDCT.ComputeInverseDCT(waveFloatBuffer, uResult);
|
|
|
|
for (int i=0; i<SND_DCT_SIZE_MATRIX_COEFS; i++)
|
|
{
|
|
total2 += waveFloatBuffer[i];
|
|
}
|
|
total2 /= SND_DCT_SIZE_MATRIX_COEFS;
|
|
|
|
pWaveFloatBuffer = waveFloatBuffer;
|
|
for (; pBufferInOutBegin<pBufferInOut;
|
|
pBufferInOutBegin+=waveFormat.nChannels, pWaveFloatBuffer++)
|
|
{
|
|
if (*pWaveFloatBuffer > valMax)
|
|
*pWaveFloatBuffer = valMax;
|
|
if (*pWaveFloatBuffer < valMin)
|
|
*pWaveFloatBuffer = valMin;
|
|
*pBufferInOutBegin = (BYTE)(*pWaveFloatBuffer + 0.5f);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 16:
|
|
//valMin = 0;
|
|
//valMax = 65535.0f;
|
|
//valCenter = 32767.0f;
|
|
valMin = -32767.0f;
|
|
valMax = 32767.0f;
|
|
valCenter = 0.0f;
|
|
size >>= 1;
|
|
pShortBufferInOutInit = (short *)pBufferInOutInit;
|
|
for (curChannel = 0; curChannel < waveFormat.nChannels; curChannel++)
|
|
{
|
|
pShortBufferInOut = pShortBufferInOutInit + curChannel;
|
|
for (int i=0; i<size; )
|
|
{
|
|
pShortBufferInOutBegin = pShortBufferInOut;
|
|
float *pWaveFloatBuffer = waveFloatBuffer;
|
|
int j;
|
|
|
|
for (j=0; j<SND_DCT_SIZE_MATRIX_COEFS && i < size;
|
|
j++, pWaveFloatBuffer++, i+=waveFormat.nChannels, pShortBufferInOut+=waveFormat.nChannels)
|
|
*pWaveFloatBuffer = (float)*pShortBufferInOut;
|
|
|
|
for (;j<SND_DCT_SIZE_MATRIX_COEFS;j++)
|
|
*pWaveFloatBuffer = valCenter;
|
|
|
|
double total1 = 0, total2 = 0;
|
|
for (int i=0; i<SND_DCT_SIZE_MATRIX_COEFS; i++)
|
|
{
|
|
total1 += waveFloatBuffer[i];
|
|
}
|
|
total1 /= SND_DCT_SIZE_MATRIX_COEFS;
|
|
|
|
//u32 uResult = waveDCT.ComputeDCT(waveFloatBuffer, SND_DCT_SIZE_MATRIX_COEFS);
|
|
waveDCT.AlterSample(waveFloatBuffer, SND_DCT_SIZE_MATRIX_COEFS, valCenter);
|
|
//waveDCT.ComputeInverseDCT(waveFloatBuffer, uResult);
|
|
|
|
for (int i=0; i<SND_DCT_SIZE_MATRIX_COEFS; i++)
|
|
{
|
|
total2 += waveFloatBuffer[i];
|
|
}
|
|
total2 /= SND_DCT_SIZE_MATRIX_COEFS;
|
|
|
|
pWaveFloatBuffer = waveFloatBuffer;
|
|
for (; pShortBufferInOutBegin<pShortBufferInOut;
|
|
pShortBufferInOutBegin+=waveFormat.nChannels, pWaveFloatBuffer++)
|
|
{
|
|
if (*pWaveFloatBuffer > valMax)
|
|
*pWaveFloatBuffer = valMax;
|
|
if (*pWaveFloatBuffer < valMin)
|
|
*pWaveFloatBuffer = valMin;
|
|
*pShortBufferInOutBegin = (short)(*pWaveFloatBuffer + 0.5f);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
//memset(pBufferInOut, 127, size);
|
|
|
|
pSample->SetSyncPoint(true);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
CUnknown * WINAPI CAudioFilter::CreateInstance(IUnknown *pUnk, HRESULT *phr)
|
|
{
|
|
CAudioFilter *pNewFilter = new CAudioFilter(pUnk, phr );
|
|
|
|
if (phr)
|
|
{
|
|
if (pNewFilter == NULL)
|
|
*phr = E_OUTOFMEMORY;
|
|
else
|
|
*phr = S_OK;
|
|
}
|
|
|
|
return pNewFilter;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT AddToGraphEdit(IUnknown *pUnkGraph, DWORD *pdwRegister);
|
|
HRESULT GetDevice(REFCLSID ref, int pos, IBaseFilter **ppFilter);
|
|
void RemoveFromGraphEdit(DWORD pdwRegister);
|
|
|
|
|
|
class CSampleGrabberCBMicro : public ISampleGrabberCB
|
|
{
|
|
public:
|
|
IMediaControl *mediaControl;
|
|
u32 Locked;
|
|
|
|
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 ...
|
|
memset(pBuffer, 127, lBufferSize);
|
|
//for (int i=0; i<lBufferSize; i++, pBuffer++)
|
|
//{
|
|
// *pBuffer = (*pBuffer - 127)/2 + 127;
|
|
//}
|
|
return 0;
|
|
}
|
|
|
|
};
|
|
|
|
|
|
class MicroWrapper {
|
|
|
|
public :
|
|
CComPtr<ICaptureGraphBuilder2> graphBuilder;
|
|
|
|
CComPtr<IFilterGraph2> filterGraph;
|
|
CComPtr<IBaseFilter> audioSource;
|
|
CAudioFilter *audioFilter;
|
|
CComPtr<IBaseFilter> waveRenderer;
|
|
CComPtr<IBaseFilter> grabberFilter;
|
|
CComPtr<IBaseFilter> nullRenderer;
|
|
CComPtr<IBasicAudio> audioConfig;
|
|
|
|
CComPtr<IMediaControl> mediaControl;
|
|
CSampleGrabberCBMicro CB;
|
|
|
|
bool microInitialized;
|
|
WAVEFORMATEX microFormat;
|
|
|
|
DWORD grabberNum;
|
|
|
|
MicroWrapper() {
|
|
// This must be callled before
|
|
// interfaces can be accessed
|
|
CoInitialize(NULL);
|
|
microInitialized = false;
|
|
grabberNum = 0;
|
|
}
|
|
|
|
~MicroWrapper() {
|
|
// 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 openMicro();
|
|
void uninitMicro();
|
|
};
|
|
|
|
|
|
|
|
class MICRO_Grabber:public INPUT_IO
|
|
{
|
|
WORLD * pScn;
|
|
HRESULT hrinit;
|
|
|
|
public:
|
|
DWORD sTimer;
|
|
double lastTime;
|
|
MicroWrapper *mw;
|
|
float volume;
|
|
|
|
int INIT (WORLD *pScene);
|
|
int FRAME ();
|
|
int END ();
|
|
IOTYPE GetType() {return IOtype_MICRO;};
|
|
};
|
|
|
|
|
|
|
|
bool MicroWrapper::openMicro() {
|
|
HRESULT result;
|
|
|
|
if (microInitialized) {
|
|
uninitMicro();
|
|
}
|
|
|
|
// 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.
|
|
GetDevice(CLSID_AudioInputDeviceCategory, 0, &audioSource);
|
|
filterGraph->AddFilter(audioSource, L"Microphone");
|
|
|
|
HRESULT res;
|
|
|
|
audioFilter = (CAudioFilter *)CAudioFilter::CreateInstance(NULL, &res);
|
|
filterGraph->AddFilter(audioFilter, L"Camcam Audio Filter");
|
|
|
|
|
|
// direct render
|
|
CComPtr<IPin> myPin;
|
|
CComPtr<IBaseFilter> renderFilter;
|
|
|
|
FindPin(audioSource, PINDIR_OUTPUT, 0, &myPin);
|
|
result = filterGraph->Render(myPin);
|
|
myPin.Release();
|
|
|
|
AddToGraphEdit(filterGraph, &grabberNum);
|
|
|
|
if (result != S_OK)
|
|
{
|
|
uninitMicro();
|
|
return false;
|
|
}
|
|
|
|
filterGraph->QueryInterface(IID_IBasicAudio, (void **)&audioConfig);
|
|
filterGraph->QueryInterface(IID_IMediaControl, (void **)&mediaControl);
|
|
|
|
CB.mediaControl = mediaControl;
|
|
|
|
if (SUCCEEDED(mediaControl->Run())) {
|
|
microInitialized = true;
|
|
return true;
|
|
} else {
|
|
uninitMicro();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
void MicroWrapper::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 MicroWrapper::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 MicroWrapper::uninitMicro() {
|
|
if (microInitialized) {
|
|
if (mediaControl) mediaControl->Stop();
|
|
|
|
if (grabberNum)
|
|
RemoveFromGraphEdit(grabberNum);
|
|
grabberNum = 0;
|
|
|
|
audioConfig.Release();
|
|
mediaControl.Release();
|
|
grabberFilter.Release();
|
|
audioSource.Release();
|
|
nullRenderer.Release();
|
|
filterGraph.Release();
|
|
graphBuilder.Release();
|
|
|
|
CB.mediaControl = NULL;
|
|
}
|
|
microInitialized = false;
|
|
}
|
|
|
|
|
|
|
|
int MICRO_Grabber::INIT(WORLD *pScene)
|
|
{
|
|
lastTime =
|
|
dCurrentTime = 0.0f;
|
|
dTotalTime = 0.0f;
|
|
|
|
ulCurrentFrame = 0;
|
|
ulMediaParams = 0;
|
|
lTimeState = 0;
|
|
volume = 1.0f;
|
|
|
|
mw = new MicroWrapper();
|
|
if (!mw->openMicro())
|
|
{
|
|
delete mw;
|
|
mw = NULL;
|
|
} else
|
|
{
|
|
mw->mediaControl->Pause();
|
|
}
|
|
|
|
Image.SX =
|
|
Image.SY = 0;
|
|
pScn = pScene;
|
|
return 1;
|
|
}
|
|
|
|
int MICRO_Grabber::FRAME()
|
|
{
|
|
float prevTime;
|
|
if (mw)
|
|
{
|
|
switch (lTimeState)
|
|
{
|
|
case 0:
|
|
case 255:
|
|
mw->mediaControl->Stop();
|
|
break;
|
|
case 1:
|
|
mw->mediaControl->Run();
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int MICRO_Grabber::END()
|
|
{
|
|
mw->uninitMicro();
|
|
delete mw;
|
|
return 0;
|
|
}
|
|
|
|
INPUT_IO *MICRO_CREATE(WORLD *pScene)
|
|
{
|
|
INPUT_IO *Ret;
|
|
Ret = (INPUT_IO *)new(MICRO_Grabber);
|
|
Ret->INIT(pScene);
|
|
return Ret;
|
|
}
|
|
|