diff options
Diffstat (limited to 'src/plugins/directshow')
17 files changed, 1236 insertions, 27 deletions
diff --git a/src/plugins/directshow/camera/camera.pri b/src/plugins/directshow/camera/camera.pri index d8ee59aa9..0e1c1e895 100644 --- a/src/plugins/directshow/camera/camera.pri +++ b/src/plugins/directshow/camera/camera.pri @@ -11,7 +11,11 @@ HEADERS += \ $$PWD/dscamerasession.h \ $$PWD/directshowcameraglobal.h \ $$PWD/dscameraviewfindersettingscontrol.h \ - $$PWD/dscameraimageprocessingcontrol.h + $$PWD/dscameraimageprocessingcontrol.h \ + $$PWD/directshowcameraexposurecontrol.h \ + $$PWD/directshowcameracapturedestinationcontrol.h \ + $$PWD/directshowcameracapturebufferformatcontrol.h \ + $$PWD/directshowcamerazoomcontrol.h SOURCES += \ $$PWD/dscameraservice.cpp \ @@ -21,7 +25,11 @@ SOURCES += \ $$PWD/dsimagecapturecontrol.cpp \ $$PWD/dscamerasession.cpp \ $$PWD/dscameraviewfindersettingscontrol.cpp \ - $$PWD/dscameraimageprocessingcontrol.cpp + $$PWD/dscameraimageprocessingcontrol.cpp \ + $$PWD/directshowcameraexposurecontrol.cpp \ + $$PWD/directshowcameracapturedestinationcontrol.cpp \ + $$PWD/directshowcameracapturebufferformatcontrol.cpp \ + $$PWD/directshowcamerazoomcontrol.cpp *-msvc*:INCLUDEPATH += $$(DXSDK_DIR)/include QMAKE_USE += directshow diff --git a/src/plugins/directshow/camera/directshowcameracapturebufferformatcontrol.cpp b/src/plugins/directshow/camera/directshowcameracapturebufferformatcontrol.cpp new file mode 100644 index 000000000..cc0a0ad17 --- /dev/null +++ b/src/plugins/directshow/camera/directshowcameracapturebufferformatcontrol.cpp @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 "directshowcameracapturebufferformatcontrol.h" + +#include "dscamerasession.h" + +QT_BEGIN_NAMESPACE + +DirectShowCameraCaptureBufferFormatControl::DirectShowCameraCaptureBufferFormatControl() +{ +} + +QList<QVideoFrame::PixelFormat> DirectShowCameraCaptureBufferFormatControl::supportedBufferFormats() const +{ + return QList<QVideoFrame::PixelFormat>() << QVideoFrame::Format_RGB32; +} + +QVideoFrame::PixelFormat DirectShowCameraCaptureBufferFormatControl::bufferFormat() const +{ + return QVideoFrame::Format_RGB32; +} + +void DirectShowCameraCaptureBufferFormatControl::setBufferFormat(QVideoFrame::PixelFormat format) +{ + Q_UNUSED(format); +} + +QT_END_NAMESPACE diff --git a/src/plugins/directshow/camera/directshowcameracapturebufferformatcontrol.h b/src/plugins/directshow/camera/directshowcameracapturebufferformatcontrol.h new file mode 100644 index 000000000..cacd3652b --- /dev/null +++ b/src/plugins/directshow/camera/directshowcameracapturebufferformatcontrol.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 DIRECTSHOWCAMERACAPTUREBUFFERFORMATCONTROL_H +#define DIRECTSHOWCAMERACAPTUREBUFFERFORMATCONTROL_H + +#include <QtMultimedia/qcameracapturebufferformatcontrol.h> + +QT_BEGIN_NAMESPACE + +class DirectShowCameraCaptureBufferFormatControl : public QCameraCaptureBufferFormatControl +{ + Q_OBJECT +public: + DirectShowCameraCaptureBufferFormatControl(); + + QList<QVideoFrame::PixelFormat> supportedBufferFormats() const override; + QVideoFrame::PixelFormat bufferFormat() const override; + void setBufferFormat(QVideoFrame::PixelFormat format) override; +}; + +QT_END_NAMESPACE + +#endif // DIRECTSHOWCAMERACAPTUREBUFFERFORMATCONTROL_H diff --git a/src/plugins/directshow/camera/directshowcameracapturedestinationcontrol.cpp b/src/plugins/directshow/camera/directshowcameracapturedestinationcontrol.cpp new file mode 100644 index 000000000..bfb10fc03 --- /dev/null +++ b/src/plugins/directshow/camera/directshowcameracapturedestinationcontrol.cpp @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 "directshowcameracapturedestinationcontrol.h" + +#include "dscamerasession.h" + +QT_BEGIN_NAMESPACE + +DirectShowCameraCaptureDestinationControl::DirectShowCameraCaptureDestinationControl(DSCameraSession *session) + : m_session(session) +{ + connect(m_session, &DSCameraSession::captureDestinationChanged, + this, &DirectShowCameraCaptureDestinationControl::captureDestinationChanged); +} + +bool DirectShowCameraCaptureDestinationControl::isCaptureDestinationSupported(QCameraImageCapture::CaptureDestinations destination) const +{ + return m_session->isCaptureDestinationSupported(destination); +} + +QCameraImageCapture::CaptureDestinations DirectShowCameraCaptureDestinationControl::captureDestination() const +{ + return m_session->captureDestination(); +} + +void DirectShowCameraCaptureDestinationControl::setCaptureDestination(QCameraImageCapture::CaptureDestinations destination) +{ + m_session->setCaptureDestination(destination); +} + +QT_END_NAMESPACE diff --git a/src/plugins/directshow/camera/directshowcameracapturedestinationcontrol.h b/src/plugins/directshow/camera/directshowcameracapturedestinationcontrol.h new file mode 100644 index 000000000..224df9dbc --- /dev/null +++ b/src/plugins/directshow/camera/directshowcameracapturedestinationcontrol.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 DIRECTSHOWCAMERACAPTUREDESTINATIONCONTROL_H +#define DIRECTSHOWCAMERACAPTUREDESTINATIONCONTROL_H + +#include <QtMultimedia/qcameracapturedestinationcontrol.h> + +QT_BEGIN_NAMESPACE + +class DSCameraSession; + +class DirectShowCameraCaptureDestinationControl : public QCameraCaptureDestinationControl +{ + Q_OBJECT +public: + DirectShowCameraCaptureDestinationControl(DSCameraSession *session); + + bool isCaptureDestinationSupported(QCameraImageCapture::CaptureDestinations destination) const override; + QCameraImageCapture::CaptureDestinations captureDestination() const override; + void setCaptureDestination(QCameraImageCapture::CaptureDestinations destination) override; + +private: + DSCameraSession *m_session; + +}; + +QT_END_NAMESPACE + +#endif // DIRECTSHOWCAMERACAPTUREDESTINATIONCONTROL_H diff --git a/src/plugins/directshow/camera/directshowcameraexposurecontrol.cpp b/src/plugins/directshow/camera/directshowcameraexposurecontrol.cpp new file mode 100644 index 000000000..7ece366ea --- /dev/null +++ b/src/plugins/directshow/camera/directshowcameraexposurecontrol.cpp @@ -0,0 +1,411 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 "directshowcameraexposurecontrol.h" +#include "dscamerasession.h" +#include "directshowglobal.h" +#include "directshowutils.h" + +#include <functional> +#include <cmath> + +QT_BEGIN_NAMESPACE + +static qreal convertToSec(long v) { return (v < 0) ? (1 / std::pow(2., qreal(v))) : std::pow(2., qreal(v)); } +static Q_DECL_CONSTEXPR qreal convertToFvalue(long v) { return qreal(v) / 10.; } + +DirectShowCameraExposureControl::DirectShowCameraExposureControl(DSCameraSession *session) + : m_session(session) + , m_shutterSpeedValues({ 0, 0, 0, 0, 0 }) + , m_apertureValues({ 0, 0, 0, 0, 0 }) + , m_requestedShutterSpeed(qreal(0.0)) + , m_currentShutterSpeed(qreal(-1.0)) + , m_requestedAperture(qreal(0.0)) + , m_currentAperture(qreal(-1.0)) + , m_requestedExposureMode(QCameraExposure::ExposureAuto) + , m_currentExposureMode(QCameraExposure::ExposureAuto) +{ + Q_ASSERT(m_session); + connect(m_session, &DSCameraSession::statusChanged, + this, &DirectShowCameraExposureControl::onStatusChanged); +} + +bool DirectShowCameraExposureControl::isParameterSupported(QCameraExposureControl::ExposureParameter parameter) const +{ + if (parameter == ShutterSpeed) + return (m_shutterSpeedValues.caps & CameraControl_Flags_Manual); + if (parameter == Aperture) + return (m_apertureValues.caps & CameraControl_Flags_Manual); + if (parameter == ExposureMode) + return true; + + return false; +} + +QVariantList DirectShowCameraExposureControl::supportedParameterRange(QCameraExposureControl::ExposureParameter parameter, + bool *continuous) const +{ + if (continuous) + *continuous = false; + + if (parameter == ShutterSpeed) + return m_supportedShutterSpeeds; + + if (parameter == Aperture) + return m_supportedApertureValues; + + if (parameter == ExposureMode) + return m_supportedExposureModes; + + return QVariantList(); +} + +QVariant DirectShowCameraExposureControl::requestedValue(QCameraExposureControl::ExposureParameter parameter) const +{ + if (parameter == ShutterSpeed) + return QVariant::fromValue(m_requestedShutterSpeed); + + if (parameter == Aperture) + return QVariant::fromValue(m_requestedAperture); + + if (parameter == ExposureMode) + return QVariant::fromValue(m_requestedExposureMode); + + return QVariant(); +} + +QVariant DirectShowCameraExposureControl::actualValue(QCameraExposureControl::ExposureParameter parameter) const +{ + if (parameter == ExposureMode) + return QVariant::fromValue(m_currentExposureMode); + + if (parameter == ShutterSpeed) { + return qFuzzyCompare(m_currentShutterSpeed, qreal(-1.0)) + ? QVariant() + : QVariant::fromValue(m_currentShutterSpeed); + } + + if (parameter == Aperture) { + return qFuzzyCompare(m_currentAperture, qreal(-1.0)) + ? QVariant() + : QVariant::fromValue(m_currentAperture); + } + + return QVariant(); +} + +bool DirectShowCameraExposureControl::setValue(QCameraExposureControl::ExposureParameter parameter, + const QVariant &value) +{ + IAMCameraControl *cameraControl = nullptr; + const DirectShowUtils::ScopedSafeRelease<IAMCameraControl> rControl { &cameraControl }; + if (!m_session->getCameraControlInterface(&cameraControl)) + return false; + + // Reset exposure mode if the value is invalid. + if (!value.isValid()) { + m_requestedExposureMode = QCameraExposure::ExposureAuto; + return setExposureMode(cameraControl, m_requestedExposureMode); + } + + if (parameter == ShutterSpeed || parameter == Aperture) { + bool ok = false; + const qreal newValue = value.toReal(&ok); + if (!ok) + return false; + + // Change the exposure mode first + setExposureMode(cameraControl, QCameraExposure::ExposureManual); + + if (parameter == ShutterSpeed) { + m_requestedShutterSpeed = newValue; + return setShutterSpeed(cameraControl, m_requestedShutterSpeed); + } else { + m_requestedAperture = newValue; + return setAperture(cameraControl, m_requestedAperture); + } + } + + if (parameter == ExposureMode) { + m_requestedExposureMode = value.value<QCameraExposure::ExposureMode>(); + return setExposureMode(cameraControl, m_requestedExposureMode); + } + + return false; +} + +void DirectShowCameraExposureControl::onStatusChanged(QCamera::Status status) +{ + const bool shouldUpdate = (qFuzzyCompare(m_currentAperture, qreal(-1.0)) && qFuzzyCompare(m_currentShutterSpeed, qreal(-1.0))); + + if (status == QCamera::LoadedStatus && shouldUpdate) + updateExposureSettings(); + + if (status == QCamera::UnloadedStatus) { + m_supportedApertureValues.clear(); + m_supportedExposureModes.clear(); + m_supportedShutterSpeeds.clear(); + m_currentAperture = qreal(-1.0); + m_currentShutterSpeed = qreal(-1.0); + m_currentExposureMode = QCameraExposure::ExposureAuto; + } +} + +void DirectShowCameraExposureControl::updateExposureSettings() +{ + IAMCameraControl *cameraControl = nullptr; + const DirectShowUtils::ScopedSafeRelease<IAMCameraControl> rControl { &cameraControl }; + if (!m_session->getCameraControlInterface(&cameraControl)) + return; + + const auto updateValues = [cameraControl](long property, + ExposureValues ¤tValues, + QVariantList ¶meterRange, + const std::function<qreal(long)> &converter, + bool *changed) -> bool { + ExposureValues values { 0, 0, 0, 0, 0 }; + if (FAILED(cameraControl->GetRange(property, + &values.minValue, + &values.maxValue, + &values.stepping, + &values.defaultValue, + &values.caps))) { + return false; + } + + const bool minValueChanged = values.minValue != currentValues.minValue; + const bool maxValueChanged = values.maxValue != currentValues.maxValue; + const bool steppingChanged = values.stepping != currentValues.stepping; + + if (minValueChanged || maxValueChanged || steppingChanged) { + parameterRange.clear(); + long nextValue = values.minValue; + while (nextValue != values.maxValue && values.stepping != 0) { + parameterRange << converter(nextValue); + nextValue += values.stepping; + } + + if (changed) + *changed = true; + } + + currentValues = values; + return true; + }; + + const auto getCurrentValue = [cameraControl](long property, const std::function<qreal(long)> &converter, qreal *value) -> bool { + long currentValue; + long currentFlags; + if (FAILED(cameraControl->Get(property, ¤tValue, ¤tFlags))) + return false; + + *value = converter(currentValue); + return true; + }; + + // Shutter speed + bool changed = false; + if (!updateValues(CameraControl_Exposure, m_shutterSpeedValues, m_supportedShutterSpeeds, convertToSec, &changed)) + qCDebug(qtDirectShowPlugin, "Unable to update the shutter speed values"); + + if (changed) + Q_EMIT parameterRangeChanged(int(ShutterSpeed)); + + if ((m_shutterSpeedValues.caps & CameraControl_Flags_Manual)) { + if (getCurrentValue(CameraControl_Exposure, convertToSec, &m_currentShutterSpeed)) { + if (m_currentExposureMode == QCameraExposure::ExposureManual) + setShutterSpeed(cameraControl, m_requestedShutterSpeed); + } else { + m_currentShutterSpeed = qreal(-1.0); + qCDebug(qtDirectShowPlugin, "Unable to get the current shutter speed!"); + } + } + + // Aperture + changed = false; + if (!updateValues(CameraControl_Iris, m_apertureValues, m_supportedApertureValues, convertToFvalue, &changed)) + qCDebug(qtDirectShowPlugin, "Unable to update the aperture values"); + + if (changed) + Q_EMIT parameterRangeChanged(int(Aperture)); + + if (getCurrentValue(CameraControl_Iris, convertToFvalue, &m_currentAperture)) { + if (m_currentExposureMode == QCameraExposure::ExposureManual) + setAperture(cameraControl, m_requestedAperture); + } else { + m_currentAperture = qreal(-1.0); + qCDebug(qtDirectShowPlugin, "Unable to get the current aperture value!"); + } + + // Update exposure modes + const bool hasAutoExposure = (m_apertureValues.caps & CameraControl_Flags_Auto) + || (m_shutterSpeedValues.caps & CameraControl_Flags_Auto); + const bool hasManualExposure = (m_apertureValues.caps & CameraControl_Flags_Manual) + || (m_shutterSpeedValues.caps & CameraControl_Flags_Manual); + + QVariantList exposureModes; + if (hasAutoExposure && !m_supportedExposureModes.contains(QVariant::fromValue(QCameraExposure::ExposureAuto))) + exposureModes << QVariant::fromValue(QCameraExposure::ExposureAuto); + + if (hasManualExposure && !m_supportedExposureModes.contains(QVariant::fromValue(QCameraExposure::ExposureManual))) + exposureModes << QVariant::fromValue(QCameraExposure::ExposureManual); + + if (!exposureModes.isEmpty() || !m_supportedExposureModes.isEmpty()) { + m_supportedExposureModes = exposureModes; + Q_EMIT parameterRangeChanged(int(ExposureMode)); + } +} + +bool DirectShowCameraExposureControl::setShutterSpeed(IAMCameraControl *cameraControl, qreal shutterSpeed) +{ + if (m_currentExposureMode != QCameraExposure::ExposureManual) { + qCDebug(qtDirectShowPlugin, "Trying to set shutter speed value while in auto exposure mode!"); + return false; + } + + if (qFuzzyCompare(m_currentShutterSpeed, shutterSpeed)) + return true; + + if ((m_shutterSpeedValues.caps & CameraControl_Flags_Manual) == 0) + return false; + + if (!m_supportedShutterSpeeds.contains(QVariant::fromValue(shutterSpeed))) + return false; + + if (qFuzzyIsNull(shutterSpeed) || (shutterSpeed < qreal(0.0))) + return false; + + const long newValue = long(log2(shutterSpeed)); + if (FAILED(cameraControl->Set(CameraControl_Exposure, newValue, CameraControl_Flags_Manual))) { + qCDebug(qtDirectShowPlugin, "Unable to set shutter speed value to: %d", int(shutterSpeed)); + return false; + } + + m_currentShutterSpeed = shutterSpeed; + Q_EMIT actualValueChanged(int(ShutterSpeed)); + return true; +} + +bool DirectShowCameraExposureControl::setAperture(IAMCameraControl *cameraControl, qreal aperture) +{ + if (m_currentExposureMode != QCameraExposure::ExposureManual) { + qCDebug(qtDirectShowPlugin, "Trying to set aperture value while in auto exposure mode!"); + return false; + } + + if (qFuzzyCompare(m_currentAperture, aperture)) + return true; + + if ((m_apertureValues.caps & CameraControl_Flags_Manual) == 0) + return false; + + if (!m_supportedApertureValues.contains(QVariant::fromValue(aperture))) + return false; + + if (aperture < qreal(0.0)) + return false; + + const long newValue = long(10 * aperture); + if (FAILED(cameraControl->Set(CameraControl_Iris, newValue, CameraControl_Flags_Manual))) { + qCDebug(qtDirectShowPlugin, "Unable to set aperture value to: %d", int(aperture)); + return false; + } + + m_currentAperture = aperture; + Q_EMIT actualValueChanged(int(Aperture)); + + return true; +} + +bool DirectShowCameraExposureControl::setExposureMode(IAMCameraControl *cameraControl, QCameraExposure::ExposureMode mode) +{ + if (m_currentExposureMode == mode) + return true; + + bool exposureModeChanged = true; + + // Set auto exposure mode + if (mode == QCameraExposure::ExposureAuto) { + if ((m_apertureValues.caps & CameraControl_Flags_Auto) + && FAILED(cameraControl->Set(CameraControl_Iris, 0, CameraControl_Flags_Auto))) { + qCDebug(qtDirectShowPlugin, "Setting auto exposure mode failed!"); + exposureModeChanged = false; + } + + if ((m_shutterSpeedValues.caps & CameraControl_Flags_Auto) + && FAILED(cameraControl->Set(CameraControl_Exposure, 0, CameraControl_Flags_Auto))) { + qCDebug(qtDirectShowPlugin, "Setting auto exposure mode failed"); + exposureModeChanged = false; + } + + if (exposureModeChanged) { + m_currentExposureMode = mode; + Q_EMIT actualValueChanged(int(ExposureMode)); + } + + return exposureModeChanged; + } + + // Change the current exposure mode to manual first. + m_currentExposureMode = QCameraExposure::ExposureManual; + + const qreal newShutterSpeed = qFuzzyCompare(m_requestedShutterSpeed, -1.0) + ? convertToSec(m_shutterSpeedValues.defaultValue) + : m_requestedShutterSpeed; + if ((m_shutterSpeedValues.caps & CameraControl_Flags_Manual)) + setShutterSpeed(cameraControl, newShutterSpeed); + + const qreal newAperture = qFuzzyCompare(m_requestedAperture, -1.0) + ? convertToFvalue(m_apertureValues.defaultValue) + : m_requestedAperture; + if ((m_apertureValues.caps & CameraControl_Flags_Manual)) + setAperture(cameraControl, newAperture); + + + // Check if any of the values changed. + exposureModeChanged = (qFuzzyCompare(m_currentShutterSpeed, newShutterSpeed) + || qFuzzyCompare(m_currentAperture, newAperture)); + + if (exposureModeChanged) + Q_EMIT actualValueChanged(int(ExposureMode)); + + return exposureModeChanged; +} + +QT_END_NAMESPACE diff --git a/src/plugins/directshow/camera/directshowcameraexposurecontrol.h b/src/plugins/directshow/camera/directshowcameraexposurecontrol.h new file mode 100644 index 000000000..db3fc5984 --- /dev/null +++ b/src/plugins/directshow/camera/directshowcameraexposurecontrol.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 DIRECTSHOWCAMERAEXPOSURECONTROL_H +#define DIRECTSHOWCAMERAEXPOSURECONTROL_H + +#include <QtMultimedia/qcameraexposurecontrol.h> + +struct IAMCameraControl; + +QT_BEGIN_NAMESPACE + +class DSCameraSession; + +class DirectShowCameraExposureControl : public QCameraExposureControl +{ + Q_OBJECT +public: + DirectShowCameraExposureControl(DSCameraSession *session); + + bool isParameterSupported(ExposureParameter parameter) const override; + QVariantList supportedParameterRange(ExposureParameter parameter, bool *continuous) const override; + QVariant requestedValue(ExposureParameter parameter) const override; + QVariant actualValue(ExposureParameter parameter) const override; + bool setValue(ExposureParameter parameter, const QVariant &value) override; + +private Q_SLOTS: + void onStatusChanged(QCamera::Status status); + +private: + DSCameraSession *m_session; + + struct ExposureValues + { + long caps; + long minValue; + long maxValue; + long stepping; + long defaultValue; + } m_shutterSpeedValues, m_apertureValues; + + qreal m_requestedShutterSpeed; + qreal m_currentShutterSpeed; + + qreal m_requestedAperture; + qreal m_currentAperture; + + QVariantList m_supportedShutterSpeeds; + QVariantList m_supportedApertureValues; + QVariantList m_supportedExposureModes; + + QCameraExposure::ExposureMode m_requestedExposureMode; + QCameraExposure::ExposureMode m_currentExposureMode; + + void updateExposureSettings(); + + bool setShutterSpeed(IAMCameraControl *cameraControl, qreal shutterSpeed); + bool setAperture(IAMCameraControl *cameraControl, qreal aperture); + bool setExposureMode(IAMCameraControl *cameraControl, QCameraExposure::ExposureMode mode); +}; + +QT_END_NAMESPACE + +#endif // DIRECTSHOWCAMERAEXPOSURECONTROL_H diff --git a/src/plugins/directshow/camera/directshowcamerazoomcontrol.cpp b/src/plugins/directshow/camera/directshowcamerazoomcontrol.cpp new file mode 100644 index 000000000..209cb5d96 --- /dev/null +++ b/src/plugins/directshow/camera/directshowcamerazoomcontrol.cpp @@ -0,0 +1,209 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 "directshowcamerazoomcontrol.h" +#include "dscamerasession.h" +#include "directshowutils.h" + +QT_BEGIN_NAMESPACE + +inline static qreal defaultZoomValue() { return qreal(1.0); } + +DirectShowCameraZoomControl::DirectShowCameraZoomControl(DSCameraSession *session) + : m_session(session) + , m_opticalZoom({0, 0, 0, 0, 0}) + , m_currentOpticalZoom(qreal(0.0)) + , m_requestedOpticalZoom(qreal(0.0)) + , m_maxOpticalZoom(qreal(1.0)) +{ + Q_ASSERT(m_session); + connect(m_session, &DSCameraSession::statusChanged, + this, &DirectShowCameraZoomControl::onStatusChanged); +} + +qreal DirectShowCameraZoomControl::maximumOpticalZoom() const +{ + return m_maxOpticalZoom; +} + +qreal DirectShowCameraZoomControl::maximumDigitalZoom() const +{ + return defaultZoomValue(); +} + +qreal DirectShowCameraZoomControl::requestedOpticalZoom() const +{ + return qMax(defaultZoomValue(), m_requestedOpticalZoom); +} + +qreal DirectShowCameraZoomControl::requestedDigitalZoom() const +{ + return defaultZoomValue(); +} + +qreal DirectShowCameraZoomControl::currentOpticalZoom() const +{ + return qMax(defaultZoomValue(), m_currentOpticalZoom); +} + +qreal DirectShowCameraZoomControl::currentDigitalZoom() const +{ + return defaultZoomValue(); +} + +void DirectShowCameraZoomControl::zoomTo(qreal optical, qreal digital) +{ + Q_UNUSED(digital); + if (!(m_opticalZoom.caps & CameraControl_Flags_Manual)) + return; + + if (qFuzzyCompare(optical, m_requestedOpticalZoom)) + return; + + m_requestedOpticalZoom = optical; + Q_EMIT requestedOpticalZoomChanged(m_requestedOpticalZoom); + + if (qFuzzyCompare(m_requestedOpticalZoom, m_currentOpticalZoom)) + return; + + if (m_session->status() != QCamera::LoadedStatus && m_session->status() != QCamera::ActiveStatus) + return; // We'll wait until the camera is loaded, see: statusChanged connection + + opticalZoomToPrivate(optical); +} + +void DirectShowCameraZoomControl::onStatusChanged(QCamera::Status status) +{ + if (status == QCamera::LoadedStatus) { + updateZoomValues(); + } else if (status == QCamera::UnloadedStatus) { + SecureZeroMemory(&m_opticalZoom, sizeof(ZoomValues)); + m_currentOpticalZoom = qreal(0.0); + m_requestedOpticalZoom = qreal(0.0); + } + +} + +void DirectShowCameraZoomControl::updateZoomValues() +{ + IAMCameraControl *cameraControl = nullptr; + const DirectShowUtils::ScopedSafeRelease<IAMCameraControl> rControl { &cameraControl }; + if (!m_session->getCameraControlInterface(&cameraControl)) + return; + + ZoomValues values { 0, 0, 0, 0, 0 }; + // Zoom levels in DS are in the range [10, 600] + // The default zoom is device specific. + HRESULT hr = cameraControl->GetRange(CameraControl_Zoom, + &values.minZoom, + &values.maxZoom, + &values.stepping, + &values.defaultZoom, + &values.caps); + + if (FAILED(hr)) { + qCDebug(qtDirectShowPlugin, "Getting the camera's zoom properties failed"); + SecureZeroMemory(&m_opticalZoom, sizeof(ZoomValues)); + return; + } + + if (!(values.caps & CameraControl_Flags_Manual)) { + qCDebug(qtDirectShowPlugin, "Camera does not support manual zoom"); + SecureZeroMemory(&m_opticalZoom, sizeof(ZoomValues)); + return; + } + + if (values.maxZoom != m_opticalZoom.maxZoom) { + const qreal newMaxZoomScale = (values.minZoom == 0) ? defaultZoomValue() + : (qreal(values.maxZoom) / qreal(values.minZoom)); + if (!qFuzzyCompare(newMaxZoomScale, m_maxOpticalZoom)) { + m_maxOpticalZoom = newMaxZoomScale; + Q_EMIT maximumOpticalZoomChanged(m_maxOpticalZoom); + } + } + + m_opticalZoom = values; + + long currentZoom = 0; + long flags = 0; + if (FAILED(cameraControl->Get(CameraControl_Zoom, ¤tZoom, &flags))) { + qCDebug(qtDirectShowPlugin, "Getting the camera's current zoom value failed!"); + return; + } + + qreal currentOpticalZoom = (m_opticalZoom.minZoom == 0) ? defaultZoomValue() + : (qreal(currentZoom) / qreal(m_opticalZoom.minZoom)); + currentOpticalZoom = qMax(defaultZoomValue(), currentOpticalZoom); + if (!qFuzzyCompare(m_currentOpticalZoom, currentOpticalZoom)) { + m_currentOpticalZoom = currentOpticalZoom; + Q_EMIT currentOpticalZoomChanged(m_currentOpticalZoom); + } + + // Check if there is a pending zoom value. + if (!qFuzzyCompare(m_currentOpticalZoom, m_requestedOpticalZoom)) + opticalZoomToPrivate(m_requestedOpticalZoom); +} + +bool DirectShowCameraZoomControl::opticalZoomToPrivate(qreal scaleFactor) +{ + IAMCameraControl *cameraControl = nullptr; + const DirectShowUtils::ScopedSafeRelease<IAMCameraControl> rControl { &cameraControl }; + if (!m_session->getCameraControlInterface(&cameraControl)) + return false; + + // Convert to DS zoom value + const int newDSOpticalZoom = qRound(m_opticalZoom.minZoom * scaleFactor); + long newDSOpticalZoomAdjusted = newDSOpticalZoom - (newDSOpticalZoom % m_opticalZoom.stepping); + newDSOpticalZoomAdjusted = qBound(m_opticalZoom.minZoom, newDSOpticalZoomAdjusted, m_opticalZoom.maxZoom); + + if (FAILED(cameraControl->Set(CameraControl_Zoom, newDSOpticalZoomAdjusted, CameraControl_Flags_Manual))) { + qCDebug(qtDirectShowPlugin, "Setting the camera's zoom value failed"); + return false; + } + + const qreal newScaleFactor = (m_opticalZoom.minZoom == 0) ? defaultZoomValue() + : (qreal(newDSOpticalZoomAdjusted) / qreal(m_opticalZoom.minZoom)); + // convert back to Qt scale value + m_currentOpticalZoom = qMax(defaultZoomValue(), newScaleFactor); + Q_EMIT currentOpticalZoomChanged(m_currentOpticalZoom); + + return true; +} + +QT_END_NAMESPACE diff --git a/src/plugins/directshow/camera/directshowcamerazoomcontrol.h b/src/plugins/directshow/camera/directshowcamerazoomcontrol.h new file mode 100644 index 000000000..f6fb05b0e --- /dev/null +++ b/src/plugins/directshow/camera/directshowcamerazoomcontrol.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 DIRECTSHOWCAMERAZOOMCONTROL_H +#define DIRECTSHOWCAMERAZOOMCONTROL_H + +#include <QtMultimedia/qcamerazoomcontrol.h> +#include <QtMultimedia/qcamera.h> + +QT_BEGIN_NAMESPACE + +class DSCameraSession; + +class DirectShowCameraZoomControl : public QCameraZoomControl +{ + Q_OBJECT +public: + DirectShowCameraZoomControl(DSCameraSession *session); + + qreal maximumOpticalZoom() const override; + qreal maximumDigitalZoom() const override; + qreal requestedOpticalZoom() const override; + qreal requestedDigitalZoom() const override; + qreal currentOpticalZoom() const override; + qreal currentDigitalZoom() const override; + void zoomTo(qreal optical, qreal digital) override; + +private Q_SLOTS: + void onStatusChanged(QCamera::Status status); + +private: + DSCameraSession *m_session; + struct ZoomValues + { + long maxZoom; + long minZoom; + long stepping; + long defaultZoom; + long caps; + } m_opticalZoom; + + qreal m_currentOpticalZoom; + qreal m_requestedOpticalZoom; + qreal m_maxOpticalZoom; + + void updateZoomValues(); + bool opticalZoomToPrivate(qreal value); +}; + +QT_END_NAMESPACE + +#endif // DIRECTSHOWCAMERAZOOMCONTROL_H diff --git a/src/plugins/directshow/camera/dscameraservice.cpp b/src/plugins/directshow/camera/dscameraservice.cpp index 836f1aaa5..a806cabe3 100644 --- a/src/plugins/directshow/camera/dscameraservice.cpp +++ b/src/plugins/directshow/camera/dscameraservice.cpp @@ -48,19 +48,29 @@ #include "dsimagecapturecontrol.h" #include "dscameraviewfindersettingscontrol.h" #include "dscameraimageprocessingcontrol.h" +#include "directshowcameraexposurecontrol.h" +#include "directshowcameracapturedestinationcontrol.h" +#include "directshowcameracapturebufferformatcontrol.h" +#include "directshowvideoprobecontrol.h" +#include "directshowcamerazoomcontrol.h" QT_BEGIN_NAMESPACE DSCameraService::DSCameraService(QObject *parent): QMediaService(parent) + , m_session(new DSCameraSession(this)) + , m_control(new DSCameraControl(m_session)) + , m_videoDevice(new DSVideoDeviceControl(m_session)) , m_videoRenderer(0) + , m_imageCapture(new DSImageCaptureControl(m_session)) + , m_viewfinderSettings(new DSCameraViewfinderSettingsControl(m_session)) + , m_imageProcessingControl(new DSCameraImageProcessingControl(m_session)) + , m_exposureControl(new DirectShowCameraExposureControl(m_session)) + , m_captureDestinationControl(new DirectShowCameraCaptureDestinationControl(m_session)) + , m_captureBufferFormatControl(new DirectShowCameraCaptureBufferFormatControl) + , m_videoProbeControl(nullptr) + , m_zoomControl(new DirectShowCameraZoomControl(m_session)) { - m_session = new DSCameraSession(this); - m_control = new DSCameraControl(m_session); - m_videoDevice = new DSVideoDeviceControl(m_session); - m_imageCapture = new DSImageCaptureControl(m_session); - m_viewfinderSettings = new DSCameraViewfinderSettingsControl(m_session); - m_imageProcessingControl = new DSCameraImageProcessingControl(m_session); } DSCameraService::~DSCameraService() @@ -72,6 +82,11 @@ DSCameraService::~DSCameraService() delete m_videoRenderer; delete m_imageCapture; delete m_session; + delete m_exposureControl; + delete m_captureDestinationControl; + delete m_captureBufferFormatControl; + delete m_videoProbeControl; + delete m_zoomControl; } QMediaControl* DSCameraService::requestControl(const char *name) @@ -98,6 +113,27 @@ QMediaControl* DSCameraService::requestControl(const char *name) if (qstrcmp(name, QCameraImageProcessingControl_iid) == 0) return m_imageProcessingControl; + if (qstrcmp(name, QCameraExposureControl_iid) == 0) + return m_exposureControl; + + if (qstrcmp(name, QCameraCaptureDestinationControl_iid) == 0) + return m_captureDestinationControl; + + if (qstrcmp(name, QCameraCaptureBufferFormatControl_iid) == 0) + return m_captureBufferFormatControl; + + if (qstrcmp(name, QMediaVideoProbeControl_iid) == 0) { + if (!m_videoProbeControl) + m_videoProbeControl = new DirectShowVideoProbeControl; + + m_videoProbeControl->ref(); + m_session->addVideoProbe(m_videoProbeControl); + return m_videoProbeControl; + } + + if (qstrcmp(name, QCameraZoomControl_iid) == 0) + return m_zoomControl; + return 0; } @@ -108,6 +144,14 @@ void DSCameraService::releaseControl(QMediaControl *control) m_videoRenderer = 0; return; } + + if (control == m_videoProbeControl) { + m_session->removeVideoProbe(m_videoProbeControl); + if (!m_videoProbeControl->deref()) { + delete m_videoProbeControl; + m_videoProbeControl = nullptr; + } + } } QT_END_NAMESPACE diff --git a/src/plugins/directshow/camera/dscameraservice.h b/src/plugins/directshow/camera/dscameraservice.h index 8976e41cf..f444eeb51 100644 --- a/src/plugins/directshow/camera/dscameraservice.h +++ b/src/plugins/directshow/camera/dscameraservice.h @@ -52,6 +52,11 @@ class DSVideoDeviceControl; class DSImageCaptureControl; class DSCameraViewfinderSettingsControl; class DSCameraImageProcessingControl; +class DirectShowCameraExposureControl; +class DirectShowCameraCaptureDestinationControl; +class DirectShowCameraCaptureBufferFormatControl; +class DirectShowVideoProbeControl; +class DirectShowCameraZoomControl; class DSCameraService : public QMediaService { @@ -65,13 +70,18 @@ public: virtual void releaseControl(QMediaControl *control); private: - DSCameraControl *m_control; DSCameraSession *m_session; + DSCameraControl *m_control; DSVideoDeviceControl *m_videoDevice; QMediaControl *m_videoRenderer; DSImageCaptureControl *m_imageCapture; DSCameraViewfinderSettingsControl *m_viewfinderSettings; DSCameraImageProcessingControl *m_imageProcessingControl; + DirectShowCameraExposureControl *m_exposureControl; + DirectShowCameraCaptureDestinationControl *m_captureDestinationControl; + DirectShowCameraCaptureBufferFormatControl *m_captureBufferFormatControl; + DirectShowVideoProbeControl *m_videoProbeControl; + DirectShowCameraZoomControl *m_zoomControl; }; QT_END_NAMESPACE diff --git a/src/plugins/directshow/camera/dscamerasession.cpp b/src/plugins/directshow/camera/dscamerasession.cpp index dc0dfc8b3..9b642872a 100644 --- a/src/plugins/directshow/camera/dscamerasession.cpp +++ b/src/plugins/directshow/camera/dscamerasession.cpp @@ -51,24 +51,27 @@ #include "directshowcameraglobal.h" #include "directshowmediatype.h" #include "directshowutils.h" +#include "directshowvideoprobecontrol.h" QT_BEGIN_NAMESPACE DSCameraSession::DSCameraSession(QObject *parent) : QObject(parent) - , m_graphBuilder(Q_NULLPTR) - , m_filterGraph(Q_NULLPTR) + , m_graphBuilder(nullptr) + , m_filterGraph(nullptr) , m_sourceDeviceName(QLatin1String("default")) - , m_sourceFilter(Q_NULLPTR) + , m_sourceFilter(nullptr) , m_needsHorizontalMirroring(false) - , m_previewSampleGrabber(Q_NULLPTR) - , m_nullRendererFilter(Q_NULLPTR) + , m_previewSampleGrabber(nullptr) + , m_nullRendererFilter(nullptr) , m_previewStarted(false) - , m_surface(Q_NULLPTR) + , m_surface(nullptr) , m_previewPixelFormat(QVideoFrame::Format_Invalid) , m_readyForCapture(false) , m_imageIdCounter(0) , m_currentImageId(-1) + , m_captureDestinations(QCameraImageCapture::CaptureToFile) + , m_videoProbeControl(nullptr) , m_status(QCamera::UnloadedStatus) { connect(this, SIGNAL(statusChanged(QCamera::Status)), @@ -354,6 +357,39 @@ bool DSCameraSession::getCameraControlInterface(IAMCameraControl **cameraControl return true; } +bool DSCameraSession::isCaptureDestinationSupported(QCameraImageCapture::CaptureDestinations destination) const +{ + return destination & (QCameraImageCapture::CaptureToFile | QCameraImageCapture::CaptureToBuffer); +} + +QCameraImageCapture::CaptureDestinations DSCameraSession::captureDestination() const +{ + return m_captureDestinations; +} + +void DSCameraSession::setCaptureDestination(QCameraImageCapture::CaptureDestinations destinations) +{ + if (m_captureDestinations == destinations) + return; + + m_captureDestinations = destinations; + Q_EMIT captureDestinationChanged(m_captureDestinations); +} + +void DSCameraSession::addVideoProbe(DirectShowVideoProbeControl *probe) +{ + const QMutexLocker locker(&m_probeMutex); + m_videoProbeControl = probe; +} + +void DSCameraSession::removeVideoProbe(DirectShowVideoProbeControl *probe) +{ + Q_UNUSED(probe); + Q_ASSERT(m_videoProbeControl == probe); + const QMutexLocker locker(&m_probeMutex); + m_videoProbeControl = nullptr; +} + bool DSCameraSession::load() { unload(); @@ -547,6 +583,12 @@ void DSCameraSession::onFrameAvailable(double time, const QByteArray &data) m_presentMutex.unlock(); + { + const QMutexLocker locker(&m_probeMutex); + if (m_currentFrame.isValid() && m_videoProbeControl) + Q_EMIT m_videoProbeControl->videoFrameProbed(m_currentFrame); + } + // Image capture QMutexLocker locker(&m_captureMutex); if (m_currentImageId != -1 && !m_capturedFrame.isValid()) { @@ -586,8 +628,8 @@ void DSCameraSession::presentFrame() m_capturedFrame.unmap(); - QtConcurrent::run(this, &DSCameraSession::saveCapturedImage, - m_currentImageId, captureImage, m_imageCaptureFileName); + QtConcurrent::run(this, &DSCameraSession::processCapturedImage, + m_currentImageId, m_captureDestinations, captureImage, m_imageCaptureFileName); m_imageCaptureFileName.clear(); m_currentImageId = -1; @@ -603,14 +645,22 @@ void DSCameraSession::presentFrame() updateReadyForCapture(); } -void DSCameraSession::saveCapturedImage(int id, const QImage &image, const QString &path) +void DSCameraSession::processCapturedImage(int id, + QCameraImageCapture::CaptureDestinations captureDestinations, + const QImage &image, + const QString &path) { - if (image.save(path, "JPG")) { - emit imageSaved(id, path); - } else { - emit captureError(id, QCameraImageCapture::ResourceError, - tr("Could not save image to file.")); + if (captureDestinations & QCameraImageCapture::CaptureToFile) { + if (image.save(path, "JPG")) { + Q_EMIT imageSaved(id, path); + } else { + Q_EMIT captureError(id, QCameraImageCapture::ResourceError, + tr("Could not save image to file.")); + } } + + if (captureDestinations & QCameraImageCapture::CaptureToBuffer) + Q_EMIT imageAvailable(id, QVideoFrame(image)); } bool DSCameraSession::createFilterGraph() diff --git a/src/plugins/directshow/camera/dscamerasession.h b/src/plugins/directshow/camera/dscamerasession.h index 90407f49e..e28015534 100644 --- a/src/plugins/directshow/camera/dscamerasession.h +++ b/src/plugins/directshow/camera/dscamerasession.h @@ -50,6 +50,7 @@ #include <QtMultimedia/qabstractvideosurface.h> #include <QtMultimedia/qvideosurfaceformat.h> #include <QtMultimedia/qcameraimageprocessingcontrol.h> +#include <QtMultimedia/qcameraimagecapture.h> #include <private/qmediastoragelocation_p.h> #include <tchar.h> @@ -76,6 +77,7 @@ struct ICaptureGraphBuilder2; QT_BEGIN_NAMESPACE class DirectShowSampleGrabber; +class DirectShowVideoProbeControl; class DSCameraSession : public QObject { @@ -120,13 +122,22 @@ public: bool getCameraControlInterface(IAMCameraControl **cameraControl) const; + bool isCaptureDestinationSupported(QCameraImageCapture::CaptureDestinations destination) const; + QCameraImageCapture::CaptureDestinations captureDestination() const; + void setCaptureDestination(QCameraImageCapture::CaptureDestinations destinations); + + void addVideoProbe(DirectShowVideoProbeControl *probe); + void removeVideoProbe(DirectShowVideoProbeControl *probe); + Q_SIGNALS: void statusChanged(QCamera::Status); void imageExposed(int id); void imageCaptured(int id, const QImage &preview); void imageSaved(int id, const QString &fileName); + void imageAvailable(int id, const QVideoFrame &buffer); void readyForCaptureChanged(bool); void captureError(int id, int error, const QString &errorString); + void captureDestinationChanged(QCameraImageCapture::CaptureDestinations); private Q_SLOTS: void presentFrame(); @@ -157,7 +168,7 @@ private: void setStatus(QCamera::Status status); void onFrameAvailable(double time, const QByteArray &data); - void saveCapturedImage(int id, const QImage &image, const QString &path); + void processCapturedImage(int id, QCameraImageCapture::CaptureDestinations captureDestinations, const QImage &image, const QString &path); bool createFilterGraph(); bool connectGraph(); @@ -208,6 +219,11 @@ private: int m_imageIdCounter; int m_currentImageId; QVideoFrame m_capturedFrame; + QCameraImageCapture::CaptureDestinations m_captureDestinations; + + // Video probe + QMutex m_probeMutex; + DirectShowVideoProbeControl *m_videoProbeControl; // Internal state QCamera::Status m_status; diff --git a/src/plugins/directshow/camera/dsimagecapturecontrol.cpp b/src/plugins/directshow/camera/dsimagecapturecontrol.cpp index 9d4a7ea1d..c92ce98e1 100644 --- a/src/plugins/directshow/camera/dsimagecapturecontrol.cpp +++ b/src/plugins/directshow/camera/dsimagecapturecontrol.cpp @@ -57,6 +57,8 @@ DSImageCaptureControl::DSImageCaptureControl(DSCameraSession *session) this, SIGNAL(readyForCaptureChanged(bool))); connect(m_session, SIGNAL(captureError(int,int,QString)), this, SIGNAL(error(int,int,QString))); + connect(m_session, &DSCameraSession::imageAvailable, + this, &DSImageCaptureControl::imageAvailable); } DSImageCaptureControl::~DSImageCaptureControl() diff --git a/src/plugins/directshow/directshow.pro b/src/plugins/directshow/directshow.pro index 2857f87d9..54d617166 100644 --- a/src/plugins/directshow/directshow.pro +++ b/src/plugins/directshow/directshow.pro @@ -8,7 +8,13 @@ win32:!qtHaveModule(opengl)|qtConfig(dynamicgl) { HEADERS += dsserviceplugin.h SOURCES += dsserviceplugin.cpp -mingw: DEFINES += NO_DSHOW_STRSAFE +# Remove WINVER/_WIN32_WINNT definitions added to qt_build_config.prf +# by qtbase/d57a7c41712f8627a462d893329dc3f0dbb52d32 since the multimedia +# headers of MinGW 5.3/7.1 are too broken to compile with 0x0601. +mingw { + DEFINES -= WINVER=0x0601 _WIN32_WINNT=0x0601 + DEFINES += NO_DSHOW_STRSAFE +} include(common/common.pri) qtConfig(directshow-player): include(player/player.pri) diff --git a/src/plugins/directshow/dsserviceplugin.cpp b/src/plugins/directshow/dsserviceplugin.cpp index 51be7e500..cb4f0cdf9 100644 --- a/src/plugins/directshow/dsserviceplugin.cpp +++ b/src/plugins/directshow/dsserviceplugin.cpp @@ -123,7 +123,9 @@ QMediaServiceProviderHint::Features DSServicePlugin::supportedFeatures( QByteArray DSServicePlugin::defaultDevice(const QByteArray &service) const { if (service == Q_MEDIASERVICE_CAMERA) { + addRefCount(); const QList<DSVideoDeviceInfo> &devs = DSVideoDeviceControl::availableDevices(); + releaseRefCount(); if (!devs.isEmpty()) return devs.first().first; } @@ -135,7 +137,9 @@ QList<QByteArray> DSServicePlugin::devices(const QByteArray &service) const QList<QByteArray> result; if (service == Q_MEDIASERVICE_CAMERA) { + addRefCount(); const QList<DSVideoDeviceInfo> &devs = DSVideoDeviceControl::availableDevices(); + releaseRefCount(); for (const DSVideoDeviceInfo &info : devs) result.append(info.first); } @@ -146,7 +150,9 @@ QList<QByteArray> DSServicePlugin::devices(const QByteArray &service) const QString DSServicePlugin::deviceDescription(const QByteArray &service, const QByteArray &device) { if (service == Q_MEDIASERVICE_CAMERA) { + addRefCount(); const QList<DSVideoDeviceInfo> &devs = DSVideoDeviceControl::availableDevices(); + releaseRefCount(); for (const DSVideoDeviceInfo &info : devs) { if (info.first == device) return info.second; diff --git a/src/plugins/directshow/player/directshowvideorenderercontrol.cpp b/src/plugins/directshow/player/directshowvideorenderercontrol.cpp index 40f77e899..ee7f5ec9e 100644 --- a/src/plugins/directshow/player/directshowvideorenderercontrol.cpp +++ b/src/plugins/directshow/player/directshowvideorenderercontrol.cpp @@ -63,7 +63,7 @@ DirectShowVideoRendererControl::~DirectShowVideoRendererControl() { #if QT_CONFIG(evr) if (m_evrPresenter) { - m_evrPresenter->setSurface(Q_NULLPTR); + m_evrPresenter->setSurface(nullptr); m_evrPresenter->Release(); } #endif @@ -83,7 +83,7 @@ void DirectShowVideoRendererControl::setSurface(QAbstractVideoSurface *surface) #if QT_CONFIG(evr) if (m_evrPresenter) { - m_evrPresenter->setSurface(Q_NULLPTR); + m_evrPresenter->setSurface(nullptr); m_evrPresenter->Release(); m_evrPresenter = 0; } |