From 8545df07b486077d7389b6f541bbf971dc2a23fc Mon Sep 17 00:00:00 2001 From: smorlat <smorlat@3f6dc0c8-ddfe-455d-9043-3cd528dc4637> Date: Tue, 31 Mar 2009 21:31:56 +0000 Subject: [PATCH] new directshow/mingw filter works git-svn-id: svn+ssh://svn.savannah.nongnu.org/linphone/trunk@396 3f6dc0c8-ddfe-455d-9043-3cd528dc4637 --- .../mediastreamer2/plugins/msdscap/mdscap.cc | 471 +++++++++++++----- linphone/mediastreamer2/src/mscommon.c | 2 +- 2 files changed, 361 insertions(+), 112 deletions(-) diff --git a/linphone/mediastreamer2/plugins/msdscap/mdscap.cc b/linphone/mediastreamer2/plugins/msdscap/mdscap.cc index a03f2e2106..0041956997 100755 --- a/linphone/mediastreamer2/plugins/msdscap/mdscap.cc +++ b/linphone/mediastreamer2/plugins/msdscap/mdscap.cc @@ -355,7 +355,33 @@ DECLARE_INTERFACE_(IMediaSample,IUnknown) STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; STDMETHOD_(ULONG,AddRef)(THIS) PURE; STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(GetPointer)(THIS_ BYTE **) PURE; + STDMETHOD_(long, GetSize)(THIS) PURE; }; +/* +#define INTERFACE IMediaSample +DECLARE_INTERFACE_(IMediaSample, IUnknown) +{ + STDMETHOD(GetPointer)(THIS_ BYTE **) PURE; + STDMETHOD_(long, GetSize)(THIS) PURE; + STDMETHOD(GetTime)(THIS_ REFERENCE_TIME *, REFERENCE_TIME *) PURE; + STDMETHOD(SetTime)(THIS_ REFERENCE_TIME *, REFERENCE_TIME *) PURE; + STDMETHOD(IsSyncPoint)(THIS) PURE; + STDMETHOD(SetSyncPoint)(THIS_ BOOL) PURE; + STDMETHOD(IsPreroll)(THIS) PURE; + STDMETHOD(SetPreroll)(THIS_ BOOL) PURE; + STDMETHOD_(long, GetActualDataLength)(THIS) PURE; + STDMETHOD(SetActualDataLength)(THIS_ long) PURE; + STDMETHOD(GetMediaType)(THIS_ AM_MEDIA_TYPE **) PURE; + STDMETHOD(SetMediaType)(THIS_ AM_MEDIA_TYPE *) PURE; + STDMETHOD(IsDiscontinuity)(THIS) PURE; + STDMETHOD(SetDiscontinuity)(THIS_ BOOL) PURE; + STDMETHOD(GetMediaTime)(THIS_ LONGLONG *, LONGLONG *) PURE; + STDMETHOD(SetMediaTime)(THIS_ LONGLONG *, LONGLONG *) PURE; +}; +*/ + + #undef INTERFACE #define INTERFACE IMemAllocator @@ -437,11 +463,13 @@ ComPtr< IPin > getPin( IBaseFilter *filter, PIN_DIRECTION direction, int num ) return retVal; } -class Callback: public ISampleGrabberCB +struct DscapState; + +class MSCallback: public ISampleGrabberCB { public: - Callback(void); - virtual ~Callback(void); + MSCallback(DscapState *s); + virtual ~MSCallback(void); STDMETHODIMP QueryInterface( REFIID riid, void **ppv ); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); @@ -449,101 +477,17 @@ public: STDMETHODIMP BufferCB(double,BYTE*,long); protected: long m_refCount; + DscapState *mState; }; -Callback::Callback(void): m_refCount(1) -{ -#ifndef NDEBUG - cerr << "Callback::Callback" << endl; -#endif -} - -Callback::~Callback(void) -{ -#ifndef NDEBUG - cerr << "Callback::~Callback" << endl; -#endif -} - -STDMETHODIMP Callback::QueryInterface(REFIID riid, void **ppv) -{ -#ifndef NDEBUG - cerr << "Callback::QueryInterface" << endl; -#endif - HRESULT retval; - if ( ppv == NULL ) return E_POINTER; - /* - if ( riid == IID_IUnknown ) { - *ppv = static_cast< IUnknown * >( this ); - AddRef(); - retval = S_OK; - } else if ( riid == IID_ISampleGrabberCB ) { - *ppv = static_cast< ISampleGrabberCB * >( this ); - AddRef(); - retval = S_OK; - } else */ { -#ifndef NDEBUG - cerr << setbase( 16 ) << setfill('0') - << "DEFINE_GUID( ..., 0x" << setw(8) << (int)riid.Data1 << ", 0x" - << setw(4) << (int)riid.Data2 << "," << endl - << " 0x" - << setw(4) << (int)riid.Data3 << ", 0x" << setw(2) - << (int)riid.Data4[0] << ", 0x" - << (int)riid.Data4[1] << ", 0x" - << (int)riid.Data4[2] << ", 0x" - << (int)riid.Data4[3] << ", 0x" - << (int)riid.Data4[4] << ", 0x" - << (int)riid.Data4[5] << ", 0x" - << (int)riid.Data4[6] << ", 0x" - << (int)riid.Data4[7] << " ) ?" << endl - << setfill( ' ' ) << setw( 0 ) << setbase( 10 ); -#endif - retval = E_NOINTERFACE; - }; - return retval; -}; - -STDMETHODIMP_(ULONG) Callback::AddRef(void) -{ -#ifndef NDEBUG - cerr << "Callback::AddRef" << endl; -#endif - m_refCount++; - return m_refCount; -} - -STDMETHODIMP_(ULONG) Callback::Release(void) -{ -#ifndef NDEBUG - cerr << "Callback::Release" << endl; -#endif - if ( !InterlockedDecrement( &m_refCount ) ) delete this; - return m_refCount; -} - -STDMETHODIMP Callback::SampleCB( double, IMediaSample * ) -{ -#ifndef NDEBUG - cerr << "Callback::SampleCB" << endl; -#endif - return S_OK; -} - -STDMETHODIMP Callback::BufferCB( double, BYTE *, long ) -{ -#ifndef NDEBUG - cerr << "Callback::BufferCB" << endl; -#endif - return E_NOTIMPL; -} - +#if 1 using namespace std; int toto(void) { int retVal = 0; bool initialized = false; - Callback *callback = NULL; + MSCallback *callback = NULL; try { COERRORMACRO( CoInitialize(NULL), Error, , "CoInitialize failed" ); initialized = true; @@ -600,8 +544,7 @@ int toto(void) mediaType->cbFormat != 0 ) { VIDEOINFOHEADER *infoHeader = (VIDEOINFOHEADER*)mediaType->pbFormat; // TODO: choose format here !!! - cerr << "Setting format " << infoHeader->bmiHeader.biWidth - << "x" << infoHeader->bmiHeader.biHeight << endl; + ms_message("Setting format %ix%i",infoHeader->bmiHeader.biWidth,infoHeader->bmiHeader.biHeight); streamConfig->SetFormat( mediaType ); ok = true; }; @@ -630,7 +573,7 @@ int toto(void) "Error disabling one-shot mode" ); COERRORMACRO( sampleGrabber->SetBufferSamples( TRUE ), Error, , "Error enabling buffer sampling" ); - callback = new Callback; + callback = new MSCallback(NULL); COERRORMACRO( sampleGrabber->SetCallBack( callback, 0 ), Error, , "Error setting callback interface for grabbing" ); ComPtr< IPin > grabberIn = getPin( grabberBase.get(), PINDIR_INPUT, 0 ); @@ -687,9 +630,15 @@ int toto(void) return retVal; } +#endif - -typedef struct DscapState{ +struct DscapState{ + DscapState(){ + callback=0; + } + ~DscapState(){ + if (callback) callback->Release(); + } int devid; MSVideoSize vsize; queue_t rq; @@ -700,11 +649,114 @@ typedef struct DscapState{ float start_time; int frame_count; MSPixFmt fmt; -} DscapState; + ComPtr< IBaseFilter > source; + ComPtr< IBaseFilter > nullRenderer; + ComPtr< IBaseFilter > grabberBase; + ComPtr< IMediaControl > mediaControl; + ComPtr< IMediaEvent > mediaEvent; + MSCallback * callback; +}; + +MSCallback::MSCallback(DscapState *s): m_refCount(1), mState(s) +{ +} + +MSCallback::~MSCallback(void) +{ + ms_message("MSCallback::~MSCallback"); +} + +STDMETHODIMP MSCallback::QueryInterface(REFIID riid, void **ppv) +{ +#ifndef NDEBUG + ms_message("MSCallback::QueryInterface"); +#endif + HRESULT retval; + if ( ppv == NULL ) return E_POINTER; + /* + if ( riid == IID_IUnknown ) { + *ppv = static_cast< IUnknown * >( this ); + AddRef(); + retval = S_OK; + } else if ( riid == IID_ISampleGrabberCB ) { + *ppv = static_cast< ISampleGrabberCB * >( this ); + AddRef(); + retval = S_OK; + } else */ { +#ifndef NDEBUG + cerr << setbase( 16 ) << setfill('0') + << "DEFINE_GUID( ..., 0x" << setw(8) << (int)riid.Data1 << ", 0x" + << setw(4) << (int)riid.Data2 << "," << endl + << " 0x" + << setw(4) << (int)riid.Data3 << ", 0x" << setw(2) + << (int)riid.Data4[0] << ", 0x" + << (int)riid.Data4[1] << ", 0x" + << (int)riid.Data4[2] << ", 0x" + << (int)riid.Data4[3] << ", 0x" + << (int)riid.Data4[4] << ", 0x" + << (int)riid.Data4[5] << ", 0x" + << (int)riid.Data4[6] << ", 0x" + << (int)riid.Data4[7] << " ) ?" << endl + << setfill( ' ' ) << setw( 0 ) << setbase( 10 ); +#endif + retval = E_NOINTERFACE; + }; + return retval; +}; + +STDMETHODIMP_(ULONG) MSCallback::AddRef(void) +{ + ms_message("MSCallback::AddRef"); + m_refCount++; + return m_refCount; +} + +STDMETHODIMP_(ULONG) MSCallback::Release(void) +{ + ms_message("MSCallback::Release"); + + if ( !InterlockedDecrement( &m_refCount ) ) { + int refcnt=m_refCount; + delete this; + return refcnt; + } + return m_refCount; +} + +static void dummy(void*p){ +} + +STDMETHODIMP MSCallback::SampleCB( double par1 , IMediaSample * sample) +{ + uint8_t *p; + unsigned int size; + if (sample->GetPointer(&p)!=S_OK){ + ms_error("error in GetPointer()"); + return S_OK; + } + size=sample->GetSize(); + ms_message( "MSCallback::SampleCB pointer=%p, size=%i",p,size); + mblk_t *m=esballoc(p,size,0,dummy); + m->b_wptr+=size; + ms_mutex_lock(&mState->mutex); + putq(&mState->rq,m); + ms_mutex_unlock(&mState->mutex); + return S_OK; +} + + + +STDMETHODIMP MSCallback::BufferCB( double, BYTE *b, long len) +{ + ms_message("MSCallback::BufferCB"); + + return S_OK; +} + static void dscap_init(MSFilter *f){ - DscapState *s=(DscapState *)ms_new0(DscapState,1); + DscapState *s=new DscapState; s->vsize.width=MS_VIDEO_SIZE_CIF_W; s->vsize.height=MS_VIDEO_SIZE_CIF_H; qinit(&s->rq); @@ -722,22 +774,219 @@ static void dscap_uninit(MSFilter *f){ DscapState *s=(DscapState*)f->data; flushq(&s->rq,0); ms_mutex_destroy(&s->mutex); - ms_free(s); + delete s; +} + +static char * fourcc_to_char(char *str, uint32_t fcc){ + memcpy(str,&fcc,4); + str[4]='\0'; + return str; +} + +static int find_best_format(ComPtr<IAMStreamConfig> streamConfig, int count, MSVideoSize *requested_size, MSPixFmt requested_fmt ){ + int i; + MSVideoSize best_found=(MSVideoSize){32768,32768}; + int best_index=-1; + char fccstr[5]; + char selected_fcc[5]; + for (i=0; i<count; i++ ) { + VIDEO_STREAM_CONFIG_CAPS videoConfig; + AM_MEDIA_TYPE *mediaType; + COERRORMACRO( streamConfig->GetStreamCaps( i, &mediaType, + (BYTE *)&videoConfig ), + Error, , "Error getting stream capabilities" ); + if ( mediaType->majortype == MEDIATYPE_Video && + mediaType->cbFormat != 0 ) { + VIDEOINFOHEADER *infoHeader = (VIDEOINFOHEADER*)mediaType->pbFormat; + ms_message("Seeing format %ix%i %s",infoHeader->bmiHeader.biWidth,infoHeader->bmiHeader.biHeight, + fourcc_to_char(fccstr,infoHeader->bmiHeader.biCompression)); + if (ms_fourcc_to_pix_fmt(infoHeader->bmiHeader.biCompression)==requested_fmt){ + MSVideoSize cur; + cur.width=infoHeader->bmiHeader.biWidth; + cur.height=infoHeader->bmiHeader.biHeight; + if (ms_video_size_greater_than(cur,*requested_size)){ + if (ms_video_size_greater_than(best_found,cur)){ + best_found=cur; + best_index=i; + fourcc_to_char(selected_fcc,infoHeader->bmiHeader.biCompression); + } + } + } + }; + if ( mediaType->cbFormat != 0 ) + CoTaskMemFree( (PVOID)mediaType->pbFormat ); + if ( mediaType->pUnk != NULL ) mediaType->pUnk->Release(); + CoTaskMemFree( (PVOID)mediaType ); + } + if (best_index!=-1) { + *requested_size=best_found; + ms_message("Best camera format is %s %ix%i",selected_fcc,best_found.width,best_found.height); + } + return best_index; } -static void dscap_callback(void *data, mblk_t *m){ - DscapState *s=(DscapState*)data; - ms_mutex_lock(&s->mutex); - putq(&s->rq,m); - ms_mutex_unlock(&s->mutex); +static int select_best_format(DscapState *s, ComPtr<IAMStreamConfig> streamConfig, int count){ + int index; + s->fmt=MS_YUV420P; + index=find_best_format(streamConfig, count, &s->vsize, s->fmt); + if (index!=-1) goto success; + s->fmt=MS_YUY2; + index=find_best_format(streamConfig, count, &s->vsize, s->fmt); + if (index!=-1) goto success; + s->fmt=MS_YUYV; + index=find_best_format(streamConfig, count, &s->vsize, s->fmt); + if (index!=-1) goto success; + s->fmt=MS_RGB24; + index=find_best_format(streamConfig, count, &s->vsize, s->fmt); + if (index!=-1) { + s->fmt=MS_RGB24_REV; + goto success; + } + ms_error("This camera does not support any of our pixel formats."); + return -1; + + success: + VIDEO_STREAM_CONFIG_CAPS videoConfig; + AM_MEDIA_TYPE *mediaType; + COERRORMACRO( streamConfig->GetStreamCaps( index, &mediaType, + (BYTE *)&videoConfig ), + Error, , "Error getting stream capabilities" ); + streamConfig->SetFormat( mediaType ); + return 0; +} + +static void create_dshow_graph(DscapState *s){ + ComPtr< ICreateDevEnum > createDevEnum; + COERRORMACRO( CoInitialize(NULL), Error, , "CoInitialize failed" ); + createDevEnum.coCreateInstance( CLSID_SystemDeviceEnum, + IID_ICreateDevEnum, "Could not create " + "device enumerator" ); + ComPtr< IEnumMoniker > enumMoniker; + if (createDevEnum->CreateClassEnumerator( CLSID_VideoInputDeviceCategory, &enumMoniker, 0 )!=S_OK){ + ms_error("Fail to create class enumerator."); + return; + } + createDevEnum.reset(); + enumMoniker->Reset(); + + int index = 0; + ULONG fetched = 0; + ComPtr< IGraphBuilder > graphBuilder; + graphBuilder.coCreateInstance( CLSID_FilterGraph, IID_IGraphBuilder, + "Could not create graph builder " + "interface" ); + ComPtr< IMoniker > moniker; + for ( int i=0;enumMoniker->Next( 1, &moniker, &fetched )==S_OK;++i ) { + if (i==s->devid){ + if (moniker->BindToObject( 0, 0, IID_IBaseFilter, (void **)&s->source )!=S_OK){ + ms_error("Error binding moniker to base filter" ); + return; + } + } + } + if (s->source.get()==0){ + ms_error("Could not interface with webcam devid=%i",s->devid); + return; + } + moniker.reset(); + enumMoniker.reset(); + s->callback = new MSCallback(s); + ms_message("Callback created"); + fflush(NULL); + try{ + COERRORMACRO( graphBuilder->AddFilter( s->source.get(), L"Source" ), + Error, , "Error adding camera source to filter graph" ); + ComPtr< IPin > sourceOut = getPin( s->source.get(), PINDIR_OUTPUT, 0 ); + ERRORMACRO( sourceOut.get() != NULL, Error, , + "Error getting output pin of camera source" ); + ComPtr< IAMStreamConfig > streamConfig; + COERRORMACRO( sourceOut-> + QueryInterface( IID_IAMStreamConfig, + (void **)&streamConfig ), + Error, , "Error requesting stream configuration API" ); + int count, size; + COERRORMACRO( streamConfig->GetNumberOfCapabilities( &count, &size ), + Error, , "Error getting number of capabilities" ); + select_best_format(s,streamConfig,count); + + streamConfig.reset(); + + COERRORMACRO( CoCreateInstance( CLSID_SampleGrabber, NULL, + CLSCTX_INPROC, IID_IBaseFilter, + (void **)&s->grabberBase ), + Error, , "Error creating sample grabber" ); + COERRORMACRO( graphBuilder->AddFilter( s->grabberBase.get(), L"Grabber" ), + Error, , "Error adding sample grabber to filter graph" ); + ComPtr< ISampleGrabber > sampleGrabber; + COERRORMACRO( s->grabberBase->QueryInterface( IID_ISampleGrabber, + (void **)&sampleGrabber ), + Error, , "Error requesting sample grabber interface" ); + COERRORMACRO( sampleGrabber->SetOneShot( FALSE ), Error, , + "Error disabling one-shot mode" ); + COERRORMACRO( sampleGrabber->SetBufferSamples( TRUE ), Error, , + "Error enabling buffer sampling" ); + + COERRORMACRO( sampleGrabber->SetCallBack( s->callback, 0 ), Error, , + "Error setting callback interface for grabbing" ); + ComPtr< IPin > grabberIn = getPin( s->grabberBase.get(), PINDIR_INPUT, 0 ); + ERRORMACRO( grabberIn.get() != NULL, Error, , + "Error getting input of sample grabber" ); + ComPtr< IPin > grabberOut = getPin( s->grabberBase.get(), PINDIR_OUTPUT, 0 ); + ERRORMACRO( grabberOut.get() != NULL, Error, , + "Error getting output of sample grabber" ); + + + COERRORMACRO( CoCreateInstance( CLSID_NullRenderer, NULL, + CLSCTX_INPROC, IID_IBaseFilter, + (void **)&s->nullRenderer ), + Error, , "Error creating Null Renderer" ); + COERRORMACRO( graphBuilder->AddFilter( s->nullRenderer.get(), L"Sink" ), + Error, , "Error adding null renderer to filter graph" ); + ComPtr< IPin > nullIn = getPin( s->nullRenderer.get(), PINDIR_INPUT, 0 ); + + ms_message("Attempting to connect"); + COERRORMACRO( graphBuilder->Connect( sourceOut.get(), grabberIn.get() ), + Error, , "Error connecting source to sample grabber" ); + COERRORMACRO( graphBuilder->Connect( grabberOut.get(), nullIn.get() ), + Error, , "Error connecting sample grabber to sink" ); + + ms_message("Success!!!!!!!!!!!!!!!!!!!!!"); + + + ms_message("Querying control interface"); + COERRORMACRO( graphBuilder->QueryInterface( IID_IMediaControl, + (void **)&s->mediaControl ), + Error, , "Error requesting media control interface" ); + ms_message("Got the control interface (%p).",s->mediaControl.get()); + ms_message("Going to start the graph"); + HRESULT r; + if ((r=s->mediaControl->Run())!=S_OK){ + ms_error("Error starting graph (%i)",r); + } + ms_message("Graph started"); + COERRORMACRO( graphBuilder->QueryInterface( IID_IMediaEvent, + (void **)&s->mediaEvent ), + Error, , "Error requesting event interface" ); + ms_message("Graph created"); + } catch ( Error &e ) { + ms_error(e.what()); + }; } static void dscap_preprocess(MSFilter * obj){ DscapState *s=(DscapState*)obj->data; + create_dshow_graph(s); + //toto(); + ms_message("preprocess done."); } static void dscap_postprocess(MSFilter * obj){ DscapState *s=(DscapState*)obj->data; + if (s->mediaControl.get()!=NULL){ + s->mediaControl->Stop(); + long evCode = 0; + s->mediaEvent->WaitForCompletion( INFINITE, &evCode ); + } flushq(&s->rq,0); } @@ -756,16 +1005,15 @@ static void dscap_process(MSFilter * obj){ if (cur_frame>s->frame_count){ mblk_t *om=NULL; /*keep the most recent frame if several frames have been captured */ - if (0){ - ms_mutex_lock(&s->mutex); - while((m=getq(&s->rq))!=NULL){ - ms_mutex_unlock(&s->mutex); - if (om!=NULL) freemsg(om); - om=m; - ms_mutex_lock(&s->mutex); - } + + ms_mutex_lock(&s->mutex); + while((m=getq(&s->rq))!=NULL){ ms_mutex_unlock(&s->mutex); + if (om!=NULL) freemsg(om); + om=m; + ms_mutex_lock(&s->mutex); } + ms_mutex_unlock(&s->mutex); if (om!=NULL){ timestamp=(uint32_t)(obj->ticker->time*90);/* rtp uses a 90000 Hz clockrate for video*/ mblk_set_timestamp_info(om,timestamp); @@ -845,6 +1093,7 @@ static void ms_dshow_detect(MSWebCamManager *obj){ int i; MSWebCam *cam; ComPtr<IPropertyBag> pBag; + COERRORMACRO( CoInitialize(NULL), Error, , "CoInitialize failed" ); ComPtr< ICreateDevEnum > createDevEnum; diff --git a/linphone/mediastreamer2/src/mscommon.c b/linphone/mediastreamer2/src/mscommon.c index ddd0f3b3fc..8d0f7c33f9 100644 --- a/linphone/mediastreamer2/src/mscommon.c +++ b/linphone/mediastreamer2/src/mscommon.c @@ -494,7 +494,7 @@ static MSWebCamDesc * ms_web_cam_descs[]={ #if defined(WIN32) && defined(HAVE_DIRECTSHOW) &ms_directx_cam_desc, #endif -#if defined(WIN32) && !defined(HAVE_DIRECTSHOW) +#if defined(WIN32) && defined(HAVE_VFW) &ms_vfw_cam_desc, #endif &mire_desc, -- GitLab