From bf82ab669c53c4b9abb724e197252a788323095e Mon Sep 17 00:00:00 2001 From: Val Doroshchuk Date: Tue, 22 Sep 2020 13:04:44 +0200 Subject: DirectShow: Use also pin category when negotiating The pin should be negotiated once and use PIN_CATEGORY_CAPTURE. The same logic is implemented in chromium. Pick-to: 5.15 Change-Id: I89ac13c1a7e982c1011b2a872e853ee5bc2036b2 Reviewed-by: Andy Shaw --- src/plugins/directshow/camera/dscamerasession.cpp | 66 ++++++++++------------- src/plugins/directshow/camera/dscamerasession.h | 2 + src/plugins/directshow/common/directshowutils.cpp | 29 ++++++++-- src/plugins/directshow/common/directshowutils.h | 2 +- 4 files changed, 57 insertions(+), 42 deletions(-) diff --git a/src/plugins/directshow/camera/dscamerasession.cpp b/src/plugins/directshow/camera/dscamerasession.cpp index e7467bf0b..7ceefe2c5 100644 --- a/src/plugins/directshow/camera/dscamerasession.cpp +++ b/src/plugins/directshow/camera/dscamerasession.cpp @@ -428,6 +428,7 @@ bool DSCameraSession::unload() SAFE_RELEASE(m_nullRendererFilter); SAFE_RELEASE(m_filterGraph); SAFE_RELEASE(m_graphBuilder); + SAFE_RELEASE(m_outputPin); setStatus(QCamera::UnloadedStatus); @@ -781,6 +782,9 @@ bool DSCameraSession::createFilterGraph() goto failed; } + if (!DirectShowUtils::getPin(m_sourceFilter, PINDIR_OUTPUT, PIN_CATEGORY_CAPTURE, &m_outputPin, &hr)) + qWarning() << "Failed to get the pin for the video control:" << hr; + // Sample grabber filter if (!m_previewSampleGrabber) { m_previewSampleGrabber = new DirectShowSampleGrabber(this); @@ -1055,24 +1059,18 @@ void DSCameraSession::updateSourceCapabilities() reinterpret_cast(&pVideoControl)); if (FAILED(hr)) { qWarning() << "Failed to get the video control"; - } else { - IPin *pPin = nullptr; - if (!DirectShowUtils::getPin(m_sourceFilter, PINDIR_OUTPUT, &pPin, &hr)) { - qWarning() << "Failed to get the pin for the video control"; - } else { - long supportedModes; - hr = pVideoControl->GetCaps(pPin, &supportedModes); - if (FAILED(hr)) { - qWarning() << "Failed to get the supported modes of the video control"; - } else if (supportedModes & VideoControlFlag_FlipHorizontal) { - long mode; - hr = pVideoControl->GetMode(pPin, &mode); - if (FAILED(hr)) - qWarning() << "Failed to get the mode of the video control"; - else if (supportedModes & VideoControlFlag_FlipHorizontal) - m_needsHorizontalMirroring = (mode & VideoControlFlag_FlipHorizontal); - } - pPin->Release(); + } else if (m_outputPin) { + long supportedModes; + hr = pVideoControl->GetCaps(m_outputPin, &supportedModes); + if (FAILED(hr)) { + qWarning() << "Failed to get the supported modes of the video control"; + } else if (supportedModes & VideoControlFlag_FlipHorizontal) { + long mode; + hr = pVideoControl->GetMode(m_outputPin, &mode); + if (FAILED(hr)) + qWarning() << "Failed to get the mode of the video control"; + else if (supportedModes & VideoControlFlag_FlipHorizontal) + m_needsHorizontalMirroring = (mode & VideoControlFlag_FlipHorizontal); } pVideoControl->Release(); } @@ -1107,28 +1105,22 @@ void DSCameraSession::updateSourceCapabilities() QList frameRateRanges; - if (pVideoControl) { - IPin *pPin = nullptr; - if (!DirectShowUtils::getPin(m_sourceFilter, PINDIR_OUTPUT, &pPin, &hr)) { - qWarning() << "Failed to get the pin for the video control"; - } else { - long listSize = 0; - LONGLONG *frameRates = nullptr; - SIZE size = { resolution.width(), resolution.height() }; - hr = pVideoControl->GetFrameRateList(pPin, iIndex, size, &listSize, &frameRates); - if (hr == S_OK && listSize > 0 && frameRates) { - for (long i = 0; i < listSize; ++i) { - qreal fr = qreal(10000000) / frameRates[i]; - frameRateRanges.append(QCamera::FrameRateRange(fr, fr)); - } - - // Make sure higher frame rates come first - std::sort(frameRateRanges.begin(), frameRateRanges.end(), qt_frameRateRangeGreaterThan); + if (pVideoControl && m_outputPin) { + long listSize = 0; + LONGLONG *frameRates = nullptr; + SIZE size = { resolution.width(), resolution.height() }; + hr = pVideoControl->GetFrameRateList(m_outputPin, iIndex, size, &listSize, &frameRates); + if (hr == S_OK && listSize > 0 && frameRates) { + for (long i = 0; i < listSize; ++i) { + qreal fr = qreal(10000000) / frameRates[i]; + frameRateRanges.append(QCamera::FrameRateRange(fr, fr)); } - CoTaskMemFree(frameRates); - pPin->Release(); + // Make sure higher frame rates come first + std::sort(frameRateRanges.begin(), frameRateRanges.end(), qt_frameRateRangeGreaterThan); } + + CoTaskMemFree(frameRates); } if (frameRateRanges.isEmpty()) { diff --git a/src/plugins/directshow/camera/dscamerasession.h b/src/plugins/directshow/camera/dscamerasession.h index 5e7d026c2..9f88163b9 100644 --- a/src/plugins/directshow/camera/dscamerasession.h +++ b/src/plugins/directshow/camera/dscamerasession.h @@ -231,6 +231,8 @@ private: QMap m_pendingImageProcessingParametrs; + IPin *m_outputPin = nullptr; + friend class SampleGrabberCallbackPrivate; }; diff --git a/src/plugins/directshow/common/directshowutils.cpp b/src/plugins/directshow/common/directshowutils.cpp index 1457837ce..9222ad779 100644 --- a/src/plugins/directshow/common/directshowutils.cpp +++ b/src/plugins/directshow/common/directshowutils.cpp @@ -93,6 +93,25 @@ bool DirectShowUtils::hasPinDirection(IPin *pin, PIN_DIRECTION direction, HRESUL return (pinDir == direction); } +bool pinMatchesCategory(IPin* pPin, REFGUID category) +{ + bool found = false; + IKsPropertySet *pKs = nullptr; + DirectShowUtils::ScopedSafeRelease ks_property { &pKs }; + HRESULT hr = pPin->QueryInterface(IID_PPV_ARGS(&pKs)); + + if (SUCCEEDED(hr)) { + GUID pin_category; + DWORD return_value; + hr = pKs->Get(AMPROPSETID_Pin, AMPROPERTY_PIN_CATEGORY, NULL, 0, + &pin_category, sizeof(pin_category), &return_value); + if (SUCCEEDED(hr) && (return_value == sizeof(pin_category))) + found = (pin_category == category); + } + + return found; +} + /** * @brief DirectShowUtils::getPin * @param filter @@ -101,7 +120,7 @@ bool DirectShowUtils::hasPinDirection(IPin *pin, PIN_DIRECTION direction, HRESUL * @param hrOut * @return */ -bool DirectShowUtils::getPin(IBaseFilter *filter, PIN_DIRECTION pinDirection, IPin **pin, HRESULT *hrOut) +bool DirectShowUtils::getPin(IBaseFilter *filter, PIN_DIRECTION pinDirection, REFGUID category, IPin **pin, HRESULT *hrOut) { IEnumPins *enumPins = nullptr; const ScopedSafeRelease releaseEnumPins { &enumPins }; @@ -122,9 +141,11 @@ bool DirectShowUtils::getPin(IBaseFilter *filter, PIN_DIRECTION pinDirection, IP PIN_DIRECTION currentPinDir; *hrOut = nextPin->QueryDirection(¤tPinDir); if (currentPinDir == pinDirection) { - *pin = nextPin; - (*pin)->AddRef(); - return true; + if (category == GUID_NULL || pinMatchesCategory(nextPin, category)) { + *pin = nextPin; + (*pin)->AddRef(); + return true; + } } } diff --git a/src/plugins/directshow/common/directshowutils.h b/src/plugins/directshow/common/directshowutils.h index 5f2cfaa23..ec761abe6 100644 --- a/src/plugins/directshow/common/directshowutils.h +++ b/src/plugins/directshow/common/directshowutils.h @@ -68,7 +68,7 @@ struct ScopedSafeRelease } }; -bool getPin(IBaseFilter *filter, PIN_DIRECTION pinDirection, IPin **pin, HRESULT *hrOut); +bool getPin(IBaseFilter *filter, PIN_DIRECTION pinDirection, REFGUID category, IPin **pin, HRESULT *hrOut); bool isPinConnected(IPin *pin, HRESULT *hrOut = nullptr); bool hasPinDirection(IPin *pin, PIN_DIRECTION direction, HRESULT *hrOut = nullptr); bool matchPin(IPin *pin, PIN_DIRECTION pinDirection, BOOL shouldBeConnected, HRESULT *hrOut = nullptr); -- cgit v1.2.1