Panda3D
|
00001 // Filename: webcamVideoDS.cxx 00002 // Created by: jyelon (01Nov2007) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 // 00015 // It goes against Panda3D coding style conventions to hide an 00016 // entire class in a C++ file and not expose it through header 00017 // files at all. However, in this case, these classes are so full 00018 // of OS-specific junk that I feel it is better to hide them 00019 // entirely. - Josh 00020 // 00021 //////////////////////////////////////////////////////////////////// 00022 // 00023 // This code was created by studying and adapting the VDOGRAB 00024 // library by Shu-Kai Yang and the videoInput library by Theodore 00025 // Watson. We owe both of them a great deal of thanks for 00026 // figuring all this out. Both of their libraries have 00027 // informal licenses (the "do whatever you want and don't blame 00028 // me" sort), so I think there's not a problem using their code. 00029 // 00030 //////////////////////////////////////////////////////////////////// 00031 00032 #ifdef HAVE_DIRECTCAM 00033 00034 #define WIN32_LEAN_AND_MEAN 00035 00036 #undef Configure 00037 00038 #pragma warning(disable:4100) // warning C4100: unreferenced formal parameter 00039 #pragma warning(disable:4201) // warning C4201: nonstandard extension used : nameless struct/union 00040 #pragma warning(disable:4511) // warning C4511: copy constructor could not be generated 00041 #pragma warning(disable:4512) // warning C4512: assignment operator could not be generated 00042 #pragma warning(disable:4514) // warning C4514: "unreferenced inline function has been removed" 00043 00044 #include <windows.h> 00045 #include <windowsx.h> 00046 #include <olectl.h> 00047 #include <mmsystem.h> 00048 #include <strmif.h> // Generated IDL header file for streams interfaces 00049 #include <amvideo.h> // ActiveMovie video interfaces and definitions 00050 #include <amaudio.h> // ActiveMovie audio interfaces and definitions 00051 #include <control.h> // generated from control.odl 00052 #include <evcode.h> // event code definitions 00053 #include <uuids.h> // declaration of type GUIDs and well-known clsids 00054 #include <errors.h> // HRESULT status and error definitions 00055 #include <edevdefs.h> // External device control interface defines 00056 #include <audevcod.h> // audio filter device error event codes 00057 #include <dvdevcod.h> // DVD error event codes 00058 #include <comutil.h> 00059 00060 #include <wchar.h> 00061 #include <string.h> 00062 #include <windows.h> 00063 00064 // NOTE: there is a problem with dxtrans.h missing from newer Microsoft DirectX SDKs (including March 2009) 00065 // See "dxtrans.h missing in Microsoft DirectX SDK" at 00066 // http://social.msdn.microsoft.com/forums/en-US/windowssdk/thread/ed097d2c-3d68-448-8448-277eaaf68252/ for example. 00067 // This header file is referenced only by qedit.h and not needed. 00068 // Solution: add this pragma and these defines before the qedit.h inclusion: 00069 #pragma include_alias( "dxtrans.h", "qedit.h" ) 00070 #define __IDxtCompositor_INTERFACE_DEFINED__ 00071 #define __IDxtAlphaSetter_INTERFACE_DEFINED__ 00072 #define __IDxtJpeg_INTERFACE_DEFINED_ 00073 #define __IDxtKey_INTERFACE_DEFINED__ 00074 #define IDXEffect IUnknown 00075 #include <qedit.h> 00076 #include <atlbase.h> 00077 00078 //////////////////////////////////////////////////////////////////// 00079 // Class : WebcamVideoDS 00080 // Description : The directshow implementation of webcams. 00081 //////////////////////////////////////////////////////////////////// 00082 00083 class WebcamVideoDS : public WebcamVideo 00084 { 00085 public: 00086 static void find_all_webcams_ds(); 00087 friend void find_all_webcams_ds(); 00088 00089 private: 00090 typedef pvector<PT(WebcamVideoDS)> WebcamVideoList; 00091 00092 static int media_score(AM_MEDIA_TYPE *media); 00093 static int media_x(AM_MEDIA_TYPE *media); 00094 static int media_y(AM_MEDIA_TYPE *media); 00095 static int media_fps(AM_MEDIA_TYPE *media); 00096 static void delete_media_type(AM_MEDIA_TYPE *media); 00097 static string bstr_to_string(const BSTR &source); 00098 static string get_moniker_name(IMoniker *pMoniker); 00099 static void add_device(WebcamVideoList &list, IMoniker *pMoniker, AM_MEDIA_TYPE *media); 00100 00101 virtual PT(MovieVideoCursor) open(); 00102 00103 IMoniker *_moniker; 00104 AM_MEDIA_TYPE *_media; 00105 00106 friend class WebcamVideoCursorDS; 00107 00108 public: 00109 static TypeHandle get_class_type() { 00110 return _type_handle; 00111 } 00112 static void init_type() { 00113 WebcamVideo::init_type(); 00114 register_type(_type_handle, "WebcamVideoDS", 00115 WebcamVideo::get_class_type()); 00116 } 00117 virtual TypeHandle get_type() const { 00118 return get_class_type(); 00119 } 00120 virtual TypeHandle force_init_type() {init_type(); return get_class_type();} 00121 00122 private: 00123 static TypeHandle _type_handle; 00124 }; 00125 00126 TypeHandle WebcamVideoDS::_type_handle; 00127 00128 //////////////////////////////////////////////////////////////////// 00129 // Class : WebcamVideoCursorDS 00130 // Description : The directshow implementation of webcams. 00131 //////////////////////////////////////////////////////////////////// 00132 00133 00134 class WebcamVideoCursorDS : public MovieVideoCursor 00135 { 00136 public: 00137 WebcamVideoCursorDS(WebcamVideoDS *src); 00138 virtual ~WebcamVideoCursorDS(); 00139 virtual PT(Buffer) fetch_buffer(); 00140 00141 public: 00142 void cleanup(); 00143 00144 class CSampleGrabberCB : public ISampleGrabberCB 00145 { 00146 public: 00147 WebcamVideoCursorDS *_host; 00148 00149 ULONG __stdcall AddRef() { return 2; } 00150 ULONG __stdcall Release() { return 1; } 00151 00152 HRESULT __stdcall QueryInterface(REFIID riid, void ** ppv); 00153 HRESULT __stdcall SampleCB(double SampleTime, IMediaSample *pSample); 00154 HRESULT __stdcall BufferCB(double dblSampleTime, BYTE *pBuffer, long lBufferSize); 00155 }; 00156 00157 unsigned char *_buffer; 00158 IMediaSample *_saved; 00159 00160 IGraphBuilder *_pGraphBuilder; 00161 ICaptureGraphBuilder2 *_pCaptureBuilder; 00162 IBaseFilter *_pSrcFilter; 00163 IAMStreamConfig *_pStreamConfig; 00164 CComPtr<ISampleGrabber> _pSampleGrabber; 00165 IBaseFilter *_pStreamRenderer; 00166 IMediaControl *_pMediaCtrl; 00167 // IMemAllocator *_pAllocator; 00168 CSampleGrabberCB _sample_cb; 00169 00170 public: 00171 static TypeHandle get_class_type() { 00172 return _type_handle; 00173 } 00174 static void init_type() { 00175 MovieVideoCursor::init_type(); 00176 register_type(_type_handle, "WebcamVideoCursorDS", 00177 MovieVideoCursor::get_class_type()); 00178 } 00179 virtual TypeHandle get_type() const { 00180 return get_class_type(); 00181 } 00182 virtual TypeHandle force_init_type() {init_type(); return get_class_type();} 00183 00184 private: 00185 static TypeHandle _type_handle; 00186 }; 00187 00188 TypeHandle WebcamVideoCursorDS::_type_handle; 00189 00190 //////////////////////////////////////////////////////////////////// 00191 // Function: WebcamVideoDS::media_score 00192 // Access: Public, Static 00193 // Description: Evaluate an AM_MEDIA_TYPE to determine how 00194 // desirable it is for our purposes. Lower is better. 00195 //////////////////////////////////////////////////////////////////// 00196 int WebcamVideoDS:: 00197 media_score(AM_MEDIA_TYPE *media) { 00198 const GUID &subtype = media->subtype; 00199 if (subtype == MEDIASUBTYPE_RGB24) return 1; 00200 if (subtype == MEDIASUBTYPE_RGB32) return 2; 00201 if (subtype == MEDIASUBTYPE_RGB555) return 3; 00202 if (subtype == MEDIASUBTYPE_RGB565) return 3; 00203 return 4; 00204 } 00205 00206 //////////////////////////////////////////////////////////////////// 00207 // Function: WebcamVideoDS::media_x 00208 // Access: Public, Static 00209 // Description: Returns the x-resolution of the AM_MEDIA_TYPE 00210 //////////////////////////////////////////////////////////////////// 00211 int WebcamVideoDS:: 00212 media_x(AM_MEDIA_TYPE *media) { 00213 VIDEOINFOHEADER *header = (VIDEOINFOHEADER*)(media->pbFormat); 00214 return (header->bmiHeader.biWidth); 00215 } 00216 00217 //////////////////////////////////////////////////////////////////// 00218 // Function: WebcamVideoDS::media_y 00219 // Access: Public, Static 00220 // Description: Returns the y-resolution of the AM_MEDIA_TYPE 00221 //////////////////////////////////////////////////////////////////// 00222 int WebcamVideoDS:: 00223 media_y(AM_MEDIA_TYPE *media) { 00224 VIDEOINFOHEADER *header = (VIDEOINFOHEADER*)(media->pbFormat); 00225 return (header->bmiHeader.biHeight); 00226 } 00227 00228 //////////////////////////////////////////////////////////////////// 00229 // Function: WebcamVideoDS::media_fps 00230 // Access: Public, Static 00231 // Description: Returns the frame-rate of the AM_MEDIA_TYPE 00232 //////////////////////////////////////////////////////////////////// 00233 int WebcamVideoDS:: 00234 media_fps(AM_MEDIA_TYPE *media) { 00235 VIDEOINFOHEADER *header = (VIDEOINFOHEADER*)(media->pbFormat); 00236 return int(10000000.0 / (header->AvgTimePerFrame)); 00237 } 00238 00239 //////////////////////////////////////////////////////////////////// 00240 // Function: WebcamVideoDS::delete_media_type 00241 // Access: Public, Static 00242 // Description: Free all memory of the AM_MEDIA_TYPE 00243 //////////////////////////////////////////////////////////////////// 00244 void WebcamVideoDS:: 00245 delete_media_type(AM_MEDIA_TYPE *pmt) { 00246 if (pmt == NULL) { 00247 return; 00248 } 00249 if (pmt->cbFormat != 0) { 00250 CoTaskMemFree((PVOID)pmt->pbFormat); 00251 pmt->cbFormat = 0; 00252 pmt->pbFormat = NULL; 00253 } 00254 if (pmt->pUnk != NULL) { 00255 // Unecessary because pUnk should not be used, but safest. 00256 pmt->pUnk->Release(); 00257 pmt->pUnk = NULL; 00258 } 00259 CoTaskMemFree(pmt); 00260 } 00261 00262 //////////////////////////////////////////////////////////////////// 00263 // Function: WebcamVideoDS::bstr_to_string 00264 // Access: Public, Static 00265 // Description: Converts a visual basic BSTR to a C++ string. 00266 //////////////////////////////////////////////////////////////////// 00267 string WebcamVideoDS:: 00268 bstr_to_string(const BSTR &source) { 00269 string res = ""; 00270 int count = 0; 00271 while( source[count] != 0x00 ) { 00272 res.push_back(source[count]); 00273 count++; 00274 } 00275 return res; 00276 } 00277 00278 //////////////////////////////////////////////////////////////////// 00279 // Function: WebcamVideoDS::get_moniker_name 00280 // Access: Public, Static 00281 // Description: Obtains the text name associated with an IMoniker 00282 //////////////////////////////////////////////////////////////////// 00283 string WebcamVideoDS:: 00284 get_moniker_name(IMoniker *pMoniker) { 00285 string res = "Unknown Device"; 00286 IPropertyBag *propBag=NULL; 00287 VARIANT name; HRESULT hResult; 00288 pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)&propBag); 00289 VariantInit(&name); 00290 hResult = propBag->Read(L"FriendlyName", &name, 0); 00291 if (!hResult != S_OK) { 00292 res = bstr_to_string(name.bstrVal); 00293 goto done; 00294 } 00295 hResult = propBag->Read(L"Description", &name, 0); 00296 if (!hResult != S_OK) { 00297 res = bstr_to_string(name.bstrVal); 00298 goto done; 00299 } 00300 done: 00301 VariantClear(&name); 00302 propBag->Release(); 00303 return res; 00304 } 00305 00306 //////////////////////////////////////////////////////////////////// 00307 // Function: WebcamVideoDS::add_device 00308 // Access: Public, Static 00309 // Description: Creates a new WebcamVideoDS and adds it to the list, 00310 // unless there is already a very similar configuration 00311 // in the list. If there is already a very similar 00312 // configuration, this routine will leave one or the 00313 // other on the list based on a scoring system. 00314 //////////////////////////////////////////////////////////////////// 00315 void WebcamVideoDS:: 00316 add_device(WebcamVideoList &list, IMoniker *pMoniker, AM_MEDIA_TYPE *media) { 00317 for (int i=0; i<(int)list.size(); i++) { 00318 if ((list[i]->_moniker == pMoniker)&& 00319 (media_x(list[i]->_media) == media_x(media))&& 00320 (media_y(list[i]->_media) == media_y(media))) { 00321 int oldscore = media_score(list[i]->_media); 00322 if (media_score(media) < oldscore) { 00323 delete_media_type(list[i]->_media); 00324 list[i]->_media = media; 00325 } else { 00326 delete_media_type(media); 00327 } 00328 return; 00329 } 00330 } 00331 PT(WebcamVideoDS) wc = new WebcamVideoDS; 00332 wc->set_name(get_moniker_name(pMoniker)); 00333 wc->_size_x = media_x(media); 00334 wc->_size_y = media_y(media); 00335 wc->_fps = media_fps(media); 00336 wc->_moniker = pMoniker; 00337 wc->_media = media; 00338 list.push_back(wc); 00339 cerr << "Added device: DirectShow: " << wc << "\n"; 00340 } 00341 00342 00343 //////////////////////////////////////////////////////////////////// 00344 // Function: WebcamVideoDS::find_all_webcams_ds 00345 // Access: Public, Static 00346 // Description: Finds all DirectShow webcams and adds them to 00347 // the global list _all_webcams. 00348 //////////////////////////////////////////////////////////////////// 00349 void WebcamVideoDS:: 00350 find_all_webcams_ds() { 00351 00352 pvector <PT(WebcamVideoDS)> list; 00353 00354 ICreateDevEnum *pCreateDevEnum=NULL; 00355 IEnumMoniker *pEnumMoniker=NULL; 00356 IGraphBuilder *pGraphBuilder=NULL; 00357 ICaptureGraphBuilder2 *pCaptureGraphBuilder2=NULL; 00358 IMoniker *pMoniker=NULL; 00359 IBaseFilter *pBaseFilter=NULL; 00360 IAMStreamConfig *pStreamConfig=NULL; 00361 HRESULT hResult; 00362 ULONG cFetched; 00363 00364 hResult=CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, 00365 IID_IGraphBuilder,(void**)&pGraphBuilder); 00366 if (hResult != S_OK) goto cleanup; 00367 hResult=CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC, 00368 IID_ICaptureGraphBuilder2, (void**)&pCaptureGraphBuilder2); 00369 if (hResult != S_OK) goto cleanup; 00370 hResult = pCaptureGraphBuilder2->SetFiltergraph(pGraphBuilder); 00371 if (hResult != S_OK) goto cleanup; 00372 hResult=CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, 00373 IID_ICreateDevEnum, (void**)&pCreateDevEnum); 00374 if (hResult != S_OK) goto cleanup; 00375 hResult=pCreateDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, 00376 &pEnumMoniker, 0); 00377 if(hResult != S_OK) goto cleanup; 00378 00379 while(1) { 00380 if (pMoniker) { pMoniker->Release(); pMoniker=0; } 00381 if (pBaseFilter) { pBaseFilter->Release(); pBaseFilter=0; } 00382 if (pStreamConfig) { pStreamConfig->Release(); pStreamConfig=0; } 00383 00384 hResult = pEnumMoniker->Next(1, &pMoniker, &cFetched); 00385 if (hResult != S_OK) break; 00386 00387 hResult = pMoniker->BindToObject(NULL,NULL,IID_IBaseFilter, (void**)&pBaseFilter); 00388 if (hResult != S_OK) continue; 00389 hResult = pCaptureGraphBuilder2->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, pBaseFilter, 00390 IID_IAMStreamConfig, (void **)&pStreamConfig); 00391 if (hResult != S_OK) continue; 00392 int iCount, iSize; 00393 hResult = pStreamConfig->GetNumberOfCapabilities(&iCount, &iSize); 00394 if (hResult != S_OK || (iSize != sizeof(VIDEO_STREAM_CONFIG_CAPS))) continue; 00395 for (int iFormat=0; iFormat<iCount; iFormat++) { 00396 AM_MEDIA_TYPE *mtype; 00397 VIDEO_STREAM_CONFIG_CAPS caps; 00398 hResult = pStreamConfig->GetStreamCaps(iFormat, &mtype, (BYTE*)&caps); 00399 if (mtype->majortype == MEDIATYPE_Video) { 00400 VIDEOINFOHEADER *header = (VIDEOINFOHEADER*)(mtype->pbFormat); 00401 header->bmiHeader.biWidth = caps.MaxOutputSize.cx; 00402 header->bmiHeader.biHeight = caps.MaxOutputSize.cy; 00403 add_device(list, pMoniker, mtype); 00404 } 00405 } 00406 00407 pMoniker = 0; 00408 } 00409 00410 cleanup: 00411 if (pCreateDevEnum) { pCreateDevEnum->Release(); pCreateDevEnum=0; } 00412 if (pEnumMoniker) { pEnumMoniker->Release(); pEnumMoniker=0; } 00413 if (pGraphBuilder) { pGraphBuilder->Release(); pGraphBuilder=0; } 00414 if (pCaptureGraphBuilder2) { pCaptureGraphBuilder2->Release(); pCaptureGraphBuilder2=0; } 00415 if (pMoniker) { pMoniker->Release(); pMoniker=0; } 00416 if (pBaseFilter) { pBaseFilter->Release(); pBaseFilter=0; } 00417 if (pStreamConfig) { pStreamConfig->Release(); pStreamConfig=0; } 00418 00419 for (int i=0; i<(int)list.size(); i++) { 00420 WebcamVideoDS *obj = list[i]; 00421 _all_webcams.push_back(obj); 00422 } 00423 } 00424 00425 void find_all_webcams_ds() { 00426 WebcamVideoDS::init_type(); 00427 WebcamVideoCursorDS::init_type(); 00428 WebcamVideoDS::find_all_webcams_ds(); 00429 } 00430 00431 //////////////////////////////////////////////////////////////////// 00432 // Function: WebcamVideoDS::open 00433 // Access: Published, Virtual 00434 // Description: Open this video, returning a MovieVideoCursor. 00435 //////////////////////////////////////////////////////////////////// 00436 PT(MovieVideoCursor) WebcamVideoDS:: 00437 open() { 00438 return new WebcamVideoCursorDS(this); 00439 } 00440 00441 //////////////////////////////////////////////////////////////////// 00442 // Function: WebcamVideoCursorDS::Constructor 00443 // Access: Published 00444 // Description: 00445 //////////////////////////////////////////////////////////////////// 00446 WebcamVideoCursorDS:: 00447 WebcamVideoCursorDS(WebcamVideoDS *src) : 00448 MovieVideoCursor(src), 00449 _pGraphBuilder(NULL), 00450 _pCaptureBuilder(NULL), 00451 _pSrcFilter(NULL), 00452 _pStreamConfig(NULL), 00453 _pStreamRenderer(NULL), 00454 _pMediaCtrl(NULL) 00455 { 00456 AM_MEDIA_TYPE mediaType; 00457 VIDEOINFOHEADER *pVideoInfo; 00458 00459 HRESULT hResult; 00460 00461 hResult=CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, 00462 IID_IGraphBuilder,(void**)&_pGraphBuilder); 00463 if(hResult != S_OK) { cleanup(); return; } 00464 00465 hResult=CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC, 00466 IID_ICaptureGraphBuilder2, (void**)&_pCaptureBuilder); 00467 if(hResult != S_OK) { cleanup(); return; } 00468 00469 _pCaptureBuilder->SetFiltergraph(_pGraphBuilder); 00470 cerr << " IID_IGraphBuilder & IID_ICaptureGraphBuilder2 are established.\n"; 00471 00472 hResult=_pGraphBuilder->QueryInterface(IID_IMediaControl, (void **)&_pMediaCtrl); 00473 if(hResult != S_OK) 00474 { cerr << " Can not get the IID_IMediaControl interface!"; 00475 cleanup(); return; } 00476 cerr << " IID_IMediaControl interface is acquired.\n"; 00477 00478 src->_moniker->BindToObject(NULL,NULL,IID_IBaseFilter, (void**)&_pSrcFilter); 00479 if(_pSrcFilter == NULL) 00480 { cerr << " Such capture device is not found.\n"; 00481 cleanup(); return; } 00482 cerr << " The capture filter is acquired.\n"; 00483 00484 hResult=_pGraphBuilder->AddFilter(_pSrcFilter, L"Capture Filter"); 00485 if(hResult != DD_OK) 00486 { cerr << " The capture filter can not be added to the graph.\n"; 00487 cleanup(); return; } 00488 cerr << " The capture filter has been added to the graph.\n"; 00489 00490 00491 hResult = _pCaptureBuilder->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, _pSrcFilter, 00492 IID_IAMStreamConfig, (void **)&_pStreamConfig); 00493 if (hResult != S_OK) { 00494 cerr << "Could not get stream config interface.\n"; 00495 cleanup(); return; 00496 } 00497 hResult = _pStreamConfig->SetFormat(src->_media); 00498 if (hResult != S_OK) { 00499 cerr << "Could not select desired video resolution\n"; 00500 cleanup(); return; 00501 } 00502 00503 _pSampleGrabber.CoCreateInstance(CLSID_SampleGrabber); 00504 if(!_pSampleGrabber) 00505 { cerr << " Can not create the sample grabber, maybe qedit.dll is not registered?"; 00506 cleanup(); return; } 00507 00508 00509 CComQIPtr< IBaseFilter, &IID_IBaseFilter > pGrabberFilter(_pSampleGrabber); 00510 cerr << " IID_IBaseFilter of CLSID_SampleGrabber is acquired.\n"; 00511 00512 ZeroMemory(&mediaType, sizeof(AM_MEDIA_TYPE)); 00513 mediaType.majortype=MEDIATYPE_Video; 00514 mediaType.subtype=MEDIASUBTYPE_RGB24; 00515 hResult=_pSampleGrabber->SetMediaType(&mediaType); 00516 if(hResult != S_OK) 00517 { cerr << " Fail to set the media type!"; 00518 cleanup(); return; } 00519 cerr << " The media type of the sample grabber is set 24-bit RGB.\n"; 00520 00521 hResult=_pGraphBuilder->AddFilter(pGrabberFilter, L"Sample Grabber"); 00522 if(hResult != S_OK) 00523 { cerr << " Fail to add the sample grabber to the graph."; 00524 cleanup(); return; } 00525 cerr << " The sample grabber has been added to the graph.\n"; 00526 00527 //used to give the video stream somewhere to go to. 00528 hResult = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&_pStreamRenderer); 00529 if(hResult != S_OK) 00530 { cerr << " Can not create the null renderer."; 00531 cleanup(); return; } 00532 cerr << " IID_IBaseFilter of CLSID_NullRenderer is acquired.\n"; 00533 00534 hResult=_pGraphBuilder->AddFilter(_pStreamRenderer, L"Stream Renderer"); 00535 if(hResult != S_OK) 00536 { cerr << " Fail to add the Null Renderer to the graph."; 00537 cleanup(); return; } 00538 cerr << " The Null Renderer has been added to the graph.\n"; 00539 00540 hResult=_pCaptureBuilder->RenderStream(&PIN_CATEGORY_CAPTURE, 00541 &MEDIATYPE_Video, _pSrcFilter, pGrabberFilter, _pStreamRenderer); 00542 if(hResult != S_OK) { 00543 cerr << " ICaptureGraphBuilder2::RenderStream() can not connect the pins\n"; 00544 cleanup(); return; 00545 } 00546 00547 hResult=_pSampleGrabber->GetConnectedMediaType(&mediaType); 00548 if(hResult != S_OK) { 00549 cerr << " Failed to read the connected media type."; 00550 cleanup(); return; 00551 } 00552 00553 // IPin *iPin; 00554 // hResult = FindInputPin(pGrabberFilter, &iPin); 00555 // if ((iPin == 0)||(hResult != S_OK)) { 00556 // cerr << "Could not get sampler input pin.\n"; 00557 // cleanup(); return; 00558 // } 00559 // CComQIPtr< IMemInputPin, &IID_IMemInputPin > pMemInputPin(iPin); 00560 // if (pMemInputPin == 0) { 00561 // cerr << "Could not get sampler meminput pin.\n"; 00562 // cleanup(); return; 00563 // } 00564 // hResult = pMemInputPin->GetAllocator(&_pAllocator); 00565 // if (hResult != S_OK) { 00566 // cerr << "Could not get sample grabber allocator handle.\n"; 00567 // } 00568 // ALLOCATOR_PROPERTIES props, aprops; 00569 // hResult = _pAllocator->GetProperties(&props); 00570 // if (hResult != S_OK) { 00571 // cerr << "Could not get allocator properties.\n"; 00572 // } 00573 // cerr << "Allocator properties: cBuffers=" << props.cBuffers << "\n"; 00574 // props.cBuffers += 10; 00575 // hResult = _pAllocator->SetProperties(&props, &aprops); 00576 // if (hResult != S_OK) { 00577 // cerr << "Could not set allocator properties.\n"; 00578 // } 00579 // cerr << "Allocator properties (adjusted): cBuffers=" << aprops.cBuffers << "\n"; 00580 00581 pVideoInfo=(VIDEOINFOHEADER*)mediaType.pbFormat; 00582 _size_x = pVideoInfo->bmiHeader.biWidth; 00583 _size_y = pVideoInfo->bmiHeader.biHeight; 00584 cerr << "Connected media type " << _size_x << " x " << _size_y << "\n"; 00585 00586 _sample_cb._host = this; 00587 _num_components = 3; 00588 _length = 1.0E10; 00589 _can_seek = false; 00590 _can_seek_fast = false; 00591 _aborted = false; 00592 _streaming = true; 00593 _buffer = new unsigned char[_size_x * _size_y * 3]; 00594 _ready = false; 00595 00596 if(mediaType.cbFormat != 0) { 00597 CoTaskMemFree((PVOID)mediaType.pbFormat); 00598 mediaType.cbFormat=0; 00599 mediaType.pbFormat=NULL; 00600 } 00601 00602 if(mediaType.pUnk != NULL) { 00603 mediaType.pUnk->Release(); 00604 mediaType.pUnk=NULL; 00605 } 00606 00607 _pSampleGrabber->SetBufferSamples(FALSE); 00608 _pSampleGrabber->SetOneShot(FALSE); 00609 00610 hResult=_pSampleGrabber->SetCallback(&_sample_cb, 0); 00611 if(hResult != S_OK) { 00612 cerr << " Can not set the callback interface!"; 00613 cleanup(); return; 00614 } 00615 00616 _pMediaCtrl->Run(); 00617 } 00618 00619 //////////////////////////////////////////////////////////////////// 00620 // Function: WebcamVideoCursorDS::cleanup 00621 // Access: Published 00622 // Description: 00623 //////////////////////////////////////////////////////////////////// 00624 void WebcamVideoCursorDS:: 00625 cleanup() { 00626 if (_buffer) { 00627 delete[] _buffer; 00628 _buffer = 0; 00629 } 00630 00631 if (_pMediaCtrl) { 00632 _pMediaCtrl->Stop(); 00633 } 00634 00635 if(_pMediaCtrl) { _pMediaCtrl->Release(); _pMediaCtrl=NULL; } 00636 if(_pCaptureBuilder) { _pCaptureBuilder->Release(); _pCaptureBuilder=NULL; } 00637 if(_pGraphBuilder) { _pGraphBuilder->Release(); _pGraphBuilder=NULL; } 00638 if(_pSampleGrabber.p) { _pSampleGrabber.Release(); } 00639 if(_pStreamRenderer) { _pStreamRenderer->Release(); _pStreamRenderer=NULL; } 00640 if(_pSrcFilter) { _pSrcFilter->Release(); _pSrcFilter=NULL; } 00641 if(_pStreamConfig) { _pStreamConfig->Release(); _pStreamConfig=NULL; } 00642 } 00643 00644 //////////////////////////////////////////////////////////////////// 00645 // Function: WebcamVideoCursorDS::Destructor 00646 // Access: Published 00647 // Description: 00648 //////////////////////////////////////////////////////////////////// 00649 WebcamVideoCursorDS:: 00650 ~WebcamVideoCursorDS() { 00651 cleanup(); 00652 } 00653 00654 //////////////////////////////////////////////////////////////////// 00655 // Function: WebcamVideoCursorDS::fetch_buffer 00656 // Access: Published 00657 // Description: 00658 //////////////////////////////////////////////////////////////////// 00659 PT(MovieVideoCursor::Buffer) WebcamVideoCursorDS:: 00660 fetch_buffer() { 00661 if (!_ready) { 00662 return NULL; 00663 } 00664 00665 Buffer *buffer = get_standard_buffer(); 00666 unsigned char *block = buffer->_block; 00667 #ifdef LOCKING_MODE 00668 unsigned char *ptr; 00669 int pixels = _size_x * _size_y; 00670 HRESULT res = _saved->GetPointer(&ptr); 00671 if (res == S_OK) { 00672 int size = _saved->GetActualDataLength(); 00673 if (size == pixels * 3) { 00674 memcpy(block, ptr, pixels * 3); 00675 } 00676 } 00677 _saved->Release(); 00678 #else 00679 int pixels = _size_x * _size_y; 00680 memcpy(block, _buffer, pixels * 3); 00681 #endif 00682 00683 _ready = false; 00684 return buffer; 00685 } 00686 00687 00688 //////////////////////////////////////////////////////////////////// 00689 // Function: WebcamVideoCursorDS::CSampleGrabberCB::QueryInterface 00690 // Access: Private 00691 // Description: 00692 //////////////////////////////////////////////////////////////////// 00693 HRESULT __stdcall WebcamVideoCursorDS::CSampleGrabberCB::QueryInterface(REFIID riid, void **ppv) 00694 { 00695 if((riid == IID_ISampleGrabberCB) || (riid == IID_IUnknown)) { 00696 *ppv=(void *)static_cast<ISampleGrabberCB *> (this); 00697 return NOERROR; 00698 } 00699 return E_NOINTERFACE; 00700 } 00701 00702 00703 //////////////////////////////////////////////////////////////////// 00704 // Function: WebcamVideoCursorDS::CSampleGrabberCB::SampleCB 00705 // Access: Private 00706 // Description: 00707 //////////////////////////////////////////////////////////////////// 00708 HRESULT __stdcall WebcamVideoCursorDS::CSampleGrabberCB::SampleCB(double SampleTime, IMediaSample *pSample) 00709 { 00710 if (_host->_ready) { 00711 return 0; 00712 } 00713 00714 #ifdef LOCKING_MODE 00715 pSample->AddRef(); 00716 _host->_saved = pSample; 00717 #else 00718 unsigned char *ptr; 00719 int pixels = _host->_size_x * _host->_size_y; 00720 HRESULT res = pSample->GetPointer(&ptr); 00721 if (res == S_OK) { 00722 int size = pSample->GetActualDataLength(); 00723 if (size == pixels * 3) { 00724 memcpy(_host->_buffer, ptr, size); 00725 } 00726 } 00727 #endif 00728 00729 _host->_ready = true; 00730 return 0; 00731 } 00732 00733 //////////////////////////////////////////////////////////////////// 00734 // Function: WebcamVideoCursorDS::CSampleGrabberCB::BufferCB 00735 // Access: Private 00736 // Description: 00737 //////////////////////////////////////////////////////////////////// 00738 HRESULT __stdcall WebcamVideoCursorDS::CSampleGrabberCB::BufferCB(double dblSampleTime, BYTE *pBuffer, long lBufferSize) 00739 { 00740 // Not used. 00741 return 0; 00742 } 00743 00744 //HRESULT FindInputPin(IBaseFilter *pFilter, IPin **ppPin) 00745 //{ 00746 // if (!pFilter || ! ppPin) 00747 // return E_POINTER; 00748 // 00749 // *ppPin = 0; 00750 // HRESULT hr; 00751 // //Find the output pin of the Source Filter 00752 // IEnumPins *pPinEnum; 00753 // hr = pFilter->EnumPins(&pPinEnum); 00754 // if (FAILED(hr)) 00755 // return E_FAIL; 00756 // 00757 // IPin *pSearchPin; 00758 // while (pPinEnum->Next(1, &pSearchPin, NULL) == S_OK) 00759 // { 00760 // PIN_DIRECTION pPinDir; 00761 // hr = pSearchPin->QueryDirection(&pPinDir); 00762 // if (FAILED(hr)) 00763 // return E_FAIL; 00764 // if (pPinDir == PINDIR_INPUT) 00765 // { 00766 // //Found out pin 00767 // *ppPin = pSearchPin; 00768 // break; 00769 // } 00770 // } 00771 // pPinEnum->Release(); 00772 // return hr; 00773 //} 00774 00775 00776 #endif // HAVE_DIRECTSHOW