27 #if defined(HAVE_DIRECTCAM) && !defined(CPPPARSER) 29 #ifndef WIN32_LEAN_AND_MEAN 30 #define WIN32_LEAN_AND_MEAN 1 35 #pragma warning(disable:4100) // warning C4100: unreferenced formal parameter 36 #pragma warning(disable:4201) // warning C4201: nonstandard extension used : nameless struct/union 37 #pragma warning(disable:4511) // warning C4511: copy constructor could not be generated 38 #pragma warning(disable:4512) // warning C4512: assignment operator could not be generated 39 #pragma warning(disable:4514) // warning C4514: "unreferenced inline function has been removed" 76 #import "libid:78530B68-61F9-11D2-8CAD-00A024580902" \
77 no_namespace named_guids raw_interfaces_only no_implementation \
78 exclude(
"_AMMediaType",
"_FilterState",
"IReferenceClock",
"IMediaFilter", \
79 "_PinDirection",
"IEnumMediaTypes",
"IFilterGraph",
"_FilterInfo", \
80 "IGraphBuilder",
"IBaseFilter",
"_PinInfo",
"IPin",
"IEnumPins", \
81 "IEnumFilters",
"IEnumMediaTypes",
"IAMSetErrorLog",
"IAMTimelineObj", \
82 "IMediaDet",
"IMediaSample",
"IPersistStream",
"IPersist",
"IStream", \
83 "ISequentialStream",
"_LARGE_INTEGER",
"_ULARGE_INTEGER", \
84 "tagSTATSTG",
"_FILETIME",
"IPropertyBag",
"IErrorLog")
93 static void find_all_webcams_ds();
94 friend void find_all_webcams_ds();
97 typedef pvector<PT(WebcamVideoDS)> WebcamVideoList;
99 static int media_score(AM_MEDIA_TYPE *media);
100 static int media_x(AM_MEDIA_TYPE *media);
101 static int media_y(AM_MEDIA_TYPE *media);
102 static int media_fps(AM_MEDIA_TYPE *media);
103 static void delete_media_type(AM_MEDIA_TYPE *media);
104 static string bstr_to_string(
const BSTR &source);
105 static string get_moniker_name(IMoniker *pMoniker);
106 static void add_device(WebcamVideoList &list, IMoniker *pMoniker, AM_MEDIA_TYPE *media);
111 AM_MEDIA_TYPE *_media;
113 friend class WebcamVideoCursorDS;
119 static void init_type() {
120 WebcamVideo::init_type();
122 WebcamVideo::get_class_type());
125 return get_class_type();
127 virtual TypeHandle force_init_type() {init_type();
return get_class_type();}
143 WebcamVideoCursorDS(WebcamVideoDS *src);
144 virtual ~WebcamVideoCursorDS();
145 virtual PT(
Buffer) fetch_buffer();
150 class CSampleGrabberCB :
public ISampleGrabberCB
153 WebcamVideoCursorDS *_host;
155 ULONG __stdcall AddRef() {
return 2; }
156 ULONG __stdcall Release() {
return 1; }
158 HRESULT __stdcall QueryInterface(REFIID riid,
void ** ppv);
159 HRESULT __stdcall SampleCB(
double SampleTime, IMediaSample *pSample);
160 HRESULT __stdcall BufferCB(
double dblSampleTime, BYTE *pBuffer,
long lBufferSize);
163 unsigned char *_buffer;
164 IMediaSample *_saved;
166 IGraphBuilder *_pGraphBuilder;
167 ICaptureGraphBuilder2 *_pCaptureBuilder;
168 IBaseFilter *_pSrcFilter;
169 IAMStreamConfig *_pStreamConfig;
170 ISampleGrabber *_pSampleGrabber;
171 IBaseFilter *_pStreamRenderer;
172 IMediaControl *_pMediaCtrl;
174 CSampleGrabberCB _sample_cb;
180 static void init_type() {
181 MovieVideoCursor::init_type();
183 MovieVideoCursor::get_class_type());
186 return get_class_type();
188 virtual TypeHandle force_init_type() {init_type();
return get_class_type();}
201 media_score(AM_MEDIA_TYPE *media) {
202 const GUID &subtype = media->subtype;
203 if (subtype == MEDIASUBTYPE_RGB24)
return 1;
204 if (subtype == MEDIASUBTYPE_RGB32)
return 2;
205 if (subtype == MEDIASUBTYPE_RGB555)
return 3;
206 if (subtype == MEDIASUBTYPE_RGB565)
return 3;
214 media_x(AM_MEDIA_TYPE *media) {
215 VIDEOINFOHEADER *header = (VIDEOINFOHEADER*)(media->pbFormat);
216 return (header->bmiHeader.biWidth);
223 media_y(AM_MEDIA_TYPE *media) {
224 VIDEOINFOHEADER *header = (VIDEOINFOHEADER*)(media->pbFormat);
225 return (header->bmiHeader.biHeight);
232 media_fps(AM_MEDIA_TYPE *media) {
233 VIDEOINFOHEADER *header = (VIDEOINFOHEADER*)(media->pbFormat);
234 return int(10000000.0 / (header->AvgTimePerFrame));
241 delete_media_type(AM_MEDIA_TYPE *pmt) {
242 if (pmt ==
nullptr) {
245 if (pmt->cbFormat != 0) {
246 CoTaskMemFree((PVOID)pmt->pbFormat);
248 pmt->pbFormat =
nullptr;
250 if (pmt->pUnk !=
nullptr) {
252 pmt->pUnk->Release();
261 string WebcamVideoDS::
262 bstr_to_string(
const BSTR &source) {
265 while( source[count] != 0x00 ) {
266 res.push_back(source[count]);
275 string WebcamVideoDS::
276 get_moniker_name(IMoniker *pMoniker) {
277 string res =
"Unknown Device";
278 IPropertyBag *propBag=
nullptr;
279 VARIANT name; HRESULT hResult;
280 pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (
void**)&propBag);
282 hResult = propBag->Read(L
"FriendlyName", &name, 0);
283 if (!hResult != S_OK) {
284 res = bstr_to_string(name.bstrVal);
287 hResult = propBag->Read(L
"Description", &name, 0);
288 if (!hResult != S_OK) {
289 res = bstr_to_string(name.bstrVal);
305 add_device(WebcamVideoList &list, IMoniker *pMoniker, AM_MEDIA_TYPE *media) {
306 for (
int i=0; i<(int)list.size(); i++) {
307 if ((list[i]->_moniker == pMoniker)&&
308 (media_x(list[i]->_media) == media_x(media))&&
309 (media_y(list[i]->_media) == media_y(media))) {
310 int oldscore = media_score(list[i]->_media);
311 if (media_score(media) < oldscore) {
312 delete_media_type(list[i]->_media);
313 list[i]->_media = media;
315 delete_media_type(media);
320 PT(WebcamVideoDS) wc =
new WebcamVideoDS;
321 wc->set_name(get_moniker_name(pMoniker));
322 wc->_size_x = media_x(media);
323 wc->_size_y = media_y(media);
324 wc->_fps = media_fps(media);
325 wc->_moniker = pMoniker;
328 cerr <<
"Added device: DirectShow: " << wc <<
"\n";
336 find_all_webcams_ds() {
338 pvector <PT(WebcamVideoDS)> list;
340 ICreateDevEnum *pCreateDevEnum=
nullptr;
341 IEnumMoniker *pEnumMoniker=
nullptr;
342 IGraphBuilder *pGraphBuilder=
nullptr;
343 ICaptureGraphBuilder2 *pCaptureGraphBuilder2=
nullptr;
344 IMoniker *pMoniker=
nullptr;
345 IBaseFilter *pBaseFilter=
nullptr;
346 IAMStreamConfig *pStreamConfig=
nullptr;
350 hResult=CoCreateInstance(CLSID_FilterGraph,
nullptr, CLSCTX_INPROC,
351 IID_IGraphBuilder,(
void**)&pGraphBuilder);
352 if (hResult != S_OK)
goto cleanup;
353 hResult=CoCreateInstance(CLSID_CaptureGraphBuilder2,
nullptr, CLSCTX_INPROC,
354 IID_ICaptureGraphBuilder2, (
void**)&pCaptureGraphBuilder2);
355 if (hResult != S_OK)
goto cleanup;
356 hResult = pCaptureGraphBuilder2->SetFiltergraph(pGraphBuilder);
357 if (hResult != S_OK)
goto cleanup;
358 hResult=CoCreateInstance(CLSID_SystemDeviceEnum,
nullptr, CLSCTX_INPROC_SERVER,
359 IID_ICreateDevEnum, (
void**)&pCreateDevEnum);
360 if (hResult != S_OK)
goto cleanup;
361 hResult=pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
363 if(hResult != S_OK)
goto cleanup;
366 if (pMoniker) { pMoniker->Release(); pMoniker=0; }
367 if (pBaseFilter) { pBaseFilter->Release(); pBaseFilter=0; }
368 if (pStreamConfig) { pStreamConfig->Release(); pStreamConfig=0; }
370 hResult = pEnumMoniker->Next(1, &pMoniker, &cFetched);
371 if (hResult != S_OK)
break;
373 hResult = pMoniker->BindToObject(
nullptr,
nullptr,IID_IBaseFilter, (
void**)&pBaseFilter);
374 if (hResult != S_OK)
continue;
375 hResult = pCaptureGraphBuilder2->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, pBaseFilter,
376 IID_IAMStreamConfig, (
void **)&pStreamConfig);
377 if (hResult != S_OK)
continue;
379 hResult = pStreamConfig->GetNumberOfCapabilities(&iCount, &iSize);
380 if (hResult != S_OK || (iSize !=
sizeof(VIDEO_STREAM_CONFIG_CAPS)))
continue;
381 for (
int iFormat=0; iFormat<iCount; iFormat++) {
382 AM_MEDIA_TYPE *mtype;
383 VIDEO_STREAM_CONFIG_CAPS caps;
384 hResult = pStreamConfig->GetStreamCaps(iFormat, &mtype, (BYTE*)&caps);
385 if (mtype->majortype == MEDIATYPE_Video) {
386 VIDEOINFOHEADER *header = (VIDEOINFOHEADER*)(mtype->pbFormat);
387 header->bmiHeader.biWidth = caps.MaxOutputSize.cx;
388 header->bmiHeader.biHeight = caps.MaxOutputSize.cy;
389 add_device(list, pMoniker, mtype);
397 if (pCreateDevEnum) { pCreateDevEnum->Release(); pCreateDevEnum=0; }
398 if (pEnumMoniker) { pEnumMoniker->Release(); pEnumMoniker=0; }
399 if (pGraphBuilder) { pGraphBuilder->Release(); pGraphBuilder=0; }
400 if (pCaptureGraphBuilder2) { pCaptureGraphBuilder2->Release(); pCaptureGraphBuilder2=0; }
401 if (pMoniker) { pMoniker->Release(); pMoniker=0; }
402 if (pBaseFilter) { pBaseFilter->Release(); pBaseFilter=0; }
403 if (pStreamConfig) { pStreamConfig->Release(); pStreamConfig=0; }
405 for (
int i=0; i<(int)list.size(); i++) {
406 WebcamVideoDS *obj = list[i];
407 _all_webcams.push_back(obj);
411 void find_all_webcams_ds() {
412 WebcamVideoDS::init_type();
413 WebcamVideoCursorDS::init_type();
414 WebcamVideoDS::find_all_webcams_ds();
422 return new WebcamVideoCursorDS(
this);
428 WebcamVideoCursorDS::
429 WebcamVideoCursorDS(WebcamVideoDS *src) :
431 _pGraphBuilder(nullptr),
432 _pCaptureBuilder(nullptr),
433 _pSrcFilter(nullptr),
434 _pStreamConfig(nullptr),
435 _pStreamRenderer(nullptr),
438 AM_MEDIA_TYPE mediaType;
439 VIDEOINFOHEADER *pVideoInfo;
443 hResult=CoCreateInstance(CLSID_FilterGraph,
nullptr, CLSCTX_INPROC,
444 IID_IGraphBuilder,(
void**)&_pGraphBuilder);
445 if(hResult != S_OK) { cleanup();
return; }
447 hResult=CoCreateInstance(CLSID_CaptureGraphBuilder2,
nullptr, CLSCTX_INPROC,
448 IID_ICaptureGraphBuilder2, (
void**)&_pCaptureBuilder);
449 if(hResult != S_OK) { cleanup();
return; }
451 _pCaptureBuilder->SetFiltergraph(_pGraphBuilder);
452 cerr <<
" IID_IGraphBuilder & IID_ICaptureGraphBuilder2 are established.\n";
454 hResult=_pGraphBuilder->QueryInterface(IID_IMediaControl, (
void **)&_pMediaCtrl);
456 { cerr <<
" Can not get the IID_IMediaControl interface!";
458 cerr <<
" IID_IMediaControl interface is acquired.\n";
460 src->_moniker->BindToObject(
nullptr,
nullptr,IID_IBaseFilter, (
void**)&_pSrcFilter);
461 if(_pSrcFilter ==
nullptr)
462 { cerr <<
" Such capture device is not found.\n";
464 cerr <<
" The capture filter is acquired.\n";
466 hResult=_pGraphBuilder->AddFilter(_pSrcFilter, L
"Capture Filter");
468 { cerr <<
" The capture filter can not be added to the graph.\n";
470 cerr <<
" The capture filter has been added to the graph.\n";
473 hResult = _pCaptureBuilder->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, _pSrcFilter,
474 IID_IAMStreamConfig, (
void **)&_pStreamConfig);
475 if (hResult != S_OK) {
476 cerr <<
"Could not get stream config interface.\n";
479 hResult = _pStreamConfig->SetFormat(src->_media);
480 if (hResult != S_OK) {
481 cerr <<
"Could not select desired video resolution\n";
485 hResult = CoCreateInstance(CLSID_SampleGrabber,
nullptr, CLSCTX_INPROC, IID_PPV_ARGS(&_pSampleGrabber));
487 { cerr <<
" Can not create the sample grabber, maybe qedit.dll is not registered?";
493 IBaseFilter *pGrabberFilter =
nullptr;
494 hResult = _pSampleGrabber->QueryInterface(IID_PPV_ARGS(&pGrabberFilter));
495 cerr <<
" IID_IBaseFilter of CLSID_SampleGrabber is acquired.\n";
497 ZeroMemory(&mediaType,
sizeof(AM_MEDIA_TYPE));
498 mediaType.majortype=MEDIATYPE_Video;
499 mediaType.subtype=MEDIASUBTYPE_RGB24;
500 hResult=_pSampleGrabber->SetMediaType(&mediaType);
502 { cerr <<
" Fail to set the media type!";
504 cerr <<
" The media type of the sample grabber is set 24-bit RGB.\n";
506 hResult=_pGraphBuilder->AddFilter(pGrabberFilter, L
"Sample Grabber");
508 { cerr <<
" Fail to add the sample grabber to the graph.";
510 cerr <<
" The sample grabber has been added to the graph.\n";
513 hResult = CoCreateInstance(CLSID_NullRenderer,
nullptr, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (
void**)&_pStreamRenderer);
515 { cerr <<
" Can not create the null renderer.";
517 cerr <<
" IID_IBaseFilter of CLSID_NullRenderer is acquired.\n";
519 hResult=_pGraphBuilder->AddFilter(_pStreamRenderer, L
"Stream Renderer");
521 { cerr <<
" Fail to add the Null Renderer to the graph.";
523 cerr <<
" The Null Renderer has been added to the graph.\n";
525 hResult=_pCaptureBuilder->RenderStream(&PIN_CATEGORY_CAPTURE,
526 &MEDIATYPE_Video, _pSrcFilter, pGrabberFilter, _pStreamRenderer);
527 if(hResult != S_OK) {
528 cerr <<
" ICaptureGraphBuilder2::RenderStream() can not connect the pins\n";
532 hResult=_pSampleGrabber->GetConnectedMediaType(&mediaType);
533 if(hResult != S_OK) {
534 cerr <<
" Failed to read the connected media type.";
554 pVideoInfo=(VIDEOINFOHEADER*)mediaType.pbFormat;
555 _size_x = pVideoInfo->bmiHeader.biWidth;
556 _size_y = pVideoInfo->bmiHeader.biHeight;
557 cerr <<
"Connected media type " << _size_x <<
" x " << _size_y <<
"\n";
559 _sample_cb._host =
this;
563 _can_seek_fast =
false;
566 _buffer =
new unsigned char[_size_x * _size_y * 3];
569 if(mediaType.cbFormat != 0) {
570 CoTaskMemFree((PVOID)mediaType.pbFormat);
571 mediaType.cbFormat=0;
572 mediaType.pbFormat=
nullptr;
575 if(mediaType.pUnk !=
nullptr) {
576 mediaType.pUnk->Release();
577 mediaType.pUnk=
nullptr;
580 if(pGrabberFilter !=
nullptr) {
581 pGrabberFilter->Release();
582 pGrabberFilter=
nullptr;
585 _pSampleGrabber->SetBufferSamples(FALSE);
586 _pSampleGrabber->SetOneShot(FALSE);
588 hResult=_pSampleGrabber->SetCallback(&_sample_cb, 0);
589 if(hResult != S_OK) {
590 cerr <<
" Can not set the callback interface!";
600 void WebcamVideoCursorDS::
611 if(_pMediaCtrl) { _pMediaCtrl->Release(); _pMediaCtrl=
nullptr; }
612 if(_pCaptureBuilder) { _pCaptureBuilder->Release(); _pCaptureBuilder=
nullptr; }
613 if(_pGraphBuilder) { _pGraphBuilder->Release(); _pGraphBuilder=
nullptr; }
614 if(_pSampleGrabber) { _pSampleGrabber->Release(); _pSampleGrabber=
nullptr; }
615 if(_pStreamRenderer) { _pStreamRenderer->Release(); _pStreamRenderer=
nullptr; }
616 if(_pSrcFilter) { _pSrcFilter->Release(); _pSrcFilter=
nullptr; }
617 if(_pStreamConfig) { _pStreamConfig->Release(); _pStreamConfig=
nullptr; }
623 WebcamVideoCursorDS::
624 ~WebcamVideoCursorDS() {
637 Buffer *buffer = get_standard_buffer();
638 unsigned char *block = buffer->_block;
641 int pixels = _size_x * _size_y;
642 HRESULT res = _saved->GetPointer(&ptr);
644 int size = _saved->GetActualDataLength();
645 if (size == pixels * 3) {
646 memcpy(block, ptr, pixels * 3);
651 int pixels = _size_x * _size_y;
652 memcpy(block, _buffer, pixels * 3);
663 HRESULT __stdcall WebcamVideoCursorDS::CSampleGrabberCB::QueryInterface(REFIID riid,
void **ppv)
665 if((riid == IID_ISampleGrabberCB) || (riid == IID_IUnknown)) {
666 *ppv=(
void *)static_cast<ISampleGrabberCB *> (
this);
669 return E_NOINTERFACE;
676 HRESULT __stdcall WebcamVideoCursorDS::CSampleGrabberCB::SampleCB(
double SampleTime, IMediaSample *pSample)
684 _host->_saved = pSample;
687 int pixels = _host->_size_x * _host->_size_y;
688 HRESULT res = pSample->GetPointer(&ptr);
690 int size = pSample->GetActualDataLength();
691 if (size == pixels * 3) {
692 memcpy(_host->_buffer, ptr, size);
697 _host->_ready =
true;
704 HRESULT __stdcall WebcamVideoCursorDS::CSampleGrabberCB::BufferCB(
double dblSampleTime, BYTE *pBuffer,
long lBufferSize)
722 #endif // HAVE_DIRECTSHOW void register_type(TypeHandle &type_handle, const std::string &name)
This inline function is just a convenient way to call TypeRegistry::register_type(),...
Allows you to open a webcam or other video capture device as a video stream.
This is our own Panda specialization on the default STL vector.
A MovieVideo is actually any source that provides a sequence of video frames.
TypeHandle is the identifier used to differentiate C++ class types.