Skip to content

Instantly share code, notes, and snippets.

@roxlu
Last active December 10, 2015 22:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save roxlu/df1dd70463d78a9fdc55 to your computer and use it in GitHub Desktop.
Save roxlu/df1dd70463d78a9fdc55 to your computer and use it in GitHub Desktop.
Trying to find a wierd bug.

Callstack:

  011_windows.exe!VideoCaptureDirectShowCallback::BufferCB(double timestamp, unsigned char * buffer, long size)  Line 49	C++
 	qedit.dll!CSampleGrabber::Receive()  + 0x18c bytes	
 	qedit.dll!CTransformInputPin::Receive()  + 0x33 bytes	
 	quartz.dll!CBaseOutputPin::Deliver()  + 0x22 bytes	
 	quartz.dll!CVideoTransformFilter::Receive()  + 0x1aa bytes	
 	quartz.dll!CTransformInputPin::Receive()  + 0x33 bytes	
 	quartz.dll!CBaseInputPin::ReceiveMultiple()  + 0x33 bytes	
 	qcap.dll!COutputQueue::ThreadProc()  + 0x103 bytes	
 	qcap.dll!COutputQueue::InitialThreadProc()  + 0x16 bytes	
 	kernel32.dll!@BaseThreadInitThunk@12()  + 0x12 bytes	
 	ntdll.dll!___RtlUserThreadStart@8()  + 0x27 bytes	
 	ntdll.dll!__RtlUserThreadStart@8()  + 0x1b bytes	

Local vars

-  	this	0x00000000 {new_frame=??? vidcap=??? critical_section={...} }	VideoCaptureDirectShowCallback * const
-		ISampleGrabberCB	{...}	ISampleGrabberCB
-		IUnknown	{...}	IUnknown
		__vfptr	CXX0030: Error: expression cannot be evaluated	
		new_frame	CXX0030: Error: expression cannot be evaluated	
		vidcap	CXX0017: Error: symbol "" not found	
-		critical_section	{DebugInfo=??? LockCount=??? RecursionCount=??? ...}	_RTL_CRITICAL_SECTION
		DebugInfo	CXX0017: Error: symbol "" not found	
		LockCount	CXX0030: Error: expression cannot be evaluated	
		RecursionCount	CXX0030: Error: expression cannot be evaluated	
		OwningThread	CXX0030: Error: expression cannot be evaluated	
		LockSemaphore	CXX0030: Error: expression cannot be evaluated	
		SpinCount	CXX0030: Error: expression cannot be evaluated	
		timestamp	3.806238257784e-317#DEN	double
-		buffer	0x00000000 	unsigned char *
			CXX0030: Error: expression cannot be evaluated	
		size	118620160	long

