/* 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 . */ #include "videorenderer_vmr9.h" #ifndef QT_NO_PHONON_VIDEO #include #include #include #include QT_BEGIN_NAMESPACE namespace Phonon { namespace DS9 { VideoRendererVMR9::~VideoRendererVMR9() { } bool VideoRendererVMR9::isNative() const { return true; } VideoRendererVMR9::VideoRendererVMR9(QWidget *target) : m_target(target) { m_filter = Filter(CLSID_VideoMixingRenderer9, IID_IBaseFilter); if (!m_filter) { return; } ComPointer 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 windowlessControl(m_filter, IID_IVMRWindowlessControl9); windowlessControl->SetVideoClippingWindow(reinterpret_cast(target->winId())); windowlessControl->SetAspectRatioMode(VMR9ARMode_None); //we're in control of the size } QImage VideoRendererVMR9::snapshot() const { ComPointer windowlessControl(m_filter, IID_IVMRWindowlessControl9); if (windowlessControl) { BYTE *buffer = 0; HRESULT hr = windowlessControl->GetCurrentImage(&buffer); if (SUCCEEDED(hr)) { const BITMAPINFOHEADER *bmi = reinterpret_cast(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 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 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 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 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 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); } } } QT_END_NAMESPACE #endif //QT_NO_PHONON_VIDEO