VideoDS.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 "VideoDS.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         VIDEOINFO* vi; 
00054         
00055         if (
00056                 ! IsEqualGUID( *media->Subtype(), MEDIASUBTYPE_RGB24) ||        // musi byt RGB format
00057                 ! ( vi = (VIDEOINFO *)media->Format() )                                         // musi se existovat platna hlavicka
00058         ) 
00059         {
00060                 //podminka nesplnena => filtr nelze pripojit
00061                 return E_FAIL;
00062         }
00063 
00064         //ulozime informace o datovem formatu
00065         m_info = vi->bmiHeader; 
00066 
00067         m_rgb_width             = m_info.biWidth;
00068         m_rgb_height    = abs(m_info.biHeight);
00069         m_rgb_size              = m_rgb_width * m_rgb_height * 3;
00070 
00071         m_rowsFliped = m_info.biHeight >= 0;
00072 
00073         //vypocitame zarovnovaci bajty - tj. delku celeho radku v puvodnim obraze
00074         int tmp_width = m_rgb_width * 3;        //sirka v bajtech
00075         if ( (tmp_width % 4) > 0 )
00076         {
00077                 m_img_align = 4 - ( tmp_width % 4 );
00078         }
00079         else
00080         {
00081                 m_img_align = 0;
00082         }
00083         m_img_stride = tmp_width + m_img_align;
00084 
00085         //vytvorime pole pro vysledky
00086         delete [] m_data1;
00087         m_data1 = NULL;
00088         delete [] m_data2;
00089         m_data2 = NULL;
00090 
00091         m_data1 = new BYTE[m_rgb_size];
00092         m_data2 = new BYTE[m_rgb_size];
00093 
00094         return  S_OK;
00095 }
00096 
00097 /** Ziskani dalsiho snimku z datoveho toku.
00098 *
00099 *       Metoda je volana grafem DirectShow.
00100 *
00101 *       \param  sample  [in] dalsi ziskany vzorek
00102 */
00103 HRESULT TDSSampler::DoRenderSample(IMediaSample *sample)
00104 {
00105         //zapiseme data do druheho snimku
00106         BYTE * src = NULL;
00107         sample->GetPointer( &src );
00108 
00109         //kopirujeme radek po radku
00110         //musime zvolit kopirovani podle poradi radku
00111         DWORD offsetSrc = 0;
00112         DWORD offsetDst = 0;
00113         if ( m_rowsFliped )
00114         {
00115                 //radky odspoda nahoru
00116                 for ( int r = (m_rgb_height - 1) ; r >= 0 ; r-- )
00117                 {
00118                         offsetDst = r * m_rgb_width * 3;
00119 
00120                         for ( int c = 0 ; c < m_rgb_width ; c++ ) //sloupce
00121                         {
00122                                 m_data2[offsetDst++] = src[offsetSrc++];        // B
00123                                 m_data2[offsetDst++] = src[offsetSrc++];        // G
00124                                 m_data2[offsetDst++] = src[offsetSrc++];        // R                            
00125                         }
00126                         offsetSrc += m_img_align;
00127                 }
00128         }
00129         else
00130         {
00131                 //radky odshoda dolu
00132                 for ( int r = 0 ; r < m_rgb_height ; r++ )
00133                 {
00134                         for ( int c = 0 ; c < m_rgb_width ; c++ ) //sloupce
00135                         {
00136                                 m_data2[offsetDst++] = src[offsetSrc++];        // B
00137                                 m_data2[offsetDst++] = src[offsetSrc++];        // G
00138                                 m_data2[offsetDst++] = src[offsetSrc++];        // R                            
00139                         }
00140                         offsetSrc += m_img_align;
00141                 }
00142         }
00143 
00144         //vymenime ukazatele
00145         m_cs.Lock();
00146                 BYTE * tmp = m_data1;
00147                 m_data1 = m_data2;
00148                 m_data2 = tmp;
00149         m_cs.Unlock();
00150 
00151         return  S_OK;
00152 }
00153 
00154 /** Metoda grafu DirectShow pro overeni co udelat se zadanym snimkem.
00155 *
00156 *       V tomto pripade se kazdy snimek bude spravne zobrazovat podle jeho zadaneho casu.
00157 *       
00158 *       \param  sample          [in] snimek o kterem se rozhoduje
00159 *       \param  start           [in] cas pro pocatek zobrazeni snimku
00160 *       \param  stop            [in] cas pro konec zobrazeni snimku
00161 */
00162 HRESULT TDSSampler::ShouldDrawSampleNow(
00163         IMediaSample *sample,
00164         REFERENCE_TIME *start,
00165         REFERENCE_TIME *stop
00166         ) 
00167 {
00168         //zadny snimek nebude zahozen - kazdy snimek bude zobrazen podle jeho casu
00169         return S_FALSE;
00170 }
00171 
00172 /** Nakopiruje data do pripraveneho bufferu.
00173 *
00174 *       \param  data    [in out] buffer pro ulozeni dat ve formatu RGB 
00175 */
00176 void TDSSampler::GetData( void * data )
00177 {
00178         //posledni snimek je ulozen v M_DATA1
00179         m_cs.Lock();
00180 
00181                 //prekopirujeme data
00182                 memcpy( data, m_data1, m_rgb_size );
00183 
00184         m_cs.Unlock();
00185 }
00186 
00187 // TDSSampler
00188 ////////////////////////////////////////////////////////////////////////////////
00189 ////////////////////////////////////////////////////////////////////////////////
00190 ////////////////////////////////////////////////////////////////////////////////
00191 
00192 /** Konstruktor.
00193 *
00194 *       Inicializuje vse na NULL.
00195 *
00196 *       Inicializace musi byt provedena metodou Initialize() !!!
00197 */
00198 TVideoDSFile::TVideoDSFile(void)
00199 {
00200         m_graph = NULL;
00201         m_ctrl = NULL;
00202         m_sampler = NULL;
00203         m_seek = NULL;
00204 }
00205 
00206 /** Destruktor.
00207 *
00208 *       Odstrani DirectShow graf a deinicializuje COM.
00209 */
00210 TVideoDSFile::~TVideoDSFile(void)
00211 {
00212         this->Destroy();
00213 }
00214 
00215 /** Inicializace DirectShow grafu.
00216 *
00217 *       Vraci TRUE pokud probehla inicializace uspesne nebo pokud byl jiz graf otevren.
00218 *
00219 *       \param  filename        [in] jmeno otviraneho souboru
00220 */
00221 bool TVideoDSFile::Initialize( const char * filename )
00222 {
00223         if ( ! m_graph )
00224         {
00225                 //vytvorime novy graf
00226 
00227                 //inicializace COM
00228                 if ( FAILED( CoInitialize( 0 ) ) )
00229                 {
00230                         return false;
00231                 }
00232 
00233                 //vytvorime graf a ziskame jeho ovladani
00234                 HRESULT hr = 
00235                         CoCreateInstance( CLSID_FilterGraph, 0, CLSCTX_INPROC, IID_IGraphBuilder, (void **)  &m_graph );
00236                 if ( FAILED( hr ) )
00237                 {
00238                         m_graph = NULL;
00239                         CoUninitialize();
00240                         return false;
00241                 }
00242 
00243                 //vytvorime graf a ziskame jeho ovladani
00244                 hr = m_graph->QueryInterface( IID_IMediaControl, (void **) &m_ctrl );
00245                 if ( FAILED( hr ) )
00246                 {
00247                         m_ctrl = NULL;
00248                         m_graph->Release(); m_graph = NULL;
00249                         CoUninitialize();
00250                         return false;
00251                 }
00252 
00253                 //vytvorime sampler - ma jednu referenci ziskanou v kontruktoru
00254                 m_sampler = new TDSSampler( 0, &hr );
00255 
00256                 //ziskame zdroj videa
00257                 size_t len =  mbstowcs( NULL, filename, strlen( filename ) + 1 );
00258                 wchar_t * tmp_filename = new wchar_t[len + 1];
00259                 mbstowcs( tmp_filename, filename, strlen( filename ) + 1 );
00260                 
00261                 IBaseFilter* video  = NULL; 
00262                 hr = m_graph->AddSourceFilter ( tmp_filename, L"File Source", &video );
00263                 delete [] tmp_filename;
00264                 if ( FAILED( hr ) )
00265                 {
00266                         m_sampler->Release(); m_sampler = NULL;
00267                         m_ctrl->Release(); m_ctrl = NULL;
00268                         m_graph->Release(); m_graph = NULL;
00269                         CoUninitialize();
00270                         return false;
00271                 }               
00272 
00273                 //vystupni pin z videosignalu
00274                 IPin* videoOut  = NULL; 
00275                 //nejrpve pokus o nacteni bezneho videa
00276                 hr = video->FindPin( L"Output", &videoOut );
00277                 if ( FAILED( hr ) )
00278                 {
00279                         //zkusime nacist jako WMV nebo ASF
00280                         hr = video->FindPin( L"Raw Video 1", &videoOut );
00281                         if ( FAILED( hr ) )
00282                         {
00283                                 video->Release();
00284                                 m_sampler->Release(); m_sampler = NULL;
00285                                 m_ctrl->Release(); m_ctrl = NULL;
00286                                 m_graph->Release(); m_graph = NULL;
00287                                 CoUninitialize();
00288                                 return false;
00289                         }
00290                 }               
00291                 video->Release();
00292 
00293                 //vstup sampleru
00294                 IPin* samplerInput = NULL; 
00295                 hr = m_sampler->FindPin( L"In", &samplerInput );
00296                 if ( FAILED ( hr ) )
00297                 {
00298                         videoOut->Release();
00299                         m_sampler->Release(); m_sampler = NULL;
00300                         m_ctrl->Release(); m_ctrl = NULL;
00301                         m_graph->Release(); m_graph = NULL;
00302                         CoUninitialize();
00303                         return false;
00304                 }
00305                 
00306                 //sestavime graf
00307                 hr = m_graph->AddFilter( (IBaseFilter*)m_sampler, L"Sampler" );
00308                 if ( FAILED( hr ) )
00309                 {
00310                         samplerInput->Release();
00311                         videoOut->Release();
00312                         m_sampler->Release(); m_sampler = NULL;
00313                         m_ctrl->Release(); m_ctrl = NULL;
00314                         m_graph->Release(); m_graph = NULL;
00315                         CoUninitialize();
00316                         return false;
00317                 }
00318 
00319                 hr = m_graph->Connect( videoOut, samplerInput );
00320                 if ( FAILED( hr ) )
00321                 {
00322                         samplerInput->Release();
00323                         videoOut->Release();
00324                         m_sampler->Release(); m_sampler = NULL;
00325                         m_ctrl->Release(); m_ctrl = NULL;
00326                         m_graph->Release(); m_graph = NULL;
00327                         CoUninitialize();
00328                         return false;
00329                 }
00330 
00331                 hr = m_graph->Render( videoOut );
00332                 //TODO - zde je chyba v navratove hodnote
00333                 //ackoliv vse funguje je vracena chyba
00334                 /*
00335                 if ( FAILED( hr ) )
00336                 {
00337                         samplerInput->Release();
00338                         videoOut->Release();
00339                         m_sampler->Release(); m_sampler = NULL;
00340                         m_ctrl->Release(); m_ctrl = NULL;
00341                         m_graph->Release(); m_graph = NULL;
00342                         CoUninitialize();
00343                         return false;
00344                 }
00345                 */
00346                 videoOut->Release();
00347                 samplerInput->Release();
00348 
00349                 //nyni by mel mit sampler informace o videoformatu
00350                 {
00351                         m_width = m_sampler->GetWidth();
00352                         m_height = m_sampler->GetHeight();
00353                 }
00354 
00355                 //ovladani pozice
00356                 hr = m_graph->QueryInterface ( IID_IMediaSeeking, (void **) &m_seek );
00357                 if ( FAILED ( hr ) )
00358                 {
00359                         m_sampler->Release(); m_sampler = NULL;
00360                         m_ctrl->Release(); m_ctrl = NULL;
00361                         m_graph->Release(); m_graph = NULL;
00362                         CoUninitialize();
00363                         return false;
00364                 }
00365 
00366                 //zjisteni delky videa
00367                 m_length = 0;
00368                 m_seek->GetDuration( &m_length );
00369 
00370                 //spustime graf
00371                 hr = m_ctrl->Run();
00372                 if ( FAILED( hr ) )
00373                 {
00374                         m_seek->Release();
00375                         m_sampler->Release(); m_sampler = NULL;
00376                         m_ctrl->Release(); m_ctrl = NULL;
00377                         m_graph->Release(); m_graph = NULL;
00378                         CoUninitialize();
00379                         return false;
00380                 }
00381 
00382                 return true;
00383         }
00384         else
00385         {
00386                 //graf uz existuje
00387                 return true;
00388         }
00389 }
00390 
00391 /** Odstraneni aktualniho grafu (pokud existuje) a deinicializace COM.
00392 */
00393 bool TVideoDSFile::Destroy(void)
00394 {
00395         if ( m_graph )
00396         {
00397                 //nejprve graf radeji zastavime
00398                 m_ctrl->Stop();
00399 
00400                 if ( m_seek )
00401                 {
00402                         m_seek->Release();
00403                         m_seek = NULL;
00404                 }
00405 
00406                 //odstranime graf
00407                 if ( m_sampler )
00408                 {
00409                         m_sampler->Release();
00410                         m_sampler = NULL;
00411                 }
00412 
00413                 if ( m_ctrl )
00414                 {
00415                         m_ctrl->Release();
00416                         m_ctrl = NULL;
00417                 }
00418 
00419                 m_graph->Release();
00420                 m_graph = NULL;
00421 
00422                 CoUninitialize();
00423         }
00424 
00425         return true;
00426 }
00427 
00428 /** Nakopiruje data ve formatu RGB z posledniho zachyceneho obrazku (pokud existuje)
00429 *       do pripraveneho bufferu, jehoz velikost musi byt minimalne 
00430 *
00431 *               GetWidth() * GetHeight() * 3 bajty
00432 *
00433 *       \param  data    [in out] buffer pro pixelu ve formatu RGB
00434 */
00435 void TVideoDSFile::GetDataRGB( void * data )
00436 {
00437         m_sampler->GetData( data );
00438 
00439         //kontrola pozice a pripadne "pretoceni"
00440         LONGLONG pos;
00441         m_seek->GetCurrentPosition( &pos );
00442         if ( pos == m_length )
00443         {
00444                 pos = 0;
00445                 m_seek->SetPositions( &pos, AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning );
00446         }
00447 }
00448 
00449 // TVideoDSFile
00450 ////////////////////////////////////////////////////////////////////////////////
00451 ////////////////////////////////////////////////////////////////////////////////
00452 ////////////////////////////////////////////////////////////////////////////////

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