summaryrefslogtreecommitdiffstats
path: root/src/plugins/common/evr/evrvideowindowcontrol.cpp
diff options
context:
space:
mode:
authorYoann Lopes <yoann.lopes@theqtcompany.com>2015-09-10 18:25:37 +0200
committerYoann Lopes <yoann.lopes@theqtcompany.com>2015-11-05 11:34:55 +0000
commit95bd9d58d8d37ddec8d37f5b35128689c0aa55a8 (patch)
treeecf8820d012953caee0f516e349757c8362a95b2 /src/plugins/common/evr/evrvideowindowcontrol.cpp
parentb2e9ae8856f5297289ab5e1f48bda12ef2201b97 (diff)
DirectShow: use the EVR in the window control.
Reuse existing code from the WMF plugin, which already uses the EVR. This enables HW-accelerated video decoding when using QMediaPlayer with a QVideoWidget. Task-number: QTBUG-45593 Change-Id: I757e4d53cd2c648aee6ba33a4851a8c6adc62843 Reviewed-by: Christian Stromme <christian.stromme@theqtcompany.com>
Diffstat (limited to 'src/plugins/common/evr/evrvideowindowcontrol.cpp')
-rw-r--r--src/plugins/common/evr/evrvideowindowcontrol.cpp355
1 files changed, 355 insertions, 0 deletions
diff --git a/src/plugins/common/evr/evrvideowindowcontrol.cpp b/src/plugins/common/evr/evrvideowindowcontrol.cpp
new file mode 100644
index 000000000..faa23d6e5
--- /dev/null
+++ b/src/plugins/common/evr/evrvideowindowcontrol.cpp
@@ -0,0 +1,355 @@
+/****************************************************************************
+**
+** 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 "evrvideowindowcontrol.h"
+
+#ifndef QT_NO_WIDGETS
+#include <qwidget.h>
+#endif
+
+EvrVideoWindowControl::EvrVideoWindowControl(QObject *parent)
+ : QVideoWindowControl(parent)
+ , m_windowId(0)
+ , m_windowColor(RGB(0, 0, 0))
+ , m_dirtyValues(0)
+ , m_aspectRatioMode(Qt::KeepAspectRatio)
+ , m_brightness(0)
+ , m_contrast(0)
+ , m_hue(0)
+ , m_saturation(0)
+ , m_fullScreen(false)
+ , m_displayControl(0)
+ , m_processor(0)
+{
+}
+
+EvrVideoWindowControl::~EvrVideoWindowControl()
+{
+ clear();
+}
+
+bool EvrVideoWindowControl::setEvr(IUnknown *evr)
+{
+ clear();
+
+ if (!evr)
+ return true;
+
+ static const GUID mr_VIDEO_RENDER_SERVICE = { 0x1092a86c, 0xab1a, 0x459a, {0xa3, 0x36, 0x83, 0x1f, 0xbc, 0x4d, 0x11, 0xff} };
+ static const GUID mr_VIDEO_MIXER_SERVICE = { 0x73cd2fc, 0x6cf4, 0x40b7, {0x88, 0x59, 0xe8, 0x95, 0x52, 0xc8, 0x41, 0xf8} };
+ IMFGetService *service = NULL;
+
+ if (SUCCEEDED(evr->QueryInterface(IID_PPV_ARGS(&service)))
+ && SUCCEEDED(service->GetService(mr_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&m_displayControl)))) {
+
+ service->GetService(mr_VIDEO_MIXER_SERVICE, IID_PPV_ARGS(&m_processor));
+
+ setWinId(m_windowId);
+ setDisplayRect(m_displayRect);
+ setAspectRatioMode(m_aspectRatioMode);
+ m_dirtyValues = DXVA2_ProcAmp_Brightness | DXVA2_ProcAmp_Contrast | DXVA2_ProcAmp_Hue | DXVA2_ProcAmp_Saturation;
+ applyImageControls();
+ }
+
+ if (service)
+ service->Release();
+
+ return m_displayControl != NULL;
+}
+
+void EvrVideoWindowControl::clear()
+{
+ if (m_displayControl)
+ m_displayControl->Release();
+ m_displayControl = NULL;
+
+ if (m_processor)
+ m_processor->Release();
+ m_processor = NULL;
+}
+
+WId EvrVideoWindowControl::winId() const
+{
+ return m_windowId;
+}
+
+void EvrVideoWindowControl::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 (m_displayControl)
+ m_displayControl->SetVideoWindow(HWND(m_windowId));
+}
+
+QRect EvrVideoWindowControl::displayRect() const
+{
+ return m_displayRect;
+}
+
+void EvrVideoWindowControl::setDisplayRect(const QRect &rect)
+{
+ m_displayRect = rect;
+
+ if (m_displayControl) {
+ RECT displayRect = { rect.left(), rect.top(), rect.right() + 1, rect.bottom() + 1 };
+ QSize sourceSize = nativeSize();
+
+ RECT sourceRect = { 0, 0, sourceSize.width(), sourceSize.height() };
+
+ if (m_aspectRatioMode == Qt::KeepAspectRatioByExpanding) {
+ QSize clippedSize = rect.size();
+ clippedSize.scale(sourceRect.right, sourceRect.bottom, Qt::KeepAspectRatio);
+
+ sourceRect.left = (sourceRect.right - clippedSize.width()) / 2;
+ sourceRect.top = (sourceRect.bottom - clippedSize.height()) / 2;
+ sourceRect.right = sourceRect.left + clippedSize.width();
+ sourceRect.bottom = sourceRect.top + clippedSize.height();
+ }
+
+ if (sourceSize.width() > 0 && sourceSize.height() > 0) {
+ MFVideoNormalizedRect sourceNormRect;
+ sourceNormRect.left = float(sourceRect.left) / float(sourceRect.right);
+ sourceNormRect.top = float(sourceRect.top) / float(sourceRect.bottom);
+ sourceNormRect.right = float(sourceRect.right) / float(sourceRect.right);
+ sourceNormRect.bottom = float(sourceRect.bottom) / float(sourceRect.bottom);
+ m_displayControl->SetVideoPosition(&sourceNormRect, &displayRect);
+ } else {
+ m_displayControl->SetVideoPosition(NULL, &displayRect);
+ }
+ }
+}
+
+bool EvrVideoWindowControl::isFullScreen() const
+{
+ return m_fullScreen;
+}
+
+void EvrVideoWindowControl::setFullScreen(bool fullScreen)
+{
+ if (m_fullScreen == fullScreen)
+ return;
+ emit fullScreenChanged(m_fullScreen = fullScreen);
+}
+
+void EvrVideoWindowControl::repaint()
+{
+ QSize size = nativeSize();
+ if (size.width() > 0 && size.height() > 0
+ && m_displayControl
+ && SUCCEEDED(m_displayControl->RepaintVideo())) {
+ return;
+ }
+
+ PAINTSTRUCT paint;
+ if (HDC dc = ::BeginPaint(HWND(m_windowId), &paint)) {
+ HPEN pen = ::CreatePen(PS_SOLID, 1, m_windowColor);
+ HBRUSH brush = ::CreateSolidBrush(m_windowColor);
+ ::SelectObject(dc, pen);
+ ::SelectObject(dc, brush);
+
+ ::Rectangle(
+ dc,
+ m_displayRect.left(),
+ m_displayRect.top(),
+ m_displayRect.right() + 1,
+ m_displayRect.bottom() + 1);
+
+ ::DeleteObject(pen);
+ ::DeleteObject(brush);
+ ::EndPaint(HWND(m_windowId), &paint);
+ }
+}
+
+QSize EvrVideoWindowControl::nativeSize() const
+{
+ QSize size;
+ if (m_displayControl) {
+ SIZE sourceSize;
+ if (SUCCEEDED(m_displayControl->GetNativeVideoSize(&sourceSize, 0)))
+ size = QSize(sourceSize.cx, sourceSize.cy);
+ }
+ return size;
+}
+
+Qt::AspectRatioMode EvrVideoWindowControl::aspectRatioMode() const
+{
+ return m_aspectRatioMode;
+}
+
+void EvrVideoWindowControl::setAspectRatioMode(Qt::AspectRatioMode mode)
+{
+ m_aspectRatioMode = mode;
+
+ if (m_displayControl) {
+ switch (mode) {
+ case Qt::IgnoreAspectRatio:
+ //comment from MSDN: Do not maintain the aspect ratio of the video. Stretch the video to fit the output rectangle.
+ m_displayControl->SetAspectRatioMode(MFVideoARMode_None);
+ break;
+ case Qt::KeepAspectRatio:
+ //comment from MSDN: Preserve the aspect ratio of the video by letterboxing or within the output rectangle.
+ m_displayControl->SetAspectRatioMode(MFVideoARMode_PreservePicture);
+ break;
+ case Qt::KeepAspectRatioByExpanding:
+ //for this mode, more adjustment will be done in setDisplayRect
+ m_displayControl->SetAspectRatioMode(MFVideoARMode_PreservePicture);
+ break;
+ default:
+ break;
+ }
+ setDisplayRect(m_displayRect);
+ }
+}
+
+int EvrVideoWindowControl::brightness() const
+{
+ return m_brightness;
+}
+
+void EvrVideoWindowControl::setBrightness(int brightness)
+{
+ if (m_brightness == brightness)
+ return;
+
+ m_brightness = brightness;
+
+ m_dirtyValues |= DXVA2_ProcAmp_Brightness;
+
+ applyImageControls();
+
+ emit brightnessChanged(brightness);
+}
+
+int EvrVideoWindowControl::contrast() const
+{
+ return m_contrast;
+}
+
+void EvrVideoWindowControl::setContrast(int contrast)
+{
+ if (m_contrast == contrast)
+ return;
+
+ m_contrast = contrast;
+
+ m_dirtyValues |= DXVA2_ProcAmp_Contrast;
+
+ applyImageControls();
+
+ emit contrastChanged(contrast);
+}
+
+int EvrVideoWindowControl::hue() const
+{
+ return m_hue;
+}
+
+void EvrVideoWindowControl::setHue(int hue)
+{
+ if (m_hue == hue)
+ return;
+
+ m_hue = hue;
+
+ m_dirtyValues |= DXVA2_ProcAmp_Hue;
+
+ applyImageControls();
+
+ emit hueChanged(hue);
+}
+
+int EvrVideoWindowControl::saturation() const
+{
+ return m_saturation;
+}
+
+void EvrVideoWindowControl::setSaturation(int saturation)
+{
+ if (m_saturation == saturation)
+ return;
+
+ m_saturation = saturation;
+
+ m_dirtyValues |= DXVA2_ProcAmp_Saturation;
+
+ applyImageControls();
+
+ emit saturationChanged(saturation);
+}
+
+void EvrVideoWindowControl::applyImageControls()
+{
+ if (m_processor) {
+ DXVA2_ProcAmpValues values;
+ if (m_dirtyValues & DXVA2_ProcAmp_Brightness) {
+ values.Brightness = scaleProcAmpValue(DXVA2_ProcAmp_Brightness, m_brightness);
+ }
+ if (m_dirtyValues & DXVA2_ProcAmp_Contrast) {
+ values.Contrast = scaleProcAmpValue(DXVA2_ProcAmp_Contrast, m_contrast);
+ }
+ if (m_dirtyValues & DXVA2_ProcAmp_Hue) {
+ values.Hue = scaleProcAmpValue(DXVA2_ProcAmp_Hue, m_hue);
+ }
+ if (m_dirtyValues & DXVA2_ProcAmp_Saturation) {
+ values.Saturation = scaleProcAmpValue(DXVA2_ProcAmp_Saturation, m_saturation);
+ }
+
+ if (SUCCEEDED(m_processor->SetProcAmpValues(m_dirtyValues, &values))) {
+ m_dirtyValues = 0;
+ }
+ }
+}
+
+DXVA2_Fixed32 EvrVideoWindowControl::scaleProcAmpValue(DWORD prop, int value) const
+{
+ float scaledValue = 0.0;
+
+ DXVA2_ValueRange range;
+ if (SUCCEEDED(m_processor->GetProcAmpRange(prop, &range))) {
+ scaledValue = DXVA2FixedToFloat(range.DefaultValue);
+ if (value > 0)
+ scaledValue += float(value) * (DXVA2FixedToFloat(range.MaxValue) - DXVA2FixedToFloat(range.DefaultValue)) / 100;
+ else if (value < 0)
+ scaledValue -= float(value) * (DXVA2FixedToFloat(range.MinValue) - DXVA2FixedToFloat(range.DefaultValue)) / 100;
+ }
+
+ return DXVA2FloatToFixed(scaledValue);
+}