diff options
Diffstat (limited to 'src/plugins/directshow')
25 files changed, 871 insertions, 156 deletions
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 <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 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 <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 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..2e92cb37d 100644 --- a/src/plugins/directshow/camera/dscamerasession.cpp +++ b/src/plugins/directshow/camera/dscamerasession.cpp @@ -230,6 +230,240 @@ void DSCameraSession::setViewfinderSettings(const QCameraViewfinderSettings &set m_viewfinderSettings = settings; } +qreal DSCameraSession::scaledImageProcessingParameterValue( + const ImageProcessingParameterInfo &sourceValueInfo) +{ + if (sourceValueInfo.currentValue == sourceValueInfo.defaultValue) { + return 0.0f; + } else if (sourceValueInfo.currentValue < sourceValueInfo.defaultValue) { + return ((sourceValueInfo.currentValue - sourceValueInfo.minimumValue) + / qreal(sourceValueInfo.defaultValue - sourceValueInfo.minimumValue)) + + (-1.0f); + } else { + return ((sourceValueInfo.currentValue - 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; + } +} + +static QCameraImageProcessingControl::ProcessingParameter searchRelatedResultingParameter( + QCameraImageProcessingControl::ProcessingParameter sourceParameter) +{ + if (sourceParameter == QCameraImageProcessingControl::WhiteBalancePreset) + return QCameraImageProcessingControl::ColorTemperature; + return sourceParameter; +} + +bool DSCameraSession::isImageProcessingParameterSupported( + QCameraImageProcessingControl::ProcessingParameter parameter) const +{ + const QCameraImageProcessingControl::ProcessingParameter resultingParameter = + searchRelatedResultingParameter(parameter); + + return m_imageProcessingParametersInfos.contains(resultingParameter); +} + +bool DSCameraSession::isImageProcessingParameterValueSupported( + QCameraImageProcessingControl::ProcessingParameter parameter, + const QVariant &value) const +{ + const QCameraImageProcessingControl::ProcessingParameter resultingParameter = + searchRelatedResultingParameter(parameter); + + QMap<QCameraImageProcessingControl::ProcessingParameter, + ImageProcessingParameterInfo>::const_iterator sourceValueInfo = + m_imageProcessingParametersInfos.constFind(resultingParameter); + + if (sourceValueInfo == m_imageProcessingParametersInfos.constEnd()) + return false; + + switch (parameter) { + + case QCameraImageProcessingControl::WhiteBalancePreset: { + const QCameraImageProcessing::WhiteBalanceMode checkedValue = + value.value<QCameraImageProcessing::WhiteBalanceMode>(); + // Supports only the Manual and the Auto values + if (checkedValue != QCameraImageProcessing::WhiteBalanceManual + && checkedValue != QCameraImageProcessing::WhiteBalanceAuto) { + return false; + } + } + break; + + case QCameraImageProcessingControl::ColorTemperature: { + const qint32 checkedValue = value.toInt(); + if (checkedValue < (*sourceValueInfo).minimumValue + || checkedValue > (*sourceValueInfo).maximumValue) { + return false; + } + } + break; + + case QCameraImageProcessingControl::ContrastAdjustment: // falling back + case QCameraImageProcessingControl::SaturationAdjustment: // falling back + case QCameraImageProcessingControl::BrightnessAdjustment: // falling back + case QCameraImageProcessingControl::SharpeningAdjustment: { + const qint32 sourceValue = sourceImageProcessingParameterValue( + value.toReal(), (*sourceValueInfo)); + if (sourceValue < (*sourceValueInfo).minimumValue + || sourceValue > (*sourceValueInfo).maximumValue) + return false; + } + break; + + default: + return false; + } + + return true; +} + +QVariant DSCameraSession::imageProcessingParameter( + QCameraImageProcessingControl::ProcessingParameter parameter) const +{ + if (!m_graphBuilder) { + qWarning() << "failed to access to the graph builder"; + return QVariant(); + } + + const QCameraImageProcessingControl::ProcessingParameter resultingParameter = + searchRelatedResultingParameter(parameter); + + QMap<QCameraImageProcessingControl::ProcessingParameter, + ImageProcessingParameterInfo>::const_iterator sourceValueInfo = + m_imageProcessingParametersInfos.constFind(resultingParameter); + + if (sourceValueInfo == m_imageProcessingParametersInfos.constEnd()) + return QVariant(); + + switch (parameter) { + + case QCameraImageProcessingControl::WhiteBalancePreset: + return QVariant::fromValue<QCameraImageProcessing::WhiteBalanceMode>( + (*sourceValueInfo).capsFlags == VideoProcAmp_Flags_Auto + ? QCameraImageProcessing::WhiteBalanceAuto + : QCameraImageProcessing::WhiteBalanceManual); + + case QCameraImageProcessingControl::ColorTemperature: + return QVariant::fromValue<qint32>((*sourceValueInfo).currentValue); + + case QCameraImageProcessingControl::ContrastAdjustment: // falling back + case QCameraImageProcessingControl::SaturationAdjustment: // falling back + case QCameraImageProcessingControl::BrightnessAdjustment: // falling back + case QCameraImageProcessingControl::SharpeningAdjustment: + return scaledImageProcessingParameterValue((*sourceValueInfo)); + + default: + return QVariant(); + } +} + +void DSCameraSession::setImageProcessingParameter( + QCameraImageProcessingControl::ProcessingParameter parameter, + const QVariant &value) +{ + if (!m_graphBuilder) { + qWarning() << "failed to access to the graph builder"; + return; + } + + const QCameraImageProcessingControl::ProcessingParameter resultingParameter = + searchRelatedResultingParameter(parameter); + + QMap<QCameraImageProcessingControl::ProcessingParameter, + ImageProcessingParameterInfo>::iterator sourceValueInfo = + m_imageProcessingParametersInfos.find(resultingParameter); + + if (sourceValueInfo == m_imageProcessingParametersInfos.constEnd()) + return; + + LONG sourceValue = 0; + LONG capsFlags = VideoProcAmp_Flags_Manual; + + switch (parameter) { + + case QCameraImageProcessingControl::WhiteBalancePreset: { + const QCameraImageProcessing::WhiteBalanceMode checkedValue = + value.value<QCameraImageProcessing::WhiteBalanceMode>(); + // Supports only the Manual and the Auto values + if (checkedValue == QCameraImageProcessing::WhiteBalanceManual) + capsFlags = VideoProcAmp_Flags_Manual; + else if (checkedValue == QCameraImageProcessing::WhiteBalanceAuto) + capsFlags = VideoProcAmp_Flags_Auto; + else + return; + + sourceValue = ((*sourceValueInfo).hasBeenExplicitlySet) + ? (*sourceValueInfo).currentValue + : (*sourceValueInfo).defaultValue; + } + break; + + case QCameraImageProcessingControl::ColorTemperature: + sourceValue = value.isValid() ? + value.value<qint32>() : (*sourceValueInfo).defaultValue; + capsFlags = (*sourceValueInfo).capsFlags; + break; + + case QCameraImageProcessingControl::ContrastAdjustment: // falling back + case QCameraImageProcessingControl::SaturationAdjustment: // falling back + case QCameraImageProcessingControl::BrightnessAdjustment: // falling back + case QCameraImageProcessingControl::SharpeningAdjustment: + if (value.isValid()) { + sourceValue = sourceImageProcessingParameterValue( + value.toReal(), (*sourceValueInfo)); + } else { + sourceValue = (*sourceValueInfo).defaultValue; + } + break; + + default: + return; + } + + 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, + capsFlags); + + pVideoProcAmp->Release(); + + if (FAILED(hr)) { + qWarning() << "failed to set the parameter value"; + } else { + (*sourceValueInfo).capsFlags = capsFlags; + (*sourceValueInfo).hasBeenExplicitlySet = true; + (*sourceValueInfo).currentValue = sourceValue; + } +} + bool DSCameraSession::load() { unload(); @@ -720,6 +954,81 @@ 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; + case VideoProcAmp_WhiteBalance: + processingParameter = QCameraImageProcessingControl::ColorTemperature; + break; + default: // unsupported or not implemented yet parameter + continue; + } + + ImageProcessingParameterInfo sourceValueInfo; + LONG steppingDelta = 0; + + HRESULT hr = pVideoProcAmp->GetRange( + property, + &sourceValueInfo.minimumValue, + &sourceValueInfo.maximumValue, + &steppingDelta, + &sourceValueInfo.defaultValue, + &sourceValueInfo.capsFlags); + + if (FAILED(hr)) + continue; + + hr = pVideoProcAmp->Get( + property, + &sourceValueInfo.currentValue, + &sourceValueInfo.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 +1115,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 +1225,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..768e3583a 100644 --- a/src/plugins/directshow/camera/dscamerasession.h +++ b/src/plugins/directshow/camera/dscamerasession.h @@ -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,27 @@ private Q_SLOTS: void updateReadyForCapture(); private: + struct ImageProcessingParameterInfo { + ImageProcessingParameterInfo() + : minimumValue(0) + , maximumValue(0) + , defaultValue(0) + , currentValue(0) + , capsFlags(0) + , hasBeenExplicitlySet(false) + , videoProcAmpProperty(VideoProcAmp_Brightness) + { + } + + LONG minimumValue; + LONG maximumValue; + LONG defaultValue; + LONG currentValue; + LONG capsFlags; + bool hasBeenExplicitlySet; + VideoProcAmpProperty videoProcAmpProperty; + }; + void setStatus(QCamera::Status status); void onFrameAvailable(const char *frameData, long len); @@ -120,6 +156,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( + const ImageProcessingParameterInfo &sourceValueInfo); + static qint32 sourceImageProcessingParameterValue( + qreal scaledValue, const ImageProcessingParameterInfo &sourceValueInfo); QMutex m_presentMutex; QMutex m_captureMutex; @@ -135,6 +179,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; diff --git a/src/plugins/directshow/directshow.pro b/src/plugins/directshow/directshow.pro index 7815927db..4d7183923 100644 --- a/src/plugins/directshow/directshow.pro +++ b/src/plugins/directshow/directshow.pro @@ -13,11 +13,6 @@ SOURCES += dsserviceplugin.cpp !config_wmsdk: DEFINES += QT_NO_WMSDK -qtHaveModule(widgets) { - QT += multimediawidgets - DEFINES += HAVE_WIDGETS -} - mingw: DEFINES += NO_DSHOW_STRSAFE !config_wmf: include(player/player.pri) diff --git a/src/plugins/directshow/player/directshowaudioendpointcontrol.cpp b/src/plugins/directshow/player/directshowaudioendpointcontrol.cpp index 798a94102..d063447e3 100644 --- a/src/plugins/directshow/player/directshowaudioendpointcontrol.cpp +++ b/src/plugins/directshow/player/directshowaudioendpointcontrol.cpp @@ -44,7 +44,7 @@ DirectShowAudioEndpointControl::DirectShowAudioEndpointControl( , m_deviceEnumerator(0) { if (CreateBindCtx(0, &m_bindContext) == S_OK) { - m_deviceEnumerator = com_new<ICreateDevEnum>(CLSID_SystemDeviceEnum, IID_ICreateDevEnum); + m_deviceEnumerator = com_new<ICreateDevEnum>(CLSID_SystemDeviceEnum); updateEndpoints(); diff --git a/src/plugins/directshow/player/directshowevrvideowindowcontrol.cpp b/src/plugins/directshow/player/directshowevrvideowindowcontrol.cpp new file mode 100644 index 000000000..22771bd4c --- /dev/null +++ b/src/plugins/directshow/player/directshowevrvideowindowcontrol.cpp @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** 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 "directshowevrvideowindowcontrol.h" + +#include "directshowglobal.h" + +DirectShowEvrVideoWindowControl::DirectShowEvrVideoWindowControl(QObject *parent) + : EvrVideoWindowControl(parent) + , m_evrFilter(NULL) +{ +} + +DirectShowEvrVideoWindowControl::~DirectShowEvrVideoWindowControl() +{ + if (m_evrFilter) + m_evrFilter->Release(); +} + +IBaseFilter *DirectShowEvrVideoWindowControl::filter() +{ + if (!m_evrFilter) { + m_evrFilter = com_new<IBaseFilter>(clsid_EnhancedVideoRenderer); + if (!setEvr(m_evrFilter)) { + m_evrFilter->Release(); + m_evrFilter = NULL; + } + } + + return m_evrFilter; +} diff --git a/src/plugins/directshow/player/directshowevrvideowindowcontrol.h b/src/plugins/directshow/player/directshowevrvideowindowcontrol.h new file mode 100644 index 000000000..46171812b --- /dev/null +++ b/src/plugins/directshow/player/directshowevrvideowindowcontrol.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** 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 DIRECTSHOWEVRVIDEOWINDOWCONTROL_H +#define DIRECTSHOWEVRVIDEOWINDOWCONTROL_H + +#include "evrvideowindowcontrol.h" + +struct IBaseFilter; + +QT_USE_NAMESPACE + +class DirectShowEvrVideoWindowControl : public EvrVideoWindowControl +{ +public: + DirectShowEvrVideoWindowControl(QObject *parent = 0); + ~DirectShowEvrVideoWindowControl(); + + IBaseFilter *filter(); + +private: + IBaseFilter *m_evrFilter; +}; + +#endif // DIRECTSHOWEVRVIDEOWINDOWCONTROL_H diff --git a/src/plugins/directshow/player/directshowglobal.h b/src/plugins/directshow/player/directshowglobal.h index 68cb23649..d8f1d1200 100644 --- a/src/plugins/directshow/player/directshowglobal.h +++ b/src/plugins/directshow/player/directshowglobal.h @@ -46,6 +46,18 @@ template <typename T> T *com_cast(IUnknown *unknown, const IID &iid) : 0; } +template <typename T> T *com_new(const IID &clsid) +{ + T *object = 0; + return CoCreateInstance( + clsid, + NULL, + CLSCTX_INPROC_SERVER, + IID_PPV_ARGS(&object)) == S_OK + ? object + : 0; +} + template <typename T> T *com_new(const IID &clsid, const IID &iid) { T *object = 0; diff --git a/src/plugins/directshow/player/directshowioreader.cpp b/src/plugins/directshow/player/directshowioreader.cpp index bee072d3b..298d099d2 100644 --- a/src/plugins/directshow/player/directshowioreader.cpp +++ b/src/plugins/directshow/player/directshowioreader.cpp @@ -132,7 +132,7 @@ HRESULT DirectShowIOReader::RequestAllocator( return S_OK; } else { - *ppActual = com_new<IMemAllocator>(CLSID_MemoryAllocator, IID_IMemAllocator); + *ppActual = com_new<IMemAllocator>(CLSID_MemoryAllocator); if (*ppActual) { if ((*ppActual)->SetProperties(pProps, &actualProperties) != S_OK) { diff --git a/src/plugins/directshow/player/directshowiosource.cpp b/src/plugins/directshow/player/directshowiosource.cpp index 424120fd8..e1034a9c6 100644 --- a/src/plugins/directshow/player/directshowiosource.cpp +++ b/src/plugins/directshow/player/directshowiosource.cpp @@ -413,7 +413,7 @@ HRESULT DirectShowIOSource::tryConnect(IPin *pin, const AM_MEDIA_TYPE *type) hr = VFW_E_NO_TRANSPORT; if (IMemInputPin *memPin = com_cast<IMemInputPin>(pin, IID_IMemInputPin)) { - if ((m_allocator = com_new<IMemAllocator>(CLSID_MemoryAllocator, IID_IMemAllocator))) { + if ((m_allocator = com_new<IMemAllocator>(CLSID_MemoryAllocator))) { ALLOCATOR_PROPERTIES properties; if (memPin->GetAllocatorRequirements(&properties) == S_OK || m_allocator->GetProperties(&properties) == S_OK) { diff --git a/src/plugins/directshow/player/directshowmetadatacontrol.cpp b/src/plugins/directshow/player/directshowmetadatacontrol.cpp index 3f58be249..5400ac8d4 100644 --- a/src/plugins/directshow/player/directshowmetadatacontrol.cpp +++ b/src/plugins/directshow/player/directshowmetadatacontrol.cpp @@ -362,7 +362,18 @@ static QString convertBSTR(BSTR *string) return value; } -void DirectShowMetaDataControl::updateGraph(IFilterGraph2 *graph, IBaseFilter *source, const QString &fileSrc) +void DirectShowMetaDataControl::reset() +{ + bool hadMetadata = !m_metadata.isEmpty(); + m_metadata.clear(); + + setMetadataAvailable(false); + + if (hadMetadata) + emit metaDataChanged(); +} + +void DirectShowMetaDataControl::updateMetadata(IFilterGraph2 *graph, IBaseFilter *source, const QString &fileSrc) { m_metadata.clear(); @@ -568,13 +579,19 @@ void DirectShowMetaDataControl::customEvent(QEvent *event) if (event->type() == QEvent::Type(MetaDataChanged)) { event->accept(); - bool oldAvailable = m_available; - m_available = !m_metadata.isEmpty(); - if (m_available != oldAvailable) - emit metaDataAvailableChanged(m_available); + setMetadataAvailable(!m_metadata.isEmpty()); emit metaDataChanged(); } else { QMetaDataReaderControl::customEvent(event); } } + +void DirectShowMetaDataControl::setMetadataAvailable(bool available) +{ + if (m_available == available) + return; + + m_available = available; + emit metaDataAvailableChanged(m_available); +} diff --git a/src/plugins/directshow/player/directshowmetadatacontrol.h b/src/plugins/directshow/player/directshowmetadatacontrol.h index d32ae8508..55504ba4b 100644 --- a/src/plugins/directshow/player/directshowmetadatacontrol.h +++ b/src/plugins/directshow/player/directshowmetadatacontrol.h @@ -56,13 +56,16 @@ public: QVariant metaData(const QString &key) const; QStringList availableMetaData() const; - void updateGraph(IFilterGraph2 *graph, IBaseFilter *source, - const QString &fileSrc = QString()); + void reset(); + void updateMetadata(IFilterGraph2 *graph, IBaseFilter *source, + const QString &fileSrc = QString()); protected: void customEvent(QEvent *event); private: + void setMetadataAvailable(bool available); + enum Event { MetaDataChanged = QEvent::User diff --git a/src/plugins/directshow/player/directshowplayercontrol.cpp b/src/plugins/directshow/player/directshowplayercontrol.cpp index a5fed4b95..3449c9270 100644 --- a/src/plugins/directshow/player/directshowplayercontrol.cpp +++ b/src/plugins/directshow/player/directshowplayercontrol.cpp @@ -53,17 +53,6 @@ static int volumeToDecibels(int volume) } } -static int decibelsToVolume(int dB) -{ - if (dB == -10000) { - return 0; - } else if (dB == 0) { - return 100; - } else { - return qRound(100 * qPow(10, qreal(dB) / 5000)); - } -} - DirectShowPlayerControl::DirectShowPlayerControl(DirectShowPlayerService *service, QObject *parent) : QMediaPlayerControl(parent) , m_service(service) @@ -73,8 +62,9 @@ DirectShowPlayerControl::DirectShowPlayerControl(DirectShowPlayerService *servic , m_status(QMediaPlayer::NoMedia) , m_error(QMediaPlayer::NoError) , m_streamTypes(0) - , m_muteVolume(-1) - , m_position(0) + , m_volume(100) + , m_muted(false) + , m_emitPosition(-1) , m_pendingPosition(-1) , m_duration(0) , m_playbackRate(0) @@ -108,11 +98,16 @@ qint64 DirectShowPlayerControl::position() const if (m_pendingPosition != -1) return m_pendingPosition; - return const_cast<qint64 &>(m_position) = m_service->position(); + return m_service->position(); } void DirectShowPlayerControl::setPosition(qint64 position) { + if (m_status == QMediaPlayer::EndOfMedia) { + m_status = QMediaPlayer::LoadedMedia; + emit mediaStatusChanged(m_status); + } + if (m_state == QMediaPlayer::StoppedState && m_pendingPosition != position) { m_pendingPosition = position; emit positionChanged(m_pendingPosition); @@ -125,63 +120,47 @@ void DirectShowPlayerControl::setPosition(qint64 position) int DirectShowPlayerControl::volume() const { - if (m_muteVolume >= 0) { - return m_muteVolume; - } else if (m_audio) { - long dB = 0; - - m_audio->get_Volume(&dB); - - return decibelsToVolume(dB); - } else { - return 0; - } + return m_volume; } void DirectShowPlayerControl::setVolume(int volume) { int boundedVolume = qBound(0, volume, 100); - if (m_muteVolume >= 0) { - m_muteVolume = boundedVolume; + if (m_volume == boundedVolume) + return; - emit volumeChanged(m_muteVolume); - } else if (m_audio) { - m_audio->put_Volume(volumeToDecibels(volume)); + m_volume = boundedVolume; - emit volumeChanged(boundedVolume); - } + if (!m_muted) + setVolumeHelper(m_volume); + + emit volumeChanged(m_volume); } bool DirectShowPlayerControl::isMuted() const { - return m_muteVolume >= 0; + return m_muted; } void DirectShowPlayerControl::setMuted(bool muted) { - if (muted && m_muteVolume < 0) { - if (m_audio) { - long dB = 0; + if (m_muted == muted) + return; - m_audio->get_Volume(&dB); + m_muted = muted; - m_muteVolume = decibelsToVolume(dB); + setVolumeHelper(m_muted ? 0 : m_volume); - m_audio->put_Volume(-10000); - } else { - m_muteVolume = 0; - } + emit mutedChanged(m_muted); +} - emit mutedChanged(muted); - } else if (!muted && m_muteVolume >= 0) { - if (m_audio) { - m_audio->put_Volume(volumeToDecibels(m_muteVolume)); - } - m_muteVolume = -1; +void DirectShowPlayerControl::setVolumeHelper(int volume) +{ + if (!m_audio) + return; - emit mutedChanged(muted); - } + m_audio->put_Volume(volumeToDecibels(volume)); } int DirectShowPlayerControl::bufferStatus() const @@ -235,6 +214,9 @@ const QIODevice *DirectShowPlayerControl::mediaStream() const void DirectShowPlayerControl::setMedia(const QMediaContent &media, QIODevice *stream) { + m_pendingPosition = -1; + m_emitPosition = -1; + m_media = media; m_stream = stream; @@ -248,34 +230,41 @@ void DirectShowPlayerControl::setMedia(const QMediaContent &media, QIODevice *st void DirectShowPlayerControl::play() { - if (m_status == QMediaPlayer::NoMedia) - return; - if (m_status == QMediaPlayer::InvalidMedia) { - setMedia(m_media, m_stream); - if (m_error != QMediaPlayer::NoError) - return; - } - m_service->play(); - if (m_pendingPosition != -1) - setPosition(m_pendingPosition); - emit stateChanged(m_state = QMediaPlayer::PlayingState); + playOrPause(QMediaPlayer::PlayingState); } void DirectShowPlayerControl::pause() { - if (m_status == QMediaPlayer::NoMedia) + playOrPause(QMediaPlayer::PausedState); +} + +void DirectShowPlayerControl::playOrPause(QMediaPlayer::State state) +{ + if (m_status == QMediaPlayer::NoMedia || state == QMediaPlayer::StoppedState) return; if (m_status == QMediaPlayer::InvalidMedia) { setMedia(m_media, m_stream); if (m_error != QMediaPlayer::NoError) return; } - m_service->pause(); - emit stateChanged(m_state = QMediaPlayer::PausedState); + + m_emitPosition = -1; + m_state = state; + + if (m_pendingPosition != -1) + setPosition(m_pendingPosition); + + if (state == QMediaPlayer::PausedState) + m_service->pause(); + else + m_service->play(); + + emit stateChanged(m_state); } void DirectShowPlayerControl::stop() { + m_emitPosition = -1; m_service->stop(); emit stateChanged(m_state = QMediaPlayer::StoppedState); } @@ -307,8 +296,8 @@ void DirectShowPlayerControl::emitPropertyChanges() emit videoAvailableChanged(m_streamTypes & DirectShowPlayerService::VideoStream); } - if (properties & PositionProperty) - emit positionChanged(m_position); + if (properties & PositionProperty && m_emitPosition != -1) + emit positionChanged(m_emitPosition); if (properties & DurationProperty) emit durationChanged(m_duration); @@ -389,6 +378,7 @@ void DirectShowPlayerControl::updateAudioOutput(IBaseFilter *filter) m_audio->Release(); m_audio = com_cast<IBasicAudio>(filter, IID_IBasicAudio); + setVolumeHelper(m_muted ? 0 : m_volume); } void DirectShowPlayerControl::updateError(QMediaPlayer::Error error, const QString &errorString) @@ -402,8 +392,8 @@ void DirectShowPlayerControl::updateError(QMediaPlayer::Error error, const QStri void DirectShowPlayerControl::updatePosition(qint64 position) { - if (m_position != position) { - m_position = position; + if (m_emitPosition != position) { + m_emitPosition = position; scheduleUpdate(PositionProperty); } diff --git a/src/plugins/directshow/player/directshowplayercontrol.h b/src/plugins/directshow/player/directshowplayercontrol.h index a42d3c7b1..f67c4108b 100644 --- a/src/plugins/directshow/player/directshowplayercontrol.h +++ b/src/plugins/directshow/player/directshowplayercontrol.h @@ -114,8 +114,11 @@ private: PropertiesChanged = QEvent::User }; + void playOrPause(QMediaPlayer::State state); + void scheduleUpdate(int properties); void emitPropertyChanges(); + void setVolumeHelper(int volume); DirectShowPlayerService *m_service; IBasicAudio *m_audio; @@ -125,8 +128,9 @@ private: QMediaPlayer::MediaStatus m_status; QMediaPlayer::Error m_error; int m_streamTypes; - int m_muteVolume; - qint64 m_position; + int m_volume; + bool m_muted; + qint64 m_emitPosition; qint64 m_pendingPosition; qint64 m_duration; qreal m_playbackRate; diff --git a/src/plugins/directshow/player/directshowplayerservice.cpp b/src/plugins/directshow/player/directshowplayerservice.cpp index 67aea6e9a..8e9e50cbf 100644 --- a/src/plugins/directshow/player/directshowplayerservice.cpp +++ b/src/plugins/directshow/player/directshowplayerservice.cpp @@ -38,8 +38,10 @@ #include "directshowmetadatacontrol.h" #include "directshowplayercontrol.h" #include "directshowvideorenderercontrol.h" -#if defined(HAVE_WIDGETS) && !defined(Q_WS_SIMULATOR) #include "vmr9videowindowcontrol.h" + +#ifdef HAVE_EVR +#include "directshowevrvideowindowcontrol.h" #endif #ifndef QT_NO_WMSDK @@ -79,9 +81,7 @@ DirectShowPlayerService::DirectShowPlayerService(QObject *parent) , m_playerControl(0) , m_metaDataControl(0) , m_videoRendererControl(0) -#if defined(HAVE_WIDGETS) && !defined(Q_WS_SIMULATOR) , m_videoWindowControl(0) -#endif , m_audioEndpointControl(0) , m_taskThread(0) , m_loop(qt_directShowEventLoop()) @@ -98,10 +98,12 @@ DirectShowPlayerService::DirectShowPlayerService(QObject *parent) , m_videoOutput(0) , m_rate(1.0) , m_position(0) + , m_seekPosition(-1) , m_duration(0) , m_buffering(false) , m_seekable(false) , m_atEnd(false) + , m_dontCacheNextSeekResult(false) { m_playerControl = new DirectShowPlayerControl(this); m_metaDataControl = new DirectShowMetaDataControl(this); @@ -139,9 +141,7 @@ DirectShowPlayerService::~DirectShowPlayerService() delete m_audioEndpointControl; delete m_metaDataControl; delete m_videoRendererControl; -#if defined(HAVE_WIDGETS) && !defined(Q_WS_SIMULATOR) delete m_videoWindowControl; -#endif ::CloseHandle(m_taskHandle); } @@ -155,11 +155,7 @@ QMediaControl *DirectShowPlayerService::requestControl(const char *name) } else if (qstrcmp(name, QMetaDataReaderControl_iid) == 0) { return m_metaDataControl; } else if (qstrcmp(name, QVideoRendererControl_iid) == 0) { -#if defined(HAVE_WIDGETS) && !defined(Q_WS_SIMULATOR) if (!m_videoRendererControl && !m_videoWindowControl) { -#else - if (!m_videoRendererControl) { -#endif m_videoRendererControl = new DirectShowVideoRendererControl(m_loop); connect(m_videoRendererControl, SIGNAL(filterChanged()), @@ -167,16 +163,28 @@ QMediaControl *DirectShowPlayerService::requestControl(const char *name) return m_videoRendererControl; } -#if defined(HAVE_WIDGETS) && !defined(Q_WS_SIMULATOR) } else if (qstrcmp(name, QVideoWindowControl_iid) == 0) { if (!m_videoRendererControl && !m_videoWindowControl) { - m_videoWindowControl = new Vmr9VideoWindowControl; + IBaseFilter *filter; - setVideoOutput(m_videoWindowControl->filter()); +#ifdef HAVE_EVR + DirectShowEvrVideoWindowControl *evrControl = new DirectShowEvrVideoWindowControl; + if ((filter = evrControl->filter())) + m_videoWindowControl = evrControl; + else + delete evrControl; +#endif + // Fall back to the VMR9 if the EVR is not available + if (!m_videoWindowControl) { + Vmr9VideoWindowControl *vmr9Control = new Vmr9VideoWindowControl; + filter = vmr9Control->filter(); + m_videoWindowControl = vmr9Control; + } + + setVideoOutput(filter); return m_videoWindowControl; } -#endif } return 0; } @@ -192,14 +200,12 @@ void DirectShowPlayerService::releaseControl(QMediaControl *control) delete m_videoRendererControl; m_videoRendererControl = 0; -#if defined(HAVE_WIDGETS) && !defined(Q_WS_SIMULATOR) } else if (control == m_videoWindowControl) { setVideoOutput(0); delete m_videoWindowControl; m_videoWindowControl = 0; -#endif } } @@ -217,13 +223,15 @@ void DirectShowPlayerService::load(const QMediaContent &media, QIODevice *stream m_error = QMediaPlayer::NoError; m_errorString = QString(); m_position = 0; + m_seekPosition = -1; m_duration = 0; m_streamTypes = 0; m_executedTasks = 0; m_buffering = false; m_seekable = false; m_atEnd = false; - m_metaDataControl->updateGraph(0, 0); + m_dontCacheNextSeekResult = false; + m_metaDataControl->reset(); if (m_resources.isEmpty() && !stream) { m_pendingTasks = 0; @@ -273,8 +281,7 @@ void DirectShowPlayerService::doSetUrlSource(QMutexLocker *locker) static const GUID iid_IFileSourceFilter = { 0x56a868a6, 0x0ad4, 0x11ce, {0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70} }; - if (IFileSourceFilter *fileSource = com_new<IFileSourceFilter>( - clsid_WMAsfReader, iid_IFileSourceFilter)) { + if (IFileSourceFilter *fileSource = com_new<IFileSourceFilter>(clsid_WMAsfReader, iid_IFileSourceFilter)) { locker->unlock(); hr = fileSource->Load(reinterpret_cast<const OLECHAR *>(m_url.toString().utf16()), 0); @@ -322,6 +329,7 @@ void DirectShowPlayerService::doSetUrlSource(QMutexLocker *locker) m_error = QMediaPlayer::FormatError; m_errorString = QString(); break; + case E_FAIL: case E_OUTOFMEMORY: case VFW_E_CANNOT_LOAD_SOURCE_FILTER: case VFW_E_NOT_FOUND: @@ -562,9 +570,6 @@ void DirectShowPlayerService::doReleaseGraph(QMutexLocker *locker) control->Release(); } - //release m_headerInfo -> decrease ref counter of m_source - m_metaDataControl->updateGraph(0, 0); - if (m_source) { m_source->Release(); m_source = 0; @@ -665,8 +670,12 @@ void DirectShowPlayerService::play() if (m_executedTasks & Render) { if (m_executedTasks & Stop) { m_atEnd = false; - m_position = 0; - m_pendingTasks |= Seek; + if (m_seekPosition == -1) { + m_dontCacheNextSeekResult = true; + m_seekPosition = 0; + m_position = 0; + m_pendingTasks |= Seek; + } m_executedTasks ^= Stop; } @@ -709,8 +718,12 @@ void DirectShowPlayerService::pause() if (m_executedTasks & Render) { if (m_executedTasks & Stop) { m_atEnd = false; - m_position = 0; - m_pendingTasks |= Seek; + if (m_seekPosition == -1) { + m_dontCacheNextSeekResult = true; + m_seekPosition = 0; + m_position = 0; + m_pendingTasks |= Seek; + } m_executedTasks ^= Stop; } @@ -780,7 +793,9 @@ void DirectShowPlayerService::doStop(QMutexLocker *locker) control->Release(); } + m_seekPosition = 0; m_position = 0; + m_dontCacheNextSeekResult = true; m_pendingTasks |= Seek; m_executedTasks &= ~(Play | Pause); @@ -884,7 +899,7 @@ void DirectShowPlayerService::seek(qint64 position) { QMutexLocker locker(&m_mutex); - m_position = position; + m_seekPosition = position; m_pendingTasks |= Seek; @@ -894,14 +909,19 @@ void DirectShowPlayerService::seek(qint64 position) void DirectShowPlayerService::doSeek(QMutexLocker *locker) { + if (m_seekPosition == -1) + return; + if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph, IID_IMediaSeeking)) { - LONGLONG seekPosition = LONGLONG(m_position) * qt_directShowTimeScale; + LONGLONG seekPosition = LONGLONG(m_seekPosition) * qt_directShowTimeScale; // Cache current values as we can't query IMediaSeeking during a seek due to the // possibility of a deadlock when flushing the VideoSurfaceFilter. LONGLONG currentPosition = 0; - seeking->GetCurrentPosition(¤tPosition); - m_position = currentPosition / qt_directShowTimeScale; + if (!m_dontCacheNextSeekResult) { + seeking->GetCurrentPosition(¤tPosition); + m_position = currentPosition / qt_directShowTimeScale; + } LONGLONG minimum = 0; LONGLONG maximum = 0; @@ -915,15 +935,18 @@ void DirectShowPlayerService::doSeek(QMutexLocker *locker) &seekPosition, AM_SEEKING_AbsolutePositioning, 0, AM_SEEKING_NoPositioning); locker->relock(); - seeking->GetCurrentPosition(¤tPosition); - m_position = currentPosition / qt_directShowTimeScale; + if (!m_dontCacheNextSeekResult) { + seeking->GetCurrentPosition(¤tPosition); + m_position = currentPosition / qt_directShowTimeScale; + } seeking->Release(); - } else { - m_position = 0; + + QCoreApplication::postEvent(this, new QEvent(QEvent::Type(PositionChange))); } - QCoreApplication::postEvent(this, new QEvent(QEvent::Type(PositionChange))); + m_seekPosition = -1; + m_dontCacheNextSeekResult = false; } int DirectShowPlayerService::bufferStatus() const @@ -1112,7 +1135,7 @@ void DirectShowPlayerService::customEvent(QEvent *event) QMutexLocker locker(&m_mutex); m_playerControl->updateMediaInfo(m_duration, m_streamTypes, m_seekable); - m_metaDataControl->updateGraph(m_graph, m_source, m_url.toString()); + m_metaDataControl->updateMetadata(m_graph, m_source, m_url.toString()); updateStatus(); } else if (event->type() == QEvent::Type(Error)) { diff --git a/src/plugins/directshow/player/directshowplayerservice.h b/src/plugins/directshow/player/directshowplayerservice.h index c9d10351e..4d3762f74 100644 --- a/src/plugins/directshow/player/directshowplayerservice.h +++ b/src/plugins/directshow/player/directshowplayerservice.h @@ -51,12 +51,10 @@ class DirectShowAudioEndpointControl; class DirectShowMetaDataControl; class DirectShowPlayerControl; class DirectShowVideoRendererControl; -#if defined(HAVE_WIDGETS) && !defined(Q_WS_SIMULATOR) -class Vmr9VideoWindowControl; -#endif QT_BEGIN_NAMESPACE class QMediaContent; +class QVideoWindowControl; QT_END_NAMESPACE QT_USE_NAMESPACE @@ -172,9 +170,7 @@ private: DirectShowPlayerControl *m_playerControl; DirectShowMetaDataControl *m_metaDataControl; DirectShowVideoRendererControl *m_videoRendererControl; -#if defined(HAVE_WIDGETS) && !defined(Q_WS_SIMULATOR) - Vmr9VideoWindowControl *m_videoWindowControl; -#endif + QVideoWindowControl *m_videoWindowControl; DirectShowAudioEndpointControl *m_audioEndpointControl; QThread *m_taskThread; @@ -194,10 +190,12 @@ private: int m_streamTypes; qreal m_rate; qint64 m_position; + qint64 m_seekPosition; qint64 m_duration; bool m_buffering; bool m_seekable; bool m_atEnd; + bool m_dontCacheNextSeekResult; QMediaTimeRange m_playbackRange; QUrl m_url; QMediaResourceList m_resources; diff --git a/src/plugins/directshow/player/directshowvideorenderercontrol.cpp b/src/plugins/directshow/player/directshowvideorenderercontrol.cpp index da4764880..027d2ce55 100644 --- a/src/plugins/directshow/player/directshowvideorenderercontrol.cpp +++ b/src/plugins/directshow/player/directshowvideorenderercontrol.cpp @@ -35,6 +35,12 @@ #include "videosurfacefilter.h" +#ifdef HAVE_EVR +#include "evrcustompresenter.h" +#endif + +#include <qabstractvideosurface.h> + DirectShowVideoRendererControl::DirectShowVideoRendererControl(DirectShowEventLoop *loop, QObject *parent) : QVideoRendererControl(parent) , m_loop(loop) @@ -45,7 +51,8 @@ DirectShowVideoRendererControl::DirectShowVideoRendererControl(DirectShowEventLo DirectShowVideoRendererControl::~DirectShowVideoRendererControl() { - delete m_filter; + if (m_filter) + m_filter->Release(); } QAbstractVideoSurface *DirectShowVideoRendererControl::surface() const @@ -55,21 +62,34 @@ QAbstractVideoSurface *DirectShowVideoRendererControl::surface() const void DirectShowVideoRendererControl::setSurface(QAbstractVideoSurface *surface) { - if (surface != m_surface) { - m_surface = surface; + if (m_surface == surface) + return; + + if (m_filter) { + m_filter->Release(); + m_filter = 0; + } - VideoSurfaceFilter *existingFilter = m_filter; + m_surface = surface; - if (surface) { - m_filter = new VideoSurfaceFilter(surface, m_loop); - } else { + if (m_surface) { +#ifdef HAVE_EVR + m_filter = com_new<IBaseFilter>(clsid_EnhancedVideoRenderer); + EVRCustomPresenter *evrPresenter = new EVRCustomPresenter(m_surface); + if (!evrPresenter->isValid() || !qt_evr_setCustomPresenter(m_filter, evrPresenter)) { + m_filter->Release(); m_filter = 0; } + evrPresenter->Release(); - emit filterChanged(); - - delete existingFilter; + if (!m_filter) +#endif + { + m_filter = new VideoSurfaceFilter(m_surface, m_loop); + } } + + emit filterChanged(); } IBaseFilter *DirectShowVideoRendererControl::filter() diff --git a/src/plugins/directshow/player/directshowvideorenderercontrol.h b/src/plugins/directshow/player/directshowvideorenderercontrol.h index b4828d1b0..484fda263 100644 --- a/src/plugins/directshow/player/directshowvideorenderercontrol.h +++ b/src/plugins/directshow/player/directshowvideorenderercontrol.h @@ -39,7 +39,6 @@ #include <dshow.h> class DirectShowEventLoop; -class VideoSurfaceFilter; QT_USE_NAMESPACE @@ -61,7 +60,7 @@ Q_SIGNALS: private: DirectShowEventLoop *m_loop; QAbstractVideoSurface *m_surface; - VideoSurfaceFilter *m_filter; + IBaseFilter *m_filter; }; #endif diff --git a/src/plugins/directshow/player/player.pri b/src/plugins/directshow/player/player.pri index c5c934a38..5ecb912b2 100644 --- a/src/plugins/directshow/player/player.pri +++ b/src/plugins/directshow/player/player.pri @@ -1,5 +1,9 @@ INCLUDEPATH += $$PWD +LIBS += -lstrmiids -ldmoguids -luuid -lmsdmo -lole32 -loleaut32 -lgdi32 + +qtHaveModule(widgets): QT += widgets + DEFINES += QMEDIA_DIRECTSHOW_PLAYER HEADERS += \ @@ -17,7 +21,8 @@ HEADERS += \ $$PWD/directshowsamplescheduler.h \ $$PWD/directshowvideorenderercontrol.h \ $$PWD/mediasamplevideobuffer.h \ - $$PWD/videosurfacefilter.h + $$PWD/videosurfacefilter.h \ + $$PWD/vmr9videowindowcontrol.h SOURCES += \ $$PWD/directshowaudioendpointcontrol.cpp \ @@ -33,14 +38,19 @@ SOURCES += \ $$PWD/directshowsamplescheduler.cpp \ $$PWD/directshowvideorenderercontrol.cpp \ $$PWD/mediasamplevideobuffer.cpp \ - $$PWD/videosurfacefilter.cpp + $$PWD/videosurfacefilter.cpp \ + $$PWD/vmr9videowindowcontrol.cpp + +config_evr { + DEFINES += HAVE_EVR + + include($$PWD/../../common/evr.pri) -qtHaveModule(widgets):!simulator { HEADERS += \ - $$PWD/vmr9videowindowcontrol.h + $$PWD/directshowevrvideowindowcontrol.h SOURCES += \ - $$PWD/vmr9videowindowcontrol.cpp + $$PWD/directshowevrvideowindowcontrol.cpp } config_wshellitem { @@ -48,6 +58,3 @@ config_wshellitem { } else { DEFINES += QT_NO_SHELLITEM } - -LIBS += -lstrmiids -ldmoguids -luuid -lmsdmo -lole32 -loleaut32 -lgdi32 - diff --git a/src/plugins/directshow/player/videosurfacefilter.cpp b/src/plugins/directshow/player/videosurfacefilter.cpp index 2f52e33de..1fa7329cc 100644 --- a/src/plugins/directshow/player/videosurfacefilter.cpp +++ b/src/plugins/directshow/player/videosurfacefilter.cpp @@ -69,7 +69,7 @@ VideoSurfaceFilter::VideoSurfaceFilter( VideoSurfaceFilter::~VideoSurfaceFilter() { - Q_ASSERT(m_ref == 1); + Q_ASSERT(m_ref == 0); } HRESULT VideoSurfaceFilter::QueryInterface(REFIID riid, void **ppvObject) @@ -110,8 +110,8 @@ ULONG VideoSurfaceFilter::AddRef() ULONG VideoSurfaceFilter::Release() { ULONG ref = InterlockedDecrement(&m_ref); - - Q_ASSERT(ref != 0); + if (ref == 0) + delete this; return ref; } @@ -147,6 +147,14 @@ HRESULT VideoSurfaceFilter::Stop() m_sampleScheduler.stop(); + if (thread() == QThread::currentThread()) { + flush(); + } else { + QMutexLocker locker(&m_mutex); + m_loop->postEvent(this, new QEvent(QEvent::Type(FlushSurface))); + m_wait.wait(&m_mutex); + } + return S_OK; } @@ -606,10 +614,24 @@ void VideoSurfaceFilter::sampleReady() IMediaSample *sample = m_sampleScheduler.takeSample(&eos); if (sample) { - m_surface->present(QVideoFrame( - new MediaSampleVideoBuffer(sample, m_bytesPerLine), - m_surfaceFormat.frameSize(), - m_surfaceFormat.pixelFormat())); + QVideoFrame frame(new MediaSampleVideoBuffer(sample, m_bytesPerLine), + m_surfaceFormat.frameSize(), + m_surfaceFormat.pixelFormat()); + + if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph, IID_IMediaSeeking)) { + LONGLONG position = 0; + seeking->GetCurrentPosition(&position); + seeking->Release(); + + frame.setStartTime(position * 0.1); + + REFERENCE_TIME startTime = -1; + REFERENCE_TIME endTime = -1; + if (sample->GetTime(&startTime, &endTime) == S_OK) + frame.setEndTime(frame.startTime() + (endTime - startTime) * 0.1); + } + + m_surface->present(frame); sample->Release(); diff --git a/src/plugins/directshow/player/vmr9videowindowcontrol.cpp b/src/plugins/directshow/player/vmr9videowindowcontrol.cpp index 48ff6c2c3..853ca031c 100644 --- a/src/plugins/directshow/player/vmr9videowindowcontrol.cpp +++ b/src/plugins/directshow/player/vmr9videowindowcontrol.cpp @@ -35,13 +35,16 @@ #include "directshowglobal.h" +#ifndef QT_NO_WIDGETS #include <QtGui/QPalette> #include <QtWidgets/QWidget> +#endif Vmr9VideoWindowControl::Vmr9VideoWindowControl(QObject *parent) : QVideoWindowControl(parent) - , m_filter(com_new<IBaseFilter>(CLSID_VideoMixingRenderer9, IID_IBaseFilter)) + , m_filter(com_new<IBaseFilter>(CLSID_VideoMixingRenderer9)) , m_windowId(0) + , m_windowColor(RGB(0, 0, 0)) , m_dirtyValues(0) , m_aspectRatioMode(Qt::KeepAspectRatio) , m_brightness(0) @@ -74,11 +77,13 @@ void Vmr9VideoWindowControl::setWinId(WId id) { m_windowId = id; +#ifndef QT_NO_WIDGETS if (QWidget *widget = QWidget::find(m_windowId)) { const QColor color = widget->palette().color(QPalette::Window); m_windowColor = RGB(color.red(), color.green(), color.blue()); } +#endif if (IVMRWindowlessControl9 *control = com_cast<IVMRWindowlessControl9>( m_filter, IID_IVMRWindowlessControl9)) { |