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

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