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 <yoann.lopes@theqtcompany.com>
This commit is contained in:
Denis Shienkov
2015-11-08 18:34:01 +03:00
committed by Yoann Lopes
parent 1950765b65
commit 7f04598859
7 changed files with 412 additions and 2 deletions

View File

@@ -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

View File

@@ -0,0 +1,74 @@
/****************************************************************************
**
** Copyright (C) 2015 Denis Shienkov <denis.shienkov@gmail.com>
** 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

View File

@@ -0,0 +1,63 @@
/****************************************************************************
**
** Copyright (C) 2015 Denis Shienkov <denis.shienkov@gmail.com>
** 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 <qcamera.h>
#include <qcameraimageprocessingcontrol.h>
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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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<QCameraImageProcessingControl::ProcessingParameter,
ImageProcessingParameterInfo>::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<QCameraImageProcessingControl::ProcessingParameter,
ImageProcessingParameterInfo>::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<void**>(&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<QCameraImageProcessingControl::ProcessingParameter,
ImageProcessingParameterInfo>::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<void**>(&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<void**>(&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<VideoProcAmpProperty>(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)

View File

@@ -43,6 +43,7 @@
#include <QtMultimedia/qvideoframe.h>
#include <QtMultimedia/qabstractvideosurface.h>
#include <QtMultimedia/qvideosurfaceformat.h>
#include <QtMultimedia/qcameraimageprocessingcontrol.h>
#include <private/qmediastoragelocation_p.h>
#include <tchar.h>
@@ -97,6 +98,20 @@ public:
QList<QCameraViewfinderSettings> 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<AM_MEDIA_TYPE> m_supportedFormats;
QList<QCameraViewfinderSettings> m_supportedViewfinderSettings;
AM_MEDIA_TYPE m_sourceFormat;
QMap<QCameraImageProcessingControl::ProcessingParameter, ImageProcessingParameterInfo> m_imageProcessingParametersInfos;
// Preview
IBaseFilter *m_previewFilter;