CameraSource.cpp

Go to the documentation of this file.
00001 /*
00002 *       This file contains class that load images from specified video sequence.
00003 *
00004 *       Author:
00005 *                       Tomas Mrkvicka
00006 *                       xmrkvi03@stud.fit.vutbr.cz
00007 *
00008 */
00009 
00010 
00011 #include "StdAfx.h"
00012 #include <tchar.h>
00013 #include <strsafe.h>
00014 #include <cstdlib>
00015 #include "CameraSource.h"
00016 
00017 
00018 ////////////////////////////////////////////////////////////////////////////////
00019 ////////////////////////////////////////////////////////////////////////////////
00020 ////////////////////////////////////////////////////////////////////////////////
00021 // TDSSampler
00022 
00023 /** Vytvori filter s jednou referenci.
00024 *
00025 *       \param  unk             [in] povinne predavane rozhrani pro bazovou tridu CBaseVideoRenderer - muze byt NULL
00026 *       \param  hr              [in] promenna pro ulozeni vysledku
00027 */
00028 TDSSampler::TDSSampler( IUnknown* unk, HRESULT *hr ):
00029                 CBaseVideoRenderer(__uuidof(CLSID_Sampler), NAME("RGB Sampler"), unk, hr)
00030 {       
00031         this->AddRef();
00032 
00033         m_data1 = NULL;
00034         m_data2 = NULL;
00035 };
00036 
00037 /** Destruktor.
00038 *
00039 *       Uvolni vsechny prostredky.
00040 */
00041 TDSSampler::~TDSSampler()
00042 {
00043         delete [] m_data1;
00044         delete [] m_data2;
00045 }
00046 
00047 /** Overeni typu pripojeneho datoveho zdroje.
00048 *
00049 *       \param  media   [in] parametry vstupniho datoveho zdroje zaslane DirectShow grafem.
00050 */
00051 HRESULT TDSSampler::CheckMediaType( const CMediaType* media ) 
00052 {
00053         if ( NULL == media )
00054         {
00055                 return E_FAIL;
00056         }
00057 
00058         //mozne formaty jsou pouze VIDEOINFO a VIDEOINFO2
00059         //FORMAT_VideoInfo
00060         if ( FORMAT_VideoInfo == ( *media->FormatType() ) )
00061         {
00062                 VIDEOINFOHEADER* vi;
00063 
00064                 if (
00065                         ! IsEqualGUID( *( media->Subtype() ), MEDIASUBTYPE_RGB24) ||    // musi byt RGB format
00066                         ! ( vi = (VIDEOINFOHEADER *)media->Format() )                                   // musi existovat platna hlavicka
00067                 ) 
00068                 {
00069                         //podminka nesplnena => filtr nelze pripojit
00070                         return E_FAIL;
00071                 }
00072                 else
00073                 {
00074                         //pouzitelny format
00075                         m_info = vi->bmiHeader;
00076                 }
00077         }
00078         else
00079         {
00080                 //FORMAT_VideoInfo2
00081                 if ( FORMAT_VideoInfo2 == ( *media->FormatType() ) )
00082                 {
00083                         VIDEOINFOHEADER2* vi;
00084 
00085                         if (
00086                                 ! IsEqualGUID( *( media->Subtype() ), MEDIASUBTYPE_RGB24) ||    // musi byt RGB format
00087                                 ! ( vi = (VIDEOINFOHEADER2 *)media->Format() )                                  // musi existovat platna hlavicka
00088                         ) 
00089                         {
00090                                 //podminka nesplnena => filtr nelze pripojit
00091                                 return E_FAIL;
00092                         }
00093                         else
00094                         {
00095                                 //pouzitelny format
00096                                 m_info = vi->bmiHeader;
00097                         }
00098                 }
00099                 else
00100                 {
00101                         // nepouzitelny format
00102                         return E_FAIL;
00103                 }
00104         }       
00105 
00106         //ulozime informace o datovem formatu
00107 
00108         m_rgb_width             = m_info.biWidth;
00109         m_rgb_height    = abs(m_info.biHeight);
00110         m_rgb_size              = m_rgb_width * m_rgb_height * 3;
00111 
00112         m_rowsFliped    = m_info.biHeight >= 0;
00113 
00114         //vypocitame zarovnovaci bajty - tj. delku celeho radku v puvodnim obraze
00115         int tmp_width = m_rgb_width * 3;        //sirka v bajtech
00116         if ( (tmp_width % 4) > 0 )
00117         {
00118                 m_img_align = 4 - ( tmp_width % 4 );
00119         }
00120         else
00121         {
00122                 m_img_align = 0;
00123         }
00124         m_img_stride = tmp_width + m_img_align;
00125 
00126         //vytvorime pole pro vysledky
00127         delete [] m_data1;
00128         m_data1 = NULL;
00129         delete [] m_data2;
00130         m_data2 = NULL;
00131 
00132         m_data1 = new BYTE[m_rgb_size];
00133         m_data2 = new BYTE[m_rgb_size];
00134 
00135         return  S_OK;
00136 }
00137 
00138 /** Ziskani dalsiho snimku z datoveho toku.
00139 *
00140 *       Metoda je volana grafem DirectShow.
00141 *
00142 *       \param  sample  [in] dalsi ziskany vzorek
00143 */
00144 HRESULT TDSSampler::DoRenderSample(IMediaSample *sample)
00145 {
00146         //zapiseme data do druheho snimku
00147         BYTE * src = NULL;
00148         sample->GetPointer( &src );
00149 
00150         //kopirujeme radek po radku
00151         //musime zvolit kopirovani podle poradi radku
00152         DWORD offsetSrc = 0;
00153         DWORD offsetDst = 0;    
00154         if ( m_rowsFliped )
00155         {
00156                 //radky odspoda nahoru
00157                 for ( int r = (m_rgb_height - 1) ; r >= 0 ; r-- )
00158                 {
00159                         offsetDst = r * m_rgb_width * 3;
00160 
00161                         for ( int c = 0 ; c < m_rgb_width ; c++ ) //sloupce
00162                         {
00163                                 m_data2[offsetDst++] = src[offsetSrc++];        // B
00164                                 m_data2[offsetDst++] = src[offsetSrc++];        // G
00165                                 m_data2[offsetDst++] = src[offsetSrc++];        // R                            
00166                         }
00167                         offsetSrc += m_img_align;
00168                 }
00169         }
00170         else
00171         {
00172                 //radky odshoda dolu
00173                 for ( int r = 0 ; r < m_rgb_height ; r++ )
00174                 {
00175                         for ( int c = 0 ; c < m_rgb_width ; c++ ) //sloupce
00176                         {
00177                                 m_data2[offsetDst++] = src[offsetSrc++];        // B
00178                                 m_data2[offsetDst++] = src[offsetSrc++];        // G
00179                                 m_data2[offsetDst++] = src[offsetSrc++];        // R                            
00180                         }
00181                         offsetSrc += m_img_align;
00182                 }
00183         }
00184 
00185         //vymenime ukazatele
00186         m_cs.Lock();
00187                 BYTE * tmp = m_data1;
00188                 m_data1 = m_data2;
00189                 m_data2 = tmp;
00190         m_cs.Unlock();
00191 
00192         return  S_OK;
00193 }
00194 
00195 /** Metoda grafu DirectShow pro overeni co udelat se zadanym snimkem.
00196 *
00197 *       V tomto pripade se kazdy snimek bude spravne zobrazovat podle jeho zadaneho casu.
00198 *       
00199 *       \param  sample          [in] snimek o kterem se rozhoduje
00200 *       \param  start           [in] cas pro pocatek zobrazeni snimku
00201 *       \param  stop            [in] cas pro konec zobrazeni snimku
00202 */
00203 HRESULT TDSSampler::ShouldDrawSampleNow(
00204         IMediaSample *sample,
00205         REFERENCE_TIME *start,
00206         REFERENCE_TIME *stop
00207         ) 
00208 {
00209         //zadny snimek nebude zahozen - kazdy snimek bude zobrazen podle jeho casu
00210         // vracenim S_OK dosahneme okamziteho zobrazeni snimku !!!
00211         return S_FALSE;
00212 }
00213 
00214 /** Nakopiruje data do pripraveneho bufferu.
00215 *
00216 *       \param  data    [in out] buffer pro ulozeni dat ve formatu RGB 
00217 */
00218 void TDSSampler::GetData( void * data )
00219 {
00220         //posledni snimek je ulozen v M_DATA1
00221         m_cs.Lock();
00222 
00223                 //prekopirujeme data
00224                 memcpy( data, m_data1, m_rgb_size );
00225 
00226         m_cs.Unlock();
00227 }
00228 
00229 // TDSSampler
00230 ////////////////////////////////////////////////////////////////////////////////
00231 ////////////////////////////////////////////////////////////////////////////////
00232 ////////////////////////////////////////////////////////////////////////////////
00233 
00234 /** Konstruktor.
00235 *
00236 *       Inicializuje vse na NULL.
00237 *
00238 *       Inicializace musi byt provedena metodou Initialize() !!!
00239 */
00240 TVideoDSFile::TVideoDSFile(void)
00241 {
00242         m_graph = NULL;
00243         m_ctrl = NULL;
00244         m_sampler = NULL;
00245 }
00246 
00247 /** Destruktor.
00248 *
00249 *       Odstrani DirectShow graf a deinicializuje COM.
00250 */
00251 TVideoDSFile::~TVideoDSFile(void)
00252 {
00253         this->Destroy();
00254 }
00255 
00256 /** Najde prvni kameru v systemu a jeji vystupni pin.
00257 *
00258 *       Vraci TRUE pri nalezeni kamery. Jinak jsou vystupni parametry neplatne.
00259 *
00260 *       \param  camera          [out] adresa pro ulozeni ukazatele na kameru
00261 *       \param  cameraOut       [out] adresa pro ulozeni ukazatele na vystup z kamery
00262 */
00263 bool TVideoDSFile::EnumCamera( IBaseFilter ** camera, IPin ** cameraOut )
00264 {
00265         HRESULT hr;
00266 
00267     ICreateDevEnum* enums = NULL;
00268         hr = CoCreateInstance ( CLSID_SystemDeviceEnum, 0, CLSCTX_INPROC, IID_ICreateDevEnum, (void **) &enums );
00269         if ( FAILED ( hr ) )
00270         {
00271                 return false;
00272         }
00273 
00274     IEnumMoniker* enumsMon = NULL; 
00275         hr = enums->CreateClassEnumerator ( CLSID_VideoInputDeviceCategory, &enumsMon, 0 );  
00276         if ( FAILED ( hr ) )
00277         {
00278                 enums->Release();
00279                 return false;
00280         }
00281 
00282     IMoniker* moniker = NULL; 
00283         hr = enumsMon->Next (1, &moniker, 0 );
00284         if ( FAILED( hr ) )
00285         {
00286                 enumsMon->Release();
00287                 enums->Release();
00288                 return false;
00289         }
00290 
00291     IBaseFilter* lcamera = NULL;
00292         hr = moniker->BindToObject( 0, 0, IID_IBaseFilter, (void**) &lcamera );
00293         if ( FAILED ( hr ) )
00294         {
00295                 moniker->Release();
00296                 enumsMon->Release();
00297                 enums->Release();
00298                 return false;
00299         }
00300 
00301     IEnumPins* enumsPins = NULL; 
00302         hr = lcamera->EnumPins( &enumsPins ); 
00303         if ( FAILED( hr ) )
00304         {
00305                 lcamera->Release();
00306                 moniker->Release();
00307                 enumsMon->Release();
00308                 enums->Release();
00309                 return false;
00310         }
00311 
00312     IPin* lcameraOut  = 0;
00313         hr = enumsPins->Next( 1, &lcameraOut, 0);
00314         if ( FAILED( hr ) )
00315         {
00316                 enumsPins->Release();
00317                 lcamera->Release();
00318                 moniker->Release();
00319                 enumsMon->Release();
00320                 enums->Release();
00321                 return false;
00322         }
00323 
00324         *camera = lcamera;
00325         *cameraOut = lcameraOut;
00326 
00327         return true;
00328 }
00329 
00330 /** Inicializace DirectShow grafu.
00331 *
00332 *       Vraci TRUE pokud probehla inicializace uspesne nebo pokud byl jiz graf otevren.
00333 *
00334 */
00335 bool TVideoDSFile::Initialize( void )
00336 {
00337         if ( ! m_graph )
00338         {
00339                 //vytvorime novy graf
00340 
00341                 //inicializace COM
00342                 if ( FAILED( CoInitialize( 0 ) ) )
00343                 {
00344                         return false;
00345                 }
00346 
00347                 //vytvorime graf a ziskame jeho ovladani
00348                 HRESULT hr = 
00349                         CoCreateInstance( CLSID_FilterGraph, 0, CLSCTX_INPROC, IID_IGraphBuilder, (void **)  &m_graph );
00350                 if ( FAILED( hr ) )
00351                 {
00352                         m_graph = NULL;
00353                         CoUninitialize();
00354                         return false;
00355                 }
00356 
00357                 hr = m_graph->QueryInterface( IID_IMediaControl, (void **) &m_ctrl );
00358                 if ( FAILED( hr ) )
00359                 {
00360                         m_ctrl = NULL;
00361                         m_graph->Release(); m_graph = NULL;
00362                         CoUninitialize();
00363                         return false;
00364                 }
00365 
00366                 //pomocny objekt pro tvorbu grafu
00367                 ICaptureGraphBuilder2 * builder = NULL;
00368                 hr = CoCreateInstance( CLSID_CaptureGraphBuilder2, 0, CLSCTX_INPROC, IID_ICaptureGraphBuilder2, (void **)  &builder );
00369                 if ( FAILED( hr ) )
00370                 {
00371                         m_ctrl->Release(); m_ctrl = NULL;
00372                         m_graph->Release(); m_graph = NULL;
00373                         CoUninitialize();
00374                         return false;
00375                 }
00376 
00377                 hr = builder->SetFiltergraph( m_graph );
00378                 if ( FAILED( hr ) )
00379                 {
00380                         builder->Release(); builder = NULL;
00381                         m_ctrl->Release(); m_ctrl = NULL;
00382                         m_graph->Release(); m_graph = NULL;
00383                         CoUninitialize();
00384                         return false;
00385                 }
00386 
00387                 //vytvorime sampler - ma jednu referenci ziskanou v kontruktoru
00388                 m_sampler = new TDSSampler( 0, &hr );
00389 
00390                 //ziskame zdroj videa
00391                 
00392                 IBaseFilter* video  = NULL; 
00393                 IPin* videoOut  = NULL;
00394 
00395                 if ( ! this->EnumCamera( &video, &videoOut ) )
00396                 {
00397                         m_sampler->Release(); m_sampler = NULL;
00398                         builder->Release(); builder = NULL;
00399                         m_ctrl->Release(); m_ctrl = NULL;
00400                         m_graph->Release(); m_graph = NULL;
00401                         CoUninitialize();
00402                         return false;
00403                 }
00404                 //pin nebudeme potrebovat
00405                 videoOut->Release();
00406                 videoOut = NULL;
00407                 
00408                 //pridame kameru do grafu
00409                 hr = m_graph->AddFilter( video, L"DirectShow camera" );
00410                 if ( FAILED ( hr ) )
00411                 {                       
00412                         video->Release(); video = NULL;
00413                         m_sampler->Release(); m_sampler = NULL;
00414                         builder->Release(); builder = NULL;
00415                         m_ctrl->Release(); m_ctrl = NULL;
00416                         m_graph->Release(); m_graph = NULL;
00417                         CoUninitialize();
00418                         return false;
00419                 }               
00420                 
00421                 //sestavime graf
00422                 hr = m_graph->AddFilter( (IBaseFilter*)m_sampler, L"Sampler" );
00423                 if ( FAILED( hr ) )
00424                 {
00425                         video->Release(); video = NULL;
00426                         m_sampler->Release(); m_sampler = NULL;
00427                         builder->Release(); builder = NULL;
00428                         m_ctrl->Release(); m_ctrl = NULL;
00429                         m_graph->Release(); m_graph = NULL;
00430                         CoUninitialize();
00431                         return false;
00432                 }
00433 
00434                 hr = builder->RenderStream( &PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, video, NULL, m_sampler );
00435                 if ( FAILED( hr ) )
00436                 {
00437                         video->Release(); video = NULL;
00438                         m_sampler->Release(); m_sampler = NULL;
00439                         builder->Release(); builder = NULL;
00440                         m_ctrl->Release(); m_ctrl = NULL;
00441                         m_graph->Release(); m_graph = NULL;
00442                         CoUninitialize();
00443                         return false;
00444                 }
00445 
00446                 //bulider uz neni dale potreba
00447                 builder->Release();
00448                 builder = NULL;
00449 
00450                 //kameru uz take ne - je v grafu
00451                 video->Release();
00452                 video = NULL;   
00453 
00454                 //nyni by mel mit sampler informace o videoformatu
00455                 {
00456                         m_width = m_sampler->GetWidth();
00457                         m_height = m_sampler->GetHeight();
00458                 }
00459 
00460                 //spustime graf
00461                 hr = m_ctrl->Run();
00462                 if ( FAILED( hr ) )
00463                 {
00464                         m_sampler->Release(); m_sampler = NULL;
00465                         m_ctrl->Release(); m_ctrl = NULL;
00466                         m_graph->Release(); m_graph = NULL;
00467                         CoUninitialize();
00468                         return false;
00469                 }
00470 
00471                 return true;
00472         }
00473         else
00474         {
00475                 //graf uz existuje
00476                 return true;
00477         }
00478 }
00479 
00480 /** Odstraneni aktualniho grafu (pokud existuje) a deinicializace COM.
00481 */
00482 bool TVideoDSFile::Destroy(void)
00483 {
00484         if ( m_graph )
00485         {
00486                 //nejprve graf radeji zastavime
00487                 m_ctrl->Stop();
00488 
00489                 //odstranime graf
00490                 if ( m_sampler )
00491                 {
00492                         m_sampler->Release();
00493                         m_sampler = NULL;
00494                 }
00495 
00496                 if ( m_ctrl )
00497                 {
00498                         m_ctrl->Release();
00499                         m_ctrl = NULL;
00500                 }
00501 
00502                 m_graph->Release();
00503                 m_graph = NULL;
00504 
00505                 CoUninitialize();
00506         }
00507 
00508         return true;
00509 }
00510 
00511 /** Nakopiruje data ve formatu RGB z posledniho zachyceneho obrazku (pokud existuje)
00512 *       do pripraveneho bufferu, jehoz velikost musi byt minimalne 
00513 *
00514 *               GetWidth() * GetHeight() * 3 bajty
00515 *
00516 *       \param  data    [in out] buffer pro pixely ve formatu RGB
00517 */
00518 void TVideoDSFile::GetDataRGB( void * data )
00519 {
00520         m_sampler->GetData( data );
00521 }
00522 
00523 // TVideoDSFile
00524 ////////////////////////////////////////////////////////////////////////////////
00525 ////////////////////////////////////////////////////////////////////////////////
00526 ////////////////////////////////////////////////////////////////////////////////

Generated on Sat Nov 17 16:23:33 2007 for Image Processing Pipeline - Camera Sources Implementation by  doxygen 1.4.6-NO