Panda3D

webcamVideoDS.cxx

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
 All Classes Functions Variables Enumerations