00001
00002 #include "stdafx.h"
00003
00004 #define _WIN32_WINNT 0x400
00005
00006 #include <atlbase.h>
00007 #include <windows.h>
00008 #include <dshow.h>
00009 #include <qedit.h>
00010 #include <objbase.h>
00011
00012 #include <stdio.h>
00013 #include <stdlib.h>
00014
00015 #include "dshowcb.h"
00016
00017 #include "iniparser.h"
00018
00019 const LONGLONG MILLISECONDS = (1000);
00020 const LONGLONG NANOSECONDS = (1000000000);
00021 const LONGLONG UNITS = (NANOSECONDS / 100);
00022
00023 void DShowCBFactory::registerParameters(ParamSection *sec) {
00024 sec->addBoolParam("useDShowCB", &use, true);
00025 };
00026
00027 VideoSource *DShowCBFactory::construct() {
00028 if (use) {
00029 DShowCB *vs = new DShowCB();
00030 if (vs->initialize()) return vs;
00031 delete vs;
00032 }
00033 return 0;
00034 }
00035
00036
00037
00038
00039
00040
00041 class SampleGrabberCB : public ISampleGrabberCB
00042 {
00043
00044 public:
00045
00046
00047
00048 long Width;
00049 long Height;
00050 IplImage *image;
00051 int frameId;
00052 bool frameWanted;
00053 HANDLE event;
00054
00055
00056
00057 STDMETHODIMP_(ULONG) AddRef() { return 2; }
00058 STDMETHODIMP_(ULONG) Release() { return 1; }
00059
00060
00061
00062 STDMETHODIMP QueryInterface(REFIID riid, void ** ppv)
00063 {
00064 if (!ppv) return E_POINTER;
00065
00066 if( riid == IID_ISampleGrabberCB || riid == IID_IUnknown )
00067 {
00068 *ppv = (void *) static_cast<ISampleGrabberCB*> ( this );
00069 return NOERROR;
00070 }
00071
00072 return E_NOINTERFACE;
00073 }
00074
00075
00076
00077
00078 STDMETHODIMP SampleCB( double SampleTime, IMediaSample * pSample )
00079 {
00080 return 0;
00081 }
00082
00083
00084
00085
00086
00087 STDMETHODIMP BufferCB( double SampleTime, BYTE * pBuffer, long BufferSize )
00088 {
00089 frameId++;
00090 if (!frameWanted) return 0;
00091
00092 if (BufferSize > image->imageSize) {
00093 fprintf(stderr, __FILE__ ": error ! image size too big !!\n");
00094 return 0;
00095 }
00096
00097 memcpy(image->imageData, pBuffer, BufferSize);
00098 frameWanted=false;
00099 SetEvent(event);
00100 return 0;
00101 }
00102 };
00103
00104
00105
00106 SampleGrabberCB CB;
00107
00108
00109 int GrabBitmaps(TCHAR * szFile);
00110 HRESULT GetPin(IBaseFilter * pFilter, PIN_DIRECTION dirrequired, int iNum, IPin **ppPin);
00111 IPin * GetInPin ( IBaseFilter *pFilter, int Num );
00112 IPin * GetOutPin( IBaseFilter *pFilter, int Num );
00113
00114 DShowCB::DShowCB()
00115 {
00116 image =0;
00117 frameCnt=0;
00118 g_psCurrent = Stopped;
00119 }
00120
00121 DShowCB::~DShowCB()
00122 {
00123 m_pCapture->Release();
00124 m_pMC->Release();
00125 if (image) cvReleaseImage(&image);
00126 }
00127
00128 bool DShowCB::initialize()
00129 {
00130 HRESULT hr;
00131
00132
00133 if(FAILED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)))
00134 {
00135 fprintf(stderr, "CoInitialize Failed!\r\n");
00136
00137 }
00138
00139
00140
00141 pGrabber.CoCreateInstance( CLSID_SampleGrabber );
00142 if( !pGrabber )
00143 {
00144 fprintf(stderr, "Could not create CLSID_SampleGrabber\r\n");
00145 return false;
00146 }
00147 CComQIPtr< IBaseFilter, &IID_IBaseFilter > pGrabberBase( pGrabber );
00148
00149
00150
00151 pGraph.CoCreateInstance( CLSID_FilterGraph );
00152 if( !pGraph )
00153 {
00154 fprintf(stderr, "Could not not create the graph\r\n");
00155 return false;
00156 }
00157
00158 hr = CoCreateInstance (CLSID_CaptureGraphBuilder2 , NULL, CLSCTX_INPROC,
00159 IID_ICaptureGraphBuilder2, (void **) &m_pCapture);
00160 if (FAILED(hr)) return false;
00161
00162
00163 hr = pGraph->QueryInterface(IID_IMediaControl,(LPVOID *) &m_pMC);
00164 if (FAILED(hr)) return false;
00165
00166
00167 hr = m_pCapture->SetFiltergraph(pGraph);
00168 if (FAILED(hr))
00169 {
00170 fprintf(stderr, "Failed to set capture filter graph! hr=0x%x", hr);
00171 return false;
00172 }
00173
00174
00175
00176 IBaseFilter *pSrcFilter=NULL;
00177 hr = FindCaptureDevice(&pSrcFilter);
00178 if (FAILED(hr)) return false;
00179
00180
00181 hr = pGraph->AddFilter(pSrcFilter, L"Video Capture");
00182 if (FAILED(hr))
00183 {
00184 fprintf(stderr, "Couldn't add the capture filter to the graph! hr=0x%x\r\n\r\n"
00185 "If you have a working video capture device, please make sure\r\n"
00186 "that it is connected and is not being used by another application.\r\n\r\n", hr);
00187 pSrcFilter->Release();
00188 return false;
00189 }
00190
00191
00192
00193 hr = pGraph->AddFilter( pGrabberBase, L"Grabber" );
00194
00195
00196
00197
00198
00199 AM_MEDIA_TYPE mt;
00200 ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
00201 mt.majortype = MEDIATYPE_Video;
00202 mt.subtype = MEDIASUBTYPE_RGB24;
00203 hr = pGrabber->SetMediaType(&mt);
00204 if (FAILED(hr)) return false;
00205
00206
00207
00208
00209 CComPtr< IPin > pSourcePin;
00210 CComPtr< IPin > pGrabPin;
00211
00212 pSourcePin = GetOutPin( pSrcFilter, 0 );
00213 pGrabPin = GetInPin( pGrabberBase, 0 );
00214
00215
00216
00217 hr = pGraph->Connect( pSourcePin, pGrabPin );
00218 if( FAILED( hr ) )
00219 {
00220 fprintf(stderr, "Could not connect source filter to grabber\r\n");
00221 return false;
00222 }
00223
00224
00225
00226 hr = pGrabber->GetConnectedMediaType( &mt );
00227
00228 VIDEOINFOHEADER * vih = (VIDEOINFOHEADER*) mt.pbFormat;
00229 CB.Width = vih->bmiHeader.biWidth;
00230 CB.Height = vih->bmiHeader.biHeight;
00231 CB.image = image = cvCreateImage(cvSize(CB.Width, CB.Height), IPL_DEPTH_8U, 3);
00232
00233
00234
00235 CComPtr <IPin> pGrabOutPin = GetOutPin( pGrabberBase, 0 );
00236 hr = pGraph->Render( pGrabOutPin );
00237 if( FAILED( hr ) )
00238 {
00239 fprintf(stderr, "Could not render grabber output pin\r\n");
00240 return false;
00241 }
00242
00243
00244
00245 hr = pGrabber->SetBufferSamples( FALSE );
00246
00247
00248
00249
00250 hr = pGrabber->SetOneShot( FALSE );
00251
00252
00253
00254 hr = pGrabber->SetCallback( &CB, 1 );
00255
00256
00257
00258
00259 CComQIPtr< IVideoWindow, &IID_IVideoWindow > pWindow = pGraph;
00260 if (pWindow)
00261 {
00262 hr = pWindow->put_AutoShow(OAFALSE);
00263 }
00264
00265 CB.event = CreateEvent(0, FALSE, FALSE, _T("newFrameEvent"));
00266 if (CB.event == NULL) {
00267 fprintf(stderr, "CreateEvent failed!\n");
00268 return false;
00269 }
00270
00271 pSrcFilter->Release();
00272 pSrcFilter=0;
00273
00274 start();
00275
00276 return true;
00277 }
00278
00279 bool DShowCB::getFrame(IplImage *dst) {
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289 CB.frameWanted = true;
00290
00291
00292 WaitForSingleObject(CB.event, 100);
00293 deinterlaceAndResize(image, dst);
00294
00295 return true;
00296 }
00297
00298
00299 void DShowCB::getSize(int &width, int &height)
00300 {
00301 width = CB.Width;
00302 height = CB.Height;
00303 }
00304
00305 void DShowCB::start()
00306 {
00307 g_psCurrent = Playing;
00308 m_pMC->Run();
00309 }
00310
00311 void DShowCB::stop()
00312 {
00313 g_psCurrent = Paused;
00314 m_pMC->Pause();
00315 }
00316
00317 static HRESULT GetPin( IBaseFilter * pFilter, PIN_DIRECTION dirrequired, int iNum, IPin **ppPin)
00318 {
00319 CComPtr< IEnumPins > pEnum;
00320 *ppPin = NULL;
00321
00322 HRESULT hr = pFilter->EnumPins(&pEnum);
00323 if(FAILED(hr))
00324 return hr;
00325
00326 ULONG ulFound;
00327 IPin *pPin;
00328 hr = E_FAIL;
00329
00330 while(S_OK == pEnum->Next(1, &pPin, &ulFound))
00331 {
00332 PIN_DIRECTION pindir = (PIN_DIRECTION)3;
00333
00334 pPin->QueryDirection(&pindir);
00335 if(pindir == dirrequired)
00336 {
00337 if(iNum == 0)
00338 {
00339 *ppPin = pPin;
00340 hr = S_OK;
00341 break;
00342 }
00343 iNum--;
00344 }
00345
00346 pPin->Release();
00347 }
00348
00349 return hr;
00350 }
00351
00352
00353 static IPin * GetInPin( IBaseFilter * pFilter, int nPin )
00354 {
00355 CComPtr<IPin> pComPin=0;
00356 GetPin(pFilter, PINDIR_INPUT, nPin, &pComPin);
00357 return pComPin;
00358 }
00359
00360
00361 static IPin * GetOutPin( IBaseFilter * pFilter, int nPin )
00362 {
00363 CComPtr<IPin> pComPin=0;
00364 GetPin(pFilter, PINDIR_OUTPUT, nPin, &pComPin);
00365 return pComPin;
00366 }
00367
00368
00369 static void deinterlaceAndResize(IplImage *image, IplImage *realDst)
00370 {
00371
00372 static IplImage *tmpIm = 0;
00373
00374 if (tmpIm==0)
00375 tmpIm = cvCreateImage(cvGetSize(realDst), IPL_DEPTH_8U, 3);
00376
00377 IplImage *dst = realDst;
00378
00379
00380 if (image->nChannels != realDst->nChannels)
00381 dst = tmpIm;
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395 if ((dst->width == (image->width/2)) && (dst->height == (image->height/2))) {
00396
00397 for(int y = 0; y < dst->height; y++)
00398 {
00399 unsigned char *srcpix = ((unsigned char *)(image->imageData)) + 2*y*image->widthStep;
00400 unsigned char *dstpix = ((unsigned char *)(dst->imageData)) + (dst->height-1 - y)*dst->widthStep;
00401 if (image->nChannels == 1) {
00402 for (int x=0; x < dst->width; ++x) {
00403 *dstpix++ = unsigned char((int(srcpix[0])+int(srcpix[1]))>>1);
00404 srcpix+=2;
00405 }
00406 } else {
00407 for (int x=0; x < dst->width; ++x) {
00408 *dstpix++ = unsigned char((int(srcpix[0])+int(srcpix[3]))>>1);
00409 *dstpix++ = unsigned char((int(srcpix[1])+int(srcpix[4]))>>1);
00410 *dstpix++ = unsigned char((int(srcpix[2])+int(srcpix[5]))>>1);
00411 srcpix+=6;
00412 }
00413 }
00414 }
00415 } else {
00416 static IplImage *tmpIm = 0;
00417 if (tmpIm==0)
00418 tmpIm = cvCreateImage(cvSize(image->width, image->height/2), IPL_DEPTH_8U, 3);
00419
00420
00421 for(int y = 0; y < tmpIm->height; y++)
00422 {
00423 int srcY = (image->height-1 - 2*y);
00424
00425 memcpy(tmpIm->imageData + y*tmpIm->widthStep, image->imageData + srcY*image->widthStep,
00426 image->widthStep);
00427 }
00428
00429 cvResize(tmpIm, dst);
00430 }
00431 if (image->nChannels != realDst->nChannels)
00432 cvCvtColor(tmpIm, realDst, CV_RGB2GRAY);
00433 }
00434
00435 HRESULT DShowCB::FindCaptureDevice(IBaseFilter ** ppSrcFilter)
00436 {
00437 HRESULT hr;
00438 IBaseFilter * pSrc = NULL;
00439 CComPtr <IMoniker> pMoniker =NULL;
00440 ULONG cFetched;
00441
00442 if (!ppSrcFilter)
00443 return E_POINTER;
00444
00445
00446 CComPtr <ICreateDevEnum> pDevEnum =NULL;
00447
00448 hr = CoCreateInstance (CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
00449 IID_ICreateDevEnum, (void **) &pDevEnum);
00450 if (FAILED(hr))
00451 {
00452 fprintf(stderr, "Couldn't create system enumerator! hr=0x%x", hr);
00453 return hr;
00454 }
00455
00456
00457 CComPtr <IEnumMoniker> pClassEnum = NULL;
00458
00459 hr = pDevEnum->CreateClassEnumerator (CLSID_VideoInputDeviceCategory, &pClassEnum, 0);
00460 if (FAILED(hr))
00461 {
00462 fprintf(stderr, "Couldn't create class enumerator! hr=0x%x", hr);
00463 return hr;
00464 }
00465
00466
00467
00468 if (pClassEnum == NULL)
00469 {
00470 fprintf(stderr,"No Video Capture Hardware found\n");
00471 return E_FAIL;
00472 }
00473
00474
00475
00476
00477
00478 if (S_OK == (pClassEnum->Next (1, &pMoniker, &cFetched)))
00479 {
00480
00481 hr = pMoniker->BindToObject(0,0,IID_IBaseFilter, (void**)&pSrc);
00482 if (FAILED(hr))
00483 {
00484 fprintf(stderr, "Couldn't bind moniker to filter object! hr=0x%x", hr);
00485 return hr;
00486 }
00487 }
00488 else
00489 {
00490 fprintf(stderr,"Unable to access video capture device!\n");
00491 return E_FAIL;
00492 }
00493
00494
00495
00496
00497 *ppSrcFilter = pSrc;
00498
00499 return hr;
00500 }
00501