📄 ddgrab.cpp
字号:
/***************************************************
This is the main Grabber code. It builds the Direct Show graphs
and then inserts SampleGrabbers right before the renderers. It
then changes all of the renderers to NullRenderers. This code
supports any number of audio or video streams. Raw midi streams
are not supported -- I didn't think I should bother.
This code was intended to be used inside of a matlab interface,
but can be used as a generic grabber class for anyone who needs
one.
Written by Micah Richert.
07/14/2005
**************************************************/
#include "DDGrab.h"
GUID NULLGUID = {0};
CSampleGrabberCB::CSampleGrabberCB()
{
pbFormat = NULL;
frameNr = 0;
disabled = FALSE;
}
CSampleGrabberCB::~CSampleGrabberCB()
{
if (pbFormat) free(pbFormat);
for (int f=0;f<frames.size();f++) if (frames[f]) free(frames[f]);
}
// Fake out any COM QI'ing
//
STDMETHODIMP CSampleGrabberCB::QueryInterface(REFIID riid, void ** ppv)
{
if (!ppv) return E_POINTER;
if( riid == IID_ISampleGrabberCB || riid == IID_IUnknown )
{
*ppv = (void *) static_cast<ISampleGrabberCB*> ( this );
return NOERROR;
}
return E_NOINTERFACE;
}
// The sample grabber is calling us back on its deliver thread.
// This is NOT the main app thread!
//
STDMETHODIMP CSampleGrabberCB::BufferCB( double dblSampleTime, BYTE * pBuffer, long lBufferSize )
{
if (disabled) return 0;
if (!pBuffer) return E_POINTER;
frameNr++;
bool foundNr = false;
for (int i=0;i<frameNrs.size();i++) if (frameNrs[i] == frameNr) foundNr = true;
if (frameNrs.size() == 0 || foundNr)
{
BYTE* tmp = new BYTE[lBufferSize];
if (!tmp) return E_OUTOFMEMORY;
memcpy(tmp,pBuffer,lBufferSize);
frames.push_back(tmp);
frameBytes.push_back(lBufferSize);
}
return 0;
}
void DDGrabber::cleanUp()
{
IEnumFilters* filterList;
IBaseFilter* filt;
ULONG tmp;
int i;
for (i=0; i<VideoCBs.size(); i++) delete VideoCBs[i];
for (i=0; i<AudioCBs.size(); i++) delete AudioCBs[i];
VideoCBs.clear();
AudioCBs.clear();
if (!FAILED(pGraphBuilder->EnumFilters(&filterList)))
{
filterList->Reset();
while (filterList->Next(1, &filt, &tmp) == S_OK)
{
filt->Release();
}
filterList->Release();
}
pGraphBuilder = NULL;
}
void DDGrabber::MyFreeMediaType(AM_MEDIA_TYPE& mt)
{
if (mt.cbFormat != 0)
{
CoTaskMemFree((PVOID)mt.pbFormat);
mt.cbFormat = 0;
mt.pbFormat = NULL;
}
if (mt.pUnk != NULL)
{
// Unecessary because pUnk should not be used, but safest.
mt.pUnk->Release();
mt.pUnk = NULL;
}
}
PIN_INFO DDGrabber::getPinInfo(IPin* pin)
{
PIN_INFO info = {0};
if (pin)
{
if (!FAILED(pin->QueryPinInfo(&info)))
{
info.pFilter->Release();
}
}
return info;
}
IPin* DDGrabber::getInputPin(IBaseFilter* filt)
{
IPin* pin = NULL;
IEnumPins* pinList;
ULONG tmp;
if (!filt) return NULL;
//get the input
if (!FAILED(filt->EnumPins(&pinList)))
{
pinList->Reset();
while (pinList->Next(1, &pin, &tmp) == S_OK && getPinInfo(pin).dir != PINDIR_INPUT);
pinList->Release();
if (getPinInfo(pin).dir != PINDIR_INPUT) return NULL;
}
return pin;
}
IPin* DDGrabber::getOutputPin(IBaseFilter* filt)
{
IPin* pin = NULL;
IEnumPins* pinList;
ULONG tmp;
if (!filt) return NULL;
//get the output
if (!FAILED(filt->EnumPins(&pinList)))
{
pinList->Reset();
while (pinList->Next(1, &pin, &tmp) == S_OK && getPinInfo(pin).dir != PINDIR_OUTPUT);
pinList->Release();
if (getPinInfo(pin).dir != PINDIR_OUTPUT) return NULL;
}
return pin;
}
bool DDGrabber::isRenderer(IBaseFilter* filt)
{
if (!filt) return false;
IEnumPins* pinList;
int nrOutput = 0;
int nrInput = 0;
IPin* pin = NULL;
ULONG tmp;
if (FAILED(filt->EnumPins(&pinList))) return false;
pinList->Reset();
while (pinList->Next(1, &pin, &tmp) == S_OK)
{
if (getPinInfo(pin).dir == PINDIR_OUTPUT) nrOutput++;
else nrInput++;
}
pinList->Release();
#ifdef _DEBUG
FILTER_INFO info;
filt->QueryFilterInfo(&info);
char str[100];
WideCharToMultiByte( CP_ACP, 0, info.achName, -1, str, 100, NULL, NULL );
_RPT0(_CRT_WARN,str);
_RPT2(_CRT_WARN," %d %d\n", nrOutput, nrInput);
#endif
return nrOutput == 0 && nrInput == 1; // the only filters that have no outputs are renderers
}
IPin* DDGrabber::connectedToInput(IBaseFilter* filt)
{
if (!filt) return NULL;
IPin* inPin;
IPin* outPin;
inPin = getInputPin(filt);
if (!inPin) return NULL;
if (FAILED(inPin->ConnectedTo(&outPin))) return NULL;
return outPin;
}
GUID DDGrabber::getMajorType(IBaseFilter* filt)
{
if (!filt) return NULLGUID;
IPin* inPin;
inPin = getInputPin(filt);
if (!inPin) return NULLGUID;
AM_MEDIA_TYPE mt = {0};
// ZeroMemory(&MediaType,sizeof(MediaType));
if (FAILED(inPin->ConnectionMediaType(&mt))) return NULLGUID;
GUID ret = mt.majortype;
MyFreeMediaType(mt);
return ret;
}
HRESULT DDGrabber::getVideoInfo(unsigned int id, int* width, int* height, int* nrFramesCaptured, int* nrFramesTotal)
{
if (!width || !height || !nrFramesCaptured || !nrFramesTotal) return E_POINTER;
if (id >= VideoCBs.size()) return E_NOINTERFACE;
CSampleGrabberCB* CB = VideoCBs[id];
if (!CB) return E_POINTER;
if (CB->frameNr == 0)
{
*width = 0;
*height = 0;
} else {
VIDEOINFOHEADER * h = (VIDEOINFOHEADER*) CB->pbFormat;
if (!h) return E_POINTER;
*width = h->bmiHeader.biWidth;
*height = h->bmiHeader.biHeight;
}
*nrFramesCaptured = CB->frames.size();
*nrFramesTotal = CB->frameNr;
return S_OK;
}
HRESULT DDGrabber::getAudioInfo(unsigned int id, int* nrChannels, int* rate, int* bits, int* nrFramesCaptured, int* nrFramesTotal)
{
if (!nrChannels || !rate || !bits || !nrFramesCaptured || !nrFramesTotal) return E_POINTER;
if (id >= AudioCBs.size()) return E_NOINTERFACE;
CSampleGrabberCB* CB = AudioCBs[id];
if (!CB) return E_POINTER;
if (CB->frameNr == 0)
{
*nrChannels = 0;
*rate = 0;
*bits = 0;
} else {
WAVEFORMATEX * h = (WAVEFORMATEX*) CB->pbFormat;
if (!h) return E_POINTER;
*nrChannels = h->nChannels;
*rate = h->nSamplesPerSec;
*bits = h->wBitsPerSample;
}
*nrFramesCaptured = CB->frames.size();
*nrFramesTotal = CB->frameNr;
return S_OK;
}
void DDGrabber::getCaptureInfo(int* nrVideo, int* nrAudio)
{
if (!nrVideo || !nrAudio) return;
*nrVideo = (VideoCBs.size()>0&&VideoCBs[0]&&VideoCBs[0]->disabled)?0:VideoCBs.size();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -