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 "videowidget.h"
19
#include "x11renderer.h"
20
21
#ifndef Q_WS_QWS
22
23
#include <QtGui/QPalette>
24
#include <QtGui/QApplication>
25
#include <QtGui/QPainter>
26
#include <X11/Xlib.h>
27
#include <gst/gst.h>
28
#include <gst/interfaces/xoverlay.h>
29
#include <gst/interfaces/propertyprobe.h>
30
#include "common.h"
31
#include "mediaobject.h"
32
#include "message.h"
33
34
QT_BEGIN_NAMESPACE
35
36
namespace Phonon
37
{
38
namespace Gstreamer
39
{
40
41
class OverlayWidget : public QWidget
42
{
43
public:
44
    OverlayWidget(VideoWidget *videoWidget, X11Renderer *renderer) : 
45
                  QWidget(videoWidget), 
46
                  m_videoWidget(videoWidget), 
47
                  m_renderer(renderer) { }
48
    void paintEvent(QPaintEvent *) {
49
        Phonon::State state = m_videoWidget->root() ? m_videoWidget->root()->state() : Phonon::LoadingState;
50
        if (state == Phonon::PlayingState || state == Phonon::PausedState) {
51
            m_renderer->windowExposed();
52
        } else {
53
            QPainter painter(this);
54
            painter.fillRect(m_videoWidget->rect(), m_videoWidget->palette().background());
55
        }
56
    }
57
private:
58
    VideoWidget *m_videoWidget;
59
    X11Renderer *m_renderer;
60
};
61
62
X11Renderer::X11Renderer(VideoWidget *videoWidget)
63
        : AbstractRenderer(videoWidget)
64
{
65
    m_renderWidget = new OverlayWidget(videoWidget, this);
66
    videoWidget->backend()->logMessage("Creating X11 overlay renderer");
67
    QPalette palette;
68
    palette.setColor(QPalette::Background, Qt::black);
69
    m_videoWidget->setPalette(palette);
70
    m_videoWidget->setAutoFillBackground(true);
71
    m_renderWidget->setMouseTracking(true);
72
    m_videoSink = createVideoSink();
73
    aspectRatioChanged(videoWidget->aspectRatio());
74
    setOverlay();
75
}
76
77
X11Renderer::~X11Renderer()
78
{
79
    m_renderWidget->setAttribute(Qt::WA_PaintOnScreen, false);
80
    m_renderWidget->setAttribute(Qt::WA_NoSystemBackground, false);
81
    delete m_renderWidget;
82
}
83
84
GstElement* X11Renderer::createVideoSink()
85
{
86
    GstElement *videoSink = gst_element_factory_make ("xvimagesink", NULL);
87
    if (videoSink) {
88
        // Check if the xv sink is usable
89
        if (gst_element_set_state(videoSink, GST_STATE_READY) != GST_STATE_CHANGE_SUCCESS) {
90
            gst_object_unref(GST_OBJECT(videoSink));
91
            videoSink = 0;
92
        } else {
93
            // Note that this should not really be necessary as these are
94
            // default values, though under certain conditions values are retained
95
            // even between application instances. (reproducible on 0.10.16/Gutsy)
96
            g_object_set(G_OBJECT(videoSink), "brightness", 0, (const char*)NULL);
97
            g_object_set(G_OBJECT(videoSink), "contrast", 0, (const char*)NULL);
98
            g_object_set(G_OBJECT(videoSink), "hue", 0, (const char*)NULL);
99
            g_object_set(G_OBJECT(videoSink), "saturation", 0, (const char*)NULL);
100
        }
101
    }
102
103
    if (!videoSink)
104
        videoSink = gst_element_factory_make ("ximagesink", NULL);
105
106
    gst_object_ref (GST_OBJECT (videoSink)); //Take ownership
107
    gst_object_sink (GST_OBJECT (videoSink));
108
109
    return videoSink;
110
}
111
112
void X11Renderer::handleMediaNodeEvent(const MediaNodeEvent *event)
113
{
114
    switch (event->type()) {
115
    case MediaNodeEvent::SourceChanged:
116
        setOverlay(); // We need to do this whenever the pipeline is reset
117
        break;        // otherwise the videosink will open in its own window
118
    default:
119
        break;
120
    }
121
}
122
123
124
void X11Renderer::aspectRatioChanged(Phonon::VideoWidget::AspectRatio)
125
{
126
    if (m_renderWidget) {
127
        m_renderWidget->setGeometry(m_videoWidget->calculateDrawFrameRect());
128
    }
129
}
130
131
void X11Renderer::scaleModeChanged(Phonon::VideoWidget::ScaleMode)
132
{
133
    if (m_renderWidget) {
134
        m_renderWidget->setGeometry(m_videoWidget->calculateDrawFrameRect());
135
    }
136
}
137
138
void X11Renderer::movieSizeChanged(const QSize &movieSize)
139
{
140
    Q_UNUSED(movieSize);
141
142
    if (m_renderWidget) {
143
        m_renderWidget->setGeometry(m_videoWidget->calculateDrawFrameRect());
144
    }
145
}
146
147
bool X11Renderer::eventFilter(QEvent *e)
148
{
149
    if (e->type() == QEvent::Show) {
150
        // Setting these values ensures smooth resizing since it
151
        // will prevent the system from clearing the background
152
        m_renderWidget->setAttribute(Qt::WA_NoSystemBackground, true);
153
        m_renderWidget->setAttribute(Qt::WA_PaintOnScreen, true);
154
        setOverlay();
155
    } else if (e->type() == QEvent::Resize) {
156
        // This is a workaround for missing background repaints
157
        // when reducing window size
158
        m_renderWidget->setGeometry(m_videoWidget->calculateDrawFrameRect());
159
        windowExposed();
160
    }
161
    return false;
162
}
163
164
void X11Renderer::handlePaint(QPaintEvent *)
165
{
166
    QPainter painter(m_videoWidget);
167
    painter.fillRect(m_videoWidget->rect(), m_videoWidget->palette().background());
168
}
169
170
void X11Renderer::setOverlay()
171
{
172
    if (m_videoSink && GST_IS_X_OVERLAY(m_videoSink)) {
173
        WId windowId = m_renderWidget->winId();
174
        // Even if we have created a winId at this point, other X applications
175
        // need to be aware of it.
176
        QApplication::syncX();
177
        gst_x_overlay_set_xwindow_id ( GST_X_OVERLAY(m_videoSink) ,  windowId );
178
    }
179
    windowExposed();
180
    m_overlaySet = true;
181
}
182
183
void X11Renderer::windowExposed()
184
{
185
    QApplication::syncX();
186
    if (m_videoSink && GST_IS_X_OVERLAY(m_videoSink))
187
        gst_x_overlay_expose(GST_X_OVERLAY(m_videoSink));
188
}
189
190
}
191
} //namespace Phonon::Gstreamer
192
193
QT_END_NAMESPACE
194
195
#endif // Q_WS_QWS