include/avcap/windows/HelpFunc.h

Go to the documentation of this file.
00001 /*
00002  * (c) 2005, 2008 Nico Pranke <Nico.Pranke@googlemail.com>, Robin Luedtke <RobinLu@gmx.de> 
00003  *
00004  * This file is part of avcap.
00005  *
00006  * avcap is free software: you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation, either version 3 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * avcap is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with avcap.  If not, see <http://www.gnu.org/licenses/>.
00018  */
00019 
00020 /* avcap is free for non-commercial use.
00021  * To use it in commercial endeavors, please contact Nico Pranke <Nico.Pranke@googlemail.com>.
00022  */
00023 
00024 
00025 #ifndef HELPFUNC_H_
00026 #define HELPFUNC_H_
00027 
00028 #include <list>
00029 #include <math.h>
00030 #include <string>
00031 
00032 #include <DShow.h> // DirectShow
00033 #include <mtype.h> // DeleteMediaType() function
00034 #include <qedit.h> // CLSID_NullRenderer/CLSID_ISampleGrabber definitions
00035 #include <winnls.h>
00036 
00037 #ifndef __STREAMS__
00038 # include <streams.h>
00039 #endif
00040 
00041 // Some definitions
00042 #define VIDEO_SAMPLEGRABBER_FILTER_NAME L"SampleGrabber Video"
00043 #define AUDIO_SAMPLEGRABBER_FILTER_NAME L"SampleGrabber Audio"
00044 
00045 #define CAP_VIDEO_CAPTURE  0x00000001  /* Is a video capture device */
00046 #define CAP_VIDEO_OUTPUT   0x00000002  /* Is a video output device */
00047 #define CAP_VIDEO_OVERLAY  0x00000004  /* Can do video overlay */
00048 #define CAP_VBI_CAPTURE    0x00000010  /* Is a VBI capture device */
00049 
00050 #define CAP_TUNERDEVICE    0x00010000  /* Has radio tuner or tv tuner */
00051 #define CAP_TUNER          0x00020000  /* Has a tuner */
00052 #define CAP_AUDIO_CAPTURE  0x00040000  /* Has audio support */
00053 #define CAP_RADIO                  0x00080000  /* Is a radio device */
00054 
00055 // Helper Functions -> see end of file
00056 static inline void DeleteList(std::list<IPin*> &PinList);
00057 
00058 static inline void DeleteList(std::list<IBaseFilter*> &AudioCaptureFilterList);
00059 
00060 static inline void DeleteList(std::list<AM_MEDIA_TYPE*> &MediaTypeList);
00061 
00062 static inline void EnumMediaTypesOnPin(IPin *Pin,
00063                 std::list<AM_MEDIA_TYPE*> &MediaTypeList);
00064 
00065 static inline void EnumPinsOnFilter(IBaseFilter *Filter,
00066                 std::list<IPin*> &PinList);
00067 
00068 static inline bool GetFilterGraphFromFilter(IBaseFilter *Filter,
00069                 IGraphBuilder **FilterGraph,
00070                 ICaptureGraphBuilder2 **CaptureGraphBuilder=NULL);
00071 
00072 static inline char* WChar2Char(const wchar_t* szWChar);
00073 
00074 static inline bool FindTunerRadioSupport(IBaseFilter *CaptureFilter,
00075                 int *Capabilities);
00076 
00077 static inline bool RenderStream(IUnknown *FilterOrPinToRender,
00078                 bool RenderVideo, bool RenderAudio);
00079 
00080 static inline bool GetInstalledDeviceIDs(
00081                 std::list<std::string> &UniqueDeviceIDList);
00082 
00083 static inline std::string bstr2string(BSTR bstr);
00084 
00085 static inline std::string bstr2string(BSTR bstr)
00086 {
00087 
00088         int length = ((DWORD*) bstr)[0];
00089         wchar_t* wchar_data = (wchar_t*) (((DWORD*) bstr) );
00090 
00091         int converted_length = WideCharToMultiByte(CP_ACP, 0, wchar_data, -1, 0, 0,
00092                         0, 0);
00093         char* char_data = new char[converted_length];
00094         WideCharToMultiByte(CP_ACP, 0, wchar_data, -1, char_data, converted_length,
00095                         0, 0);
00096         std::string res = char_data;
00097         delete[] char_data;
00098         return res;
00099 }
00100 
00101 //######################### DEBUG FUNCTIONS - MAKE THE FILTERGRAPH VISIBLE IN GRPAHEDIT ###################
00102 
00103 static inline void EnumMediaTypesOnPin(IPin *Pin,
00104                 std::list<AM_MEDIA_TYPE*> &MediaTypeList)
00105 {
00106         QzCComPtr<IEnumMediaTypes> EnumMediaTypes;
00107         if (Pin->EnumMediaTypes(&EnumMediaTypes)==S_OK) {
00108                 AM_MEDIA_TYPE *MediaType=NULL;
00109                 while (EnumMediaTypes->Next(1, &MediaType, NULL) == S_OK) {
00110                         MediaTypeList.push_back(MediaType);
00111                 }
00112         }
00113 }
00114 
00115 static inline void EnumPinsOnFilter(IBaseFilter *Filter,
00116                 std::list<IPin*> &PinList)
00117 {
00118         QzCComPtr<IEnumPins> EnumPins;
00119         IPin *Pin=NULL;
00120         if (Filter->EnumPins(&EnumPins)==S_OK) {
00121                 while (EnumPins->Next(1, &Pin, 0) == S_OK) {
00122                         PinList.push_back(Pin);
00123                 }
00124         }
00125 }
00126 
00127 static inline bool GetFilterGraphFromFilter(IBaseFilter *Filter,
00128                 IGraphBuilder **FilterGraph,
00129                 ICaptureGraphBuilder2 **CaptureGraphBuilder)
00130 {
00131         if (Filter==NULL) {
00132                 return false;
00133         }
00134         // Get the FilterGraph from the Filter
00135         FILTER_INFO FilterInfo;
00136         if (FAILED(Filter->QueryFilterInfo(&FilterInfo))) {
00137                 return false;
00138         }
00139         if (FilterInfo.pGraph==NULL) {
00140                 return false;
00141         }
00142         if (FAILED(FilterInfo.pGraph->QueryInterface(IID_IGraphBuilder,
00143                         (void**) &*FilterGraph))) {
00144                 return false;
00145         }
00146         // Get the CaptureGraphBuilder2
00147         // CaptureGraphBuilder is useful for building many kinds of custom filter graphs, not only capture graphs
00148         if (CaptureGraphBuilder!=NULL) {
00149                 if (FAILED(CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL,
00150                                 CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2,
00151                                 (void**)&*CaptureGraphBuilder))) {
00152                         return false;
00153                 }
00154                 if (FAILED((*CaptureGraphBuilder)->SetFiltergraph(*FilterGraph))) {
00155                         return false;
00156                 }
00157         }
00158 
00159         return true;
00160 }
00161 
00162 static inline char* WChar2Char(const wchar_t* szWChar)
00163 {
00164         if (szWChar == NULL) {
00165                 return NULL;
00166         }
00167         char* szChar = NULL;
00168         size_t size = 0;
00169         if ((size = wcstombs(0, szWChar, 0)) == -1) {
00170                 return NULL;
00171         }
00172         szChar = new char[size + 1];
00173         szChar[size] = 0;
00174         wcstombs(szChar, szWChar, size);
00175         return szChar;
00176 }
00177 
00178 static inline bool FindTunerRadioSupport(IBaseFilter *CaptureFilter,
00179                 int *Capabilities)
00180 {
00181         if (CaptureFilter==NULL) {
00182                 return false;
00183         }
00184 
00185         // Get the CaptureBuilderGraph COM-Interface from CaptureFilter
00186         QzCComPtr<ICaptureGraphBuilder2> CaptureGraphBuilder;
00187         QzCComPtr<IGraphBuilder> FilterGraph;
00188         if (!GetFilterGraphFromFilter(CaptureFilter, &FilterGraph,
00189                         &CaptureGraphBuilder)) {
00190                 return false;
00191         }
00192 
00193         // Look for the tuner, radio
00194         QzCComPtr<IAMTVTuner> Tuner;
00195         if (SUCCEEDED(CaptureGraphBuilder->FindInterface(&LOOK_UPSTREAM_ONLY, NULL,
00196                         CaptureFilter, IID_IAMTVTuner, (void**)&Tuner))) {
00197                 long lModes = 0;
00198                 HRESULT hr = Tuner->GetAvailableModes(&lModes);
00199                 if (SUCCEEDED(hr) && (lModes & AMTUNER_MODE_FM_RADIO)) {
00200                         *Capabilities |= CAP_RADIO;
00201                 }
00202                 if (SUCCEEDED(hr) && (lModes & AMTUNER_MODE_TV)) {
00203                         *Capabilities |= CAP_TUNER;
00204                 }
00205         }
00206 
00207         return true;
00208 }
00209 
00210 static inline void GetInstalledAudioDevices(
00211                 std::list<IBaseFilter*> &AudioCaptureFilterList)
00212 {
00213         // Enumerate the audio category
00214         std::list<CLSID> EnumCategoriesList;
00215         EnumCategoriesList.push_back(CLSID_AudioInputDeviceCategory);
00216 
00217         for (std::list<CLSID>::iterator EnumCategoriesListIter=
00218                         EnumCategoriesList.begin(); EnumCategoriesListIter
00219                         !=EnumCategoriesList.end(); EnumCategoriesListIter++) {
00220                 // Create the System Device Enumerator.
00221                 HRESULT hr;
00222                 ICreateDevEnum *SysDevEnum = NULL;
00223                 if (FAILED(CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
00224                                 CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&SysDevEnum))) {
00225                         return;
00226                 }
00227 
00228                 // Obtain a class enumerator for the device capture category.
00229                 IEnumMoniker *EnumCat = NULL;
00230                 hr = SysDevEnum->CreateClassEnumerator(*EnumCategoriesListIter,
00231                                 &EnumCat, 0);
00232 
00233                 if (hr == S_OK) {
00234                         // Enumerate the monikers.
00235                         IMoniker *Moniker = NULL;
00236                         ULONG Fetched;
00237                         while (EnumCat->Next(1, &Moniker, &Fetched) == S_OK) {
00238                                 IBaseFilter *AudioCaptureFilter=NULL;
00239                                 if (SUCCEEDED(Moniker->BindToObject(0, 0, IID_IBaseFilter,
00240                                                 (void**)&AudioCaptureFilter))) {
00241                                         AudioCaptureFilterList.push_back(AudioCaptureFilter);
00242                                 }
00243                                 else {
00244                                         if (AudioCaptureFilter!=NULL) {
00245                                                 AudioCaptureFilter->Release();
00246                                         }
00247                                 }
00248                                 Moniker->Release();
00249                         }
00250                         EnumCat->Release();
00251                 }
00252                 SysDevEnum->Release();
00253         }
00254 }
00255 
00256 static inline bool RenderStream(IUnknown *FilterOrPinToRender,
00257                 bool RenderVideo, bool RenderAudio)
00258 {
00259         QzCComPtr<IGraphBuilder> FilterGraph;
00260         QzCComPtr<ICaptureGraphBuilder2> CaptureGraphBuilder;
00261 
00262         // Get the IGraphBuilder and CaptureGraphBuilder2 interfaces from pin or filter
00263         QzCComPtr<IPin> Pin;
00264         bool IsPin=false;
00265         if (SUCCEEDED(FilterOrPinToRender->QueryInterface(IID_IPin, (void**)&Pin))) // It's a pin
00266         {
00267                 PIN_INFO PinInfo;
00268                 Pin->QueryPinInfo(&PinInfo);
00269                 IsPin=true;
00270 
00271                 if (!GetFilterGraphFromFilter(PinInfo.pFilter, &FilterGraph,
00272                                 &CaptureGraphBuilder)) {
00273                         return false;
00274                 }
00275         }
00276         else // It's a filter
00277         {
00278                 if (!GetFilterGraphFromFilter((IBaseFilter*)FilterOrPinToRender,
00279                                 &FilterGraph, &CaptureGraphBuilder)) {
00280                         return false;
00281                 }
00282         }
00283 
00284         //if(SUCCEEDED(CaptureGraphBuilder->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Interleaved, CaptureFilter, NULL, NullRendererVideo))){return true;}
00285 
00286         // Build complete filter graph
00287         if (RenderVideo) {
00288                 // Add NullRenderer filters because we want to set formats with IAMStreamConfig COM-Interface while the complete
00289                 // filtergraph is connected. NullRenderer filters and the samplegrabber filter accept all formats.
00290                 QzCComPtr<IBaseFilter> RendererVideo;
00291                 if (FAILED(CoCreateInstance(CLSID_NullRenderer, 0,
00292                                 CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&RendererVideo))) {
00293                         return false;
00294                 }
00295                 if (FAILED(FilterGraph->AddFilter(RendererVideo,L"Video Null Renderer" ))) {return false;}
00296                 QzCComPtr<IBaseFilter> SampleGrabberVideo;
00297                 if(FAILED(CoCreateInstance(CLSID_SampleGrabber, 0, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&SampleGrabberVideo))) {return false;}
00298                 if(FAILED(FilterGraph->AddFilter(SampleGrabberVideo, VIDEO_SAMPLEGRABBER_FILTER_NAME))) {return false;}
00299                 // Set the video samplegrabber
00300                 QzCComPtr<ISampleGrabber> SampleGrabber;
00301                 if(FAILED(SampleGrabberVideo->QueryInterface(IID_ISampleGrabber, (void**)&SampleGrabber))) {return false;}
00302                 AM_MEDIA_TYPE mt;
00303                 mt.majortype=MEDIATYPE_Video;
00304                 mt.subtype=GUID_NULL;
00305                 mt.pUnk=NULL;
00306                 mt.cbFormat=0;
00307                 if(FAILED(SampleGrabber->SetMediaType(&mt))) {return false;}
00308                 //render the pin or filter
00309                 if(FAILED(CaptureGraphBuilder->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, FilterOrPinToRender, SampleGrabberVideo, RendererVideo))) {return false;}
00310         }
00311 
00312         if(RenderAudio)
00313         {
00314                 // Add NullRenderer filters because we want to set formats with IAMStreamConfig COM-Interface while the complete
00315                 // filtergraph is connected. NullRenderer filters and the SampleGrabber filter accept all formats.
00316                 QzCComPtr<IBaseFilter> RendererAudio;
00317                 CoCreateInstance(CLSID_NullRenderer, 0, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&RendererAudio); //CLSID_DSoundRender for DirectSound Filter
00318                 FilterGraph->AddFilter(RendererAudio, L"Audio Null Renderer");
00319                 QzCComPtr<IBaseFilter> SampleGrabberAudio;
00320                 CoCreateInstance(CLSID_SampleGrabber, 0, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&SampleGrabberAudio);
00321                 FilterGraph->AddFilter(SampleGrabberAudio, AUDIO_SAMPLEGRABBER_FILTER_NAME);
00322                 // Set the audio samplegrabber filter
00323                 QzCComPtr<ISampleGrabber> SampleGrabber;
00324                 SampleGrabberAudio->QueryInterface(IID_ISampleGrabber, (void**)&SampleGrabber);
00325                 AM_MEDIA_TYPE mt;
00326                 mt.majortype=MEDIATYPE_Audio;
00327                 mt.subtype=GUID_NULL;
00328                 mt.pUnk=NULL;
00329                 mt.cbFormat=0;
00330                 SampleGrabber->SetMediaType(&mt);
00331 
00332                 //Render Audio
00333                 if(IsPin) //if we should render a pin
00334                 {
00335                         HRESULT hr=CaptureGraphBuilder->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Audio, FilterOrPinToRender, SampleGrabberAudio, RendererAudio);
00336                         if(hr!=S_OK) {return false;}
00337                 }
00338                 // If we should render a filter
00339 
00340                 else if(FAILED(CaptureGraphBuilder->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Audio, FilterOrPinToRender, SampleGrabberAudio, RendererAudio)))
00341                 {
00342                         /* The avcap library doesn't provide full audio support at this time. There are only some basic audio
00343                          functions implemented (not implemented: audio capture functions, ...)*/
00344 
00345                         /* Some notes about DirectShow and audio capture
00346                          - Old VFW driver based capture devices don't support audio.
00347                          - New WDM driver based capture devices can support audio:
00348                          1. The capture filter has audio output pins which have to be connected to a sound rendering DirectShow filter
00349                          2. The capture filter has crossbar support and the audio output pins are on the crossbar and have to
00350                          be connected to a sound rendering DirectShow filter.
00351                          3. Many capture devices (e.g. tv tuner cards) don't provide direct audio support. They have audio
00352                          connectors which have to be connected to a soundcard by cable. The soundcard takes up the
00353                          capture process of the audio data. In this case, a soundcard capture DirectShow filter is needed.
00354                          What we do if the function above fails?? We insert a audio capture DirectShow filter in the filtergraph
00355                          and connect it to the sound rendering DirectShow filter. What can we do if multiple soundcards
00356                          are installed - which audio capture DirectShow filter should we use?? Normally the user has to choose the
00357                          audio capture DirectShow filter. But because of the uncomplete audio implementation of the avcap library 
00358                          we use the first audio capture DirectShow Filter we'll find in the system. */
00359 
00360                         /* TODO: Complete the audio functionality */
00361 
00362                         std::list<IBaseFilter*> AudioCaptureFilterList;
00363                         GetInstalledAudioDevices(AudioCaptureFilterList);
00364                         for(std::list<IBaseFilter*>::iterator Iter=AudioCaptureFilterList.begin(); Iter!=AudioCaptureFilterList.end(); Iter++)
00365                         {
00366                                 FilterGraph->AddFilter((*Iter), L"AudioCaptureFilter");
00367                                 if(SUCCEEDED(CaptureGraphBuilder->RenderStream(NULL, &MEDIATYPE_Audio, (*Iter), SampleGrabberAudio, RendererAudio)))
00368                                 {
00369                                         break;
00370                                 }
00371                                 FilterGraph->RemoveFilter((*Iter));
00372                         }
00373                         DeleteList(AudioCaptureFilterList);
00374                 }
00375         }
00376 
00377         return true;
00378 }
00379 
00380 static inline void DeleteList(std::list<IPin*> &PinList)
00381 {
00382         for (std::list<IPin*>::iterator Iter=PinList.begin(); Iter!=PinList.end(); Iter++) {
00383                 if ((*Iter)!=NULL) {
00384                         (*Iter)->Release();
00385                 }
00386         }
00387         PinList.clear();
00388 }
00389 
00390 static inline void DeleteList(std::list<IBaseFilter*> &AudioCaptureFilterList)
00391 {
00392         for (std::list<IBaseFilter*>::iterator Iter=AudioCaptureFilterList.begin(); Iter
00393                         !=AudioCaptureFilterList.end(); Iter++) {
00394                 if ((*Iter)!=NULL) {
00395                         (*Iter)->Release();
00396                 }
00397         }
00398         AudioCaptureFilterList.clear();
00399 }
00400 
00401 static inline void DeleteList(std::list<AM_MEDIA_TYPE*> &MediaTypeList)
00402 {
00403         for (std::list<AM_MEDIA_TYPE*>::iterator Iter=MediaTypeList.begin(); Iter
00404                         !=MediaTypeList.end(); Iter++) {
00405                 DeleteMediaType(*Iter);
00406         }
00407         MediaTypeList.clear();
00408 }
00409 
00410 #endif

Generated on Mon Nov 30 11:10:30 2009 for avcap-0.1 by  doxygen 1.5.1