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