32 #if defined(HAVE_DIRECTCAM) && !defined(CPPPARSER)
34 #ifndef WIN32_LEAN_AND_MEAN
35 #define WIN32_LEAN_AND_MEAN 1
40 #pragma warning(disable:4100) // warning C4100: unreferenced formal parameter
41 #pragma warning(disable:4201) // warning C4201: nonstandard extension used : nameless struct/union
42 #pragma warning(disable:4511) // warning C4511: copy constructor could not be generated
43 #pragma warning(disable:4512) // warning C4512: assignment operator could not be generated
44 #pragma warning(disable:4514) // warning C4514: "unreferenced inline function has been removed"
79 #import "libid:78530B68-61F9-11D2-8CAD-00A024580902" \
80 no_namespace named_guids raw_interfaces_only no_implementation \
81 exclude(
"_AMMediaType",
"_FilterState",
"IReferenceClock",
"IMediaFilter", \
82 "_PinDirection",
"IEnumMediaTypes",
"IFilterGraph",
"_FilterInfo", \
83 "IGraphBuilder",
"IBaseFilter",
"_PinInfo",
"IPin",
"IEnumPins", \
84 "IEnumFilters",
"IEnumMediaTypes",
"IAMSetErrorLog",
"IAMTimelineObj", \
85 "IMediaDet",
"IMediaSample",
"IPersistStream",
"IPersist",
"IStream", \
86 "ISequentialStream",
"_LARGE_INTEGER",
"_ULARGE_INTEGER", \
87 "tagSTATSTG",
"_FILETIME",
"IPropertyBag",
"IErrorLog")
97 static void find_all_webcams_ds();
98 friend void find_all_webcams_ds();
103 static int media_score(AM_MEDIA_TYPE *media);
104 static int media_x(AM_MEDIA_TYPE *media);
105 static int media_y(AM_MEDIA_TYPE *media);
106 static int media_fps(AM_MEDIA_TYPE *media);
107 static void delete_media_type(AM_MEDIA_TYPE *media);
108 static string bstr_to_string(
const BSTR &source);
109 static string get_moniker_name(IMoniker *pMoniker);
110 static void add_device(WebcamVideoList &list, IMoniker *pMoniker, AM_MEDIA_TYPE *media);
115 AM_MEDIA_TYPE *_media;
117 friend class WebcamVideoCursorDS;
123 static void init_type() {
124 WebcamVideo::init_type();
125 register_type(_type_handle,
"WebcamVideoDS",
126 WebcamVideo::get_class_type());
129 return get_class_type();
131 virtual TypeHandle force_init_type() {init_type();
return get_class_type();}
148 WebcamVideoCursorDS(WebcamVideoDS *src);
149 virtual ~WebcamVideoCursorDS();
150 virtual PT(
Buffer) fetch_buffer();
155 class CSampleGrabberCB : public ISampleGrabberCB
158 WebcamVideoCursorDS *_host;
160 ULONG __stdcall AddRef() {
return 2; }
161 ULONG __stdcall Release() {
return 1; }
163 HRESULT __stdcall QueryInterface(REFIID riid,
void ** ppv);
164 HRESULT __stdcall SampleCB(
double SampleTime, IMediaSample *pSample);
165 HRESULT __stdcall BufferCB(
double dblSampleTime, BYTE *pBuffer,
long lBufferSize);
168 unsigned char *_buffer;
169 IMediaSample *_saved;
171 IGraphBuilder *_pGraphBuilder;
172 ICaptureGraphBuilder2 *_pCaptureBuilder;
173 IBaseFilter *_pSrcFilter;
174 IAMStreamConfig *_pStreamConfig;
175 ISampleGrabber *_pSampleGrabber;
176 IBaseFilter *_pStreamRenderer;
177 IMediaControl *_pMediaCtrl;
179 CSampleGrabberCB _sample_cb;
185 static void init_type() {
186 MovieVideoCursor::init_type();
187 register_type(_type_handle,
"WebcamVideoCursorDS",
188 MovieVideoCursor::get_class_type());
191 return get_class_type();
193 virtual TypeHandle force_init_type() {init_type();
return get_class_type();}
208 media_score(AM_MEDIA_TYPE *media) {
209 const GUID &subtype = media->subtype;
210 if (subtype == MEDIASUBTYPE_RGB24)
return 1;
211 if (subtype == MEDIASUBTYPE_RGB32)
return 2;
212 if (subtype == MEDIASUBTYPE_RGB555)
return 3;
213 if (subtype == MEDIASUBTYPE_RGB565)
return 3;
223 media_x(AM_MEDIA_TYPE *media) {
224 VIDEOINFOHEADER *header = (VIDEOINFOHEADER*)(media->pbFormat);
225 return (header->bmiHeader.biWidth);
234 media_y(AM_MEDIA_TYPE *media) {
235 VIDEOINFOHEADER *header = (VIDEOINFOHEADER*)(media->pbFormat);
236 return (header->bmiHeader.biHeight);
245 media_fps(AM_MEDIA_TYPE *media) {
246 VIDEOINFOHEADER *header = (VIDEOINFOHEADER*)(media->pbFormat);
247 return int(10000000.0 / (header->AvgTimePerFrame));
256 delete_media_type(AM_MEDIA_TYPE *pmt) {
260 if (pmt->cbFormat != 0) {
261 CoTaskMemFree((PVOID)pmt->pbFormat);
263 pmt->pbFormat = NULL;
265 if (pmt->pUnk != NULL) {
267 pmt->pUnk->Release();
278 string WebcamVideoDS::
279 bstr_to_string(
const BSTR &source) {
282 while( source[count] != 0x00 ) {
283 res.push_back(source[count]);
294 string WebcamVideoDS::
295 get_moniker_name(IMoniker *pMoniker) {
296 string res =
"Unknown Device";
297 IPropertyBag *propBag=NULL;
298 VARIANT name; HRESULT hResult;
299 pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (
void**)&propBag);
301 hResult = propBag->Read(L
"FriendlyName", &name, 0);
302 if (!hResult != S_OK) {
303 res = bstr_to_string(name.bstrVal);
306 hResult = propBag->Read(L
"Description", &name, 0);
307 if (!hResult != S_OK) {
308 res = bstr_to_string(name.bstrVal);
327 add_device(WebcamVideoList &list, IMoniker *pMoniker, AM_MEDIA_TYPE *media) {
328 for (
int i=0; i<(int)list.size(); i++) {
329 if ((list[i]->_moniker == pMoniker)&&
330 (media_x(list[i]->_media) == media_x(media))&&
331 (media_y(list[i]->_media) == media_y(media))) {
332 int oldscore = media_score(list[i]->_media);
333 if (media_score(media) < oldscore) {
334 delete_media_type(list[i]->_media);
335 list[i]->_media = media;
337 delete_media_type(media);
342 PT(WebcamVideoDS) wc = new WebcamVideoDS;
343 wc->set_name(get_moniker_name(pMoniker));
344 wc->_size_x = media_x(media);
345 wc->_size_y = media_y(media);
346 wc->_fps = media_fps(media);
347 wc->_moniker = pMoniker;
350 cerr << "Added device: DirectShow: " << wc << "\n";
361 find_all_webcams_ds() {
365 ICreateDevEnum *pCreateDevEnum=NULL;
366 IEnumMoniker *pEnumMoniker=NULL;
367 IGraphBuilder *pGraphBuilder=NULL;
368 ICaptureGraphBuilder2 *pCaptureGraphBuilder2=NULL;
369 IMoniker *pMoniker=NULL;
370 IBaseFilter *pBaseFilter=NULL;
371 IAMStreamConfig *pStreamConfig=NULL;
375 hResult=CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC,
376 IID_IGraphBuilder,(
void**)&pGraphBuilder);
377 if (hResult != S_OK)
goto cleanup;
378 hResult=CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC,
379 IID_ICaptureGraphBuilder2, (
void**)&pCaptureGraphBuilder2);
380 if (hResult != S_OK)
goto cleanup;
381 hResult = pCaptureGraphBuilder2->SetFiltergraph(pGraphBuilder);
382 if (hResult != S_OK)
goto cleanup;
383 hResult=CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
384 IID_ICreateDevEnum, (
void**)&pCreateDevEnum);
385 if (hResult != S_OK)
goto cleanup;
386 hResult=pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
388 if(hResult != S_OK)
goto cleanup;
391 if (pMoniker) { pMoniker->Release(); pMoniker=0; }
392 if (pBaseFilter) { pBaseFilter->Release(); pBaseFilter=0; }
393 if (pStreamConfig) { pStreamConfig->Release(); pStreamConfig=0; }
395 hResult = pEnumMoniker->Next(1, &pMoniker, &cFetched);
396 if (hResult != S_OK)
break;
398 hResult = pMoniker->BindToObject(NULL,NULL,IID_IBaseFilter, (
void**)&pBaseFilter);
399 if (hResult != S_OK)
continue;
400 hResult = pCaptureGraphBuilder2->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, pBaseFilter,
401 IID_IAMStreamConfig, (
void **)&pStreamConfig);
402 if (hResult != S_OK)
continue;
404 hResult = pStreamConfig->GetNumberOfCapabilities(&iCount, &iSize);
405 if (hResult != S_OK || (iSize !=
sizeof(VIDEO_STREAM_CONFIG_CAPS)))
continue;
406 for (
int iFormat=0; iFormat<iCount; iFormat++) {
407 AM_MEDIA_TYPE *mtype;
408 VIDEO_STREAM_CONFIG_CAPS caps;
409 hResult = pStreamConfig->GetStreamCaps(iFormat, &mtype, (BYTE*)&caps);
410 if (mtype->majortype == MEDIATYPE_Video) {
411 VIDEOINFOHEADER *header = (VIDEOINFOHEADER*)(mtype->pbFormat);
412 header->bmiHeader.biWidth = caps.MaxOutputSize.cx;
413 header->bmiHeader.biHeight = caps.MaxOutputSize.cy;
414 add_device(list, pMoniker, mtype);
422 if (pCreateDevEnum) { pCreateDevEnum->Release(); pCreateDevEnum=0; }
423 if (pEnumMoniker) { pEnumMoniker->Release(); pEnumMoniker=0; }
424 if (pGraphBuilder) { pGraphBuilder->Release(); pGraphBuilder=0; }
425 if (pCaptureGraphBuilder2) { pCaptureGraphBuilder2->Release(); pCaptureGraphBuilder2=0; }
426 if (pMoniker) { pMoniker->Release(); pMoniker=0; }
427 if (pBaseFilter) { pBaseFilter->Release(); pBaseFilter=0; }
428 if (pStreamConfig) { pStreamConfig->Release(); pStreamConfig=0; }
430 for (
int i=0; i<(int)list.size(); i++) {
431 WebcamVideoDS *obj = list[i];
432 _all_webcams.push_back(obj);
436 void find_all_webcams_ds() {
437 WebcamVideoDS::init_type();
438 WebcamVideoCursorDS::init_type();
439 WebcamVideoDS::find_all_webcams_ds();
449 return new WebcamVideoCursorDS(
this);
457 WebcamVideoCursorDS::
458 WebcamVideoCursorDS(WebcamVideoDS *src) :
460 _pGraphBuilder(NULL),
461 _pCaptureBuilder(NULL),
463 _pStreamConfig(NULL),
464 _pStreamRenderer(NULL),
467 AM_MEDIA_TYPE mediaType;
468 VIDEOINFOHEADER *pVideoInfo;
472 hResult=CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC,
473 IID_IGraphBuilder,(
void**)&_pGraphBuilder);
474 if(hResult != S_OK) { cleanup();
return; }
476 hResult=CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC,
477 IID_ICaptureGraphBuilder2, (
void**)&_pCaptureBuilder);
478 if(hResult != S_OK) { cleanup();
return; }
480 _pCaptureBuilder->SetFiltergraph(_pGraphBuilder);
481 cerr <<
" IID_IGraphBuilder & IID_ICaptureGraphBuilder2 are established.\n";
483 hResult=_pGraphBuilder->QueryInterface(IID_IMediaControl, (
void **)&_pMediaCtrl);
485 { cerr <<
" Can not get the IID_IMediaControl interface!";
487 cerr <<
" IID_IMediaControl interface is acquired.\n";
489 src->_moniker->BindToObject(NULL,NULL,IID_IBaseFilter, (
void**)&_pSrcFilter);
490 if(_pSrcFilter == NULL)
491 { cerr <<
" Such capture device is not found.\n";
493 cerr <<
" The capture filter is acquired.\n";
495 hResult=_pGraphBuilder->AddFilter(_pSrcFilter, L
"Capture Filter");
497 { cerr <<
" The capture filter can not be added to the graph.\n";
499 cerr <<
" The capture filter has been added to the graph.\n";
502 hResult = _pCaptureBuilder->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, _pSrcFilter,
503 IID_IAMStreamConfig, (
void **)&_pStreamConfig);
504 if (hResult != S_OK) {
505 cerr <<
"Could not get stream config interface.\n";
508 hResult = _pStreamConfig->SetFormat(src->_media);
509 if (hResult != S_OK) {
510 cerr <<
"Could not select desired video resolution\n";
514 hResult = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC, IID_PPV_ARGS(&_pSampleGrabber));
516 { cerr <<
" Can not create the sample grabber, maybe qedit.dll is not registered?";
522 IBaseFilter *pGrabberFilter = NULL;
523 hResult = _pSampleGrabber->QueryInterface(IID_PPV_ARGS(&pGrabberFilter));
524 cerr <<
" IID_IBaseFilter of CLSID_SampleGrabber is acquired.\n";
526 ZeroMemory(&mediaType,
sizeof(AM_MEDIA_TYPE));
527 mediaType.majortype=MEDIATYPE_Video;
528 mediaType.subtype=MEDIASUBTYPE_RGB24;
529 hResult=_pSampleGrabber->SetMediaType(&mediaType);
531 { cerr <<
" Fail to set the media type!";
533 cerr <<
" The media type of the sample grabber is set 24-bit RGB.\n";
535 hResult=_pGraphBuilder->AddFilter(pGrabberFilter, L
"Sample Grabber");
537 { cerr <<
" Fail to add the sample grabber to the graph.";
539 cerr <<
" The sample grabber has been added to the graph.\n";
542 hResult = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (
void**)&_pStreamRenderer);
544 { cerr <<
" Can not create the null renderer.";
546 cerr <<
" IID_IBaseFilter of CLSID_NullRenderer is acquired.\n";
548 hResult=_pGraphBuilder->AddFilter(_pStreamRenderer, L
"Stream Renderer");
550 { cerr <<
" Fail to add the Null Renderer to the graph.";
552 cerr <<
" The Null Renderer has been added to the graph.\n";
554 hResult=_pCaptureBuilder->RenderStream(&PIN_CATEGORY_CAPTURE,
555 &MEDIATYPE_Video, _pSrcFilter, pGrabberFilter, _pStreamRenderer);
556 if(hResult != S_OK) {
557 cerr <<
" ICaptureGraphBuilder2::RenderStream() can not connect the pins\n";
561 hResult=_pSampleGrabber->GetConnectedMediaType(&mediaType);
562 if(hResult != S_OK) {
563 cerr <<
" Failed to read the connected media type.";
595 pVideoInfo=(VIDEOINFOHEADER*)mediaType.pbFormat;
596 _size_x = pVideoInfo->bmiHeader.biWidth;
597 _size_y = pVideoInfo->bmiHeader.biHeight;
598 cerr <<
"Connected media type " << _size_x <<
" x " << _size_y <<
"\n";
600 _sample_cb._host =
this;
604 _can_seek_fast =
false;
607 _buffer =
new unsigned char[_size_x * _size_y * 3];
610 if(mediaType.cbFormat != 0) {
611 CoTaskMemFree((PVOID)mediaType.pbFormat);
612 mediaType.cbFormat=0;
613 mediaType.pbFormat=NULL;
616 if(mediaType.pUnk != NULL) {
617 mediaType.pUnk->Release();
621 if(pGrabberFilter != NULL) {
622 pGrabberFilter->Release();
626 _pSampleGrabber->SetBufferSamples(FALSE);
627 _pSampleGrabber->SetOneShot(FALSE);
629 hResult=_pSampleGrabber->SetCallback(&_sample_cb, 0);
630 if(hResult != S_OK) {
631 cerr <<
" Can not set the callback interface!";
643 void WebcamVideoCursorDS::
654 if(_pMediaCtrl) { _pMediaCtrl->Release(); _pMediaCtrl=NULL; }
655 if(_pCaptureBuilder) { _pCaptureBuilder->Release(); _pCaptureBuilder=NULL; }
656 if(_pGraphBuilder) { _pGraphBuilder->Release(); _pGraphBuilder=NULL; }
657 if(_pSampleGrabber) { _pSampleGrabber->Release(); _pSampleGrabber=NULL; }
658 if(_pStreamRenderer) { _pStreamRenderer->Release(); _pStreamRenderer=NULL; }
659 if(_pSrcFilter) { _pSrcFilter->Release(); _pSrcFilter=NULL; }
660 if(_pStreamConfig) { _pStreamConfig->Release(); _pStreamConfig=NULL; }
668 WebcamVideoCursorDS::
669 ~WebcamVideoCursorDS() {
684 Buffer *buffer = get_standard_buffer();
685 unsigned char *block = buffer->_block;
688 int pixels = _size_x * _size_y;
689 HRESULT res = _saved->GetPointer(&ptr);
691 int size = _saved->GetActualDataLength();
692 if (size == pixels * 3) {
693 memcpy(block, ptr, pixels * 3);
698 int pixels = _size_x * _size_y;
699 memcpy(block, _buffer, pixels * 3);
712 HRESULT __stdcall WebcamVideoCursorDS::CSampleGrabberCB::QueryInterface(REFIID riid,
void **ppv)
714 if((riid == IID_ISampleGrabberCB) || (riid == IID_IUnknown)) {
715 *ppv=(
void *)static_cast<ISampleGrabberCB *> (
this);
718 return E_NOINTERFACE;
727 HRESULT __stdcall WebcamVideoCursorDS::CSampleGrabberCB::SampleCB(
double SampleTime, IMediaSample *pSample)
735 _host->_saved = pSample;
738 int pixels = _host->_size_x * _host->_size_y;
739 HRESULT res = pSample->GetPointer(&ptr);
741 int size = pSample->GetActualDataLength();
742 if (size == pixels * 3) {
743 memcpy(_host->_buffer, ptr, size);
748 _host->_ready =
true;
757 HRESULT __stdcall WebcamVideoCursorDS::CSampleGrabberCB::BufferCB(
double dblSampleTime, BYTE *pBuffer,
long lBufferSize)
795 #endif // HAVE_DIRECTSHOW
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.