Panda3D
 All Classes Functions Variables Enumerations
webcamVideoDS.cxx
1 // Filename: webcamVideoDS.cxx
2 // Created by: jyelon (01Nov2007)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 //
15 // It goes against Panda3D coding style conventions to hide an
16 // entire class in a C++ file and not expose it through header
17 // files at all. However, in this case, these classes are so full
18 // of OS-specific junk that I feel it is better to hide them
19 // entirely. - Josh
20 //
21 ////////////////////////////////////////////////////////////////////
22 //
23 // This code was created by studying and adapting the VDOGRAB
24 // library by Shu-Kai Yang and the videoInput library by Theodore
25 // Watson. We owe both of them a great deal of thanks for
26 // figuring all this out. Both of their libraries have
27 // informal licenses (the "do whatever you want and don't blame
28 // me" sort), so I think there's not a problem using their code.
29 //
30 ////////////////////////////////////////////////////////////////////
31 
32 #if defined(HAVE_DIRECTCAM) && !defined(CPPPARSER)
33 
34 #ifndef WIN32_LEAN_AND_MEAN
35 #define WIN32_LEAN_AND_MEAN 1
36 #endif
37 
38 #undef Configure
39 
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"
45 
46 #include <windows.h>
47 #include <windowsx.h>
48 #include <olectl.h>
49 #include <mmsystem.h>
50 #include <strmif.h> // Generated IDL header file for streams interfaces
51 #include <amvideo.h> // ActiveMovie video interfaces and definitions
52 #include <amaudio.h> // ActiveMovie audio interfaces and definitions
53 #include <control.h> // generated from control.odl
54 #include <evcode.h> // event code definitions
55 #include <uuids.h> // declaration of type GUIDs and well-known clsids
56 #include <errors.h> // HRESULT status and error definitions
57 #include <edevdefs.h> // External device control interface defines
58 #include <audevcod.h> // audio filter device error event codes
59 #include <dvdevcod.h> // DVD error event codes
60 #include <comutil.h>
61 
62 #include <wchar.h>
63 #include <string.h>
64 #include <windows.h>
65 
66 // This used to work back when qedit.h still existed. The hacks
67 // served to prevent it from including the defunct dxtrans.h.
68 //#pragma include_alias( "dxtrans.h", "qedit.h" )
69 //#define __IDxtCompositor_INTERFACE_DEFINED__
70 //#define __IDxtAlphaSetter_INTERFACE_DEFINED__
71 //#define __IDxtJpeg_INTERFACE_DEFINED_
72 //#define __IDxtKey_INTERFACE_DEFINED__
73 //#define IDXEffect IUnknown
74 //#include <qedit.h>
75 
76 // We can use this fugly hack to still access the qedit.h interfaces.
77 // When this stops working, we'll have to just copy the relevant
78 // definitions to this file.
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")
88 
89 ////////////////////////////////////////////////////////////////////
90 // Class : WebcamVideoDS
91 // Description : The directshow implementation of webcams.
92 ////////////////////////////////////////////////////////////////////
93 
94 class WebcamVideoDS : public WebcamVideo
95 {
96 public:
97  static void find_all_webcams_ds();
98  friend void find_all_webcams_ds();
99 
100 private:
101  typedef pvector<PT(WebcamVideoDS)> WebcamVideoList;
102 
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);
111 
112  virtual PT(MovieVideoCursor) open();
113 
114  IMoniker *_moniker;
115  AM_MEDIA_TYPE *_media;
116 
117  friend class WebcamVideoCursorDS;
118 
119 public:
120  static TypeHandle get_class_type() {
121  return _type_handle;
122  }
123  static void init_type() {
124  WebcamVideo::init_type();
125  register_type(_type_handle, "WebcamVideoDS",
126  WebcamVideo::get_class_type());
127  }
128  virtual TypeHandle get_type() const {
129  return get_class_type();
130  }
131  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
132 
133 private:
134  static TypeHandle _type_handle;
135 };
136 
137 TypeHandle WebcamVideoDS::_type_handle;
138 
139 ////////////////////////////////////////////////////////////////////
140 // Class : WebcamVideoCursorDS
141 // Description : The directshow implementation of webcams.
142 ////////////////////////////////////////////////////////////////////
143 
144 
145 class WebcamVideoCursorDS : public MovieVideoCursor
146 {
147 public:
148  WebcamVideoCursorDS(WebcamVideoDS *src);
149  virtual ~WebcamVideoCursorDS();
150  virtual PT(Buffer) fetch_buffer();
151 
152 public:
153  void cleanup();
154 
155  class CSampleGrabberCB : public ISampleGrabberCB
156  {
157  public:
158  WebcamVideoCursorDS *_host;
159 
160  ULONG __stdcall AddRef() { return 2; }
161  ULONG __stdcall Release() { return 1; }
162 
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);
166  };
167 
168  unsigned char *_buffer;
169  IMediaSample *_saved;
170 
171  IGraphBuilder *_pGraphBuilder;
172  ICaptureGraphBuilder2 *_pCaptureBuilder;
173  IBaseFilter *_pSrcFilter;
174  IAMStreamConfig *_pStreamConfig;
175  ISampleGrabber *_pSampleGrabber;
176  IBaseFilter *_pStreamRenderer;
177  IMediaControl *_pMediaCtrl;
178  // IMemAllocator *_pAllocator;
179  CSampleGrabberCB _sample_cb;
180 
181 public:
182  static TypeHandle get_class_type() {
183  return _type_handle;
184  }
185  static void init_type() {
186  MovieVideoCursor::init_type();
187  register_type(_type_handle, "WebcamVideoCursorDS",
188  MovieVideoCursor::get_class_type());
189  }
190  virtual TypeHandle get_type() const {
191  return get_class_type();
192  }
193  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
194 
195 private:
196  static TypeHandle _type_handle;
197 };
198 
199 TypeHandle WebcamVideoCursorDS::_type_handle;
200 
201 ////////////////////////////////////////////////////////////////////
202 // Function: WebcamVideoDS::media_score
203 // Access: Public, Static
204 // Description: Evaluate an AM_MEDIA_TYPE to determine how
205 // desirable it is for our purposes. Lower is better.
206 ////////////////////////////////////////////////////////////////////
207 int WebcamVideoDS::
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;
214  return 4;
215 }
216 
217 ////////////////////////////////////////////////////////////////////
218 // Function: WebcamVideoDS::media_x
219 // Access: Public, Static
220 // Description: Returns the x-resolution of the AM_MEDIA_TYPE
221 ////////////////////////////////////////////////////////////////////
222 int WebcamVideoDS::
223 media_x(AM_MEDIA_TYPE *media) {
224  VIDEOINFOHEADER *header = (VIDEOINFOHEADER*)(media->pbFormat);
225  return (header->bmiHeader.biWidth);
226 }
227 
228 ////////////////////////////////////////////////////////////////////
229 // Function: WebcamVideoDS::media_y
230 // Access: Public, Static
231 // Description: Returns the y-resolution of the AM_MEDIA_TYPE
232 ////////////////////////////////////////////////////////////////////
233 int WebcamVideoDS::
234 media_y(AM_MEDIA_TYPE *media) {
235  VIDEOINFOHEADER *header = (VIDEOINFOHEADER*)(media->pbFormat);
236  return (header->bmiHeader.biHeight);
237 }
238 
239 ////////////////////////////////////////////////////////////////////
240 // Function: WebcamVideoDS::media_fps
241 // Access: Public, Static
242 // Description: Returns the frame-rate of the AM_MEDIA_TYPE
243 ////////////////////////////////////////////////////////////////////
244 int WebcamVideoDS::
245 media_fps(AM_MEDIA_TYPE *media) {
246  VIDEOINFOHEADER *header = (VIDEOINFOHEADER*)(media->pbFormat);
247  return int(10000000.0 / (header->AvgTimePerFrame));
248 }
249 
250 ////////////////////////////////////////////////////////////////////
251 // Function: WebcamVideoDS::delete_media_type
252 // Access: Public, Static
253 // Description: Free all memory of the AM_MEDIA_TYPE
254 ////////////////////////////////////////////////////////////////////
255 void WebcamVideoDS::
256 delete_media_type(AM_MEDIA_TYPE *pmt) {
257  if (pmt == NULL) {
258  return;
259  }
260  if (pmt->cbFormat != 0) {
261  CoTaskMemFree((PVOID)pmt->pbFormat);
262  pmt->cbFormat = 0;
263  pmt->pbFormat = NULL;
264  }
265  if (pmt->pUnk != NULL) {
266  // Unecessary because pUnk should not be used, but safest.
267  pmt->pUnk->Release();
268  pmt->pUnk = NULL;
269  }
270  CoTaskMemFree(pmt);
271 }
272 
273 ////////////////////////////////////////////////////////////////////
274 // Function: WebcamVideoDS::bstr_to_string
275 // Access: Public, Static
276 // Description: Converts a visual basic BSTR to a C++ string.
277 ////////////////////////////////////////////////////////////////////
278 string WebcamVideoDS::
279 bstr_to_string(const BSTR &source) {
280  string res = "";
281  int count = 0;
282  while( source[count] != 0x00 ) {
283  res.push_back(source[count]);
284  count++;
285  }
286  return res;
287 }
288 
289 ////////////////////////////////////////////////////////////////////
290 // Function: WebcamVideoDS::get_moniker_name
291 // Access: Public, Static
292 // Description: Obtains the text name associated with an IMoniker
293 ////////////////////////////////////////////////////////////////////
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);
300  VariantInit(&name);
301  hResult = propBag->Read(L"FriendlyName", &name, 0);
302  if (!hResult != S_OK) {
303  res = bstr_to_string(name.bstrVal);
304  goto done;
305  }
306  hResult = propBag->Read(L"Description", &name, 0);
307  if (!hResult != S_OK) {
308  res = bstr_to_string(name.bstrVal);
309  goto done;
310  }
311  done:
312  VariantClear(&name);
313  propBag->Release();
314  return res;
315 }
316 
317 ////////////////////////////////////////////////////////////////////
318 // Function: WebcamVideoDS::add_device
319 // Access: Public, Static
320 // Description: Creates a new WebcamVideoDS and adds it to the list,
321 // unless there is already a very similar configuration
322 // in the list. If there is already a very similar
323 // configuration, this routine will leave one or the
324 // other on the list based on a scoring system.
325 ////////////////////////////////////////////////////////////////////
326 void WebcamVideoDS::
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;
336  } else {
337  delete_media_type(media);
338  }
339  return;
340  }
341  }
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;
348  wc->_media = media;
349  list.push_back(wc);
350  cerr << "Added device: DirectShow: " << wc << "\n";
351 }
352 
353 
354 ////////////////////////////////////////////////////////////////////
355 // Function: WebcamVideoDS::find_all_webcams_ds
356 // Access: Public, Static
357 // Description: Finds all DirectShow webcams and adds them to
358 // the global list _all_webcams.
359 ////////////////////////////////////////////////////////////////////
360 void WebcamVideoDS::
361 find_all_webcams_ds() {
362 
364 
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;
372  HRESULT hResult;
373  ULONG cFetched;
374 
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,
387  &pEnumMoniker, 0);
388  if(hResult != S_OK) goto cleanup;
389 
390  while(1) {
391  if (pMoniker) { pMoniker->Release(); pMoniker=0; }
392  if (pBaseFilter) { pBaseFilter->Release(); pBaseFilter=0; }
393  if (pStreamConfig) { pStreamConfig->Release(); pStreamConfig=0; }
394 
395  hResult = pEnumMoniker->Next(1, &pMoniker, &cFetched);
396  if (hResult != S_OK) break;
397 
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;
403  int iCount, iSize;
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);
415  }
416  }
417 
418  pMoniker = 0;
419  }
420 
421  cleanup:
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; }
429 
430  for (int i=0; i<(int)list.size(); i++) {
431  WebcamVideoDS *obj = list[i];
432  _all_webcams.push_back(obj);
433  }
434 }
435 
436 void find_all_webcams_ds() {
437  WebcamVideoDS::init_type();
438  WebcamVideoCursorDS::init_type();
439  WebcamVideoDS::find_all_webcams_ds();
440 }
441 
442 ////////////////////////////////////////////////////////////////////
443 // Function: WebcamVideoDS::open
444 // Access: Published, Virtual
445 // Description: Open this video, returning a MovieVideoCursor.
446 ////////////////////////////////////////////////////////////////////
447 PT(MovieVideoCursor) WebcamVideoDS::
448 open() {
449  return new WebcamVideoCursorDS(this);
450 }
451 
452 ////////////////////////////////////////////////////////////////////
453 // Function: WebcamVideoCursorDS::Constructor
454 // Access: Published
455 // Description:
456 ////////////////////////////////////////////////////////////////////
457 WebcamVideoCursorDS::
458 WebcamVideoCursorDS(WebcamVideoDS *src) :
459  MovieVideoCursor(src),
460  _pGraphBuilder(NULL),
461  _pCaptureBuilder(NULL),
462  _pSrcFilter(NULL),
463  _pStreamConfig(NULL),
464  _pStreamRenderer(NULL),
465  _pMediaCtrl(NULL)
466 {
467  AM_MEDIA_TYPE mediaType;
468  VIDEOINFOHEADER *pVideoInfo;
469 
470  HRESULT hResult;
471 
472  hResult=CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC,
473  IID_IGraphBuilder,(void**)&_pGraphBuilder);
474  if(hResult != S_OK) { cleanup(); return; }
475 
476  hResult=CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC,
477  IID_ICaptureGraphBuilder2, (void**)&_pCaptureBuilder);
478  if(hResult != S_OK) { cleanup(); return; }
479 
480  _pCaptureBuilder->SetFiltergraph(_pGraphBuilder);
481  cerr << " IID_IGraphBuilder & IID_ICaptureGraphBuilder2 are established.\n";
482 
483  hResult=_pGraphBuilder->QueryInterface(IID_IMediaControl, (void **)&_pMediaCtrl);
484  if(hResult != S_OK)
485  { cerr << " Can not get the IID_IMediaControl interface!";
486  cleanup(); return; }
487  cerr << " IID_IMediaControl interface is acquired.\n";
488 
489  src->_moniker->BindToObject(NULL,NULL,IID_IBaseFilter, (void**)&_pSrcFilter);
490  if(_pSrcFilter == NULL)
491  { cerr << " Such capture device is not found.\n";
492  cleanup(); return; }
493  cerr << " The capture filter is acquired.\n";
494 
495  hResult=_pGraphBuilder->AddFilter(_pSrcFilter, L"Capture Filter");
496  if(hResult != DD_OK)
497  { cerr << " The capture filter can not be added to the graph.\n";
498  cleanup(); return; }
499  cerr << " The capture filter has been added to the graph.\n";
500 
501 
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";
506  cleanup(); return;
507  }
508  hResult = _pStreamConfig->SetFormat(src->_media);
509  if (hResult != S_OK) {
510  cerr << "Could not select desired video resolution\n";
511  cleanup(); return;
512  }
513 
514  hResult = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC, IID_PPV_ARGS(&_pSampleGrabber));
515  if(hResult != S_OK)
516  { cerr << " Can not create the sample grabber, maybe qedit.dll is not registered?";
517  cleanup(); return; }
518 
519 
520  //hResult = CoCreateInstance(CLSID_SampleGrabber,)
521  //CComQIPtr< IBaseFilter, &IID_IBaseFilter > pGrabberFilter(_pSampleGrabber);
522  IBaseFilter *pGrabberFilter = NULL;
523  hResult = _pSampleGrabber->QueryInterface(IID_PPV_ARGS(&pGrabberFilter));
524  cerr << " IID_IBaseFilter of CLSID_SampleGrabber is acquired.\n";
525 
526  ZeroMemory(&mediaType, sizeof(AM_MEDIA_TYPE));
527  mediaType.majortype=MEDIATYPE_Video;
528  mediaType.subtype=MEDIASUBTYPE_RGB24;
529  hResult=_pSampleGrabber->SetMediaType(&mediaType);
530  if(hResult != S_OK)
531  { cerr << " Fail to set the media type!";
532  cleanup(); return; }
533  cerr << " The media type of the sample grabber is set 24-bit RGB.\n";
534 
535  hResult=_pGraphBuilder->AddFilter(pGrabberFilter, L"Sample Grabber");
536  if(hResult != S_OK)
537  { cerr << " Fail to add the sample grabber to the graph.";
538  cleanup(); return; }
539  cerr << " The sample grabber has been added to the graph.\n";
540 
541  //used to give the video stream somewhere to go to.
542  hResult = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&_pStreamRenderer);
543  if(hResult != S_OK)
544  { cerr << " Can not create the null renderer.";
545  cleanup(); return; }
546  cerr << " IID_IBaseFilter of CLSID_NullRenderer is acquired.\n";
547 
548  hResult=_pGraphBuilder->AddFilter(_pStreamRenderer, L"Stream Renderer");
549  if(hResult != S_OK)
550  { cerr << " Fail to add the Null Renderer to the graph.";
551  cleanup(); return; }
552  cerr << " The Null Renderer has been added to the graph.\n";
553 
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";
558  cleanup(); return;
559  }
560 
561  hResult=_pSampleGrabber->GetConnectedMediaType(&mediaType);
562  if(hResult != S_OK) {
563  cerr << " Failed to read the connected media type.";
564  cleanup(); return;
565  }
566 
567  // IPin *iPin;
568  // hResult = FindInputPin(pGrabberFilter, &iPin);
569  // if ((iPin == 0)||(hResult != S_OK)) {
570  // cerr << "Could not get sampler input pin.\n";
571  // cleanup(); return;
572  // }
573  // CComQIPtr< IMemInputPin, &IID_IMemInputPin > pMemInputPin(iPin);
574  // if (pMemInputPin == 0) {
575  // cerr << "Could not get sampler meminput pin.\n";
576  // cleanup(); return;
577  // }
578  // hResult = pMemInputPin->GetAllocator(&_pAllocator);
579  // if (hResult != S_OK) {
580  // cerr << "Could not get sample grabber allocator handle.\n";
581  // }
582  // ALLOCATOR_PROPERTIES props, aprops;
583  // hResult = _pAllocator->GetProperties(&props);
584  // if (hResult != S_OK) {
585  // cerr << "Could not get allocator properties.\n";
586  // }
587  // cerr << "Allocator properties: cBuffers=" << props.cBuffers << "\n";
588  // props.cBuffers += 10;
589  // hResult = _pAllocator->SetProperties(&props, &aprops);
590  // if (hResult != S_OK) {
591  // cerr << "Could not set allocator properties.\n";
592  // }
593  // cerr << "Allocator properties (adjusted): cBuffers=" << aprops.cBuffers << "\n";
594 
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";
599 
600  _sample_cb._host = this;
601  _num_components = 3;
602  _length = 1.0E10;
603  _can_seek = false;
604  _can_seek_fast = false;
605  _aborted = false;
606  _streaming = true;
607  _buffer = new unsigned char[_size_x * _size_y * 3];
608  _ready = false;
609 
610  if(mediaType.cbFormat != 0) {
611  CoTaskMemFree((PVOID)mediaType.pbFormat);
612  mediaType.cbFormat=0;
613  mediaType.pbFormat=NULL;
614  }
615 
616  if(mediaType.pUnk != NULL) {
617  mediaType.pUnk->Release();
618  mediaType.pUnk=NULL;
619  }
620 
621  if(pGrabberFilter != NULL) {
622  pGrabberFilter->Release();
623  pGrabberFilter=NULL;
624  }
625 
626  _pSampleGrabber->SetBufferSamples(FALSE);
627  _pSampleGrabber->SetOneShot(FALSE);
628 
629  hResult=_pSampleGrabber->SetCallback(&_sample_cb, 0);
630  if(hResult != S_OK) {
631  cerr << " Can not set the callback interface!";
632  cleanup(); return;
633  }
634 
635  _pMediaCtrl->Run();
636 }
637 
638 ////////////////////////////////////////////////////////////////////
639 // Function: WebcamVideoCursorDS::cleanup
640 // Access: Published
641 // Description:
642 ////////////////////////////////////////////////////////////////////
643 void WebcamVideoCursorDS::
644 cleanup() {
645  if (_buffer) {
646  delete[] _buffer;
647  _buffer = 0;
648  }
649 
650  if (_pMediaCtrl) {
651  _pMediaCtrl->Stop();
652  }
653 
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; }
661 }
662 
663 ////////////////////////////////////////////////////////////////////
664 // Function: WebcamVideoCursorDS::Destructor
665 // Access: Published
666 // Description:
667 ////////////////////////////////////////////////////////////////////
668 WebcamVideoCursorDS::
669 ~WebcamVideoCursorDS() {
670  cleanup();
671 }
672 
673 ////////////////////////////////////////////////////////////////////
674 // Function: WebcamVideoCursorDS::fetch_buffer
675 // Access: Published
676 // Description:
677 ////////////////////////////////////////////////////////////////////
678 PT(MovieVideoCursor::Buffer) WebcamVideoCursorDS::
679 fetch_buffer() {
680  if (!_ready) {
681  return NULL;
682  }
683 
684  Buffer *buffer = get_standard_buffer();
685  unsigned char *block = buffer->_block;
686 #ifdef LOCKING_MODE
687  unsigned char *ptr;
688  int pixels = _size_x * _size_y;
689  HRESULT res = _saved->GetPointer(&ptr);
690  if (res == S_OK) {
691  int size = _saved->GetActualDataLength();
692  if (size == pixels * 3) {
693  memcpy(block, ptr, pixels * 3);
694  }
695  }
696  _saved->Release();
697 #else
698  int pixels = _size_x * _size_y;
699  memcpy(block, _buffer, pixels * 3);
700 #endif
701 
702  _ready = false;
703  return buffer;
704 }
705 
706 
707 ////////////////////////////////////////////////////////////////////
708 // Function: WebcamVideoCursorDS::CSampleGrabberCB::QueryInterface
709 // Access: Private
710 // Description:
711 ////////////////////////////////////////////////////////////////////
712 HRESULT __stdcall WebcamVideoCursorDS::CSampleGrabberCB::QueryInterface(REFIID riid, void **ppv)
713 {
714  if((riid == IID_ISampleGrabberCB) || (riid == IID_IUnknown)) {
715  *ppv=(void *)static_cast<ISampleGrabberCB *> (this);
716  return NOERROR;
717  }
718  return E_NOINTERFACE;
719 }
720 
721 
722 ////////////////////////////////////////////////////////////////////
723 // Function: WebcamVideoCursorDS::CSampleGrabberCB::SampleCB
724 // Access: Private
725 // Description:
726 ////////////////////////////////////////////////////////////////////
727 HRESULT __stdcall WebcamVideoCursorDS::CSampleGrabberCB::SampleCB(double SampleTime, IMediaSample *pSample)
728 {
729  if (_host->_ready) {
730  return 0;
731  }
732 
733 #ifdef LOCKING_MODE
734  pSample->AddRef();
735  _host->_saved = pSample;
736 #else
737  unsigned char *ptr;
738  int pixels = _host->_size_x * _host->_size_y;
739  HRESULT res = pSample->GetPointer(&ptr);
740  if (res == S_OK) {
741  int size = pSample->GetActualDataLength();
742  if (size == pixels * 3) {
743  memcpy(_host->_buffer, ptr, size);
744  }
745  }
746 #endif
747 
748  _host->_ready = true;
749  return 0;
750 }
751 
752 ////////////////////////////////////////////////////////////////////
753 // Function: WebcamVideoCursorDS::CSampleGrabberCB::BufferCB
754 // Access: Private
755 // Description:
756 ////////////////////////////////////////////////////////////////////
757 HRESULT __stdcall WebcamVideoCursorDS::CSampleGrabberCB::BufferCB(double dblSampleTime, BYTE *pBuffer, long lBufferSize)
758 {
759  // Not used.
760  return 0;
761 }
762 
763 //HRESULT FindInputPin(IBaseFilter *pFilter, IPin **ppPin)
764 //{
765 // if (!pFilter || ! ppPin)
766 // return E_POINTER;
767 //
768 // *ppPin = 0;
769 // HRESULT hr;
770 // //Find the output pin of the Source Filter
771 // IEnumPins *pPinEnum;
772 // hr = pFilter->EnumPins(&pPinEnum);
773 // if (FAILED(hr))
774 // return E_FAIL;
775 //
776 // IPin *pSearchPin;
777 // while (pPinEnum->Next(1, &pSearchPin, NULL) == S_OK)
778 // {
779 // PIN_DIRECTION pPinDir;
780 // hr = pSearchPin->QueryDirection(&pPinDir);
781 // if (FAILED(hr))
782 // return E_FAIL;
783 // if (pPinDir == PINDIR_INPUT)
784 // {
785 // //Found out pin
786 // *ppPin = pSearchPin;
787 // break;
788 // }
789 // }
790 // pPinEnum->Release();
791 // return hr;
792 //}
793 
794 
795 #endif // HAVE_DIRECTSHOW
Allows you to open a webcam or other video capture device as a video stream.
Definition: webcamVideo.h:25
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:39
Definition: buffer.h:26
A MovieVideo is actually any source that provides a sequence of video frames.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85