summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Strømme <christian.stromme@qt.io>2016-11-09 15:29:39 +0100
committerYoann Lopes <yoann.lopes@qt.io>2017-01-27 13:27:20 +0000
commitade8f281cb1e4f4e03fc3bfdf8a0b7b9ccd819c9 (patch)
treee7bc5a3f04cd143dd0120d1fbafaa57136bef918
parent57a4cabd78aba3d6c1dd4802b0e3baf5ed3e4758 (diff)
DirectShow: Add utility class
Centralized place for helper functions etc. Change-Id: Ia4474d0681a37fc95a100a3766800141a8b1d900 Reviewed-by: Yoann Lopes <yoann.lopes@qt.io>
-rw-r--r--src/plugins/directshow/camera/dscamerasession.cpp35
-rw-r--r--src/plugins/directshow/dsserviceplugin.cpp6
-rw-r--r--src/plugins/directshow/helpers/directshowutils.cpp309
-rw-r--r--src/plugins/directshow/helpers/directshowutils.h87
-rw-r--r--src/plugins/directshow/helpers/helpers.pri6
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(&currentPinDir);
+ 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