From c8794c89c7a53195a586343582e232a728bb8988 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Thu, 4 Jan 2018 07:12:18 +0100 Subject: [PATCH] modules/videoio: fix PS3Eye camera property window v2: fix stray trailing whitespace v3: only allow for up to one property window at the time Opening multiple windows in the same process will just confuse the camera filter or outright crash. Suggested-by: @alalek Also return whether a dialog was opened at the time. --- modules/videoio/src/cap_dshow.cpp | 100 ++++++++++++++++++++++-------- 1 file changed, 75 insertions(+), 25 deletions(-) diff --git a/modules/videoio/src/cap_dshow.cpp b/modules/videoio/src/cap_dshow.cpp index d8a9e84418..0148f67083 100644 --- a/modules/videoio/src/cap_dshow.cpp +++ b/modules/videoio/src/cap_dshow.cpp @@ -434,6 +434,8 @@ class videoDevice{ int myID; long requestedFrameTime; //ie fps + LONG volatile property_window_count; + char nDeviceName[255]; WCHAR wDeviceName[255]; @@ -499,7 +501,7 @@ class videoInput{ //Launches a pop up settings window //For some reason in GLUT you have to call it twice each time. - void showSettingsWindow(int deviceID); + bool showSettingsWindow(int deviceID); //Manual control over settings thanks..... //These are experimental for now. @@ -535,6 +537,8 @@ class videoInput{ bool isDeviceDisconnected(int deviceID); + int property_window_count(int device_idx); + private: void setPhyCon(int deviceID, int conn); void setAttemptCaptureSize(int deviceID, int w, int h,GUID mediaType=MEDIASUBTYPE_RGB24); @@ -578,7 +582,6 @@ class videoInput{ static void __cdecl basicThread(void * objPtr); static char deviceNames[VI_MAX_CAMERAS][255]; - }; /////////////////////////// HANDY FUNCTIONS ///////////////////////////// @@ -764,6 +767,8 @@ videoDevice::videoDevice(){ pixels = 0; formatType = 0; + property_window_count = 0; + memset(wDeviceName, 0, sizeof(WCHAR) * 255); memset(nDeviceName, 0, sizeof(char) * 255); @@ -1240,6 +1245,7 @@ bool videoInput::setFormat(int deviceNumber, int format){ if(VDList[deviceNumber]->pVideoInputFilter)VDList[deviceNumber]->pVideoInputFilter->Release(); if(VDList[deviceNumber]->pVideoInputFilter)VDList[deviceNumber]->pVideoInputFilter = NULL; + if(FAILED(hr)){ DebugPrintOut("SETUP: couldn't set requested format\n"); }else{ @@ -1586,36 +1592,47 @@ bool videoInput::isDeviceSetup(int id) const // ---------------------------------------------------------------------- -void __cdecl videoInput::basicThread(void * objPtr){ - //get a reference to the video device - //not a copy as we need to free the filter - videoDevice * vd = *( (videoDevice **)(objPtr) ); - ShowFilterPropertyPages(vd->pVideoInputFilter); - - - - //now we free the filter and make sure it set to NULL - if(vd->pVideoInputFilter)vd->pVideoInputFilter->Release(); - if(vd->pVideoInputFilter)vd->pVideoInputFilter = NULL; +void __cdecl videoInput::basicThread(void* ptr) +{ + videoDevice* dev = (videoDevice*) ptr; + IBaseFilter* filter = dev->pVideoInputFilter; - return; + (void) ShowFilterPropertyPages(filter); + (void) InterlockedDecrement(&dev->property_window_count); } -void videoInput::showSettingsWindow(int id){ - +bool videoInput::showSettingsWindow(int id){ if(isDeviceSetup(id)){ //HANDLE myTempThread; //we reconnect to the device as we have freed our reference to it //why have we freed our reference? because there seemed to be an issue //with some mpeg devices if we didn't - HRESULT hr = getDevice(&VDList[id]->pVideoInputFilter, id, VDList[id]->wDeviceName, VDList[id]->nDeviceName); - if(hr == S_OK){ - //myTempThread = (HANDLE) - _beginthread(basicThread, 0, (void *)&VDList[id]); + + // XXX TODO compare fourcc for mpeg devices? is this comment still valid? -sh 20180104 + + videoDevice* dev = VDList[id]; + HRESULT hr = getDevice(&dev->pVideoInputFilter, id, dev->wDeviceName, dev->nDeviceName); + if(hr == S_OK) + { + // it's pointless to keep the filter around. it crashes in + // pGraph or ISampleGrabber anyway + //dev->pVideoInputFilter->AddRef(); + + int new_window_count = InterlockedIncrement(&dev->property_window_count); + // don't open multiple property windows at a time. + // will cause the camera to confuse itself anyway. + if (new_window_count == 1) + { + _beginthread(basicThread, 0, dev); + return true; + } + else + (void) InterlockedDecrement(&dev->property_window_count); } } + return false; } @@ -1639,8 +1656,10 @@ bool videoInput::getVideoSettingFilter(int deviceID, long Property, long &min, l hr = VD->pVideoInputFilter->QueryInterface(IID_IAMVideoProcAmp, (void**)&pAMVideoProcAmp); if(FAILED(hr)){ DebugPrintOut("setVideoSetting - QueryInterface Error\n"); +#if 0 if(VD->pVideoInputFilter)VD->pVideoInputFilter->Release(); if(VD->pVideoInputFilter)VD->pVideoInputFilter = NULL; +#endif return false; } @@ -1654,8 +1673,10 @@ bool videoInput::getVideoSettingFilter(int deviceID, long Property, long &min, l pAMVideoProcAmp->Get(Property, ¤tValue, &flags); if(pAMVideoProcAmp)pAMVideoProcAmp->Release(); +#if 0 if(VD->pVideoInputFilter)VD->pVideoInputFilter->Release(); if(VD->pVideoInputFilter)VD->pVideoInputFilter = NULL; +#endif return true; @@ -1721,8 +1742,10 @@ bool videoInput::setVideoSettingFilter(int deviceID, long Property, long lValue, hr = VD->pVideoInputFilter->QueryInterface(IID_IAMVideoProcAmp, (void**)&pAMVideoProcAmp); if(FAILED(hr)){ DebugPrintOut("setVideoSetting - QueryInterface Error\n"); +#if 0 if(VD->pVideoInputFilter)VD->pVideoInputFilter->Release(); if(VD->pVideoInputFilter)VD->pVideoInputFilter = NULL; +#endif return false; } @@ -1745,8 +1768,10 @@ bool videoInput::setVideoSettingFilter(int deviceID, long Property, long lValue, } if(pAMVideoProcAmp)pAMVideoProcAmp->Release(); +#if 0 if(VD->pVideoInputFilter)VD->pVideoInputFilter->Release(); if(VD->pVideoInputFilter)VD->pVideoInputFilter = NULL; +#endif return true; @@ -1802,8 +1827,10 @@ bool videoInput::setVideoSettingCamera(int deviceID, long Property, long lValue, hr = VDList[deviceID]->pVideoInputFilter->QueryInterface(IID_IAMCameraControl, (void**)&pIAMCameraControl); if (FAILED(hr)) { DebugPrintOut("Error\n"); +#if 0 if(VDList[deviceID]->pVideoInputFilter)VDList[deviceID]->pVideoInputFilter->Release(); if(VDList[deviceID]->pVideoInputFilter)VDList[deviceID]->pVideoInputFilter = NULL; +#endif return false; } else @@ -1822,8 +1849,10 @@ bool videoInput::setVideoSettingCamera(int deviceID, long Property, long lValue, pIAMCameraControl->Set(Property, lValue, Flags); } pIAMCameraControl->Release(); +#if 0 if(VDList[deviceID]->pVideoInputFilter)VDList[deviceID]->pVideoInputFilter->Release(); if(VDList[deviceID]->pVideoInputFilter)VDList[deviceID]->pVideoInputFilter = NULL; +#endif return true; } } @@ -1851,8 +1880,10 @@ bool videoInput::getVideoSettingCamera(int deviceID, long Property, long &min, l hr = VD->pVideoInputFilter->QueryInterface(IID_IAMCameraControl, (void**)&pIAMCameraControl); if(FAILED(hr)){ DebugPrintOut("setVideoSetting - QueryInterface Error\n"); +#if 0 if(VD->pVideoInputFilter)VD->pVideoInputFilter->Release(); if(VD->pVideoInputFilter)VD->pVideoInputFilter = NULL; +#endif return false; } @@ -1865,8 +1896,10 @@ bool videoInput::getVideoSettingCamera(int deviceID, long Property, long &min, l pIAMCameraControl->Get(Property, ¤tValue, &flags); if(pIAMCameraControl)pIAMCameraControl->Release(); +#if 0 if(VD->pVideoInputFilter)VD->pVideoInputFilter->Release(); if(VD->pVideoInputFilter)VD->pVideoInputFilter = NULL; +#endif return true; @@ -2203,7 +2236,6 @@ void videoInput::getVideoPropertyAsString(int prop, char * propertyAsString){ int videoInput::getVideoPropertyFromCV(int cv_property){ - // see VideoProcAmpProperty in strmif.h switch (cv_property) { case CV_CAP_PROP_BRIGHTNESS: @@ -2780,8 +2812,10 @@ int videoInput::start(int deviceID, videoDevice *VD){ //if we release this then we don't have access to the settings //we release our video input filter but then reconnect with it //each time we need to use it +#if 0 VD->pVideoInputFilter->Release(); VD->pVideoInputFilter = NULL; +#endif VD->pGrabberF->Release(); VD->pGrabberF = NULL; @@ -2902,8 +2936,12 @@ HRESULT videoInput::getDevice(IBaseFilter** gottaFilter, int deviceId, WCHAR * w count++; } - // We found it, so send it back to the caller - hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)gottaFilter); + // reuse existing filter due to webcam problems + if (*gottaFilter) + hr = S_OK; + else + // We found it, so send it back to the caller + hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)gottaFilter); done = true; } VariantClear(&varName); @@ -3125,6 +3163,14 @@ HRESULT videoInput::routeCrossbar(ICaptureGraphBuilder2 **ppBuild, IBaseFilter * return hr; } +int videoInput::property_window_count(int idx) +{ + if (isDeviceSetup(idx)) + return (int)InterlockedCompareExchange(&VDList[idx]->property_window_count, 0L, 0L); + + return 0; +} + namespace cv { videoInput VideoCapture_DShow::g_VI; @@ -3189,6 +3235,11 @@ double VideoCapture_DShow::getProperty(int propIdx) const return (double)current_value; } + if (propIdx == CV_CAP_PROP_SETTINGS ) + { + return g_VI.property_window_count(m_index); + } + // unknown parameter or value not available return -1; } @@ -3260,8 +3311,7 @@ bool VideoCapture_DShow::setProperty(int propIdx, double propVal) // show video/camera filter dialog if (propIdx == CV_CAP_PROP_SETTINGS ) { - g_VI.showSettingsWindow(m_index); - return true; + return g_VI.showSettingsWindow(m_index); } //video Filter properties