diff options
author | Christian Strømme <christian.stromme@qt.io> | 2016-11-09 15:29:39 +0100 |
---|---|---|
committer | Yoann Lopes <yoann.lopes@qt.io> | 2017-01-27 13:27:20 +0000 |
commit | ade8f281cb1e4f4e03fc3bfdf8a0b7b9ccd819c9 (patch) | |
tree | e7bc5a3f04cd143dd0120d1fbafaa57136bef918 /src/plugins/directshow | |
parent | 57a4cabd78aba3d6c1dd4802b0e3baf5ed3e4758 (diff) | |
download | qtmultimedia-ade8f281cb1e4f4e03fc3bfdf8a0b7b9ccd819c9.tar.gz |
DirectShow: Add utility class
Centralized place for helper functions etc.
Change-Id: Ia4474d0681a37fc95a100a3766800141a8b1d900
Reviewed-by: Yoann Lopes <yoann.lopes@qt.io>
Diffstat (limited to 'src/plugins/directshow')
-rw-r--r-- | src/plugins/directshow/camera/dscamerasession.cpp | 35 | ||||
-rw-r--r-- | src/plugins/directshow/dsserviceplugin.cpp | 6 | ||||
-rw-r--r-- | src/plugins/directshow/helpers/directshowutils.cpp | 309 | ||||
-rw-r--r-- | src/plugins/directshow/helpers/directshowutils.h | 87 | ||||
-rw-r--r-- | src/plugins/directshow/helpers/helpers.pri | 6 |
5 files changed, 407 insertions, 36 deletions
diff --git a/src/plugins/directshow/camera/dscamerasession.cpp b/src/plugins/directshow/camera/dscamerasession.cpp index 83abd983e..2b0795b44 100644 --- a/src/plugins/directshow/camera/dscamerasession.cpp +++ b/src/plugins/directshow/camera/dscamerasession.cpp @@ -49,11 +49,10 @@ #include "dsvideorenderer.h" #include "directshowcameraglobal.h" #include "directshowmediatype.h" +#include "directshowutils.h" QT_BEGIN_NAMESPACE -static HRESULT getPin(IBaseFilter *filter, PIN_DIRECTION pinDir, IPin **pin); - class SampleGrabberCallbackPrivate : public ISampleGrabberCB { public: @@ -1036,8 +1035,7 @@ void DSCameraSession::updateSourceCapabilities() qWarning() << "Failed to get the video control"; } else { IPin *pPin = 0; - hr = getPin(m_sourceFilter, PINDIR_OUTPUT, &pPin); - if (FAILED(hr)) { + if (!DirectShowUtils::getPin(m_sourceFilter, PINDIR_OUTPUT, &pPin, &hr)) { qWarning() << "Failed to get the pin for the video control"; } else { long supportedModes; @@ -1089,8 +1087,7 @@ void DSCameraSession::updateSourceCapabilities() if (pVideoControl) { IPin *pPin = 0; - hr = getPin(m_sourceFilter, PINDIR_OUTPUT, &pPin); - if (FAILED(hr)) { + if (!DirectShowUtils::getPin(m_sourceFilter, PINDIR_OUTPUT, &pPin, &hr)) { qWarning() << "Failed to get the pin for the video control"; } else { long listSize = 0; @@ -1137,30 +1134,4 @@ void DSCameraSession::updateSourceCapabilities() updateImageProcessingParametersInfos(); } -HRESULT getPin(IBaseFilter *pFilter, PIN_DIRECTION PinDir, IPin **ppPin) -{ - *ppPin = 0; - IEnumPins *pEnum = 0; - IPin *pPin = 0; - - HRESULT hr = pFilter->EnumPins(&pEnum); - if (FAILED(hr)) { - return hr; - } - - pEnum->Reset(); - while (pEnum->Next(1, &pPin, NULL) == S_OK) { - PIN_DIRECTION ThisPinDir; - pPin->QueryDirection(&ThisPinDir); - if (ThisPinDir == PinDir) { - pEnum->Release(); - *ppPin = pPin; - return S_OK; - } - pPin->Release(); - } - pEnum->Release(); - return E_FAIL; -} - QT_END_NAMESPACE diff --git a/src/plugins/directshow/dsserviceplugin.cpp b/src/plugins/directshow/dsserviceplugin.cpp index 1c9d0eee1..4b84841bd 100644 --- a/src/plugins/directshow/dsserviceplugin.cpp +++ b/src/plugins/directshow/dsserviceplugin.cpp @@ -78,9 +78,11 @@ extern const CLSID CLSID_VideoInputDeviceCategory; #include <ocidl.h> #endif -QT_USE_NAMESPACE - +QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(qtDirectShowPlugin, "qt.multimedia.plugins.directshow") +QT_END_NAMESPACE + +QT_USE_NAMESPACE static int g_refCount = 0; void addRefCount() diff --git a/src/plugins/directshow/helpers/directshowutils.cpp b/src/plugins/directshow/helpers/directshowutils.cpp new file mode 100644 index 000000000..d9701fd99 --- /dev/null +++ b/src/plugins/directshow/helpers/directshowutils.cpp @@ -0,0 +1,309 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "directshowutils.h" + +/** + * @brief DirectShowUtils::isPinConnected + * @param pin + * @param hrOut + * @return + */ +bool DirectShowUtils::isPinConnected(IPin *pin, HRESULT *hrOut) +{ + IPin *connectedPin = nullptr; + const ScopedSafeRelease<IPin> releasePin { &connectedPin }; + HRESULT hr = S_OK; + if (!hrOut) + hrOut = &hr; + + *hrOut = pin->ConnectedTo(&connectedPin); + if (*hrOut == VFW_E_NOT_CONNECTED) // Not an error in this case + *hrOut = S_OK; + + if (FAILED(*hrOut)) { + qCDebug(qtDirectShowPlugin, "Querying pin connection failed!"); + return false; + } + + return true; +} + +/** + * @brief DirectShowUtils::hasPinDirection + * @param pin + * @param direction + * @param hrOut + * @return + */ +bool DirectShowUtils::hasPinDirection(IPin *pin, PIN_DIRECTION direction, HRESULT *hrOut) +{ + PIN_DIRECTION pinDir; + HRESULT hr = S_OK; + if (!hrOut) + hrOut = &hr; + + *hrOut = pin->QueryDirection(&pinDir); + + if (FAILED(*hrOut)) { + qCDebug(qtDirectShowPlugin, "Querying pin direction failed!"); + return false; + } + + return (pinDir == direction); +} + +/** + * @brief DirectShowUtils::getPin + * @param filter + * @param pinDirection + * @param pin + * @param hrOut + * @return + */ +bool DirectShowUtils::getPin(IBaseFilter *filter, PIN_DIRECTION pinDirection, IPin **pin, HRESULT *hrOut) +{ + IEnumPins *enumPins = nullptr; + const ScopedSafeRelease<IEnumPins> releaseEnumPins { &enumPins }; + HRESULT hr S_OK; + if (!hrOut) + hrOut = &hr; + + *hrOut = filter->EnumPins(&enumPins); + if (FAILED(*hrOut)) { + qCDebug(qtDirectShowPlugin, "Unable to retrieve pins from the filter!"); + return false; + } + + enumPins->Reset(); + IPin *nextPin = nullptr; + while (enumPins->Next(1, &nextPin, NULL) == S_OK) { + const ScopedSafeRelease<IPin> releasePin { &nextPin }; + PIN_DIRECTION currentPinDir; + *hrOut = nextPin->QueryDirection(¤tPinDir); + if (currentPinDir == pinDirection) { + *pin = nextPin; + (*pin)->AddRef(); + return true; + } + } + + return false; +} + +/** + * @brief DirectShowUtils::matchPin + * @param pin + * @param pinDirection + * @param shouldBeConnected + * @param hrOut + * @return + */ +bool DirectShowUtils::matchPin(IPin *pin, PIN_DIRECTION pinDirection, BOOL shouldBeConnected, HRESULT *hrOut) +{ + HRESULT hr = S_OK; + if (!hrOut) + hrOut = &hr; + + const BOOL isConnected = isPinConnected(pin, hrOut); + if (FAILED(*hrOut)) // Error reason will already be logged, so just return. + return false; + + if (isConnected == shouldBeConnected) + return hasPinDirection(pin, pinDirection, hrOut); + + return SUCCEEDED(*hrOut); +} + +/** + * @brief DirectShowUtils::findUnconnectedPin + * @param filter + * @param pinDirection + * @param pin + * @param hrOut + * @return + */ +bool DirectShowUtils::findUnconnectedPin(IBaseFilter *filter, PIN_DIRECTION pinDirection, IPin **pin, HRESULT *hrOut) +{ + HRESULT hr = S_OK; + if (!hrOut) + hrOut = &hr; + + IEnumPins *enumPins = nullptr; + const ScopedSafeRelease<IEnumPins> releaseEnumPins { &enumPins }; + *hrOut = filter->EnumPins(&enumPins); + if (FAILED(*hrOut)) { + qCDebug(qtDirectShowPlugin, "Unable to retrieve pins from the DS filter"); + return false; + } + + IPin *nextPin = nullptr; + while (S_OK == enumPins->Next(1, &nextPin, nullptr)) { + const ScopedSafeRelease<IPin> releaseNextPin { &nextPin }; + if (matchPin(nextPin, pinDirection, FALSE, hrOut)) { + *pin = nextPin; + (*pin)->AddRef(); + return true; + } + + if (FAILED(*hrOut)) + return false; + } + + qCDebug(qtDirectShowPlugin, "No unconnected pins found"); + *hrOut = VFW_E_NOT_FOUND; + + return false; +} + +/** + * @brief DirectShowUtils::connectFilters - Attempts to connect \a outputPin to \a filter + * @param graph + * @param outputPin + * @param filter + * @param hrOut + * @return + */ +bool DirectShowUtils::connectFilters(IGraphBuilder *graph, IPin *outputPin, IBaseFilter *filter, HRESULT *hrOut) +{ + + // Find an input pin on the downstream filter. + HRESULT hr = S_OK; + if (!hrOut) + hrOut = &hr; + + IPin *inputPin = nullptr; + const ScopedSafeRelease<IPin> releaseInputPin { &inputPin }; + if (!findUnconnectedPin(filter, PINDIR_INPUT, &inputPin, hrOut)) + return false; + + + // Try to connect them. + *hrOut = graph->Connect(outputPin, inputPin); + if (FAILED(*hrOut)) { + qCDebug(qtDirectShowPlugin, "Unable to connect output pin to filter!"); + return false; + } + + return true; +} + +/** + * @brief DirectShowUtils::connectFilters - Attempts to connect \a filter to \a inputPin. + * @param graph + * @param filter + * @param inputPin + * @param hrOut + * @return + */ +bool DirectShowUtils::connectFilters(IGraphBuilder *graph, IBaseFilter *filter, IPin *inputPin, HRESULT *hrOut) +{ + HRESULT hr = S_OK; + if (!hrOut) + hrOut = &hr; + + IPin *outputPin = nullptr; + const ScopedSafeRelease<IPin> releaseOutputPin { &outputPin }; + // Find an output pin on the upstream filter. + if (findUnconnectedPin(filter, PINDIR_OUTPUT, &outputPin, hrOut)) + return false; + + *hrOut = graph->Connect(outputPin, inputPin); + if (FAILED(*hrOut)) { + qCDebug(qtDirectShowPlugin, "Unable to connect filter to input pin!"); + return false; + } + + return true; +} + +/** + * @brief DirectShowUtils::connectFilters - Attempts to connect the \a upstreamFilter to \a downstreamFilter. + * @param graph + * @param upstreamFilter + * @param downstreamFilter + * @param autoConnect - If set to true all filters in the graph will be considered. + * @param hrOut + * @return true if the the filters were connected, false otherwise. + */ +bool DirectShowUtils::connectFilters(IGraphBuilder *graph, + IBaseFilter *upstreamFilter, + IBaseFilter *downstreamFilter, + bool autoConnect, + HRESULT *hrOut) +{ + HRESULT hr = S_OK; + if (!hrOut) + hrOut = &hr; + + const auto findAndConnect = [graph, downstreamFilter, hrOut](IBaseFilter *filter) -> bool { + IPin *outputPin = nullptr; + const ScopedSafeRelease<IPin> releaseOutputPin { &outputPin }; + if (findUnconnectedPin(filter, PINDIR_OUTPUT, &outputPin, hrOut)) + return connectFilters(graph, outputPin, downstreamFilter, hrOut); + + return false; + }; + + // Try to connect to the upstream filter first. + if (findAndConnect(upstreamFilter)) + return S_OK; + + const auto getFilters = [graph, hrOut]() -> IEnumFilters * { + IEnumFilters *f = nullptr; + *hrOut = graph->EnumFilters(&f); + return f; + }; + IEnumFilters *filters = autoConnect ? getFilters() + : nullptr; + const ScopedSafeRelease<IEnumFilters> releaseEnumFilters { &filters }; + if (!filters) { + qCDebug(qtDirectShowPlugin, "No filters found!"); + return false; + } + + IBaseFilter *nextFilter = nullptr; + while (S_OK == filters->Next(1, &nextFilter, 0)) { + const ScopedSafeRelease<IBaseFilter> releaseNextFilter { &nextFilter }; + if (nextFilter && findAndConnect(nextFilter)) + break; + } + + return SUCCEEDED(*hrOut); +} diff --git a/src/plugins/directshow/helpers/directshowutils.h b/src/plugins/directshow/helpers/directshowutils.h new file mode 100644 index 000000000..09c81c257 --- /dev/null +++ b/src/plugins/directshow/helpers/directshowutils.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DIRECTSHOWUTILS_H +#define DIRECTSHOWUTILS_H + +#include "directshowglobal.h" + +QT_BEGIN_NAMESPACE + +namespace DirectShowUtils +{ +template <typename T> +void safeRelease(T **iface) { + if (!iface) + return; + + if (!*iface) + return; + + (*iface)->Release(); + *iface = nullptr; +} + +template <typename T> +struct ScopedSafeRelease +{ + T **iunknown; + ~ScopedSafeRelease() + { + DirectShowUtils::safeRelease(iunknown); + } +}; + +bool getPin(IBaseFilter *filter, PIN_DIRECTION pinDirection, 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); +bool findUnconnectedPin(IBaseFilter *filter, PIN_DIRECTION pinDirection, IPin **pin, HRESULT *hrOut = nullptr); +bool connectFilters(IGraphBuilder *graph, IPin *outputPin, IBaseFilter *filter, HRESULT *hrOut = nullptr); +bool connectFilters(IGraphBuilder *graph, IBaseFilter *filter, IPin *inputPin, HRESULT *hrOut = nullptr); +bool connectFilters(IGraphBuilder *graph, + IBaseFilter *upstreamFilter, + IBaseFilter *downstreamFilter, + bool autoConnect = false, + HRESULT *hrOut = nullptr); +} + +QT_END_NAMESPACE + +#endif // DIRECTSHOWUTILS_H diff --git a/src/plugins/directshow/helpers/helpers.pri b/src/plugins/directshow/helpers/helpers.pri index b3743a680..ca883eeb8 100644 --- a/src/plugins/directshow/helpers/helpers.pri +++ b/src/plugins/directshow/helpers/helpers.pri @@ -9,7 +9,8 @@ HEADERS += \ $$PWD/directshowobject.h \ $$PWD/directshowpin.h \ $$PWD/directshowpinenum.h \ - $$PWD/directshowvideobuffer.h + $$PWD/directshowvideobuffer.h \ + $$PWD/directshowutils.h SOURCES += \ $$PWD/directshowbasefilter.cpp \ @@ -19,4 +20,5 @@ SOURCES += \ $$PWD/directshowobject.cpp \ $$PWD/directshowpin.cpp \ $$PWD/directshowpinenum.cpp \ - $$PWD/directshowvideobuffer.cpp + $$PWD/directshowvideobuffer.cpp \ + $$PWD/directshowutils.cpp |