|
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 #include <QtCore/qglobal.h> |
|
19 #ifdef QT_MAC_USE_COCOA |
|
20 #import <QTKit/QTMovieLayer.h> |
|
21 #endif |
|
22 |
|
23 #include "videowidget.h" |
|
24 #include "backendheader.h" |
|
25 #include "quicktimevideoplayer.h" |
|
26 #include "medianode.h" |
|
27 #include "medianodeevent.h" |
|
28 #include "mediaobject.h" |
|
29 |
|
30 #include <QtOpenGL/QGLWidget> |
|
31 #include <QtCore/QTime> |
|
32 #include <QtCore/QEvent> |
|
33 #include <QtCore/QCoreApplication> |
|
34 |
|
35 #import <AppKit/NSImage.h> |
|
36 #import <QTKit/QTMovieView.h> |
|
37 |
|
38 ///////////////////////////////////////////////////////////////////////////////////////// |
|
39 |
|
40 #ifdef QT_MAC_USE_COCOA // Rendering to a QTMovieView can only be done in Cocoa |
|
41 |
|
42 #define VIDEO_TRANSPARENT(m) -(void)m:(NSEvent *)e{[[self superview] m:e];} |
|
43 |
|
44 @interface SharedQTMovieView : QTMovieView |
|
45 { |
|
46 @private |
|
47 Phonon::QT7::QuickTimeVideoPlayer *m_player; |
|
48 QList<QWidget *> *m_parents; |
|
49 QWidget *m_window; |
|
50 QRect *m_drawRect; |
|
51 bool m_newImageReady; |
|
52 bool m_usingWindow; |
|
53 } |
|
54 |
|
55 - (SharedQTMovieView *) init; |
|
56 - (void) registerParent:(QWidget *)parent; |
|
57 - (void) unregisterParent:(QWidget *)parent; |
|
58 - (void) setDrawRect:(QRect &)rect; |
|
59 - (void) drawVideoFrame:(Phonon::QT7::VideoFrame &)frame forWidget:(QWidget *)widget shareImages:(bool)share; |
|
60 - (void) useOffscreenWindow:(bool)offscreen; |
|
61 - (void) applyDrawRectOnSelf; |
|
62 @end |
|
63 |
|
64 ///////////////////////////////////////////////////////////////////////////////////////// |
|
65 |
|
66 @implementation SharedQTMovieView |
|
67 |
|
68 - (SharedQTMovieView *) init |
|
69 { |
|
70 self = [super initWithFrame:NSZeroRect]; |
|
71 if (self){ |
|
72 [self setControllerVisible:NO]; |
|
73 m_parents = new QList<QWidget *>(); |
|
74 m_drawRect = new QRect(0, 0, 1, 1); |
|
75 [self applyDrawRectOnSelf]; |
|
76 m_usingWindow = false; |
|
77 } |
|
78 return self; |
|
79 } |
|
80 |
|
81 - (void) dealloc |
|
82 { |
|
83 Phonon::QT7::PhononAutoReleasePool pool; |
|
84 delete m_window; |
|
85 delete m_drawRect; |
|
86 delete m_parents; |
|
87 [super dealloc]; |
|
88 } |
|
89 |
|
90 - (void) applyDrawRectOnSelf |
|
91 { |
|
92 NSRect nsrect; |
|
93 nsrect.origin.x = m_drawRect->x(); |
|
94 nsrect.origin.y = m_drawRect->y(); |
|
95 nsrect.size.width = m_drawRect->width(); |
|
96 nsrect.size.height = m_drawRect->height(); |
|
97 [self setFrame:nsrect]; |
|
98 } |
|
99 |
|
100 - (void) setDrawRect:(QRect &)rect |
|
101 { |
|
102 *m_drawRect = rect; |
|
103 if (!m_usingWindow) |
|
104 [self applyDrawRectOnSelf]; |
|
105 } |
|
106 |
|
107 - (void) waitForFrame |
|
108 { |
|
109 if (m_usingWindow){ |
|
110 QTMovie *movie = [self movie]; |
|
111 if (movie){ |
|
112 // CIImages are expected, but not received. |
|
113 // Try to wait a couple of seconds for them: |
|
114 m_newImageReady = false; |
|
115 float rate = [movie rate]; |
|
116 if (!rate) |
|
117 [movie setRate:1]; |
|
118 QTime t; t.start(); |
|
119 while (!m_newImageReady && t.elapsed() < 2000) |
|
120 ; |
|
121 [movie setRate:rate]; |
|
122 } |
|
123 } |
|
124 } |
|
125 |
|
126 - (void) useOffscreenWindow:(bool)offscreen |
|
127 { |
|
128 if (offscreen == m_usingWindow) |
|
129 return; |
|
130 if (offscreen){ |
|
131 if (!m_window){ |
|
132 m_window = new QWidget; |
|
133 m_window->setWindowOpacity(0.0); |
|
134 m_window->show(); |
|
135 m_window->hide(); |
|
136 } |
|
137 m_usingWindow = true; |
|
138 [self setDelegate:self]; |
|
139 [self waitForFrame]; |
|
140 foreach(QWidget *w, *m_parents) |
|
141 w->repaint(); |
|
142 qApp->processEvents(); |
|
143 [self removeFromSuperview]; |
|
144 [(NSView *)m_window->winId() addSubview:self]; |
|
145 } else if (!m_parents->isEmpty()){ |
|
146 m_usingWindow = false; |
|
147 [self removeFromSuperview]; |
|
148 [(NSView*)m_parents->first()->winId() addSubview:self]; |
|
149 [self setDelegate:0]; |
|
150 [self setDrawRect:*m_drawRect]; |
|
151 } |
|
152 } |
|
153 |
|
154 - (void) drawVideoFrame:(Phonon::QT7::VideoFrame &)frame forWidget:(QWidget *)widget shareImages:(bool)share; |
|
155 { |
|
156 // Detect if the video that produces the frame has changed: |
|
157 Phonon::QT7::QuickTimeVideoPlayer *player = frame.videoPlayer(); |
|
158 if (player && player->qtMovie() != [self movie]){ |
|
159 m_player = player; |
|
160 [self setMovie:player->qtMovie()]; |
|
161 [self waitForFrame]; |
|
162 } |
|
163 |
|
164 [self useOffscreenWindow:(share || m_parents->size() > 1)]; |
|
165 if (m_usingWindow) |
|
166 widget->update(); |
|
167 } |
|
168 |
|
169 // Override this method so that the movie doesn't stop if |
|
170 // the window becomes invisible |
|
171 - (void)viewWillMoveToWindow:(NSWindow *)newWindow |
|
172 { |
|
173 Q_UNUSED(newWindow); |
|
174 } |
|
175 |
|
176 - (CIImage *) view:(QTMovieView *)view willDisplayImage:(CIImage *)img |
|
177 { |
|
178 // This method is called from QTMovieView just |
|
179 // before the image will be drawn. |
|
180 Q_UNUSED(view); |
|
181 m_player->setPrimaryRenderingCIImage(img); |
|
182 m_newImageReady = true; |
|
183 return img; |
|
184 } |
|
185 |
|
186 - (void) registerParent:(QWidget *)parent |
|
187 { |
|
188 if (m_parents->contains(parent)) |
|
189 return; |
|
190 m_parents->append(parent); |
|
191 if (m_parents->size() == 1){ |
|
192 Phonon::QT7::PhononAutoReleasePool pool; |
|
193 m_usingWindow = true; |
|
194 [self applyDrawRectOnSelf]; |
|
195 [self useOffscreenWindow:NO]; |
|
196 } |
|
197 } |
|
198 |
|
199 - (void) unregisterParent:(QWidget *)parent |
|
200 { |
|
201 m_parents->removeAll(parent); |
|
202 if (m_parents->size() == 1) |
|
203 [self applyDrawRectOnSelf]; |
|
204 } |
|
205 |
|
206 VIDEO_TRANSPARENT(mouseDown); |
|
207 VIDEO_TRANSPARENT(mouseDragged); |
|
208 VIDEO_TRANSPARENT(mouseUp); |
|
209 VIDEO_TRANSPARENT(mouseMoved); |
|
210 VIDEO_TRANSPARENT(mouseEntered); |
|
211 VIDEO_TRANSPARENT(mouseExited); |
|
212 VIDEO_TRANSPARENT(rightMouseDown); |
|
213 VIDEO_TRANSPARENT(rightMouseDragged); |
|
214 VIDEO_TRANSPARENT(rightMouseUp); |
|
215 VIDEO_TRANSPARENT(otherMouseDown); |
|
216 VIDEO_TRANSPARENT(otherMouseDragged); |
|
217 VIDEO_TRANSPARENT(otherMouseUp); |
|
218 VIDEO_TRANSPARENT(keyDown); |
|
219 VIDEO_TRANSPARENT(keyUp); |
|
220 VIDEO_TRANSPARENT(scrollWheel) |
|
221 |
|
222 @end |
|
223 |
|
224 #endif // QT_MAC_USE_COCOA |
|
225 |
|
226 ///////////////////////////////////////////////////////////////////////////////////////// |
|
227 |
|
228 QT_BEGIN_NAMESPACE |
|
229 |
|
230 namespace Phonon |
|
231 { |
|
232 namespace QT7 |
|
233 { |
|
234 |
|
235 class IVideoRenderDrawWidget |
|
236 { |
|
237 public: |
|
238 virtual ~IVideoRenderDrawWidget(){} |
|
239 virtual void setVideoFrame(VideoFrame &) = 0; |
|
240 virtual void setDrawFrameRect(const QRect &) = 0; |
|
241 virtual void updateVideoOutputCount(int){} |
|
242 virtual void setMovieIsPaused(bool){} |
|
243 }; |
|
244 |
|
245 ///////////////////////////////////////////////////////////////////////////////////////// |
|
246 |
|
247 QGLWidget *PhononSharedQGLWidget(){ |
|
248 static QGLWidget *glWidget = 0; |
|
249 if (!glWidget) |
|
250 glWidget = new QGLWidget(); |
|
251 return glWidget; |
|
252 } |
|
253 |
|
254 ///////////////////////////////////////////////////////////////////////////////////////// |
|
255 |
|
256 class RenderOpenGL : public QGLWidget, public IVideoRenderDrawWidget |
|
257 { |
|
258 public: |
|
259 VideoFrame m_currentFrame; |
|
260 QRect m_drawFrameRect; |
|
261 |
|
262 RenderOpenGL(QWidget *parent, const QGLFormat &format, const QSize &size) : QGLWidget(format, parent, PhononSharedQGLWidget()) |
|
263 { |
|
264 resize(size); |
|
265 setAutoFillBackground(false); |
|
266 show(); |
|
267 } |
|
268 |
|
269 void initializeGL() |
|
270 { |
|
271 glClearColor(0.0f, 0.0f, 0.0f, 1.0f); |
|
272 } |
|
273 |
|
274 void resizeGL(int w, int h) |
|
275 { |
|
276 glMatrixMode(GL_MODELVIEW); |
|
277 glLoadIdentity(); |
|
278 glMatrixMode(GL_PROJECTION); |
|
279 glLoadIdentity(); |
|
280 glViewport(0, 0, GLsizei(w), GLsizei(h)); |
|
281 gluOrtho2D(0, GLsizei(w), 0, GLsizei(h)); |
|
282 updateGL(); |
|
283 } |
|
284 |
|
285 void paintGL() |
|
286 { |
|
287 glClear(GL_COLOR_BUFFER_BIT); |
|
288 m_currentFrame.drawCVTexture(m_drawFrameRect); |
|
289 } |
|
290 |
|
291 void setVideoFrame(VideoFrame &frame) |
|
292 { |
|
293 m_currentFrame = frame; |
|
294 makeCurrent(); |
|
295 paintGL(); |
|
296 swapBuffers(); |
|
297 } |
|
298 |
|
299 void setDrawFrameRect(const QRect &rect) |
|
300 { |
|
301 m_drawFrameRect = rect; |
|
302 } |
|
303 }; |
|
304 |
|
305 ///////////////////////////////////////////////////////////////////////////////////////// |
|
306 |
|
307 class RenderQTMovieView : public QWidget, public IVideoRenderDrawWidget |
|
308 { |
|
309 public: |
|
310 #if defined(QT_MAC_USE_COCOA) |
|
311 QRect m_drawRect; |
|
312 VideoFrame m_videoFrame; |
|
313 SharedQTMovieView *m_currentView; |
|
314 bool m_setDrawRectPending; |
|
315 bool m_share; |
|
316 |
|
317 RenderQTMovieView(bool share, QWidget *parent, const QSize &size=QSize()) : QWidget(parent), m_currentView(0) |
|
318 { |
|
319 m_setDrawRectPending = true; |
|
320 m_share = share; |
|
321 setAutoFillBackground(false); |
|
322 if (share){ |
|
323 // In 'share' mode, this widget will only make sure |
|
324 // that CIIImages are produced, and not actually |
|
325 // draw anything: |
|
326 hide(); |
|
327 } else { |
|
328 resize(size); |
|
329 show(); |
|
330 } |
|
331 } |
|
332 |
|
333 ~RenderQTMovieView() |
|
334 { |
|
335 [m_currentView unregisterParent:this]; |
|
336 } |
|
337 |
|
338 void showEvent(QShowEvent *) |
|
339 { |
|
340 if (m_share) |
|
341 return; |
|
342 [m_currentView registerParent:this]; |
|
343 } |
|
344 |
|
345 void hideEvent(QHideEvent *) |
|
346 { |
|
347 if (m_share) |
|
348 return; |
|
349 [m_currentView unregisterParent:this]; |
|
350 } |
|
351 |
|
352 void paintEvent(QPaintEvent *) |
|
353 { |
|
354 if (m_share) |
|
355 return; |
|
356 QPainter p(this); |
|
357 p.fillRect(rect(), Qt::black); |
|
358 m_videoFrame.drawCIImage(m_drawRect); |
|
359 } |
|
360 |
|
361 void updateVideoOutputCount(int count) |
|
362 { |
|
363 Q_UNUSED(count); |
|
364 } |
|
365 |
|
366 void setMovieIsPaused(bool paused) |
|
367 { |
|
368 Q_UNUSED(paused); |
|
369 } |
|
370 |
|
371 void setVideoFrame(VideoFrame &frame) |
|
372 { |
|
373 m_videoFrame = frame; |
|
374 |
|
375 if (!m_videoFrame.isEmpty()){ |
|
376 Phonon::QT7::QuickTimeVideoPlayer *player = m_videoFrame.videoPlayer(); |
|
377 if (!player->m_primaryRenderingTarget){ |
|
378 // First movie view. Create the shared resource: |
|
379 SharedQTMovieView *view = [[[SharedQTMovieView alloc] init] autorelease]; |
|
380 player->setPrimaryRenderingTarget(view); |
|
381 } |
|
382 |
|
383 SharedQTMovieView *view = static_cast<SharedQTMovieView *>(player->m_primaryRenderingTarget); |
|
384 if (!m_share && view != m_currentView){ |
|
385 [m_currentView unregisterParent:this]; |
|
386 m_currentView = view; |
|
387 [m_currentView registerParent:this]; |
|
388 } |
|
389 |
|
390 [view drawVideoFrame:m_videoFrame forWidget:this shareImages:m_share || m_videoFrame.hasColorAdjustments()]; |
|
391 |
|
392 if (m_setDrawRectPending){ |
|
393 m_setDrawRectPending = false; |
|
394 [view setDrawRect:m_drawRect]; |
|
395 } |
|
396 } |
|
397 } |
|
398 |
|
399 void setDrawFrameRect(const QRect &rect) |
|
400 { |
|
401 m_drawRect = rect; |
|
402 Phonon::QT7::QuickTimeVideoPlayer *player = m_videoFrame.videoPlayer(); |
|
403 if (player && player->m_primaryRenderingTarget){ |
|
404 SharedQTMovieView *view = static_cast<SharedQTMovieView *>(player->m_primaryRenderingTarget); |
|
405 [view setDrawRect:m_drawRect]; |
|
406 } else |
|
407 m_setDrawRectPending = true; |
|
408 } |
|
409 |
|
410 #else // QT_MAC_USE_COCOA == false |
|
411 RenderQTMovieView(bool, QWidget *, const QSize& = QSize()){} |
|
412 void setVideoFrame(VideoFrame &){} |
|
413 void setDrawFrameRect(const QRect &){} |
|
414 #endif |
|
415 }; |
|
416 |
|
417 ///////////////////////////////////////////////////////////////////////////////////////// |
|
418 |
|
419 class RenderQTMovieLayer : public QWidget, public IVideoRenderDrawWidget |
|
420 { |
|
421 public: |
|
422 #ifdef QT_MAC_USE_COCOA |
|
423 QTMovieLayer *m_movieLayer; |
|
424 |
|
425 RenderQTMovieLayer(QWidget *parent, const QSize&) : QWidget(parent) |
|
426 { |
|
427 PhononAutoReleasePool pool; |
|
428 setAutoFillBackground(false); |
|
429 m_movieLayer = 0; |
|
430 [(NSView *)winId() setWantsLayer:YES]; |
|
431 } |
|
432 |
|
433 void setVideoFrame(VideoFrame &frame) |
|
434 { |
|
435 QuickTimeVideoPlayer *player = frame.videoPlayer(); |
|
436 if (!player || player->qtMovie() == [m_movieLayer movie]) |
|
437 return; |
|
438 |
|
439 if (m_movieLayer) |
|
440 [m_movieLayer setMovie:player->qtMovie()]; |
|
441 else { |
|
442 m_movieLayer = [QTMovieLayer layerWithMovie:player->qtMovie()]; |
|
443 [(NSView *)winId() setLayer:m_movieLayer]; |
|
444 } |
|
445 } |
|
446 |
|
447 void setDrawFrameRect(const QRect &rect) |
|
448 { |
|
449 m_movieLayer.frame.origin.x = rect.x(); |
|
450 m_movieLayer.frame.origin.y = rect.y(); |
|
451 m_movieLayer.frame.size.width = rect.width(); |
|
452 m_movieLayer.frame.size.height = rect.height(); |
|
453 } |
|
454 |
|
455 #else // QT_MAC_USE_COCOA == false |
|
456 RenderQTMovieLayer(QWidget *, const QSize&){} |
|
457 void setVideoFrame(VideoFrame &){} |
|
458 void setDrawFrameRect(const QRect &){} |
|
459 #endif |
|
460 }; |
|
461 |
|
462 ///////////////////////////////////////////////////////////////////////////////////////// |
|
463 |
|
464 class VideoRenderWidget : public QWidget |
|
465 { |
|
466 public: |
|
467 enum RenderSystem { RS_NoRendering = 0, |
|
468 RS_QGLWidget = 1, |
|
469 RS_QPainter = 2, |
|
470 RS_CIImage = 3, |
|
471 RS_CVTexture = 4, |
|
472 RS_QImage = 5, |
|
473 RS_QTMovieView = 6, |
|
474 RS_QTMovieLayer = 7 |
|
475 } m_renderSystem; |
|
476 |
|
477 VideoFrame m_currentFrame; |
|
478 QRect m_movieFrameRect; |
|
479 QRect m_drawFrameRect; |
|
480 Phonon::VideoWidget::ScaleMode m_scaleMode; |
|
481 Phonon::VideoWidget::AspectRatio m_aspect; |
|
482 IVideoRenderDrawWidget *m_renderDrawWidget; |
|
483 |
|
484 qreal m_brightness; |
|
485 qreal m_contrast; |
|
486 qreal m_hue; |
|
487 qreal m_saturation; |
|
488 qreal m_opacity; |
|
489 |
|
490 VideoRenderWidget() : QWidget(0), |
|
491 m_scaleMode(Phonon::VideoWidget::FitInView), m_aspect(Phonon::VideoWidget::AspectRatioAuto) |
|
492 { |
|
493 PhononAutoReleasePool pool; |
|
494 m_brightness = 0; |
|
495 m_contrast = 0; |
|
496 m_hue = 0; |
|
497 m_saturation = 0; |
|
498 m_opacity = 1; |
|
499 m_renderDrawWidget = 0; |
|
500 m_renderSystem = RS_NoRendering; |
|
501 |
|
502 setAutoFillBackground(false); |
|
503 updateDrawFrameRect(); |
|
504 } |
|
505 |
|
506 RenderSystem selectBestRenderSystem(){ |
|
507 if (!isVisible()) |
|
508 return RS_NoRendering; |
|
509 else if (window() && window()->testAttribute(Qt::WA_DontShowOnScreen)) |
|
510 return RS_QPainter; |
|
511 else { |
|
512 #ifdef QUICKTIME_C_API_AVAILABLE |
|
513 return RS_QGLWidget; |
|
514 #else |
|
515 return RS_QTMovieView; |
|
516 #endif |
|
517 } |
|
518 } |
|
519 |
|
520 void setRenderSystem(RenderSystem renderSystem){ |
|
521 PhononAutoReleasePool pool; |
|
522 static QString userSystem = qgetenv("PHONON_RENDER_SYSTEM"); |
|
523 if (!userSystem.isEmpty()) |
|
524 renderSystem = RenderSystem(userSystem.toInt()); |
|
525 |
|
526 if (m_renderSystem == renderSystem) |
|
527 return; |
|
528 |
|
529 m_renderSystem = renderSystem; |
|
530 if (m_renderDrawWidget){ |
|
531 delete m_renderDrawWidget; |
|
532 m_renderDrawWidget = 0; |
|
533 } |
|
534 |
|
535 switch (m_renderSystem){ |
|
536 case RS_QGLWidget:{ |
|
537 QGLFormat format = QGLFormat::defaultFormat(); |
|
538 format.setSwapInterval(1); // Vertical sync (avoid tearing) |
|
539 m_renderDrawWidget = new RenderOpenGL(this, format, size()); |
|
540 break;} |
|
541 case RS_QTMovieView:{ |
|
542 m_renderDrawWidget = new RenderQTMovieView(false, this, size()); |
|
543 break;} |
|
544 case RS_QTMovieLayer:{ |
|
545 m_renderDrawWidget = new RenderQTMovieLayer(this, size()); |
|
546 break;} |
|
547 case RS_QPainter: |
|
548 case RS_CIImage: |
|
549 case RS_CVTexture: |
|
550 case RS_QImage: |
|
551 #ifndef QUICKTIME_C_API_AVAILABLE |
|
552 // On cocoa-64, let QTMovieView produce |
|
553 // video frames for us: |
|
554 m_renderDrawWidget = new RenderQTMovieView(true, this); |
|
555 #endif |
|
556 break; |
|
557 case RS_NoRendering: |
|
558 break; |
|
559 } |
|
560 |
|
561 if (m_renderDrawWidget){ |
|
562 m_renderDrawWidget->setVideoFrame(m_currentFrame); |
|
563 m_renderDrawWidget->setDrawFrameRect(m_drawFrameRect); |
|
564 } |
|
565 } |
|
566 |
|
567 QSize sizeHint() const |
|
568 { |
|
569 return m_movieFrameRect.size(); |
|
570 } |
|
571 |
|
572 bool event(QEvent *event) |
|
573 { |
|
574 switch (event->type()){ |
|
575 // Try to detect if one of this objects |
|
576 // anchestors might have changed: |
|
577 case QEvent::Resize:{ |
|
578 PhononAutoReleasePool pool; |
|
579 updateDrawFrameRect(); |
|
580 if (m_renderDrawWidget) |
|
581 dynamic_cast<QWidget *>(m_renderDrawWidget)->resize(size()); |
|
582 break; } |
|
583 case QEvent::Paint:{ |
|
584 PhononAutoReleasePool pool; |
|
585 float opacity = parentWidget() ? parentWidget()->windowOpacity() : 1; |
|
586 switch (m_renderSystem){ |
|
587 case RS_QPainter:{ |
|
588 QPainter p(this); |
|
589 p.fillRect(rect(), Qt::black); |
|
590 if (p.paintEngine()->type() == QPaintEngine::OpenGL) |
|
591 m_currentFrame.drawCVTexture(m_drawFrameRect, opacity); |
|
592 else |
|
593 m_currentFrame.drawQImage(&p, m_drawFrameRect); |
|
594 break; } |
|
595 case RS_CIImage: |
|
596 m_currentFrame.drawCIImage(m_drawFrameRect, opacity); |
|
597 break; |
|
598 case RS_CVTexture: |
|
599 m_currentFrame.drawCVTexture(m_drawFrameRect, opacity); |
|
600 break; |
|
601 case RS_QImage:{ |
|
602 QPainter p(this); |
|
603 p.fillRect(rect(), Qt::black); |
|
604 m_currentFrame.drawQImage(&p, m_drawFrameRect); |
|
605 break; } |
|
606 case RS_QGLWidget: |
|
607 case RS_QTMovieView: |
|
608 case RS_QTMovieLayer: |
|
609 // draw in separate widget |
|
610 break; |
|
611 case RS_NoRendering: |
|
612 QPainter p(this); |
|
613 p.fillRect(rect(), Qt::black); |
|
614 break; |
|
615 } |
|
616 break; } |
|
617 default: |
|
618 break; |
|
619 } |
|
620 |
|
621 return QWidget::event(event); |
|
622 } |
|
623 |
|
624 void setVideoFrame(VideoFrame &frame) |
|
625 { |
|
626 PhononAutoReleasePool pool; |
|
627 m_currentFrame = frame; |
|
628 m_currentFrame.setColors(m_brightness, m_contrast, m_hue, m_saturation); |
|
629 |
|
630 if (m_renderDrawWidget) |
|
631 m_renderDrawWidget->setVideoFrame(m_currentFrame); |
|
632 |
|
633 setRenderSystem(selectBestRenderSystem()); |
|
634 switch (m_renderSystem){ |
|
635 case RS_QGLWidget: |
|
636 case RS_QTMovieView: |
|
637 case RS_QTMovieLayer: |
|
638 case RS_NoRendering: |
|
639 break; |
|
640 case RS_CIImage: |
|
641 case RS_CVTexture: |
|
642 case RS_QImage: |
|
643 case RS_QPainter: |
|
644 repaint(); |
|
645 break; |
|
646 } |
|
647 } |
|
648 |
|
649 void updateVideoFrame() |
|
650 { |
|
651 setVideoFrame(m_currentFrame); |
|
652 } |
|
653 |
|
654 void setMovieRect(const QRect &mrect) |
|
655 { |
|
656 if (mrect == m_movieFrameRect) |
|
657 return; |
|
658 m_movieFrameRect = mrect; |
|
659 updateDrawFrameRect(); |
|
660 updateGeometry(); |
|
661 if (isVisible()) |
|
662 qApp->processEvents(QEventLoop::ExcludeUserInputEvents | QEventLoop::ExcludeSocketNotifiers); |
|
663 } |
|
664 |
|
665 void setScaleMode(Phonon::VideoWidget::ScaleMode scaleMode) |
|
666 { |
|
667 m_scaleMode = scaleMode; |
|
668 updateDrawFrameRect(); |
|
669 updateVideoFrame(); |
|
670 repaint(); |
|
671 } |
|
672 |
|
673 void setAspectRatio(Phonon::VideoWidget::AspectRatio aspect) |
|
674 { |
|
675 m_aspect = aspect; |
|
676 updateDrawFrameRect(); |
|
677 updateVideoFrame(); |
|
678 repaint(); |
|
679 } |
|
680 |
|
681 void updateVideoOutputCount(int count) |
|
682 { |
|
683 if (m_renderDrawWidget) |
|
684 m_renderDrawWidget->updateVideoOutputCount(count); |
|
685 } |
|
686 |
|
687 void setMovieIsPaused(bool paused) |
|
688 { |
|
689 if (m_renderDrawWidget) |
|
690 m_renderDrawWidget->setMovieIsPaused(paused); |
|
691 } |
|
692 |
|
693 void updateDrawFrameRect() |
|
694 { |
|
695 if (m_movieFrameRect.width() <= 0 || m_movieFrameRect.height() <= 0) |
|
696 m_movieFrameRect = QRect(0, 0, 640, 480); |
|
697 |
|
698 // Set m_drawFrameRect to be the size of the smallest possible |
|
699 // rect conforming to the aspect and containing the whole frame: |
|
700 switch(m_aspect){ |
|
701 case Phonon::VideoWidget::AspectRatioWidget: |
|
702 m_drawFrameRect = rect(); |
|
703 break; |
|
704 case Phonon::VideoWidget::AspectRatio4_3: |
|
705 m_drawFrameRect = scaleToAspect(m_movieFrameRect, 4, 3); |
|
706 break; |
|
707 case Phonon::VideoWidget::AspectRatio16_9: |
|
708 m_drawFrameRect = scaleToAspect(m_movieFrameRect, 16, 9); |
|
709 break; |
|
710 case Phonon::VideoWidget::AspectRatioAuto: |
|
711 default: |
|
712 m_drawFrameRect = m_movieFrameRect; |
|
713 break; |
|
714 } |
|
715 |
|
716 // Scale m_drawFrameRect to fill the widget |
|
717 // without breaking aspect: |
|
718 int widgetWidth = rect().width(); |
|
719 int widgetHeight = rect().height(); |
|
720 int frameWidth = widgetWidth; |
|
721 int frameHeight = m_drawFrameRect.height() * float(widgetWidth) / float(m_drawFrameRect.width()); |
|
722 |
|
723 switch(m_scaleMode){ |
|
724 case Phonon::VideoWidget::ScaleAndCrop: |
|
725 if (frameHeight < widgetHeight){ |
|
726 frameWidth *= float(widgetHeight) / float(frameHeight); |
|
727 frameHeight = widgetHeight; |
|
728 } |
|
729 break; |
|
730 case Phonon::VideoWidget::FitInView: |
|
731 default: |
|
732 if (frameHeight > widgetHeight){ |
|
733 frameWidth *= float(widgetHeight) / float(frameHeight); |
|
734 frameHeight = widgetHeight; |
|
735 } |
|
736 break; |
|
737 } |
|
738 |
|
739 m_drawFrameRect.setSize(QSize(frameWidth, frameHeight)); |
|
740 m_drawFrameRect.moveTo((widgetWidth - frameWidth) / 2.0f, (widgetHeight - frameHeight) / 2.0f); |
|
741 |
|
742 if (m_renderDrawWidget) |
|
743 m_renderDrawWidget->setDrawFrameRect(m_drawFrameRect); |
|
744 } |
|
745 |
|
746 QRect scaleToAspect(QRect srcRect, int w, int h) |
|
747 { |
|
748 int width = srcRect.width(); |
|
749 int height = srcRect.width() * (float(h) / float(w)); |
|
750 if (height > srcRect.height()){ |
|
751 height = srcRect.height(); |
|
752 width = srcRect.height() * (float(w) / float(h)); |
|
753 } |
|
754 return QRect(0, 0, width, height); |
|
755 } |
|
756 }; |
|
757 |
|
758 ///////////////////////////////////////////////////////////////////////////////////////// |
|
759 |
|
760 VideoWidget::VideoWidget(QObject *parent) : MediaNode(VideoSink, parent) |
|
761 { |
|
762 m_videoRenderWidget = new VideoRenderWidget(); |
|
763 } |
|
764 |
|
765 VideoWidget::~VideoWidget() |
|
766 { |
|
767 delete m_videoRenderWidget; |
|
768 } |
|
769 |
|
770 QWidget *VideoWidget::widget() |
|
771 { |
|
772 IMPLEMENTED; |
|
773 return m_videoRenderWidget; |
|
774 } |
|
775 |
|
776 Phonon::VideoWidget::AspectRatio VideoWidget::aspectRatio() const |
|
777 { |
|
778 IMPLEMENTED; |
|
779 return m_videoRenderWidget->m_aspect; |
|
780 } |
|
781 |
|
782 void VideoWidget::setAspectRatio(Phonon::VideoWidget::AspectRatio aspect) |
|
783 { |
|
784 IMPLEMENTED; |
|
785 m_videoRenderWidget->setAspectRatio(aspect); |
|
786 } |
|
787 |
|
788 Phonon::VideoWidget::ScaleMode VideoWidget::scaleMode() const |
|
789 { |
|
790 IMPLEMENTED; |
|
791 return m_videoRenderWidget->m_scaleMode; |
|
792 } |
|
793 |
|
794 void VideoWidget::setScaleMode(Phonon::VideoWidget::ScaleMode scaleMode) |
|
795 { |
|
796 IMPLEMENTED; |
|
797 m_videoRenderWidget->setScaleMode(scaleMode); |
|
798 } |
|
799 |
|
800 qreal VideoWidget::brightness() const |
|
801 { |
|
802 IMPLEMENTED; |
|
803 return m_videoRenderWidget->m_brightness; |
|
804 } |
|
805 |
|
806 void VideoWidget::setBrightness(qreal value) |
|
807 { |
|
808 IMPLEMENTED; |
|
809 m_videoRenderWidget->m_brightness = value; |
|
810 if (m_owningMediaObject && m_owningMediaObject->state() == Phonon::PausedState) |
|
811 m_videoRenderWidget->updateVideoFrame(); |
|
812 } |
|
813 |
|
814 qreal VideoWidget::contrast() const |
|
815 { |
|
816 IMPLEMENTED; |
|
817 return m_videoRenderWidget->m_contrast; |
|
818 } |
|
819 |
|
820 void VideoWidget::setContrast(qreal value) |
|
821 { |
|
822 IMPLEMENTED; |
|
823 m_videoRenderWidget->m_contrast = value; |
|
824 if (m_owningMediaObject && m_owningMediaObject->state() == Phonon::PausedState) |
|
825 m_videoRenderWidget->updateVideoFrame(); |
|
826 } |
|
827 |
|
828 qreal VideoWidget::hue() const |
|
829 { |
|
830 IMPLEMENTED; |
|
831 return m_videoRenderWidget->m_hue; |
|
832 } |
|
833 |
|
834 void VideoWidget::setHue(qreal value) |
|
835 { |
|
836 IMPLEMENTED; |
|
837 m_videoRenderWidget->m_hue = value; |
|
838 if (m_owningMediaObject && m_owningMediaObject->state() == Phonon::PausedState) |
|
839 m_videoRenderWidget->updateVideoFrame(); |
|
840 } |
|
841 |
|
842 qreal VideoWidget::saturation() const |
|
843 { |
|
844 IMPLEMENTED; |
|
845 return m_videoRenderWidget->m_saturation; |
|
846 } |
|
847 |
|
848 void VideoWidget::setSaturation(qreal value) |
|
849 { |
|
850 IMPLEMENTED; |
|
851 m_videoRenderWidget->m_saturation = value; |
|
852 if (m_owningMediaObject && m_owningMediaObject->state() == Phonon::PausedState) |
|
853 m_videoRenderWidget->updateVideoFrame(); |
|
854 } |
|
855 |
|
856 void VideoWidget::mediaNodeEvent(const MediaNodeEvent *event) |
|
857 { |
|
858 switch (event->type()){ |
|
859 case MediaNodeEvent::VideoFrameSizeChanged: |
|
860 m_videoRenderWidget->setMovieRect(*static_cast<QRect *>(event->data())); |
|
861 break; |
|
862 case MediaNodeEvent::VideoOutputCountChanged: |
|
863 m_videoRenderWidget->updateVideoOutputCount(*static_cast<int *>(event->data())); |
|
864 break; |
|
865 case MediaNodeEvent::MediaPlaying: |
|
866 m_videoRenderWidget->setMovieIsPaused(!(*static_cast<bool *>(event->data()))); |
|
867 break; |
|
868 default: |
|
869 break; |
|
870 } |
|
871 } |
|
872 |
|
873 void VideoWidget::updateVideo(VideoFrame &frame){ |
|
874 PhononAutoReleasePool pool; |
|
875 m_videoRenderWidget->setVideoFrame(frame); |
|
876 MediaNode::updateVideo(frame); |
|
877 } |
|
878 |
|
879 }} // namespace Phonon::QT7 |
|
880 |
|
881 QT_END_NAMESPACE |
|
882 |
|
883 #include "moc_videowidget.cpp" |