From 7f0459885991d56307cd79d94ad932ecd3df0666 Mon Sep 17 00:00:00 2001 From: Denis Shienkov Date: Sun, 8 Nov 2015 18:34:01 +0300 Subject: DirectShow: Implement basic QCameraImageProcessingControl interface This commit implements the contrast, saturation, brightness and sharpening adjustments, using DirectShow backend. Change-Id: I438595550ff804f2a20028b4bc020c566d309127 Reviewed-by: Yoann Lopes --- src/plugins/directshow/camera/camera.pri | 6 +- .../camera/dscameraimageprocessingcontrol.cpp | 74 +++++++ .../camera/dscameraimageprocessingcontrol.h | 63 ++++++ src/plugins/directshow/camera/dscameraservice.cpp | 6 + src/plugins/directshow/camera/dscameraservice.h | 2 + src/plugins/directshow/camera/dscamerasession.cpp | 224 +++++++++++++++++++++ src/plugins/directshow/camera/dscamerasession.h | 39 ++++ 7 files changed, 412 insertions(+), 2 deletions(-) create mode 100644 src/plugins/directshow/camera/dscameraimageprocessingcontrol.cpp create mode 100644 src/plugins/directshow/camera/dscameraimageprocessingcontrol.h (limited to 'src/plugins/directshow') diff --git a/src/plugins/directshow/camera/camera.pri b/src/plugins/directshow/camera/camera.pri index 3a532f472..c6b16da59 100644 --- a/src/plugins/directshow/camera/camera.pri +++ b/src/plugins/directshow/camera/camera.pri @@ -14,7 +14,8 @@ HEADERS += \ $$PWD/dsimagecapturecontrol.h \ $$PWD/dscamerasession.h \ $$PWD/directshowglobal.h \ - $$PWD/dscameraviewfindersettingscontrol.h + $$PWD/dscameraviewfindersettingscontrol.h \ + $$PWD/dscameraimageprocessingcontrol.h SOURCES += \ $$PWD/dscameraservice.cpp \ @@ -23,7 +24,8 @@ SOURCES += \ $$PWD/dsvideodevicecontrol.cpp \ $$PWD/dsimagecapturecontrol.cpp \ $$PWD/dscamerasession.cpp \ - $$PWD/dscameraviewfindersettingscontrol.cpp + $$PWD/dscameraviewfindersettingscontrol.cpp \ + $$PWD/dscameraimageprocessingcontrol.cpp *-msvc*:INCLUDEPATH += $$(DXSDK_DIR)/include LIBS += -lstrmiids -ldmoguids -luuid -lmsdmo -lole32 -loleaut32 diff --git a/src/plugins/directshow/camera/dscameraimageprocessingcontrol.cpp b/src/plugins/directshow/camera/dscameraimageprocessingcontrol.cpp new file mode 100644 index 000000000..39fa471ec --- /dev/null +++ b/src/plugins/directshow/camera/dscameraimageprocessingcontrol.cpp @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Denis Shienkov +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "dscameraimageprocessingcontrol.h" +#include "dscamerasession.h" + +QT_BEGIN_NAMESPACE + +DSCameraImageProcessingControl::DSCameraImageProcessingControl(DSCameraSession *session) + : QCameraImageProcessingControl(session) + , m_session(session) +{ +} + +DSCameraImageProcessingControl::~DSCameraImageProcessingControl() +{ +} + +bool DSCameraImageProcessingControl::isParameterSupported( + QCameraImageProcessingControl::ProcessingParameter parameter) const +{ + return m_session->isImageProcessingParameterSupported(parameter); +} + +bool DSCameraImageProcessingControl::isParameterValueSupported( + QCameraImageProcessingControl::ProcessingParameter parameter, + const QVariant &value) const +{ + return m_session->isImageProcessingParameterValueSupported(parameter, value); +} + +QVariant DSCameraImageProcessingControl::parameter( + QCameraImageProcessingControl::ProcessingParameter parameter) const +{ + return m_session->imageProcessingParameter(parameter); +} + +void DSCameraImageProcessingControl::setParameter(QCameraImageProcessingControl::ProcessingParameter parameter, + const QVariant &value) +{ + m_session->setImageProcessingParameter(parameter, value); +} + +QT_END_NAMESPACE diff --git a/src/plugins/directshow/camera/dscameraimageprocessingcontrol.h b/src/plugins/directshow/camera/dscameraimageprocessingcontrol.h new file mode 100644 index 000000000..2e50fe14d --- /dev/null +++ b/src/plugins/directshow/camera/dscameraimageprocessingcontrol.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Denis Shienkov +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DSCAMERAIMAGEPROCESSINGCONTROL_H +#define DSCAMERAIMAGEPROCESSINGCONTROL_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class DSCameraSession; + +class DSCameraImageProcessingControl : public QCameraImageProcessingControl +{ + Q_OBJECT + +public: + DSCameraImageProcessingControl(DSCameraSession *session); + virtual ~DSCameraImageProcessingControl(); + + bool isParameterSupported(ProcessingParameter) const; + bool isParameterValueSupported(ProcessingParameter parameter, const QVariant &value) const; + QVariant parameter(ProcessingParameter parameter) const; + void setParameter(ProcessingParameter parameter, const QVariant &value); + +private: + DSCameraSession *m_session; +}; + +QT_END_NAMESPACE + +#endif // DSCAMERAIMAGEPROCESSINGCONTROL_H diff --git a/src/plugins/directshow/camera/dscameraservice.cpp b/src/plugins/directshow/camera/dscameraservice.cpp index 9fcd4de70..6c92df04b 100644 --- a/src/plugins/directshow/camera/dscameraservice.cpp +++ b/src/plugins/directshow/camera/dscameraservice.cpp @@ -41,6 +41,7 @@ #include "dsvideodevicecontrol.h" #include "dsimagecapturecontrol.h" #include "dscameraviewfindersettingscontrol.h" +#include "dscameraimageprocessingcontrol.h" QT_BEGIN_NAMESPACE @@ -53,12 +54,14 @@ DSCameraService::DSCameraService(QObject *parent): 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() { delete m_control; delete m_viewfinderSettings; + delete m_imageProcessingControl; delete m_videoDevice; delete m_videoRenderer; delete m_imageCapture; @@ -86,6 +89,9 @@ QMediaControl* DSCameraService::requestControl(const char *name) if (qstrcmp(name, QCameraViewfinderSettingsControl2_iid) == 0) return m_viewfinderSettings; + if (qstrcmp(name, QCameraImageProcessingControl_iid) == 0) + return m_imageProcessingControl; + return 0; } diff --git a/src/plugins/directshow/camera/dscameraservice.h b/src/plugins/directshow/camera/dscameraservice.h index c3c881d0e..05222ebc4 100644 --- a/src/plugins/directshow/camera/dscameraservice.h +++ b/src/plugins/directshow/camera/dscameraservice.h @@ -46,6 +46,7 @@ class DSVideoOutputControl; class DSVideoDeviceControl; class DSImageCaptureControl; class DSCameraViewfinderSettingsControl; +class DSCameraImageProcessingControl; class DSCameraService : public QMediaService { @@ -66,6 +67,7 @@ private: QMediaControl *m_videoRenderer; DSImageCaptureControl *m_imageCapture; DSCameraViewfinderSettingsControl *m_viewfinderSettings; + DSCameraImageProcessingControl *m_imageProcessingControl; }; QT_END_NAMESPACE diff --git a/src/plugins/directshow/camera/dscamerasession.cpp b/src/plugins/directshow/camera/dscamerasession.cpp index 2d3aa1bce..7ec91cfa2 100644 --- a/src/plugins/directshow/camera/dscamerasession.cpp +++ b/src/plugins/directshow/camera/dscamerasession.cpp @@ -230,6 +230,162 @@ void DSCameraSession::setViewfinderSettings(const QCameraViewfinderSettings &set m_viewfinderSettings = settings; } +qreal DSCameraSession::scaledImageProcessingParameterValue( + qint32 sourceValue, const ImageProcessingParameterInfo &sourceValueInfo) +{ + if (sourceValue == sourceValueInfo.defaultValue) { + return 0.0f; + } else if (sourceValue < sourceValueInfo.defaultValue) { + return ((sourceValue - sourceValueInfo.minimumValue) + / qreal(sourceValueInfo.defaultValue - sourceValueInfo.minimumValue)) + + (-1.0f); + } else { + return ((sourceValue - sourceValueInfo.defaultValue) + / qreal(sourceValueInfo.maximumValue - sourceValueInfo.defaultValue)); + } +} + +qint32 DSCameraSession::sourceImageProcessingParameterValue( + qreal scaledValue, const ImageProcessingParameterInfo &valueRange) +{ + if (qFuzzyIsNull(scaledValue)) { + return valueRange.defaultValue; + } else if (scaledValue < 0.0f) { + return ((scaledValue - (-1.0f)) * (valueRange.defaultValue - valueRange.minimumValue)) + + valueRange.minimumValue; + } else { + return (scaledValue * (valueRange.maximumValue - valueRange.defaultValue)) + + valueRange.defaultValue; + } +} + +bool DSCameraSession::isImageProcessingParameterSupported( + QCameraImageProcessingControl::ProcessingParameter parameter) const +{ + return m_imageProcessingParametersInfos.contains(parameter); +} + +bool DSCameraSession::isImageProcessingParameterValueSupported( + QCameraImageProcessingControl::ProcessingParameter parameter, + const QVariant &value) const +{ + QMap::const_iterator sourceValueInfo = + m_imageProcessingParametersInfos.constFind(parameter); + + if (sourceValueInfo == m_imageProcessingParametersInfos.constEnd()) + return false; + + // This conversion is required only for сontrast, saturation + // brightness, and sharpening. + const qint32 sourceValue = sourceImageProcessingParameterValue( + value.toReal(), (*sourceValueInfo)); + if (sourceValue < (*sourceValueInfo).minimumValue + || sourceValue > (*sourceValueInfo).maximumValue) + return false; + + return true; +} + +QVariant DSCameraSession::imageProcessingParameter( + QCameraImageProcessingControl::ProcessingParameter parameter) const +{ + if (!m_graphBuilder) { + qWarning() << "failed to access to the graph builder"; + return QVariant(); + } + + QMap::const_iterator sourceValueInfo = + m_imageProcessingParametersInfos.constFind(parameter); + + if (sourceValueInfo == m_imageProcessingParametersInfos.constEnd()) + return QVariant(); + + IAMVideoProcAmp *pVideoProcAmp = NULL; + HRESULT hr = m_graphBuilder->FindInterface( + NULL, + NULL, + m_sourceFilter, + IID_IAMVideoProcAmp, + reinterpret_cast(&pVideoProcAmp) + ); + + if (FAILED(hr) || !pVideoProcAmp) { + qWarning() << "failed to find the video proc amp"; + return QVariant(); + } + + LONG sourceValue = 0; + LONG valueFlags = 0; + + hr = pVideoProcAmp->Get( + (*sourceValueInfo).videoProcAmpProperty, + &sourceValue, + &valueFlags); + + pVideoProcAmp->Release(); + + if (FAILED(hr)) { + qWarning() << "failed to get the parameter value"; + return QVariant(); + } + + // This conversion is required only for сontrast, saturation + // brightness, and sharpening. + return scaledImageProcessingParameterValue( + sourceValue, (*sourceValueInfo)); +} + +void DSCameraSession::setImageProcessingParameter( + QCameraImageProcessingControl::ProcessingParameter parameter, + const QVariant &value) +{ + if (!m_graphBuilder) { + qWarning() << "failed to access to the graph builder"; + return; + } + + QMap::const_iterator sourceValueInfo = + m_imageProcessingParametersInfos.constFind(parameter); + + if (sourceValueInfo == m_imageProcessingParametersInfos.constEnd()) + return; + + LONG sourceValue = 0; + LONG valueFlags = VideoProcAmp_Flags_Manual; + + // This conversion is required only for сontrast, saturation + // brightness, and sharpening. + sourceValue = sourceImageProcessingParameterValue( + value.toReal(), (*sourceValueInfo)); + + IAMVideoProcAmp *pVideoProcAmp = NULL; + HRESULT hr = m_graphBuilder->FindInterface( + NULL, + NULL, + m_sourceFilter, + IID_IAMVideoProcAmp, + reinterpret_cast(&pVideoProcAmp) + ); + + if (FAILED(hr) || !pVideoProcAmp) { + qWarning() << "failed to find the video proc amp"; + return; + } + + hr = pVideoProcAmp->Set( + (*sourceValueInfo).videoProcAmpProperty, + sourceValue, + valueFlags); + + pVideoProcAmp->Release(); + + if (FAILED(hr)) + qWarning() << "failed to set the parameter value"; +} + bool DSCameraSession::load() { unload(); @@ -720,6 +876,71 @@ bool DSCameraSession::configurePreviewFormat() return true; } +void DSCameraSession::updateImageProcessingParametersInfos() +{ + if (!m_graphBuilder) { + qWarning() << "failed to access to the graph builder"; + return; + } + + IAMVideoProcAmp *pVideoProcAmp = NULL; + const HRESULT hr = m_graphBuilder->FindInterface( + NULL, + NULL, + m_sourceFilter, + IID_IAMVideoProcAmp, + reinterpret_cast(&pVideoProcAmp) + ); + + if (FAILED(hr) || !pVideoProcAmp) { + qWarning() << "failed to find the video proc amp"; + return; + } + + for (int property = VideoProcAmp_Brightness; property <= VideoProcAmp_Gain; ++property) { + + QCameraImageProcessingControl::ProcessingParameter processingParameter; // not initialized + + switch (property) { + case VideoProcAmp_Brightness: + processingParameter = QCameraImageProcessingControl::BrightnessAdjustment; + break; + case VideoProcAmp_Contrast: + processingParameter = QCameraImageProcessingControl::ContrastAdjustment; + break; + case VideoProcAmp_Saturation: + processingParameter = QCameraImageProcessingControl::SaturationAdjustment; + break; + case VideoProcAmp_Sharpness: + processingParameter = QCameraImageProcessingControl::SharpeningAdjustment; + break; + default: // unsupported or not implemented yet parameter + continue; + } + + ImageProcessingParameterInfo sourceValueInfo; + LONG steppingDelta = 0; + LONG capsFlags = 0; + + const HRESULT hr = pVideoProcAmp->GetRange( + property, + &sourceValueInfo.minimumValue, + &sourceValueInfo.maximumValue, + &steppingDelta, + &sourceValueInfo.defaultValue, + &capsFlags); + + if (FAILED(hr)) + continue; + + sourceValueInfo.videoProcAmpProperty = static_cast(property); + + m_imageProcessingParametersInfos.insert(processingParameter, sourceValueInfo); + } + + pVideoProcAmp->Release(); +} + bool DSCameraSession::connectGraph() { HRESULT hr = m_filterGraph->AddFilter(m_sourceFilter, L"Capture Filter"); @@ -806,6 +1027,7 @@ void DSCameraSession::updateSourceCapabilities() Q_FOREACH (AM_MEDIA_TYPE f, m_supportedFormats) _FreeMediaType(f); m_supportedFormats.clear(); + m_imageProcessingParametersInfos.clear(); IAMVideoControl *pVideoControl = 0; hr = m_graphBuilder->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, @@ -915,6 +1137,8 @@ void DSCameraSession::updateSourceCapabilities() } pConfig->Release(); + + updateImageProcessingParametersInfos(); } HRESULT getPin(IBaseFilter *pFilter, PIN_DIRECTION PinDir, IPin **ppPin) diff --git a/src/plugins/directshow/camera/dscamerasession.h b/src/plugins/directshow/camera/dscamerasession.h index 9ac121463..7ad3a2e3d 100644 --- a/src/plugins/directshow/camera/dscamerasession.h +++ b/src/plugins/directshow/camera/dscamerasession.h @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -97,6 +98,20 @@ public: QList supportedViewfinderSettings() const { return m_supportedViewfinderSettings; } + bool isImageProcessingParameterSupported( + QCameraImageProcessingControl::ProcessingParameter) const; + + bool isImageProcessingParameterValueSupported( + QCameraImageProcessingControl::ProcessingParameter, + const QVariant &) const; + + QVariant imageProcessingParameter( + QCameraImageProcessingControl::ProcessingParameter) const; + + void setImageProcessingParameter( + QCameraImageProcessingControl::ProcessingParameter, + const QVariant &); + Q_SIGNALS: void statusChanged(QCamera::Status); void imageExposed(int id); @@ -110,6 +125,21 @@ private Q_SLOTS: void updateReadyForCapture(); private: + struct ImageProcessingParameterInfo { + ImageProcessingParameterInfo() + : minimumValue(0) + , maximumValue(0) + , defaultValue(0) + , videoProcAmpProperty(VideoProcAmp_Brightness) + { + } + + LONG minimumValue; + LONG maximumValue; + LONG defaultValue; + VideoProcAmpProperty videoProcAmpProperty; + }; + void setStatus(QCamera::Status status); void onFrameAvailable(const char *frameData, long len); @@ -120,6 +150,14 @@ private: void disconnectGraph(); void updateSourceCapabilities(); bool configurePreviewFormat(); + void updateImageProcessingParametersInfos(); + + // These static functions are used for scaling of adjustable parameters, + // which have the ranges from -1.0 to +1.0 in the QCameraImageProcessing API. + static qreal scaledImageProcessingParameterValue( + qint32 sourceValue, const ImageProcessingParameterInfo &sourceValueInfo); + static qint32 sourceImageProcessingParameterValue( + qreal scaledValue, const ImageProcessingParameterInfo &sourceValueInfo); QMutex m_presentMutex; QMutex m_captureMutex; @@ -135,6 +173,7 @@ private: QList m_supportedFormats; QList m_supportedViewfinderSettings; AM_MEDIA_TYPE m_sourceFormat; + QMap m_imageProcessingParametersInfos; // Preview IBaseFilter *m_previewFilter; -- cgit v1.2.3