source: trunk/src/3rdparty/phonon/ds9/videorenderer_vmr9.cpp@ 651

Last change on this file since 651 was 561, checked in by Dmitry A. Kuminov, 16 years ago

trunk: Merged in qt 4.6.1 sources.

File size: 12.6 KB
Line 
1/* This file is part of the KDE project.
2
3Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4
5This library is free software: you can redistribute it and/or modify
6it under the terms of the GNU Lesser General Public License as published by
7the Free Software Foundation, either version 2.1 or 3 of the License.
8
9This library is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU Lesser General Public License for more details.
13
14You should have received a copy of the GNU Lesser General Public License
15along 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
34QT_BEGIN_NAMESPACE
35
36
37namespace 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
332QT_END_NAMESPACE
333
334#endif //QT_NO_PHONON_VIDEO
Note: See TracBrowser for help on using the repository browser.