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 <coecntrl.h> // for CCoeControl
20
21
#include <QApplication>    // for QApplication::activeWindow
22
#include <QtCore/private/qcore_symbian_p.h> // for qt_TRect2QRect
23
24
#include "utils.h"
25
#include "videooutput_dsa.h"
26
#include "videoplayer_dsa.h"
27
28
QT_BEGIN_NAMESPACE
29
30
using namespace Phonon;
31
using namespace Phonon::MMF;
32
33
// Two-phase constructor idiom is used because construct() calls virtual
34
// functions and therefore cannot be called from the AbstractVideoPlayer
35
// C++ constructor.
36
DsaVideoPlayer* DsaVideoPlayer::create(MediaObject *parent,
37
                                       const AbstractPlayer *player)
38
{
39
    QScopedPointer<DsaVideoPlayer> self(new DsaVideoPlayer(parent, player));
40
    self->construct();
41
    return self.take();
42
}
43
44
DsaVideoPlayer::DsaVideoPlayer(MediaObject *parent, const AbstractPlayer *player)
45
    :   AbstractVideoPlayer(parent, player)
46
    ,   m_dsaActive(false)
47
    ,   m_dsaWasActive(false)
48
{
49
50
}
51
52
DsaVideoPlayer::~DsaVideoPlayer()
53
{
54
55
}
56
57
58
//-----------------------------------------------------------------------------
59
// Public functions
60
//-----------------------------------------------------------------------------
61
62
void MMF::DsaVideoPlayer::videoWindowScreenRectChanged()
63
{
64
    Q_ASSERT(m_videoOutput);
65
66
    QRect windowRect = static_cast<DsaVideoOutput *>(m_videoOutput)->videoWindowScreenRect();
67
68
    // Clip to physical window size
69
    // This is due to a defect in the layout when running on S60 3.2, which
70
    // results in the rectangle of the video widget extending outside the
71
    // screen in certain circumstances.  These include the initial startup
72
    // of the mediaplayer demo in portrait mode.  When this rectangle is
73
    // passed to the CVideoPlayerUtility, no video is rendered.
74
    const TSize screenSize = m_screenDevice.SizeInPixels();
75
    const QRect screenRect(0, 0, screenSize.iWidth, screenSize.iHeight);
76
    windowRect = windowRect.intersected(screenRect);
77
78
    // Recalculate scale factors.  Pass 'false' as second parameter in order to
79
    // suppress application of the change to the player - this is done at the end
80
    // of the function.
81
    updateScaleFactors(windowRect.size(), false);
82
83
    m_videoScreenRect = qt_QRect2TRect(windowRect);
84
85
    parametersChanged(WindowScreenRect | ScaleFactors);
86
}
87
88
void MMF::DsaVideoPlayer::suspendDirectScreenAccess()
89
{
90
    m_dsaWasActive = stopDirectScreenAccess();
91
}
92
93
void MMF::DsaVideoPlayer::resumeDirectScreenAccess()
94
{
95
    if (m_dsaWasActive) {
96
        startDirectScreenAccess();
97
        m_dsaWasActive = false;
98
    }
99
}
100
101
102
//-----------------------------------------------------------------------------
103
// Private functions
104
//-----------------------------------------------------------------------------
105
106
void MMF::DsaVideoPlayer::createPlayer()
107
{
108
    // A window handle must be provided in order to construct
109
    // CVideoPlayerUtility.  If no VideoOutput has yet been connected to this
110
    // player, we temporarily use the top-level application window handle.
111
    // No video ever gets rendered into this window; SetDisplayWindowL is
112
    // always called before rendering actually begins.
113
    if (!m_window)
114
        m_window = QApplication::activeWindow()->effectiveWinId()->DrawableWindow();
115
116
    const TInt priority = 0;
117
    const TMdaPriorityPreference preference = EMdaPriorityPreferenceNone;
118
119
    CVideoPlayerUtility *player = 0;
120
    QT_TRAP_THROWING(player = CVideoPlayerUtility::NewL(*this,
121
                                     priority, preference,
122
                                     m_wsSession, m_screenDevice,
123
                                     *m_window,
124
                                     m_videoScreenRect, m_videoScreenRect));
125
    m_player.reset(player);
126
127
    // CVideoPlayerUtility::NewL starts DSA
128
    m_dsaActive = true;
129
}
130
131
void MMF::DsaVideoPlayer::initVideoOutput()
132
{
133
    Q_ASSERT(m_videoOutput);
134
135
    bool connected = connect(
136
        m_videoOutput, SIGNAL(videoWindowScreenRectChanged()),
137
        this, SLOT(videoWindowScreenRectChanged())
138
    );
139
    Q_ASSERT(connected);
140
141
    connected = connect(
142
        m_videoOutput, SIGNAL(beginVideoWindowNativePaint()),
143
        this, SLOT(suspendDirectScreenAccess())
144
    );
145
    Q_ASSERT(connected);
146
147
    connected = connect(
148
        m_videoOutput, SIGNAL(endVideoWindowNativePaint()),
149
        this, SLOT(resumeDirectScreenAccess())
150
    );
151
    Q_ASSERT(connected);
152
153
    // Suppress warnings in release builds
154
    Q_UNUSED(connected);
155
156
    AbstractVideoPlayer::initVideoOutput();
157
}
158
159
void MMF::DsaVideoPlayer::prepareCompleted()
160
{
161
    if (m_videoOutput)
162
        videoWindowScreenRectChanged();
163
}
164
165
void MMF::DsaVideoPlayer::handleVideoWindowChanged()
166
{
167
    if (!m_window) {
168
        if (QWidget *window = QApplication::activeWindow())
169
            m_window = window->effectiveWinId()->DrawableWindow();
170
        else
171
            m_window = 0;
172
        m_videoScreenRect = TRect();
173
    }
174
175
    parametersChanged(WindowHandle | WindowScreenRect);
176
}
177
178
#ifndef QT_NO_DEBUG
179
180
// The following code is for debugging problems related to video visibility.  It allows
181
// the VideoPlayer instance to query the window server in order to determine the
182
// DSA drawing region for the video window.
183
184
class CDummyAO : public CActive
185
{
186
public:
187
    CDummyAO() : CActive(CActive::EPriorityStandard) { CActiveScheduler::Add(this); }
188
    void RunL() { }
189
    void DoCancel() { }
190
    TRequestStatus& Status() { return iStatus; }
191
    void SetActive() { CActive::SetActive(); }
192
};
193
194
void getDsaRegion(RWsSession &session, const RWindowBase &window)
195
{
196
    // Dump complete window tree
197
    session.LogCommand(RWsSession::ELoggingStatusDump);
198
199
    RDirectScreenAccess dsa(session);
200
    TInt err = dsa.Construct();
201
    CDummyAO ao;
202
    RRegion* region;
203
    err = dsa.Request(region, ao.Status(), window);
204
    ao.SetActive();
205
    dsa.Close();
206
    ao.Cancel();
207
    if (region) {
208
        qDebug() << "Phonon::MMF::getDsaRegion count" << region->Count();
209
        for (int i=0; i<region->Count(); ++i) {
210
            const TRect& rect = region->RectangleList()[i];
211
            qDebug() << "Phonon::MMF::getDsaRegion rect"
212
                << rect.iTl.iX << rect.iTl.iY << rect.iBr.iX << rect.iBr.iY;
213
        }
214
        region->Close();
215
    }
216
}
217
218
#endif // QT_NO_DEBUG
219
220
void MMF::DsaVideoPlayer::handleParametersChanged(VideoParameters parameters)
221
{
222
    TRACE_CONTEXT(DsaVideoPlayer::handleParametersChanged, EVideoInternal);
223
    TRACE_ENTRY("parameters 0x%x", parameters.operator int());
224
225
    if (!m_window)
226
        return;
227
228
#ifndef QT_NO_DEBUG
229
    getDsaRegion(m_wsSession, *m_window);
230
#endif
231
232
    if (m_player) {
233
        static const TBool antialias = ETrue;
234
        int err = KErrNone;
235
236
        if (parameters & ScaleFactors) {
237
            TRAP(err, m_player->SetScaleFactorL(m_scaleWidth, m_scaleHeight,
238
                                                antialias));
239
            if(KErrNone != err) {
240
                TRACE("SetScaleFactorL (1) err %d", err);
241
                setError(tr("Video display error"), err);
242
            }
243
        }
244
245
        if (KErrNone == err) {
246
            if (parameters & WindowHandle || parameters & WindowScreenRect) {
247
                TRAP(err,
248
                    m_player->SetDisplayWindowL(m_wsSession, m_screenDevice,
249
                                                *m_window,
250
                                                m_videoScreenRect,
251
                                                m_videoScreenRect));
252
            }
253
254
            if (KErrNone != err) {
255
                TRACE("SetDisplayWindowL err %d", err);
256
                setError(tr("Video display error"), err);
257
            } else {
258
                m_dsaActive = true;
259
                if (parameters & ScaleFactors) {
260
                    TRAP(err, m_player->SetScaleFactorL(m_scaleWidth, m_scaleHeight,
261
                                                        antialias));
262
                    if (KErrNone != err) {
263
                        TRACE("SetScaleFactorL (2) err %d", err);
264
                        setError(tr("Video display error"), err);
265
                    }
266
                }
267
            }
268
        }
269
    }
270
271
    TRACE_EXIT_0();
272
}
273
274
void MMF::DsaVideoPlayer::startDirectScreenAccess()
275
{
276
    TRACE_CONTEXT(DsaVideoPlayer::startDirectScreenAccess, EVideoInternal);
277
    TRACE_ENTRY("dsaActive %d", m_dsaActive);
278
279
    int err = KErrNone;
280
281
    if (!m_dsaActive) {
282
        TRAP(err, m_player->StartDirectScreenAccessL());
283
        if (KErrNone == err)
284
            m_dsaActive = true;
285
        else
286
            setError(tr("Video display error"), err);
287
    }
288
289
    if (m_videoOutput)
290
        m_videoOutput->dump();
291
292
    TRACE_EXIT("error %d", err);
293
}
294
295
bool MMF::DsaVideoPlayer::stopDirectScreenAccess()
296
{
297
    TRACE_CONTEXT(DsaVideoPlayer::stopDirectScreenAccess, EVideoInternal);
298
    TRACE_ENTRY("dsaActive %d", m_dsaActive);
299
300
    int err = KErrNone;
301
302
    const bool dsaWasActive = m_dsaActive;
303
    if (m_dsaActive) {
304
        TRAP(err, m_player->StopDirectScreenAccessL());
305
        if (KErrNone == err)
306
            m_dsaActive = false;
307
        else
308
            setError(tr("Video display error"), err);
309
    }
310
311
    TRACE_EXIT("error %d", err);
312
313
    return dsaWasActive;
314
}
315
316
QT_END_NAMESPACE