src/3rdparty/phonon/ds9/videorenderer_vmr9.cpp
changeset 0 1918ee327afb
child 30 5dc02b23752f
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /*  This file is part of the KDE project.
       
     2 
       
     3 Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 
       
     5 This library is free software: you can redistribute it and/or modify
       
     6 it under the terms of the GNU Lesser General Public License as published by
       
     7 the Free Software Foundation, either version 2.1 or 3 of the License.
       
     8 
       
     9 This library is distributed in the hope that it will be useful,
       
    10 but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    12 GNU Lesser General Public License for more details.
       
    13 
       
    14 You should have received a copy of the GNU Lesser General Public License
       
    15 along with this library.  If not, see <http://www.gnu.org/licenses/>.
       
    16 */
       
    17 
       
    18 
       
    19 #include "videorenderer_vmr9.h"
       
    20 
       
    21 #ifndef QT_NO_PHONON_VIDEO
       
    22 
       
    23 #include <QtGui/QWidget>
       
    24 #include <QtGui/QPainter>
       
    25 #include <QtCore/QTimerEvent>
       
    26 
       
    27 #ifndef Q_OS_WINCE
       
    28 #include <d3d9.h>
       
    29 #include <vmr9.h>
       
    30 #else
       
    31 #include <uuids.h>
       
    32 #endif
       
    33 
       
    34 QT_BEGIN_NAMESPACE
       
    35 
       
    36 
       
    37 namespace Phonon
       
    38 {
       
    39     namespace DS9
       
    40     {
       
    41         VideoRendererVMR9::~VideoRendererVMR9()
       
    42         {
       
    43         }
       
    44 
       
    45         bool VideoRendererVMR9::isNative() const
       
    46         {
       
    47             return true;
       
    48         }
       
    49 
       
    50 
       
    51 #ifdef Q_OS_WINCE
       
    52         VideoRendererVMR9::VideoRendererVMR9(QWidget *target) : m_target(target)
       
    53         {
       
    54             m_target->setAttribute(Qt::WA_PaintOnScreen, true);
       
    55             m_filter = Filter(CLSID_VideoRenderer, IID_IBaseFilter);
       
    56         }
       
    57 
       
    58         QSize VideoRendererVMR9::videoSize() const
       
    59         {
       
    60             LONG w = 0,
       
    61                 h = 0;
       
    62             ComPointer<IBasicVideo> basic(m_filter, IID_IBasicVideo);
       
    63             if (basic) {
       
    64                 basic->GetVideoSize( &w, &h);
       
    65             }
       
    66             return QSize(w, h);
       
    67         }
       
    68 
       
    69         void VideoRendererVMR9::repaintCurrentFrame(QWidget * /*target*/, const QRect & /*rect*/)
       
    70         {
       
    71             //nothing to do here: the renderer paints everything
       
    72         }
       
    73 
       
    74         void VideoRendererVMR9::notifyResize(const QSize &size, Phonon::VideoWidget::AspectRatio aspectRatio,
       
    75             Phonon::VideoWidget::ScaleMode scaleMode)
       
    76         {
       
    77             if (!isActive()) {
       
    78                 ComPointer<IBasicVideo> basic(m_filter, IID_IBasicVideo);
       
    79                 if (basic) {
       
    80                     basic->SetDestinationPosition(0, 0, 0, 0);
       
    81                 }
       
    82                 return;
       
    83             }
       
    84 
       
    85             ComPointer<IVideoWindow> video(m_filter, IID_IVideoWindow);
       
    86 
       
    87             OAHWND owner;
       
    88             HRESULT hr = video->get_Owner(&owner);
       
    89             if (FAILED(hr)) {
       
    90                 return;
       
    91             }
       
    92 
       
    93             const OAHWND newOwner = reinterpret_cast<OAHWND>(m_target->winId());
       
    94             if (owner != newOwner) {
       
    95                 video->put_Owner(newOwner);
       
    96                 video->put_MessageDrain(newOwner);
       
    97                 video->put_WindowStyle(WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
       
    98             }
       
    99 
       
   100             //make sure the widget takes the whole size of the parent
       
   101             video->SetWindowPosition(0, 0, size.width(), size.height());
       
   102 
       
   103             const QSize vsize = videoSize();
       
   104             internalNotifyResize(size, vsize, aspectRatio, scaleMode);
       
   105 
       
   106             ComPointer<IBasicVideo> basic(m_filter, IID_IBasicVideo);
       
   107             if (basic) {
       
   108                 basic->SetDestinationPosition(m_dstX, m_dstY, m_dstWidth, m_dstHeight);
       
   109             }
       
   110         }
       
   111 
       
   112         void VideoRendererVMR9::applyMixerSettings(qreal /*brightness*/, qreal /*contrast*/, qreal /*m_hue*/, qreal /*saturation*/)
       
   113         {
       
   114             //this can't be supported for WinCE
       
   115         }
       
   116 
       
   117         QImage VideoRendererVMR9::snapshot() const
       
   118         {
       
   119             ComPointer<IBasicVideo> basic(m_filter, IID_IBasicVideo);
       
   120             if (basic) {
       
   121                 LONG bufferSize = 0;
       
   122                 //1st we get the buffer size
       
   123                 basic->GetCurrentImage(&bufferSize, 0);
       
   124 
       
   125                 QByteArray buffer;
       
   126                 buffer.resize(bufferSize);
       
   127                 HRESULT hr = basic->GetCurrentImage(&bufferSize, reinterpret_cast<long*>(buffer.data()));
       
   128 
       
   129                 if (SUCCEEDED(hr)) {
       
   130 
       
   131                     const BITMAPINFOHEADER  *bmi = reinterpret_cast<const BITMAPINFOHEADER*>(buffer.constData());
       
   132 
       
   133                     const int w = qAbs(bmi->biWidth),
       
   134                         h = qAbs(bmi->biHeight);
       
   135 
       
   136                     // Create image and copy data into image.
       
   137                     QImage ret(w, h, QImage::Format_RGB32);
       
   138 
       
   139                     if (!ret.isNull()) {
       
   140                         const char *data = buffer.constData() + bmi->biSize;
       
   141                         const int bytes_per_line = w * sizeof(QRgb);
       
   142                         for (int y = h - 1; y >= 0; --y) {
       
   143                             qMemCopy(ret.scanLine(y), //destination
       
   144                                 data,     //source
       
   145                                 bytes_per_line);
       
   146                             data += bytes_per_line;
       
   147                         }
       
   148                     }
       
   149                     return ret;
       
   150                 }
       
   151             }
       
   152             return QImage();
       
   153         }
       
   154 
       
   155 #else
       
   156         VideoRendererVMR9::VideoRendererVMR9(QWidget *target) : m_target(target)
       
   157         {
       
   158             m_filter = Filter(CLSID_VideoMixingRenderer9, IID_IBaseFilter);
       
   159             if (!m_filter) {
       
   160                 qWarning("the video widget could not be initialized correctly");
       
   161                 return;
       
   162             }
       
   163 
       
   164             ComPointer<IVMRFilterConfig9> config(m_filter, IID_IVMRFilterConfig9);
       
   165             Q_ASSERT(config);
       
   166             HRESULT hr = config->SetRenderingMode(VMR9Mode_Windowless);
       
   167             Q_ASSERT(SUCCEEDED(hr));
       
   168             hr = config->SetNumberOfStreams(1); //for now we limit it to 1 input stream
       
   169             Q_ASSERT(SUCCEEDED(hr));
       
   170             ComPointer<IVMRWindowlessControl9> windowlessControl(m_filter, IID_IVMRWindowlessControl9);
       
   171             windowlessControl->SetVideoClippingWindow(reinterpret_cast<HWND>(target->winId()));
       
   172             windowlessControl->SetAspectRatioMode(VMR9ARMode_None); //we're in control of the size
       
   173         }
       
   174 
       
   175         QImage VideoRendererVMR9::snapshot() const
       
   176         {
       
   177             ComPointer<IVMRWindowlessControl9> windowlessControl(m_filter, IID_IVMRWindowlessControl9);
       
   178             if (windowlessControl) {
       
   179                 BYTE *buffer = 0;
       
   180                 HRESULT hr = windowlessControl->GetCurrentImage(&buffer);
       
   181                 if (SUCCEEDED(hr)) {
       
   182 
       
   183                     const BITMAPINFOHEADER  *bmi = reinterpret_cast<BITMAPINFOHEADER*>(buffer);
       
   184                     const int w = qAbs(bmi->biWidth),
       
   185                         h = qAbs(bmi->biHeight);
       
   186 
       
   187                     // Create image and copy data into image.
       
   188                     QImage ret(w, h, QImage::Format_RGB32);
       
   189 
       
   190                     if (!ret.isNull()) {
       
   191                         uchar *data = buffer + bmi->biSize;
       
   192                         const int bytes_per_line = w * sizeof(QRgb);
       
   193                         for (int y = h - 1; y >= 0; --y) {
       
   194                             qMemCopy(ret.scanLine(y), //destination
       
   195                                 data,     //source
       
   196                                 bytes_per_line);
       
   197                             data += bytes_per_line;
       
   198                         }
       
   199                     }
       
   200                     ::CoTaskMemFree(buffer);
       
   201                     return ret;
       
   202                 }
       
   203             }
       
   204             return QImage();
       
   205         }
       
   206 
       
   207         QSize VideoRendererVMR9::videoSize() const
       
   208         {
       
   209             LONG w = 0,
       
   210                 h = 0;
       
   211             ComPointer<IVMRWindowlessControl9> windowlessControl(m_filter, IID_IVMRWindowlessControl9);
       
   212             if (windowlessControl) {
       
   213                 windowlessControl->GetNativeVideoSize( &w, &h, 0, 0);
       
   214             }
       
   215             return QSize(w, h);
       
   216         }
       
   217        
       
   218         void VideoRendererVMR9::repaintCurrentFrame(QWidget *target, const QRect &rect)
       
   219         {
       
   220             HDC hDC = target->getDC();
       
   221             // repaint the video
       
   222             ComPointer<IVMRWindowlessControl9> windowlessControl(m_filter, IID_IVMRWindowlessControl9);
       
   223 
       
   224             HRESULT hr = windowlessControl ? windowlessControl->RepaintVideo(target->winId(), hDC) : E_POINTER;
       
   225             if (FAILED(hr) || m_dstY > 0 || m_dstX > 0) {
       
   226                 const QColor c = target->palette().color(target->backgroundRole());
       
   227                 COLORREF color = RGB(c.red(), c.green(), c.blue());
       
   228                 HPEN hPen = ::CreatePen(PS_SOLID, 1, color);
       
   229                 HBRUSH hBrush = ::CreateSolidBrush(color);
       
   230                 ::SelectObject(hDC, hPen);
       
   231                 ::SelectObject(hDC, hBrush);
       
   232                 // repaint the video
       
   233                 if (FAILED(hr)) {
       
   234                     //black background : we use the Win32 API to avoid the ghost effect of the backing store
       
   235                     ::Rectangle(hDC, 0, 0, target->width(), target->height());
       
   236                 } else {
       
   237                     if (m_dstY > 0) {
       
   238                         ::Rectangle(hDC, 0, 0, target->width(), m_dstY); //top
       
   239                         ::Rectangle(hDC, 0, target->height() - m_dstY, target->width(), target->height()); //bottom
       
   240                     }
       
   241                     if (m_dstX > 0) {
       
   242                         ::Rectangle(hDC, 0, m_dstY, m_dstX, m_dstHeight + m_dstY); //left
       
   243                         ::Rectangle(hDC, m_dstWidth + m_dstX, m_dstY, target->width(), m_dstHeight + m_dstY); //right
       
   244                     }
       
   245                 }
       
   246                 ::DeleteObject(hPen);
       
   247                 ::DeleteObject(hBrush);
       
   248             }
       
   249             target->releaseDC(hDC);
       
   250 
       
   251         }
       
   252 
       
   253         void VideoRendererVMR9::notifyResize(const QSize &size, Phonon::VideoWidget::AspectRatio aspectRatio,
       
   254             Phonon::VideoWidget::ScaleMode scaleMode)
       
   255         {
       
   256             if (!isActive()) {
       
   257                 RECT dummyRect = { 0, 0, 0, 0};
       
   258                 ComPointer<IVMRWindowlessControl9> windowlessControl(m_filter, IID_IVMRWindowlessControl9);
       
   259                 windowlessControl->SetVideoPosition(&dummyRect, &dummyRect);
       
   260                 return;
       
   261             }
       
   262 
       
   263 
       
   264             const QSize vsize = videoSize();
       
   265             internalNotifyResize(size, vsize, aspectRatio, scaleMode);
       
   266 
       
   267             RECT dstRectWin = { m_dstX, m_dstY, m_dstWidth + m_dstX, m_dstHeight + m_dstY};
       
   268             RECT srcRectWin = { 0, 0, vsize.width(), vsize.height()};
       
   269 
       
   270             ComPointer<IVMRWindowlessControl9> windowlessControl(m_filter, IID_IVMRWindowlessControl9);
       
   271             if (windowlessControl) {
       
   272                 windowlessControl->SetVideoPosition(&srcRectWin, &dstRectWin);
       
   273             }
       
   274         }
       
   275 
       
   276         void VideoRendererVMR9::applyMixerSettings(qreal brightness, qreal contrast, qreal hue, qreal saturation)
       
   277         {
       
   278             InputPin sink = BackendNode::pins(m_filter, PINDIR_INPUT).first();
       
   279             OutputPin source;
       
   280             if (FAILED(sink->ConnectedTo(source.pparam()))) {
       
   281                 return; //it must be connected to work
       
   282             }
       
   283 
       
   284             //get the mixer (used for brightness/contrast/saturation/hue)
       
   285             ComPointer<IVMRMixerControl9> mixer(m_filter, IID_IVMRMixerControl9);
       
   286             Q_ASSERT(mixer);
       
   287 
       
   288             VMR9ProcAmpControl ctrl;
       
   289             ctrl.dwSize = sizeof(ctrl);
       
   290             ctrl.dwFlags = ProcAmpControl9_Contrast | ProcAmpControl9_Brightness | ProcAmpControl9_Saturation | ProcAmpControl9_Hue;
       
   291             VMR9ProcAmpControlRange range;
       
   292             range.dwSize = sizeof(range);
       
   293 
       
   294             range.dwProperty = ProcAmpControl9_Contrast;
       
   295             HRESULT hr = mixer->GetProcAmpControlRange(0, &range);
       
   296             if (FAILED(hr)) {
       
   297                 return;
       
   298             }
       
   299             ctrl.Contrast = ((contrast < 0 ? range.MinValue : range.MaxValue) - range.DefaultValue) * qAbs(contrast) + range.DefaultValue;
       
   300 
       
   301             //brightness
       
   302             range.dwProperty = ProcAmpControl9_Brightness;
       
   303             hr = mixer->GetProcAmpControlRange(0, &range);
       
   304             if (FAILED(hr)) {
       
   305                 return;
       
   306             }
       
   307             ctrl.Brightness = ((brightness < 0 ? range.MinValue : range.MaxValue) - range.DefaultValue) * qAbs(brightness) + range.DefaultValue;
       
   308 
       
   309             //saturation
       
   310             range.dwProperty = ProcAmpControl9_Saturation;
       
   311             hr = mixer->GetProcAmpControlRange(0, &range);
       
   312             if (FAILED(hr)) {
       
   313                 return;
       
   314             }
       
   315             ctrl.Saturation = ((saturation < 0 ? range.MinValue : range.MaxValue) - range.DefaultValue) * qAbs(saturation) + range.DefaultValue;
       
   316 
       
   317             //hue
       
   318             range.dwProperty = ProcAmpControl9_Hue;
       
   319             hr = mixer->GetProcAmpControlRange(0, &range);
       
   320             if (FAILED(hr)) {
       
   321                 return;
       
   322             }
       
   323             ctrl.Hue = ((hue < 0 ? range.MinValue : range.MaxValue) - range.DefaultValue) * qAbs(hue) + range.DefaultValue;
       
   324 
       
   325             //finally set the settings
       
   326             mixer->SetProcAmpControl(0, &ctrl);
       
   327         }
       
   328 #endif
       
   329     }
       
   330 }
       
   331 
       
   332 QT_END_NAMESPACE
       
   333 
       
   334 #endif //QT_NO_PHONON_VIDEO