diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2009-03-23 09:18:55 (GMT) |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2009-03-23 09:18:55 (GMT) |
commit | e5fcad302d86d316390c6b0f62759a067313e8a9 (patch) | |
tree | c2afbf6f1066b6ce261f14341cf6d310e5595bc1 /src/3rdparty/phonon/ds9/videorenderer_vmr9.cpp | |
download | Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.zip Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.gz Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.bz2 |
Long live Qt 4.5!
Diffstat (limited to 'src/3rdparty/phonon/ds9/videorenderer_vmr9.cpp')
-rw-r--r-- | src/3rdparty/phonon/ds9/videorenderer_vmr9.cpp | 333 |
1 files changed, 333 insertions, 0 deletions
diff --git a/src/3rdparty/phonon/ds9/videorenderer_vmr9.cpp b/src/3rdparty/phonon/ds9/videorenderer_vmr9.cpp new file mode 100644 index 0000000..298e9fa --- /dev/null +++ b/src/3rdparty/phonon/ds9/videorenderer_vmr9.cpp @@ -0,0 +1,333 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. +*/ + + +#include "videorenderer_vmr9.h" + +#ifndef QT_NO_PHONON_VIDEO + +#include <QtGui/QWidget> +#include <QtGui/QPainter> +#include <QtCore/QTimerEvent> + +#ifndef Q_OS_WINCE +#include <d3d9.h> +#include <vmr9.h> +#else +#include <uuids.h> +#endif + +QT_BEGIN_NAMESPACE + + +namespace Phonon +{ + namespace DS9 + { + VideoRendererVMR9::~VideoRendererVMR9() + { + } + + bool VideoRendererVMR9::isNative() const + { + return true; + } + + +#ifdef Q_OS_WINCE + VideoRendererVMR9::VideoRendererVMR9(QWidget *target) : m_target(target) + { + m_target->setAttribute(Qt::WA_PaintOnScreen, true); + m_filter = Filter(CLSID_VideoRenderer, IID_IBaseFilter); + } + + QSize VideoRendererVMR9::videoSize() const + { + LONG w = 0, + h = 0; + ComPointer<IBasicVideo> basic(m_filter, IID_IBasicVideo); + if (basic) { + basic->GetVideoSize( &w, &h); + } + return QSize(w, h); + } + + void VideoRendererVMR9::repaintCurrentFrame(QWidget * /*target*/, const QRect & /*rect*/) + { + //nothing to do here: the renderer paints everything + } + + void VideoRendererVMR9::notifyResize(const QSize &size, Phonon::VideoWidget::AspectRatio aspectRatio, + Phonon::VideoWidget::ScaleMode scaleMode) + { + if (!isActive()) { + ComPointer<IBasicVideo> basic(m_filter, IID_IBasicVideo); + if (basic) { + basic->SetDestinationPosition(0, 0, 0, 0); + } + return; + } + + ComPointer<IVideoWindow> video(m_filter, IID_IVideoWindow); + + OAHWND owner; + HRESULT hr = video->get_Owner(&owner); + if (FAILED(hr)) { + return; + } + + const OAHWND newOwner = reinterpret_cast<OAHWND>(m_target->winId()); + if (owner != newOwner) { + video->put_Owner(newOwner); + video->put_MessageDrain(newOwner); + video->put_WindowStyle(WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS); + } + + //make sure the widget takes the whole size of the parent + video->SetWindowPosition(0, 0, size.width(), size.height()); + + const QSize vsize = videoSize(); + internalNotifyResize(size, vsize, aspectRatio, scaleMode); + + ComPointer<IBasicVideo> basic(m_filter, IID_IBasicVideo); + if (basic) { + basic->SetDestinationPosition(m_dstX, m_dstY, m_dstWidth, m_dstHeight); + } + } + + void VideoRendererVMR9::applyMixerSettings(qreal /*brightness*/, qreal /*contrast*/, qreal /*m_hue*/, qreal /*saturation*/) + { + //this can't be supported for WinCE + } + + QImage VideoRendererVMR9::snapshot() const + { + ComPointer<IBasicVideo> basic(m_filter, IID_IBasicVideo); + if (basic) { + LONG bufferSize = 0; + //1st we get the buffer size + basic->GetCurrentImage(&bufferSize, 0); + + QByteArray buffer; + buffer.resize(bufferSize); + HRESULT hr = basic->GetCurrentImage(&bufferSize, reinterpret_cast<long*>(buffer.data())); + + if (SUCCEEDED(hr)) { + + const BITMAPINFOHEADER *bmi = reinterpret_cast<const BITMAPINFOHEADER*>(buffer.constData()); + + const int w = qAbs(bmi->biWidth), + h = qAbs(bmi->biHeight); + + // Create image and copy data into image. + QImage ret(w, h, QImage::Format_RGB32); + + if (!ret.isNull()) { + const char *data = buffer.constData() + bmi->biSize; + const int bytes_per_line = w * sizeof(QRgb); + for (int y = h - 1; y >= 0; --y) { + qMemCopy(ret.scanLine(y), //destination + data, //source + bytes_per_line); + data += bytes_per_line; + } + } + return ret; + } + } + return QImage(); + } + +#else + VideoRendererVMR9::VideoRendererVMR9(QWidget *target) : m_target(target) + { + m_filter = Filter(CLSID_VideoMixingRenderer9, IID_IBaseFilter); + if (!m_filter) { + qWarning("the video widget could not be initialized correctly"); + return; + } + + ComPointer<IVMRFilterConfig9> config(m_filter, IID_IVMRFilterConfig9); + Q_ASSERT(config); + HRESULT hr = config->SetRenderingMode(VMR9Mode_Windowless); + Q_ASSERT(SUCCEEDED(hr)); + hr = config->SetNumberOfStreams(1); //for now we limit it to 1 input stream + Q_ASSERT(SUCCEEDED(hr)); + ComPointer<IVMRWindowlessControl9> windowlessControl(m_filter, IID_IVMRWindowlessControl9); + windowlessControl->SetVideoClippingWindow(reinterpret_cast<HWND>(target->winId())); + } + + QImage VideoRendererVMR9::snapshot() const + { + ComPointer<IVMRWindowlessControl9> windowlessControl(m_filter, IID_IVMRWindowlessControl9); + if (windowlessControl) { + BYTE *buffer = 0; + HRESULT hr = windowlessControl->GetCurrentImage(&buffer); + if (SUCCEEDED(hr)) { + + const BITMAPINFOHEADER *bmi = reinterpret_cast<BITMAPINFOHEADER*>(buffer); + const int w = qAbs(bmi->biWidth), + h = qAbs(bmi->biHeight); + + // Create image and copy data into image. + QImage ret(w, h, QImage::Format_RGB32); + + if (!ret.isNull()) { + uchar *data = buffer + bmi->biSize; + const int bytes_per_line = w * sizeof(QRgb); + for (int y = h - 1; y >= 0; --y) { + qMemCopy(ret.scanLine(y), //destination + data, //source + bytes_per_line); + data += bytes_per_line; + } + } + ::CoTaskMemFree(buffer); + return ret; + } + } + return QImage(); + } + + QSize VideoRendererVMR9::videoSize() const + { + LONG w = 0, + h = 0; + ComPointer<IVMRWindowlessControl9> windowlessControl(m_filter, IID_IVMRWindowlessControl9); + if (windowlessControl) { + windowlessControl->GetNativeVideoSize( &w, &h, 0, 0); + } + return QSize(w, h); + } + + void VideoRendererVMR9::repaintCurrentFrame(QWidget *target, const QRect &rect) + { + HDC hDC = target->getDC(); + // repaint the video + ComPointer<IVMRWindowlessControl9> windowlessControl(m_filter, IID_IVMRWindowlessControl9); + + HRESULT hr = windowlessControl ? windowlessControl->RepaintVideo(target->winId(), hDC) : E_POINTER; + if (FAILED(hr) || m_dstY > 0 || m_dstX > 0) { + const QColor c = target->palette().color(target->backgroundRole()); + COLORREF color = RGB(c.red(), c.green(), c.blue()); + HPEN hPen = ::CreatePen(PS_SOLID, 1, color); + HBRUSH hBrush = ::CreateSolidBrush(color); + ::SelectObject(hDC, hPen); + ::SelectObject(hDC, hBrush); + // repaint the video + if (FAILED(hr)) { + //black background : we use the Win32 API to avoid the ghost effect of the backing store + ::Rectangle(hDC, 0, 0, target->width(), target->height()); + } else { + if (m_dstY > 0) { + ::Rectangle(hDC, 0, 0, target->width(), m_dstY); //top + ::Rectangle(hDC, 0, target->height() - m_dstY, target->width(), target->height()); //bottom + } + if (m_dstX > 0) { + ::Rectangle(hDC, 0, m_dstY, m_dstX, m_dstHeight + m_dstY); //left + ::Rectangle(hDC, m_dstWidth + m_dstX, m_dstY, target->width(), m_dstHeight + m_dstY); //right + } + } + ::DeleteObject(hPen); + ::DeleteObject(hBrush); + } + target->releaseDC(hDC); + + } + + void VideoRendererVMR9::notifyResize(const QSize &size, Phonon::VideoWidget::AspectRatio aspectRatio, + Phonon::VideoWidget::ScaleMode scaleMode) + { + if (!isActive()) { + RECT dummyRect = { 0, 0, 0, 0}; + ComPointer<IVMRWindowlessControl9> windowlessControl(m_filter, IID_IVMRWindowlessControl9); + windowlessControl->SetVideoPosition(&dummyRect, &dummyRect); + return; + } + + + const QSize vsize = videoSize(); + internalNotifyResize(size, vsize, aspectRatio, scaleMode); + + RECT dstRectWin = { m_dstX, m_dstY, m_dstWidth + m_dstX, m_dstHeight + m_dstY}; + RECT srcRectWin = { 0, 0, vsize.width(), vsize.height()}; + + ComPointer<IVMRWindowlessControl9> windowlessControl(m_filter, IID_IVMRWindowlessControl9); + if (windowlessControl) { + windowlessControl->SetVideoPosition(&srcRectWin, &dstRectWin); + } + } + + void VideoRendererVMR9::applyMixerSettings(qreal brightness, qreal contrast, qreal hue, qreal saturation) + { + InputPin sink = BackendNode::pins(m_filter, PINDIR_INPUT).first(); + OutputPin source; + if (FAILED(sink->ConnectedTo(source.pparam()))) { + return; //it must be connected to work + } + + //get the mixer (used for brightness/contrast/saturation/hue) + ComPointer<IVMRMixerControl9> mixer(m_filter, IID_IVMRMixerControl9); + Q_ASSERT(mixer); + + VMR9ProcAmpControl ctrl; + ctrl.dwSize = sizeof(ctrl); + ctrl.dwFlags = ProcAmpControl9_Contrast | ProcAmpControl9_Brightness | ProcAmpControl9_Saturation | ProcAmpControl9_Hue; + VMR9ProcAmpControlRange range; + range.dwSize = sizeof(range); + + range.dwProperty = ProcAmpControl9_Contrast; + HRESULT hr = mixer->GetProcAmpControlRange(0, &range); + if (FAILED(hr)) { + return; + } + ctrl.Contrast = ((contrast < 0 ? range.MinValue : range.MaxValue) - range.DefaultValue) * qAbs(contrast) + range.DefaultValue; + + //brightness + range.dwProperty = ProcAmpControl9_Brightness; + hr = mixer->GetProcAmpControlRange(0, &range); + if (FAILED(hr)) { + return; + } + ctrl.Brightness = ((brightness < 0 ? range.MinValue : range.MaxValue) - range.DefaultValue) * qAbs(brightness) + range.DefaultValue; + + //saturation + range.dwProperty = ProcAmpControl9_Saturation; + hr = mixer->GetProcAmpControlRange(0, &range); + if (FAILED(hr)) { + return; + } + ctrl.Saturation = ((saturation < 0 ? range.MinValue : range.MaxValue) - range.DefaultValue) * qAbs(saturation) + range.DefaultValue; + + //hue + range.dwProperty = ProcAmpControl9_Hue; + hr = mixer->GetProcAmpControlRange(0, &range); + if (FAILED(hr)) { + return; + } + ctrl.Hue = ((hue < 0 ? range.MinValue : range.MaxValue) - range.DefaultValue) * qAbs(hue) + range.DefaultValue; + + //finally set the settings + mixer->SetProcAmpControl(0, &ctrl); + } +#endif + } +} + +QT_END_NAMESPACE + +#endif //QT_NO_PHONON_VIDEO |