1
/* This file is part of the KDE project.
3
Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
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.
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.
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/>.
19
#include <QApplication> // for QApplication::activeWindow
24
#include <coemain.h> // for CCoeEnv
27
#include "mmf_videoplayer.h"
31
#include "objectdump.h"
36
using namespace Phonon;
37
using namespace Phonon::MMF;
39
/*! \class MMF::VideoPlayer
43
//-----------------------------------------------------------------------------
44
// Constructor / destructor
45
//-----------------------------------------------------------------------------
47
MMF::VideoPlayer::VideoPlayer()
52
, m_mmfOutputChangePending(false)
57
MMF::VideoPlayer::VideoPlayer(const AbstractPlayer& player)
58
: AbstractMediaPlayer(player)
63
, m_mmfOutputChangePending(false)
68
void MMF::VideoPlayer::construct()
70
TRACE_CONTEXT(VideoPlayer::VideoPlayer, EVideoApi);
74
m_videoOutput->setObserver(this);
76
const TInt priority = 0;
77
const TMdaPriorityPreference preference = EMdaPriorityPreferenceNone;
79
getNativeWindowSystemHandles();
81
// TODO: is this the correct way to handle errors which occur when
82
// creating a Symbian object in the constructor of a Qt object?
84
// TODO: check whether videoOutput is visible? If not, then the
85
// corresponding window will not be active, meaning that the
86
// clipping region will be set to empty and the video will not be
87
// visible. If this is the case, we should set m_mmfOutputChangePending
88
// and respond to future showEvents from the videoOutput widget.
91
m_player.reset(CVideoPlayerUtility::NewL
95
*m_wsSession, *m_screenDevice,
97
m_windowRect, m_clipRect
101
if (KErrNone != err) {
102
changeState(ErrorState);
108
MMF::VideoPlayer::~VideoPlayer()
110
TRACE_CONTEXT(VideoPlayer::~VideoPlayer, EVideoApi);
116
//-----------------------------------------------------------------------------
118
//-----------------------------------------------------------------------------
120
void MMF::VideoPlayer::doPlay()
122
TRACE_CONTEXT(VideoPlayer::doPlay, EVideoApi);
124
// See comment in updateMmfOutput
125
if(m_mmfOutputChangePending) {
126
TRACE_0("MMF output change pending - pushing now");
133
void MMF::VideoPlayer::doPause()
135
TRACE_CONTEXT(VideoPlayer::doPause, EVideoApi);
137
TRAPD(err, m_player->PauseL());
138
if (KErrNone != err) {
139
TRACE("PauseL error %d", err);
140
setError(NormalError);
144
void MMF::VideoPlayer::doStop()
149
void MMF::VideoPlayer::doSeek(qint64 ms)
151
TRACE_CONTEXT(VideoPlayer::doSeek, EVideoApi);
153
bool wasPlaying = false;
154
if(state() == PlayingState) {
155
// The call to SetPositionL does not have any effect if playback is
156
// ongoing, so we pause before seeking.
161
TRAPD(err, m_player->SetPositionL(TTimeIntervalMicroSeconds(ms * 1000)));
163
if(KErrNone == err) {
168
TRACE("SetPositionL error %d", err);
169
setError(NormalError);
173
int MMF::VideoPlayer::setDeviceVolume(int mmfVolume)
175
TRAPD(err, m_player->SetVolumeL(mmfVolume));
179
int MMF::VideoPlayer::openFile(RFile& file)
181
TRAPD(err, m_player->OpenFileL(file));
185
void MMF::VideoPlayer::close()
190
bool MMF::VideoPlayer::hasVideo() const
195
qint64 MMF::VideoPlayer::currentTime() const
197
TRACE_CONTEXT(VideoPlayer::currentTime, EVideoApi);
199
TTimeIntervalMicroSeconds us;
200
TRAPD(err, us = m_player->PositionL())
204
if (KErrNone == err) {
205
result = toMilliSeconds(us);
207
TRACE("PositionL error %d", err);
209
// If we don't cast away constness here, we simply have to ignore
211
const_cast<VideoPlayer*>(this)->setError(NormalError);
217
qint64 MMF::VideoPlayer::totalTime() const
223
//-----------------------------------------------------------------------------
224
// MVideoPlayerUtilityObserver callbacks
225
//-----------------------------------------------------------------------------
227
void MMF::VideoPlayer::MvpuoOpenComplete(TInt aError)
229
TRACE_CONTEXT(VideoPlayer::MvpuoOpenComplete, EVideoApi);
230
TRACE_ENTRY("state %d error %d", state(), aError);
232
__ASSERT_ALWAYS(LoadingState == state(), Utils::panic(InvalidStatePanic));
234
if (KErrNone == aError)
237
setError(NormalError);
242
void MMF::VideoPlayer::MvpuoPrepareComplete(TInt aError)
244
TRACE_CONTEXT(VideoPlayer::MvpuoPrepareComplete, EVideoApi);
245
TRACE_ENTRY("state %d error %d", state(), aError);
247
__ASSERT_ALWAYS(LoadingState == state(), Utils::panic(InvalidStatePanic));
249
TRAPD(err, doPrepareCompleteL(aError));
251
if (KErrNone == err) {
252
maxVolumeChanged(m_player->MaxVolume());
255
m_videoOutput->setFrameSize(m_frameSize);
257
// See comment in updateMmfOutput
258
if(m_mmfOutputChangePending) {
259
TRACE_0("MMF output change pending - pushing now");
263
emit totalTimeChanged(totalTime());
264
changeState(StoppedState);
266
setError(NormalError);
272
void MMF::VideoPlayer::doPrepareCompleteL(TInt aError)
274
User::LeaveIfError(aError);
278
m_player->VideoFrameSizeL(size);
279
m_frameSize = QSize(size.iWidth, size.iHeight);
282
m_totalTime = toMilliSeconds(m_player->DurationL());
286
void MMF::VideoPlayer::MvpuoFrameReady(CFbsBitmap &aFrame, TInt aError)
288
TRACE_CONTEXT(VideoPlayer::MvpuoFrameReady, EVideoApi);
289
TRACE_ENTRY("state %d error %d", state(), aError);
293
Q_UNUSED(aError); // suppress warnings in release builds
298
void MMF::VideoPlayer::MvpuoPlayComplete(TInt aError)
300
TRACE_CONTEXT(VideoPlayer::MvpuoPlayComplete, EVideoApi)
301
TRACE_ENTRY("state %d error %d", state(), aError);
304
Q_UNUSED(aError); // suppress warnings in release builds
309
void MMF::VideoPlayer::MvpuoEvent(const TMMFEvent &aEvent)
311
TRACE_CONTEXT(VideoPlayer::MvpuoEvent, EVideoApi);
312
TRACE_ENTRY("state %d", state());
321
//-----------------------------------------------------------------------------
322
// VideoOutputObserver
323
//-----------------------------------------------------------------------------
325
void MMF::VideoPlayer::videoOutputRegionChanged()
327
TRACE_CONTEXT(VideoPlayer::videoOutputRegionChanged, EVideoInternal);
328
TRACE_ENTRY("state %d", state());
330
getNativeWindowSystemHandles();
332
// See comment in updateMmfOutput
333
if(state() == LoadingState)
334
m_mmfOutputChangePending = true;
341
// DEBUGGING *** DO NOT INTEGRATE ***
342
class CDummyAO : public CActive
345
CDummyAO() : CActive(CActive::EPriorityStandard) { CActiveScheduler::Add(this); }
348
TRequestStatus& Status() { return iStatus; }
349
void SetActive() { CActive::SetActive(); }
352
// DEBUGGING *** DO NOT INTEGRATE ***
353
void getDsaRegion(RWsSession &session, const RWindowBase &window)
355
RDirectScreenAccess dsa(session);
356
TInt err = dsa.Construct();
359
err = dsa.Request(region, ao.Status(), window);
364
qDebug() << "Phonon::MMF::getDsaRegion count" << region->Count();
365
for(int i=0; i<region->Count(); ++i) {
366
const TRect& rect = region->RectangleList()[i];
367
qDebug() << "Phonon::MMF::getDsaRegion rect" << rect.iTl.iX << rect.iTl.iY << rect.iBr.iX << rect.iBr.iY;
373
void MMF::VideoPlayer::updateMmfOutput()
375
TRACE_CONTEXT(VideoPlayer::updateMmfOutput, EVideoInternal);
378
// Calling SetDisplayWindowL is a no-op unless the MMF controller has
379
// been loaded, so we shouldn't do it. Instead, the
380
// m_mmfOutputChangePending flag is used to record the fact that we
381
// need to call SetDisplayWindowL, and this is checked in
382
// MvpuoPrepareComplete, at which point the MMF controller has been
385
getNativeWindowSystemHandles();
387
// DEBUGGING *** DO NOT INTEGRATE ***
388
getDsaRegion(*m_wsSession, *m_window);
391
m_player->SetDisplayWindowL
393
*m_wsSession, *m_screenDevice,
395
m_windowRect, m_clipRect
399
if (KErrNone != err) {
400
TRACE("SetDisplayWindowL error %d", err);
401
setError(NormalError);
404
m_mmfOutputChangePending = false;
410
//-----------------------------------------------------------------------------
412
//-----------------------------------------------------------------------------
414
void MMF::VideoPlayer::videoOutputChanged()
416
TRACE_CONTEXT(VideoPlayer::videoOutputChanged, EVideoInternal);
420
m_videoOutput->setObserver(this);
421
m_videoOutput->setFrameSize(m_frameSize);
424
videoOutputRegionChanged();
429
void MMF::VideoPlayer::getNativeWindowSystemHandles()
431
TRACE_CONTEXT(VideoPlayer::getNativeWindowSystemHandles, EVideoInternal);
434
CCoeControl *control = 0;
437
// Create native window
438
control = m_videoOutput->winId();
440
// Get top-level window
441
control = QApplication::activeWindow()->effectiveWinId();
443
CCoeEnv* const coeEnv = control->ControlEnv();
444
m_wsSession = &(coeEnv->WsSession());
445
m_screenDevice = coeEnv->ScreenDevice();
446
m_window = control->DrawableWindow();
450
QScopedPointer<ObjectDump::QDumper> dumper(new ObjectDump::QDumper);
451
dumper->setPrefix("Phonon::MMF"); // to aid searchability of logs
452
ObjectDump::addDefaultAnnotators(*dumper);
453
TRACE_0("Dumping VideoOutput:");
454
dumper->dumpObject(*m_videoOutput);
457
TRACE_0("m_videoOutput is null - dumping top-level control info:");
458
TRACE("control %08x", control);
459
TRACE("control.parent %08x", control->Parent());
460
TRACE("control.isVisible %d", control->IsVisible());
461
TRACE("control.rect %d,%d %dx%d",
462
control->Position().iX, control->Position().iY,
463
control->Size().iWidth, control->Size().iHeight);
464
TRACE("control.ownsWindow %d", control->OwnsWindow());
468
m_windowRect = TRect(
469
control->DrawableWindow()->AbsPosition(),
470
control->DrawableWindow()->Size());
471
m_clipRect = m_windowRect;
473
TRACE("windowRect %d %d - %d %d",
474
m_windowRect.iTl.iX, m_windowRect.iTl.iY,
475
m_windowRect.iBr.iX, m_windowRect.iBr.iY);
476
TRACE("clipRect %d %d - %d %d",
477
m_clipRect.iTl.iX, m_clipRect.iTl.iY,
478
m_clipRect.iBr.iX, m_clipRect.iBr.iY);