#include <videocapture/VideoCaptureDirectShow.h>
// ---------------------------------------------------------------------
// VideoCaptureDirectShoCallback
// ---------------------------------------------------------------------
VideoCaptureDirectShowCallback::VideoCaptureDirectShowCallback(VideoCaptureDirectShow* vidcap)
:vidcap(vidcap)
{
InitializeCriticalSection(&critical_section);
}
VideoCaptureDirectShowCallback::~VideoCaptureDirectShowCallback() {
DeleteCriticalSection(&critical_section);
}
// For some reason sample is always NULL
HRESULT VideoCaptureDirectShowCallback::SampleCB(double timestamp,
IMediaSample* sample)
{
if(sample != NULL) {
printf("callback: %f. %p.\n", timestamp, sample);
}
return S_OK;
}
STDMETHODIMP VideoCaptureDirectShowCallback::QueryInterface(REFIID riid, void **obj) {
if((riid == IID_ISampleGrabberCB) || (riid == IID_IUnknown)) {
*obj = static_cast<ISampleGrabberCB*>(this);
return S_OK;
}
else {
return E_NOINTERFACE;
}
}
STDMETHODIMP_(ULONG) VideoCaptureDirectShowCallback::AddRef() {
return 1;
}
STDMETHODIMP_(ULONG) VideoCaptureDirectShowCallback::Release() {
return 2;
}
HRESULT VideoCaptureDirectShowCallback::BufferCB(
double timestamp,
BYTE* buffer,
long size)
{
return S_OK;
}
// ---------------------------------------------------------------------
// VideoCaptureDirectShow
// ---------------------------------------------------------------------
int VideoCaptureDirectShow::num_com_init = 0;
VideoCaptureDirectShow::VideoCaptureDirectShow(void)
:width(0)
,height(0)
,is_graph_setup(false)
,graph(NULL)
,builder(NULL)
,capture_device_filter(NULL)
,media_control(NULL)
,sample_grabber_filter(NULL)
,sample_grabber_iface(NULL)
,frame_cb(NULL)
,frame_user(NULL)
,callback_type(BUFFERED_CALLBACK)
{
if(!num_com_init) {
HRESULT hr = NULL;
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if(hr == S_OK) {
printf("VERBOSE: COM initialized.\n");
}
else if(hr == S_FALSE) {
printf("WARNING: COM is already initailized on this thread.\n");
}
else if(hr == RPC_E_CHANGED_MODE) {
printf("WARNING: COM concurrency model changed.\n");
}
}
num_com_init++;
}
VideoCaptureDirectShow::~VideoCaptureDirectShow(void) {
close();
}
int VideoCaptureDirectShow::openDevice(int dev) {
if(is_graph_setup) {
printf("ERROR: graph is already created which means the device is opened already.\n");
return 0;
}
if(!initCaptureGraphBuilder()) {
printf("ERROR: cannot initialize capture graph builder.\n");
return 0;
}
// -----------------------------------------------------
// STEP 1: FIND THE DEVICE AND ADD IT TO THE GRAPH
// -----------------------------------------------------
// Get enumerator so we can find the device.
ICreateDevEnum* dev_enum;
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum,
NULL,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&dev_enum)
);
if(FAILED(hr)) {
printf("ERROR: cannot create system device enumerator.\n");
return 0;
}
IEnumMoniker* enum_moniker;
hr = dev_enum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &enum_moniker, 0);
if(hr == S_FALSE) {
printf("ERROR: cannot create video input device enumerator.\n");
dev_enum->Release();
dev_enum = NULL;
return 0;
}
// Iterate over devices and select the one passed into this function.
bool device_found = false;
int dx = 0;
IMoniker* moniker = NULL;
while(enum_moniker->Next(1, &moniker, NULL) == S_OK) {
if(dx == dev) {
hr = moniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&capture_device_filter);
if(FAILED(hr)) {
printf("ERROR: Cannot bind moniker to base filter.\n");
break;
}
hr = graph->AddFilter(capture_device_filter, L"Roxlu Capture Filter");
if(FAILED(hr)) {
printf("ERROR: cannot add filter.\n");
break;
}
device_found = true;
moniker->Release();
moniker = NULL;
break;
}
++dx;
}
dev_enum->Release();
dev_enum = NULL;
if(!device_found) {
printf("ERROR: Cannot find the device index to open.\n");
return 0;
}
// -----------------------------------------------------
// STEP 2: CREATE A SAMPLE GRABBER HOOK TO GET FRAMES
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd407288(v=vs.85).aspx
// -----------------------------------------------------
hr = graph->QueryInterface(IID_IMediaControl, (void**)&media_control);
RETURN_IF_FAILED(hr, "ERROR: cannot query IID_MediaControl.\n", 0);
hr = CoCreateInstance(CLSID_SampleGrabber,
NULL,
CLSCTX_INPROC_SERVER,
IID_IBaseFilter,
(void**)&sample_grabber_filter);
RETURN_IF_FAILED(hr, "ERROR: failed to aquire a CLSID_SampleGrabber.\n", 0);
hr = graph->AddFilter(sample_grabber_filter, L"SampleGrabber");
RETURN_IF_FAILED(hr, "ERROR: cannot add sample grabber filter to the graph.\n", 0);
hr = sample_grabber_filter->QueryInterface(IID_ISampleGrabber, (void**)&sample_grabber_iface);
RETURN_IF_FAILED(hr, "ERROR: cannot query the IID_ISampleGrabber", 0);
hr = sample_grabber_iface->SetBufferSamples(TRUE);
RETURN_IF_FAILED(hr, "ERROR: cannot set buffer samples\n", 0);
hr = sample_grabber_iface->SetOneShot(FALSE);
RETURN_IF_FAILED(hr, "ERROR: cannot set the one shot feature.\n", 0);
sample_grabber_listener = new VideoCaptureDirectShowCallback(this);
sample_grabber_listener->BufferCB(0.0, NULL, 10);
hr = sample_grabber_iface->SetCallback(sample_grabber_listener, 1);
RETURN_IF_FAILED(hr, "ERROR: cannot set the grabber callback.\n", 0);
AM_MEDIA_TYPE mt;
ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
mt.majortype = MEDIATYPE_Video;
mt.subtype = MEDIASUBTYPE_RGB24;
mt.formattype = FORMAT_VideoInfo;
hr = sample_grabber_iface->SetMediaType(&mt); // we could ask another type here (e.g. YUV)
RETURN_IF_FAILED(hr, "ERROR: cannot set media type.\n", 0);
sample_grabber_iface->GetConnectedMediaType(&mt);
printAmMediaType(&mt);
// -------------------------------------------------------------
// STEP 3: CREATE NULL RENDERER; THE VIDEO NEEDS AN 'END' POINT
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd407288(v=vs.85).aspx
// -------------------------------------------------------------
hr = CoCreateInstance(CLSID_NullRenderer,
NULL,
CLSCTX_INPROC_SERVER,
IID_IBaseFilter,
(void**)&null_renderer_filter);
RETURN_IF_FAILED(hr, "ERROR: cannot query for the null renderer.\n", 0);
hr = graph->AddFilter(null_renderer_filter, L"NULLRenderer");
RETURN_IF_FAILED(hr, "ERROR: cannot add the CLSID_NullRenderer to the graph.\n", 0);
// -------------------------------------------------------------
// STEP 4: Connect the filters (we're using an helper; but could
// have done it manually following:
// - http://msdn.microsoft.com/en-us/library/windows/desktop/dd387915(v=vs.85).aspx
// -------------------------------------------------------------
hr = builder->RenderStream(&PIN_CATEGORY_PREVIEW,
&MEDIATYPE_Video,
capture_device_filter,
sample_grabber_filter,
null_renderer_filter);
RETURN_IF_FAILED(hr, "ERROR: cannot connect filters in our graph.", 0);
is_graph_setup = true;
if(!saveGraphToFile()) {
printf("ERROR: cannot save graph to file.\n");
return 0;
}
return 1;
}
int VideoCaptureDirectShow::startCapture() {
if(!is_graph_setup) {
printf("ERROR: first open a device before you start the capture.\n");
return 0;
}
HRESULT hr = media_control->Run();
RETURN_IF_FAILED(hr, "ERROR: call Run() on the MediaControl fails.\n", 0);
return 1;
}
int VideoCaptureDirectShow::stopCapture() {
if(!is_graph_setup) {
printf("ERROR: cannot stopCapture() when the graph hasn't been setup, open the device first\n");
return 0;
}
HRESULT hr = media_control->Stop();
RETURN_IF_FAILED(hr, "ERROR: cannot stop, media_control->Stop() return an error.\n", 0);
return 1;
}
// We use the CaptureGraphBuilder2 Interface to create a capture graph
bool VideoCaptureDirectShow::initCaptureGraphBuilder() {
if(is_graph_setup) {
return true;
}
HRESULT hr = NULL;
hr = CoCreateInstance(CLSID_CaptureGraphBuilder2,
NULL,
CLSCTX_INPROC_SERVER,
IID_ICaptureGraphBuilder2,
(void**)&builder);
if(!SUCCEEDED(hr)) {
printf("ERROR: cannot initialize capture graph builder.\n");
return false;
}
hr = CoCreateInstance(CLSID_FilterGraph,
0,
CLSCTX_INPROC_SERVER,
IID_IGraphBuilder,
(void**)&graph);
if(!SUCCEEDED(hr)) {
printf("ERROR: cannot initialize filter graph manager.\n");
builder->Release();
builder = NULL;
return false;
}
builder->SetFiltergraph(graph);
is_graph_setup = true;
return true;
}
int VideoCaptureDirectShow::listDevices() {
ICreateDevEnum* dev_enum;
HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum,
NULL,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&dev_enum)
);
if(SUCCEEDED(hr)) {
IEnumMoniker* moniker;
hr = dev_enum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &moniker, 0);
if(hr == S_FALSE) {
dev_enum->Release();
return 0;
}
fillDeviceInformationList(moniker);
if(devices.size()) {
printf("--------------------------------------------------\n");
for(size_t i = 0; i < devices.size(); ++i) {
printf("[%d] %s\n", int(i), devices[i].name.c_str());
}
printf("--------------------------------------------------\n");
}
return 1;
}
else {
printf("ERROR: cannot list devices; system device enumerator failed.\n");
return 0;
}
}
int VideoCaptureDirectShow::printVerboseInfo() {
if(!is_graph_setup) {
printf("ERROR: you need to open a device before calling printVerboseInfo()\n");
return 0;
}
IAMStreamConfig* conf;
HRESULT hr = NULL;
hr = builder->FindInterface(&PIN_CATEGORY_CAPTURE, // we use capture here because webcams don't have a preview pin
&MEDIATYPE_Video,
capture_device_filter,
IID_IAMStreamConfig,
(void**)&conf);
if(hr == E_NOINTERFACE) { printf("ERROR: cannot find IID_IAMStreamConfig interface\n"); return 0; }
if(hr == E_FAIL) { printf("ERROR: IID_IAMStreamConfig fail\n"); return 0; }
if(hr == E_POINTER) { printf("ERROR: IID_IAMStreamConfig passed null\n"); return 0; }
// Get preferred format
AM_MEDIA_TYPE* mt;
hr = conf->GetFormat(&mt);
if(FAILED(hr)) {
printf("ERROR: cannot get format for current device.\n");
conf->Release();
conf = NULL;
return 0;
}
printf("--------------------------------------------------\n");
printf("Preferred media type:\n");
printAmMediaType(mt);
printf("--------------------------------------------------\n");
int count = 0;
int size = 0;
hr = conf->GetNumberOfCapabilities(&count, &size);
if(FAILED(hr)) {
printf("ERROR: cannot GetNumberOfCapabilities()\n");
conf->Release();
conf = NULL;
return 0;
}
if(size != sizeof(VIDEO_STREAM_CONFIG_CAPS)) {
printf("ERROR: capabilities size incorrect.\n");
conf->Release();
conf = NULL;
}
for(int i = 0; i < count; ++i) {
VIDEO_STREAM_CONFIG_CAPS cap;
hr = conf->GetStreamCaps(i, &mt, (BYTE*)&cap);
if(FAILED(hr)) {
printf("WARNING: GetStreamCaps for index: %d failed.\n", i);
continue;
}
// if this AM_MEDIA_TYPE suits your needs you need to set it
// see here for an example: http://www.microsoftfaqs.com/msg/14713491.aspx
// backup: https://gist.github.com/bd9e4982ce2e7da2fcca
printAmMediaType(mt);
printf("--------------------------------------------------\n");
}
conf->Release();
conf = NULL;
return 1;
}
void VideoCaptureDirectShow::printAmMediaType(AM_MEDIA_TYPE* mt) {
printf("AM_MEDIA_TYPE.majortype: %s\n", mediaFormatMajorTypeToString(mt->majortype).c_str());
printf("AM_MEDIA_TYPE.subtype: %s\n", mediaFormatSubTypeToString(mt->subtype).c_str());
printf("AM_MEDIA_TYPE.bFixedSizeSamples: %c\n", (mt->bFixedSizeSamples == TRUE) ? 'y' : 'n');
printf("AM_MEDIA_TYPE.bTemporalCompression: %c\n", (mt->bTemporalCompression == TRUE) ? 'y' : 'n');
printf("AM_MEDIA_TYPE.lSampleSize: %Iu\n", mt->lSampleSize);
printf("AM_MEDIA_TYPE.formattype: %s\n", mediaFormatFormatTypeToString(mt->formattype));
printf("AM_MEDIA_TYPE.cbFormat: %Iu\n", mt->cbFormat);
if(mt->formattype == FORMAT_VideoInfo && mt->cbFormat >= sizeof(VIDEOINFOHEADER)) {
VIDEOINFOHEADER* ih = (VIDEOINFOHEADER*)mt->pbFormat;
printf("VIDEOINFOHEADER - width: %Iu\n", LONG(ih->bmiHeader.biWidth));
printf("VIDEOINFOHEADER - height: %Iu\n", LONG(ih->bmiHeader.biHeight));
// from fps in seconds to nano example: (1/30) * 10,000,000
// from fps in 100 nano units to seconds:
double fps = 1.0 / (double(ih->AvgTimePerFrame) / 10000000.0f);
printf("VIDEOINFOHEADER - fps: %f\n", fps);
}
}
void VideoCaptureDirectShow::fillDeviceInformationList(IEnumMoniker* enumerator) {
IMoniker* moniker = NULL;
while(enumerator->Next(1, &moniker, NULL) == S_OK) {
IPropertyBag* bag;
HRESULT hr = moniker->BindToStorage(0, 0, IID_PPV_ARGS(&bag));
if(FAILED(hr)) {
moniker->Release();
continue;
}
VideoCaptureDirectShowDevice device_info;
VARIANT var;
VariantInit(&var);
hr = bag->Read(L"Description", &var, 0);
if(FAILED(hr)) {
hr = bag->Read(L"FriendlyName", &var, 0);
}
if(SUCCEEDED(hr)) {
int count = 0;
while(var.bstrVal[count] != 0x00 && count < 1024) {
device_info.name.push_back(var.bstrVal[count]);
count++;
}
}
else {
device_info.name = "UNKNOWN";
}
bag->Release();
bag = NULL;
moniker->Release();
moniker = NULL;
devices.push_back(device_info);
}
}
void VideoCaptureDirectShow::close() {
if(!is_graph_setup) {
return;
}
if(media_control != NULL) {
HRESULT hr = media_control->Stop();
if(FAILED(hr)) {
printf("ERROR: IMediaControl::Stop() fails.\n");
}
}
if(capture_device_filter) {
nukeDownStream(capture_device_filter);
}
if(null_renderer_filter != NULL) {
null_renderer_filter->Release();
null_renderer_filter = NULL;
}
if(capture_device_filter != NULL) {
capture_device_filter->Release();
capture_device_filter = NULL;
}
if(sample_grabber_iface != NULL) {
sample_grabber_iface->SetCallback(NULL, 0);
sample_grabber_iface->SetCallback(NULL, 1);
sample_grabber_iface->Release();
sample_grabber_iface = NULL;
}
if(sample_grabber_filter != NULL) {
sample_grabber_filter->Release();
sample_grabber_filter = NULL;
}
if(sample_grabber_listener != NULL) {
delete sample_grabber_listener;
sample_grabber_listener = NULL;
}
if(builder != NULL) {
builder->Release();
builder = NULL;
}
if(media_control != NULL) {
media_control->Release();
media_control = NULL;
}
if(graph != NULL) {
destroyGraph();
graph->Release();
graph = NULL;
}
delete null_renderer_filter;
delete sample_grabber_filter;
delete sample_grabber_iface;
delete media_control;
delete capture_device_filter;
delete builder;
delete graph;
is_graph_setup = false;
if(num_com_init > 0) {
num_com_init--;
}
if(num_com_init == 0) {
CoUninitialize();
}
}
// From SDK
void VideoCaptureDirectShow::nukeDownStream(IBaseFilter* filter) {
IPin *p, *to;
ULONG u;
IEnumPins *pins = NULL;
PIN_INFO pininfo;
HRESULT hr = filter->EnumPins(&pins);
pins->Reset();
while(hr == NOERROR) {
hr = pins->Next(1, &p, &u);
if(hr == S_OK && p) {
p->ConnectedTo(&to);
if(to) {
hr = to->QueryPinInfo(&pininfo);
if(hr == NOERROR){
if(pininfo.dir == PINDIR_INPUT) {
nukeDownStream(pininfo.pFilter);
graph->Disconnect(to);
graph->Disconnect(p);
graph->RemoveFilter(pininfo.pFilter);
}
pininfo.pFilter->Release();
pininfo.pFilter = NULL;
}
to->Release();
}
p->Release();
}
}
if(pins) {
pins->Release();
}
}
// From SDK and
void VideoCaptureDirectShow::destroyGraph() {
HRESULT hr = NULL;
int r = 0;
int num_filters=0;
while(hr == NOERROR) {
IEnumFilters* filter_enumerator = NULL;
ULONG num_fetched;
hr = graph->EnumFilters(&filter_enumerator);
if(FAILED(hr)) {
printf("WARNING: failed to enumerate filter.\n");
return;
}
IBaseFilter* filter = NULL;
if (filter_enumerator->Next(1, &filter, &num_fetched) == S_OK) {
FILTER_INFO filter_info = {0};
hr = filter->QueryFilterInfo(&filter_info);
filter_info.pGraph->Release();
// get the name of the filter
int count = 0;
char buffer[255];
memset(buffer, 0, 255 * sizeof(char));
while(filter_info.achName[count] != 0x00) {
buffer[count] = filter_info.achName[count];
count++;
}
printf("VERBOSE: removing filter %s.\n", buffer);
hr = graph->RemoveFilter(filter);
if(FAILED(hr)) {
printf("ERROR: graph->RemoveFilter() failed.\n");
return;
}
filter->Release();
filter = NULL;
}
else {
break;
}
filter_enumerator->Release();
filter_enumerator= NULL;
}
}
// Debugging / verbosity
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd390660(v=vs.85).aspx
std::string VideoCaptureDirectShow::mediaFormatMajorTypeToString(GUID type) {
if(type == MEDIATYPE_AnalogAudio) { return "MEDIATYPE_AnalogAudio"; }
else if(type == MEDIATYPE_AnalogVideo) { return "MEDIATYPE_AnalogVideo"; }
else if(type == MEDIATYPE_Audio) { return "MEDIATYPE_Audio"; }
else if(type == MEDIATYPE_AUXLine21Data) { return "MEDIATYPE_AUXLine21Data"; }
else if(type == MEDIATYPE_File) { return "MEDIATYPE_File"; }
else if(type == MEDIATYPE_Interleaved) { return "MEDIATYPE_Interleaved"; }
else if(type == MEDIATYPE_LMRT) { return "MEDIATYPE_LMRT"; }
else if(type == MEDIATYPE_Midi) { return "MEDIATYPE_Midi"; }
else if(type == MEDIATYPE_MPEG2_PES) { return "MEDIATYPE_MPEG2_PES"; }
else if(type == MEDIATYPE_MPEG2_SECTIONS) { return "MEDIATYPE_MPEG2_SECTIONS"; }
else if(type == MEDIATYPE_ScriptCommand) { return "MEDIATYPE_ScriptCommand"; }
else if(type == MEDIATYPE_Stream) { return "MEDIATYPE_Stream"; }
else if(type == MEDIATYPE_Text) { return "MEDIATYPE_Text"; }
else if(type == MEDIATYPE_Timecode) { return "MEDIATYPE_Timecode"; }
else if(type == MEDIATYPE_URL_STREAM) { return "MEDIATYPE_URL_STREAM"; }
else if(type == MEDIATYPE_VBI) { return "MEDIATYPE_VBI"; }
else if(type == MEDIATYPE_Video) { return "MEDIATYPE_Video"; }
return "UNKNOWN - NOT ADDED TO LIST";
}
// Debugging / verbosity
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd407253(v=vs.85).aspx
std::string VideoCaptureDirectShow::mediaFormatSubTypeToString(GUID type) {
if(type == MEDIASUBTYPE_RGB1) { return "MEDIASUBTYPE_RGB1"; }
else if(type == MEDIASUBTYPE_RGB4) { return "MEDIASUBTYPE_RGB4"; }
else if(type == MEDIASUBTYPE_RGB8) { return "MEDIASUBTYPE_RGB8"; }
else if(type == MEDIASUBTYPE_RGB555) { return "MEDIASUBTYPE_RGB555"; }
else if(type == MEDIASUBTYPE_RGB565) { return "MEDIASUBTYPE_RGB565"; }
else if(type == MEDIASUBTYPE_RGB24) { return "MEDIASUBTYPE_RGB24"; }
else if(type == MEDIASUBTYPE_RGB32) { return "MEDIASUBTYPE_RGB32"; }
else if(type == MEDIASUBTYPE_ARGB1555) { return "MEDIASUBTYPE_ARGB1555"; }
else if(type == MEDIASUBTYPE_ARGB32) { return "MEDIASUBTYPE_ARGB32"; }
else if(type == MEDIASUBTYPE_ARGB4444) { return "MEDIASUBTYPE_ARGB4444"; }
else if(type == MEDIASUBTYPE_A2R10G10B10) { return "MEDIASUBTYPE_A2R10G10B10"; }
else if(type == MEDIASUBTYPE_A2B10G10R10) { return "MEDIASUBTYPE_A2B10G10R10"; }
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd391027(v=vs.85).aspx
else if(type == MEDIASUBTYPE_AYUV) { return "MEDIASUBTYPE_AYUV"; }
else if(type == MEDIASUBTYPE_YUY2) { return "MEDIASUBTYPE_YUY2"; }
else if(type == MEDIASUBTYPE_UYVY) { return "MEDIASUBTYPE_UYVY"; }
else if(type == MEDIASUBTYPE_IMC1) { return "MEDIASUBTYPE_IMC1"; }
else if(type == MEDIASUBTYPE_IMC3) { return "MEDIASUBTYPE_IMC3"; }
else if(type == MEDIASUBTYPE_IMC2) { return "MEDIASUBTYPE_IMC2"; }
else if(type == MEDIASUBTYPE_IMC4) { return "MEDIASUBTYPE_IMC4"; }
else if(type == MEDIASUBTYPE_YV12) { return "MEDIASUBTYPE_YV12"; }
else if(type == MEDIASUBTYPE_NV12) { return "MEDIASUBTYPE_NV12"; }
else if(type == MEDIASUBTYPE_IF09) { return "MEDIASUBTYPE_IF09"; }
else if(type == MEDIASUBTYPE_IYUV) { return "MEDIASUBTYPE_IYUV"; } // same as MEDIASUBTYPE_I420
else if(type == MEDIASUBTYPE_Y211) { return "MEDIASUBTYPE_Y211"; }
else if(type == MEDIASUBTYPE_Y411) { return "MEDIASUBTYPE_Y411"; }
else if(type == MEDIASUBTYPE_Y41P) { return "MEDIASUBTYPE_Y41P"; }
else if(type == MEDIASUBTYPE_YVU9) { return "MEDIASUBTYPE_YVU9"; }
else if(type == MEDIASUBTYPE_YVYU) { return "MEDIASUBTYPE_YVYU"; }
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd757808(v=vs.85).aspx
// wmcodecdsp.h
/*
else if(type == MEDIASUBTYPE_AVC1) { return "MEDIASUBTYPE_AVC1"; }
else if(type == MEDIASUBTYPE_H264) { return "MEDIASUBTYPE_H264"; }
else if(type == MEDIASUBTYPE_h264) { return "MEDIASUBTYPE_h264"; }
else if(type == MEDIASUBTYPE_X264) { return "MEDIASUBTYPE_X264"; }
else if(type == MEDIASUBTYPE_x264) { return "MEDIASUBTYPE_x264"; }
*/
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd390688(v=vs.85).aspx
else if(type == MEDIASUBTYPE_CFCC) { return "MEDIASUBTYPE_CFCC"; }
else if(type == MEDIASUBTYPE_CLJR) { return "MEDIASUBTYPE_CLJR"; }
else if(type == MEDIASUBTYPE_CPLA) { return "MEDIASUBTYPE_CPLA"; }
else if(type == MEDIASUBTYPE_CLPL) { return "MEDIASUBTYPE_CLPL"; }
else if(type == MEDIASUBTYPE_IJPG) { return "MEDIASUBTYPE_IJPG"; }
else if(type == MEDIASUBTYPE_MDVF) { return "MEDIASUBTYPE_MDVF"; }
else if(type == MEDIASUBTYPE_MJPG) { return "MEDIASUBTYPE_MJPG"; }
else if(type == MEDIASUBTYPE_Overlay) { return "MEDIASUBTYPE_Overlay"; }
else if(type == MEDIASUBTYPE_Plum) { return "MEDIASUBTYPE_Plum"; }
else if(type == MEDIASUBTYPE_QTJpeg) { return "MEDIASUBTYPE_QTJpeg"; }
else if(type == MEDIASUBTYPE_QTMovie) { return "MEDIASUBTYPE_QTMovie"; }
else if(type == MEDIASUBTYPE_QTRle) { return "MEDIASUBTYPE_QTRle"; }
else if(type == MEDIASUBTYPE_QTRpza) { return "MEDIASUBTYPE_QTRpza"; }
else if(type == MEDIASUBTYPE_QTSmc) { return "MEDIASUBTYPE_QTSmc"; }
else if(type == MEDIASUBTYPE_TVMJ) { return "MEDIASUBTYPE_TVMJ"; }
else if(type == MEDIASUBTYPE_VPVBI) { return "MEDIASUBTYPE_VPVBI"; }
else if(type == MEDIASUBTYPE_VPVideo) { return "MEDIASUBTYPE_VPVideo"; }
else if(type == MEDIASUBTYPE_WAKE) { return "MEDIASUBTYPE_WAKE"; }
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd390712(v=vs.85).aspx
else if(type == MEDIASUBTYPE_MPEG1System) { return "MEDIASUBTYPE_MPEG1System"; }
else if(type == MEDIASUBTYPE_MPEG1VideoCD) { return "MEDIASUBTYPE_MPEG1VideoCD"; }
else if(type == MEDIASUBTYPE_MPEG1Packet) { return "MEDIASUBTYPE_MPEG1Packet"; }
else if(type == MEDIASUBTYPE_MPEG1Payload) { return "MEDIASUBTYPE_MPEG1Payload"; }
else if(type == MEDIASUBTYPE_MPEG1Packet) { return "MEDIASUBTYPE_MPEG1Packet"; }
else if(type == MEDIASUBTYPE_MPEG1Video) { return "MEDIASUBTYPE_ MPEG1Video"; }
else if(type == MEDIASUBTYPE_MPEG1Audio) { return "MEDIASUBTYPE_ MPEG1Audio"; }
else if(type == MEDIASUBTYPE_MPEG2_VIDEO) { return "MEDIASUBTYPE_MPEG2_VIDEO"; }
else if(type == MEDIASUBTYPE_DOLBY_AC3) { return "MEDIASUBTYPE_DOLBY_AC3"; }
else if(type == MEDIASUBTYPE_MPEG2_AUDIO) { return "MEDIASUBTYPE_MPEG2_AUDIO";}
else { return "UNKOWN NOT ADDED TO LIST.\n"; }
}
std::string VideoCaptureDirectShow::mediaFormatFormatTypeToString(GUID type) {
if(type == FORMAT_DvInfo) { return "FORMAT_DvInfo"; }
else if(type == FORMAT_MPEG2Video) { return "FORMAT_MPEG2Video"; }
else if(type == FORMAT_MPEGStreams) { return "FORMAT_MPEGStreams"; }
else if(type == FORMAT_MPEGVideo) { return "FORMAT_MPEGVideo"; }
else if(type == FORMAT_None) { return "FORMAT_None"; }
else if(type == FORMAT_VideoInfo) { return "FORMAT_VideoInfo"; }
else if(type == FORMAT_VideoInfo2) { return "FORMAT_VideoInfo2"; }
else if(type == FORMAT_WaveFormatEx) { return "FORMAT_WaveFormatEx"; }
else if(type == GUID_NULL) { return "GUID_NULL"; }
else { return "UNKOWN NOT ADDED TO LIST.\n"; }
}
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd377551(v=vs.85).aspx
int VideoCaptureDirectShow::saveGraphToFile() {
printf("------------- SAVING GRAPH --------------\n");
const WCHAR wszStreamName[] = L"ActiveMovieGraph";
const WCHAR path[] = L"data0.grf";
HRESULT hr;
IStorage *pStorage = NULL;
hr = StgCreateDocfile(
path,
STGM_CREATE | STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
0, &pStorage);
if(FAILED(hr))
{
return 0;
}
IStream *pStream;
hr = pStorage->CreateStream(
wszStreamName,
STGM_WRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE,
0, 0, &pStream);
if (FAILED(hr))
{
pStorage->Release();
return 0;
}
IPersistStream *pPersist = NULL;
graph->QueryInterface(IID_IPersistStream, (void**)&pPersist);
hr = pPersist->Save(pStream, TRUE);
pStream->Release();
pPersist->Release();
if (SUCCEEDED(hr))
{
hr = pStorage->Commit(STGC_DEFAULT);
}
pStorage->Release();
printf("------------- DONE --------------\n");
return 1;
}
#ifndef ROXLU_VIDEOCAPTURE_DIRECTSHOW_H
#define ROXLU_VIDEOCAPTURE_DIRECTSHOW_H
#pragma warning(once : 4995)
//#define _ATL_NO_UUIDOF
#include <stdio.h>
#include <windows.h>
#include <dshow.h>
#include <vector>
#include <string>
#include <videocapture/qedit.h>
#include <videocapture/rx_capture.h>
/**
* Experimental Video Capture on Windows
*
* Setup:
* - Add strmiids.lib as linker input
*
*
* References:
* - http://msdn.microsoft.com/en-us/library/windows/desktop/dd375472(v=vs.85).aspx
* - PIN_CATEGORY_PREVIEW: for viewing; frames are dropped ; a bit latency
* - PIN_CATEGORY_CAPTURE: faster; for file writing
* - ISampleGrabberCB implementation:
* http://msdn.microsoft.com/en-us/library/windows/desktop/dd376985(v=vs.85).aspx
*/
#define LOG(x) printf x
#define RETURN_IF_FAILED(hr, msg, rval) { if(FAILED(hr)) { printf(msg); return rval; } }
class VideoCaptureDirectShow;
class VideoCaptureDirectShowCallback : public ISampleGrabberCB {
public:
VideoCaptureDirectShowCallback(VideoCaptureDirectShow* vidcap);
~VideoCaptureDirectShowCallback();
HRESULT SampleCB(double timestamp, IMediaSample* sample); // non buffered i/o
HRESULT BufferCB(double timestamp, BYTE* buffer, long size); // buffered i/o
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
STDMETHODIMP QueryInterface(REFIID riid, void** refD);
bool new_frame;
private:
VideoCaptureDirectShow* vidcap;
CRITICAL_SECTION critical_section;
};
struct VideoCaptureDirectShowDevice {
std::string name;
};
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd376992(v=vs.85).aspx
enum VideoCaptureDirectShowCallbackTypes {
SAMPLED_CALLBACK = 0
,BUFFERED_CALLBACK = 1
};
class VideoCaptureDirectShow {
public:
VideoCaptureDirectShow(void);
~VideoCaptureDirectShow(void);
int listDevices();
int printVerboseInfo();
int openDevice(int dev);
int startCapture();
int stopCapture();
int getWidth();
int getHeight();
int setFrameCallback(rx_capture_frame_cb cb, void* user);
private:
void close();
bool initCaptureGraphBuilder();
void fillDeviceInformationList(IEnumMoniker* enumerator);
void nukeDownStream(IBaseFilter* filter); // disconnect all pins from this filter and children (cleanup)
void destroyGraph(); // cleans up the complete filter graph
void printAmMediaType(AM_MEDIA_TYPE* mt);
std::string mediaFormatMajorTypeToString(GUID type);
std::string mediaFormatSubTypeToString(GUID type);
std::string mediaFormatFormatTypeToString(GUID type);
int saveGraphToFile();
public:
rx_capture_frame_cb frame_cb;
void* frame_user;
VideoCaptureDirectShowCallback* sample_grabber_listener; // the implementation
private:
int width;
int height;
IGraphBuilder* graph;
ICaptureGraphBuilder2* builder;
IBaseFilter* capture_device_filter; // represents the found capture device
IMediaControl* media_control; // used to control the event
IMediaEvent* media_event;
IBaseFilter* sample_grabber_filter; // used to retrieve sample in our callback
ISampleGrabber* sample_grabber_iface; // necessary object to retrieve samples
IBaseFilter* null_renderer_filter; // end point of our graph
bool is_graph_setup;
static int num_com_init;
std::vector<VideoCaptureDirectShowDevice> devices;
int callback_type; // 0: SampleCB (should be faster but crashes somehow), 1: BufferCB
friend class VideoCaptureDirectShowCallback;
};
inline int VideoCaptureDirectShow::getWidth() {
return width;
}
inline int VideoCaptureDirectShow::getHeight() {
return height;
}
//inline int VideoCaptureDirectShow::setFrameCallback(videocapture_directshow_cb cb, void* user) {
inline int VideoCaptureDirectShow::setFrameCallback(rx_capture_frame_cb cb, void* user) {
frame_cb = cb;
frame_user = user;
return 1;
}
struct rx_capture_t {
VideoCaptureDirectShow* cap;
};
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment