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
206VIDEO_TRANSPARENT(mouseDown);
207VIDEO_TRANSPARENT(mouseDragged);
208VIDEO_TRANSPARENT(mouseUp);
209VIDEO_TRANSPARENT(mouseMoved);
210VIDEO_TRANSPARENT(mouseEntered);
211VIDEO_TRANSPARENT(mouseExited);
212VIDEO_TRANSPARENT(rightMouseDown);
213VIDEO_TRANSPARENT(rightMouseDragged);
214VIDEO_TRANSPARENT(rightMouseUp);
215VIDEO_TRANSPARENT(otherMouseDown);
216VIDEO_TRANSPARENT(otherMouseDragged);
217VIDEO_TRANSPARENT(otherMouseUp);
218VIDEO_TRANSPARENT(keyDown);
219VIDEO_TRANSPARENT(keyUp);
220VIDEO_TRANSPARENT(scrollWheel)
221
222@end
223
224#endif // QT_MAC_USE_COCOA
225
226/////////////////////////////////////////////////////////////////////////////////////////
227
228QT_BEGIN_NAMESPACE
229
230namespace Phonon
231{
232namespace QT7
233{
234
235class IVideoRenderDrawWidget
236{
237public:
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
247QGLWidget *PhononSharedQGLWidget(){
248	static QGLWidget *glWidget = 0;
249	if (!glWidget)
250		glWidget = new QGLWidget();
251	return glWidget;
252}
253
254/////////////////////////////////////////////////////////////////////////////////////////
255
256class RenderOpenGL : public QGLWidget, public IVideoRenderDrawWidget
257{
258public:
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        glOrtho(0, GLsizei(w), 0, GLsizei(h), -1, 1);
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
307class RenderQTMovieView : public QWidget, public IVideoRenderDrawWidget
308{
309public:
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
419class RenderQTMovieLayer : public QWidget, public IVideoRenderDrawWidget
420{
421public:
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        CGRect frame = m_movieLayer.frame;
450        frame.origin.x = rect.x();
451        frame.origin.y = rect.y();
452        frame.size.width = rect.width();
453        frame.size.height = rect.height();
454        m_movieLayer.frame = frame;
455    }
456
457#else // QT_MAC_USE_COCOA == false
458	RenderQTMovieLayer(QWidget *, const QSize&){}
459	void setVideoFrame(VideoFrame &){}
460	void setDrawFrameRect(const QRect &){}
461#endif
462};
463
464/////////////////////////////////////////////////////////////////////////////////////////
465
466class VideoRenderWidget : public QWidget
467{
468public:
469    enum RenderSystem {	RS_NoRendering	= 0,
470						RS_QGLWidget	= 1,
471						RS_QPainter		= 2,
472						RS_CIImage		= 3,
473						RS_CVTexture	= 4,
474						RS_QImage		= 5,
475						RS_QTMovieView	= 6,
476						RS_QTMovieLayer = 7
477	} m_renderSystem;
478
479    VideoFrame m_currentFrame;
480    QRect m_movieFrameRect;
481    QRect m_drawFrameRect;
482    Phonon::VideoWidget::ScaleMode m_scaleMode;
483    Phonon::VideoWidget::AspectRatio m_aspect;
484	IVideoRenderDrawWidget *m_renderDrawWidget;
485
486    qreal m_brightness;
487    qreal m_contrast;
488    qreal m_hue;
489    qreal m_saturation;
490    qreal m_opacity;
491
492    VideoRenderWidget() : QWidget(0),
493        m_scaleMode(Phonon::VideoWidget::FitInView), m_aspect(Phonon::VideoWidget::AspectRatioAuto)
494    {
495		PhononAutoReleasePool pool;
496        m_brightness = 0;
497        m_contrast = 0;
498        m_hue = 0;
499        m_saturation = 0;
500        m_opacity = 1;
501		m_renderDrawWidget = 0;
502		m_renderSystem = RS_NoRendering;
503
504        setAutoFillBackground(false);
505        updateDrawFrameRect();
506    }
507
508    RenderSystem selectBestRenderSystem(){
509        if (!isVisible())
510            return RS_NoRendering;
511        else if (window() && window()->testAttribute(Qt::WA_DontShowOnScreen))
512            return RS_QPainter;
513        else {
514#ifdef QUICKTIME_C_API_AVAILABLE
515            return RS_QGLWidget;
516#else
517            return RS_QTMovieView;
518#endif
519        }
520    }
521
522    void setRenderSystem(RenderSystem renderSystem){
523		PhononAutoReleasePool pool;
524		static QString userSystem = qgetenv("PHONON_RENDER_SYSTEM");
525	    if (!userSystem.isEmpty())
526			renderSystem = RenderSystem(userSystem.toInt());
527
528        if (m_renderSystem == renderSystem)
529            return;
530
531        m_renderSystem = renderSystem;
532        if (m_renderDrawWidget){
533            delete m_renderDrawWidget;
534			m_renderDrawWidget = 0;
535		}
536
537        switch (m_renderSystem){
538            case RS_QGLWidget:{
539			    QGLFormat format = QGLFormat::defaultFormat();
540			    format.setSwapInterval(1); // Vertical sync (avoid tearing)
541			    m_renderDrawWidget = new RenderOpenGL(this, format, size());
542                break;}
543            case RS_QTMovieView:{
544			    m_renderDrawWidget = new RenderQTMovieView(false, this, size());
545                break;}
546            case RS_QTMovieLayer:{
547			    m_renderDrawWidget = new RenderQTMovieLayer(this, size());
548				break;}
549            case RS_QPainter:
550			case RS_CIImage:
551			case RS_CVTexture:
552			case RS_QImage:
553#ifndef QUICKTIME_C_API_AVAILABLE
554                // On cocoa-64, let QTMovieView produce
555                // video frames for us:
556				m_renderDrawWidget = new RenderQTMovieView(true, this);
557#endif
558				break;
559            case RS_NoRendering:
560                break;
561        }
562
563		if (m_renderDrawWidget){
564            m_renderDrawWidget->setVideoFrame(m_currentFrame);
565            m_renderDrawWidget->setDrawFrameRect(m_drawFrameRect);
566        }
567    }
568
569    QSize sizeHint() const
570    {
571        return m_movieFrameRect.size();
572    }
573
574    bool event(QEvent *event)
575    {
576        switch (event->type()){
577            // Try to detect if one of this objects
578            // anchestors might have changed:
579            case QEvent::Resize:{
580                PhononAutoReleasePool pool;
581                updateDrawFrameRect();
582                if (m_renderDrawWidget)
583                    dynamic_cast<QWidget *>(m_renderDrawWidget)->resize(size());
584                break; }
585            case QEvent::Paint:{
586                PhononAutoReleasePool pool;
587                float opacity = parentWidget() ? parentWidget()->windowOpacity() : 1;
588                switch (m_renderSystem){
589                    case RS_QPainter:{
590                        QPainter p(this);
591                        p.fillRect(rect(), Qt::black);
592                        if (p.paintEngine()->type() == QPaintEngine::OpenGL)
593                            m_currentFrame.drawCVTexture(m_drawFrameRect, opacity);
594                        else
595							m_currentFrame.drawQImage(&p, m_drawFrameRect);
596                        break; }
597					case RS_CIImage:
598                        m_currentFrame.drawCIImage(m_drawFrameRect, opacity);
599						break;
600                    case RS_CVTexture:
601	                   m_currentFrame.drawCVTexture(m_drawFrameRect, opacity);
602					   break;
603					case RS_QImage:{
604                        QPainter p(this);
605                        p.fillRect(rect(), Qt::black);
606						m_currentFrame.drawQImage(&p, m_drawFrameRect);
607                        break; }
608                    case RS_QGLWidget:
609                    case RS_QTMovieView:
610                    case RS_QTMovieLayer:
611                        // draw in separate widget
612                        break;
613                    case RS_NoRendering:
614                        QPainter p(this);
615                        p.fillRect(rect(), Qt::black);
616                        break;
617                }
618                break; }
619            default:
620                break;
621        }
622
623        return QWidget::event(event);
624    }
625
626    void setVideoFrame(VideoFrame &frame)
627    {
628		PhononAutoReleasePool pool;
629        m_currentFrame = frame;
630        m_currentFrame.setColors(m_brightness, m_contrast, m_hue, m_saturation);
631
632		if (m_renderDrawWidget)
633			m_renderDrawWidget->setVideoFrame(m_currentFrame);
634
635        setRenderSystem(selectBestRenderSystem());
636        switch (m_renderSystem){
637            case RS_QGLWidget:
638            case RS_QTMovieView:
639            case RS_QTMovieLayer:
640            case RS_NoRendering:
641                break;
642			case RS_CIImage:
643			case RS_CVTexture:
644			case RS_QImage:
645            case RS_QPainter:
646                repaint();
647                break;
648        }
649    }
650
651    void updateVideoFrame()
652    {
653        setVideoFrame(m_currentFrame);
654    }
655
656    void setMovieRect(const QRect &mrect)
657    {
658        if (mrect == m_movieFrameRect)
659            return;
660        m_movieFrameRect = mrect;
661        updateDrawFrameRect();
662        updateGeometry();
663        if (isVisible())
664            qApp->processEvents(QEventLoop::ExcludeUserInputEvents | QEventLoop::ExcludeSocketNotifiers);
665    }
666
667    void setScaleMode(Phonon::VideoWidget::ScaleMode scaleMode)
668    {
669        m_scaleMode = scaleMode;
670        updateDrawFrameRect();
671        updateVideoFrame();
672        repaint();
673    }
674
675    void setAspectRatio(Phonon::VideoWidget::AspectRatio aspect)
676    {
677        m_aspect = aspect;
678        updateDrawFrameRect();
679        updateVideoFrame();
680        repaint();
681    }
682
683	void updateVideoOutputCount(int count)
684	{
685		if (m_renderDrawWidget)
686			m_renderDrawWidget->updateVideoOutputCount(count);
687	}
688
689	void setMovieIsPaused(bool paused)
690	{
691		if (m_renderDrawWidget)
692			m_renderDrawWidget->setMovieIsPaused(paused);
693	}
694
695    void updateDrawFrameRect()
696    {
697        if (m_movieFrameRect.width() <= 0 || m_movieFrameRect.height() <= 0)
698            m_movieFrameRect = QRect(0, 0, 640, 480);
699
700        // Set m_drawFrameRect to be the size of the smallest possible
701        // rect conforming to the aspect and containing the whole frame:
702        switch(m_aspect){
703        case Phonon::VideoWidget::AspectRatioWidget:
704            m_drawFrameRect = rect();
705            break;
706        case Phonon::VideoWidget::AspectRatio4_3:
707            m_drawFrameRect = scaleToAspect(m_movieFrameRect, 4, 3);
708            break;
709        case Phonon::VideoWidget::AspectRatio16_9:
710            m_drawFrameRect = scaleToAspect(m_movieFrameRect, 16, 9);
711            break;
712        case Phonon::VideoWidget::AspectRatioAuto:
713        default:
714            m_drawFrameRect = m_movieFrameRect;
715            break;
716        }
717
718        // Scale m_drawFrameRect to fill the widget
719        // without breaking aspect:
720        int widgetWidth = rect().width();
721        int widgetHeight = rect().height();
722        int frameWidth = widgetWidth;
723        int frameHeight = m_drawFrameRect.height() * float(widgetWidth) / float(m_drawFrameRect.width());
724
725        switch(m_scaleMode){
726        case Phonon::VideoWidget::ScaleAndCrop:
727            if (frameHeight < widgetHeight){
728                frameWidth *= float(widgetHeight) / float(frameHeight);
729                frameHeight = widgetHeight;
730            }
731            break;
732        case Phonon::VideoWidget::FitInView:
733        default:
734            if (frameHeight > widgetHeight){
735                frameWidth *= float(widgetHeight) / float(frameHeight);
736                frameHeight = widgetHeight;
737            }
738            break;
739        }
740
741        m_drawFrameRect.setSize(QSize(frameWidth, frameHeight));
742        m_drawFrameRect.moveTo((widgetWidth - frameWidth) / 2.0f, (widgetHeight - frameHeight) / 2.0f);
743
744		if (m_renderDrawWidget)
745			m_renderDrawWidget->setDrawFrameRect(m_drawFrameRect);
746    }
747
748    QRect scaleToAspect(QRect srcRect, int w, int h)
749    {
750        int width = srcRect.width();
751        int height = srcRect.width() * (float(h) / float(w));
752        if (height > srcRect.height()){
753            height = srcRect.height();
754            width = srcRect.height() * (float(w) / float(h));
755        }
756        return QRect(0, 0, width, height);
757    }
758};
759
760/////////////////////////////////////////////////////////////////////////////////////////
761
762VideoWidget::VideoWidget(QObject *parent) : MediaNode(VideoSink, parent)
763{
764    m_videoRenderWidget = new VideoRenderWidget();
765}
766
767VideoWidget::~VideoWidget()
768{
769    delete m_videoRenderWidget;
770}
771
772QWidget *VideoWidget::widget()
773{
774    IMPLEMENTED;
775    return m_videoRenderWidget;
776}
777
778Phonon::VideoWidget::AspectRatio VideoWidget::aspectRatio() const
779{
780    IMPLEMENTED;
781    return  m_videoRenderWidget->m_aspect;
782}
783
784void VideoWidget::setAspectRatio(Phonon::VideoWidget::AspectRatio aspect)
785{
786    IMPLEMENTED;
787    m_videoRenderWidget->setAspectRatio(aspect);
788}
789
790Phonon::VideoWidget::ScaleMode VideoWidget::scaleMode() const
791{
792    IMPLEMENTED;
793    return m_videoRenderWidget->m_scaleMode;
794}
795
796void VideoWidget::setScaleMode(Phonon::VideoWidget::ScaleMode scaleMode)
797{
798    IMPLEMENTED;
799    m_videoRenderWidget->setScaleMode(scaleMode);
800}
801
802qreal VideoWidget::brightness() const
803{
804    IMPLEMENTED;
805    return m_videoRenderWidget->m_brightness;
806}
807
808void VideoWidget::setBrightness(qreal value)
809{
810    IMPLEMENTED;
811    m_videoRenderWidget->m_brightness = value;
812    if (m_owningMediaObject && m_owningMediaObject->state() == Phonon::PausedState)
813        m_videoRenderWidget->updateVideoFrame();
814}
815
816qreal VideoWidget::contrast() const
817{
818    IMPLEMENTED;
819    return m_videoRenderWidget->m_contrast;
820}
821
822void VideoWidget::setContrast(qreal value)
823{
824    IMPLEMENTED;
825    m_videoRenderWidget->m_contrast = value;
826    if (m_owningMediaObject && m_owningMediaObject->state() == Phonon::PausedState)
827        m_videoRenderWidget->updateVideoFrame();
828}
829
830qreal VideoWidget::hue() const
831{
832    IMPLEMENTED;
833    return m_videoRenderWidget->m_hue;
834}
835
836void VideoWidget::setHue(qreal value)
837{
838    IMPLEMENTED;
839    m_videoRenderWidget->m_hue = value;
840    if (m_owningMediaObject && m_owningMediaObject->state() == Phonon::PausedState)
841        m_videoRenderWidget->updateVideoFrame();
842}
843
844qreal VideoWidget::saturation() const
845{
846    IMPLEMENTED;
847    return m_videoRenderWidget->m_saturation;
848}
849
850void VideoWidget::setSaturation(qreal value)
851{
852    IMPLEMENTED;
853    m_videoRenderWidget->m_saturation = value;
854    if (m_owningMediaObject && m_owningMediaObject->state() == Phonon::PausedState)
855        m_videoRenderWidget->updateVideoFrame();
856}
857
858void VideoWidget::mediaNodeEvent(const MediaNodeEvent *event)
859{
860    switch (event->type()){
861    case MediaNodeEvent::VideoFrameSizeChanged:
862        m_videoRenderWidget->setMovieRect(*static_cast<QRect *>(event->data()));
863        break;
864	case MediaNodeEvent::VideoOutputCountChanged:
865	     m_videoRenderWidget->updateVideoOutputCount(*static_cast<int *>(event->data()));
866	     break;
867	case MediaNodeEvent::MediaPlaying:
868	     m_videoRenderWidget->setMovieIsPaused(!(*static_cast<bool *>(event->data())));
869	     break;
870	default:
871        break;
872    }
873}
874
875void VideoWidget::updateVideo(VideoFrame &frame){
876	PhononAutoReleasePool pool;
877    m_videoRenderWidget->setVideoFrame(frame);
878    MediaNode::updateVideo(frame);
879}
880
881}} // namespace Phonon::QT7
882
883QT_END_NAMESPACE
884
885#include "moc_videowidget.cpp"
886