/* This file is part of the KDE project.
Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
This library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2.1 or 3 of the License.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this library. If not, see .
*/
#include // for CCoeControl
#include // for QApplication::activeWindow
#include // for qt_TRect2QRect
#include "utils.h"
#include "videooutput_dsa.h"
#include "videoplayer_dsa.h"
QT_BEGIN_NAMESPACE
using namespace Phonon;
using namespace Phonon::MMF;
// Two-phase constructor idiom is used because construct() calls virtual
// functions and therefore cannot be called from the AbstractVideoPlayer
// C++ constructor.
DsaVideoPlayer* DsaVideoPlayer::create(MediaObject *parent,
const AbstractPlayer *player)
{
QScopedPointer self(new DsaVideoPlayer(parent, player));
self->construct();
return self.take();
}
DsaVideoPlayer::DsaVideoPlayer(MediaObject *parent, const AbstractPlayer *player)
: AbstractVideoPlayer(parent, player)
, m_dsaActive(false)
, m_dsaWasActive(false)
{
}
DsaVideoPlayer::~DsaVideoPlayer()
{
}
//-----------------------------------------------------------------------------
// Public functions
//-----------------------------------------------------------------------------
void MMF::DsaVideoPlayer::videoWindowScreenRectChanged()
{
Q_ASSERT(m_videoOutput);
QRect windowRect = static_cast(m_videoOutput)->videoWindowScreenRect();
// Clip to physical window size
// This is due to a defect in the layout when running on S60 3.2, which
// results in the rectangle of the video widget extending outside the
// screen in certain circumstances. These include the initial startup
// of the mediaplayer demo in portrait mode. When this rectangle is
// passed to the CVideoPlayerUtility, no video is rendered.
const TSize screenSize = m_screenDevice.SizeInPixels();
const QRect screenRect(0, 0, screenSize.iWidth, screenSize.iHeight);
windowRect = windowRect.intersected(screenRect);
// Recalculate scale factors. Pass 'false' as second parameter in order to
// suppress application of the change to the player - this is done at the end
// of the function.
updateScaleFactors(windowRect.size(), false);
m_videoScreenRect = qt_QRect2TRect(windowRect);
parametersChanged(WindowScreenRect | ScaleFactors);
}
void MMF::DsaVideoPlayer::suspendDirectScreenAccess()
{
m_dsaWasActive = stopDirectScreenAccess();
}
void MMF::DsaVideoPlayer::resumeDirectScreenAccess()
{
if (m_dsaWasActive) {
startDirectScreenAccess();
m_dsaWasActive = false;
}
}
//-----------------------------------------------------------------------------
// Private functions
//-----------------------------------------------------------------------------
void MMF::DsaVideoPlayer::createPlayer()
{
// A window handle must be provided in order to construct
// CVideoPlayerUtility. If no VideoOutput has yet been connected to this
// player, we temporarily use the top-level application window handle.
// No video ever gets rendered into this window; SetDisplayWindowL is
// always called before rendering actually begins.
if (!m_window)
m_window = QApplication::activeWindow()->effectiveWinId()->DrawableWindow();
const TInt priority = 0;
const TMdaPriorityPreference preference = EMdaPriorityPreferenceNone;
CVideoPlayerUtility *player = 0;
QT_TRAP_THROWING(player = CVideoPlayerUtility::NewL(*this,
priority, preference,
m_wsSession, m_screenDevice,
*m_window,
m_videoScreenRect, m_videoScreenRect));
m_player.reset(player);
// CVideoPlayerUtility::NewL starts DSA
m_dsaActive = true;
}
void MMF::DsaVideoPlayer::initVideoOutput()
{
Q_ASSERT(m_videoOutput);
bool connected = connect(
m_videoOutput, SIGNAL(videoWindowScreenRectChanged()),
this, SLOT(videoWindowScreenRectChanged())
);
Q_ASSERT(connected);
connected = connect(
m_videoOutput, SIGNAL(beginVideoWindowNativePaint()),
this, SLOT(suspendDirectScreenAccess())
);
Q_ASSERT(connected);
connected = connect(
m_videoOutput, SIGNAL(endVideoWindowNativePaint()),
this, SLOT(resumeDirectScreenAccess())
);
Q_ASSERT(connected);
// Suppress warnings in release builds
Q_UNUSED(connected);
AbstractVideoPlayer::initVideoOutput();
}
void MMF::DsaVideoPlayer::prepareCompleted()
{
if (m_videoOutput)
videoWindowScreenRectChanged();
}
void MMF::DsaVideoPlayer::handleVideoWindowChanged()
{
if (!m_window) {
if (QWidget *window = QApplication::activeWindow())
m_window = window->effectiveWinId()->DrawableWindow();
else
m_window = 0;
m_videoScreenRect = TRect();
}
parametersChanged(WindowHandle | WindowScreenRect);
}
#ifndef QT_NO_DEBUG
// The following code is for debugging problems related to video visibility. It allows
// the VideoPlayer instance to query the window server in order to determine the
// DSA drawing region for the video window.
class CDummyAO : public CActive
{
public:
CDummyAO() : CActive(CActive::EPriorityStandard) { CActiveScheduler::Add(this); }
void RunL() { }
void DoCancel() { }
TRequestStatus& Status() { return iStatus; }
void SetActive() { CActive::SetActive(); }
};
void getDsaRegion(RWsSession &session, const RWindowBase &window)
{
// Dump complete window tree
session.LogCommand(RWsSession::ELoggingStatusDump);
RDirectScreenAccess dsa(session);
TInt err = dsa.Construct();
CDummyAO ao;
RRegion* region;
err = dsa.Request(region, ao.Status(), window);
ao.SetActive();
dsa.Close();
ao.Cancel();
if (region) {
qDebug() << "Phonon::MMF::getDsaRegion count" << region->Count();
for (int i=0; iCount(); ++i) {
const TRect& rect = region->RectangleList()[i];
qDebug() << "Phonon::MMF::getDsaRegion rect"
<< rect.iTl.iX << rect.iTl.iY << rect.iBr.iX << rect.iBr.iY;
}
region->Close();
}
}
#endif // QT_NO_DEBUG
void MMF::DsaVideoPlayer::handleParametersChanged(VideoParameters parameters)
{
TRACE_CONTEXT(DsaVideoPlayer::handleParametersChanged, EVideoInternal);
TRACE_ENTRY("parameters 0x%x", parameters.operator int());
if (!m_window)
return;
#ifndef QT_NO_DEBUG
getDsaRegion(m_wsSession, *m_window);
#endif
if (m_player) {
static const TBool antialias = ETrue;
int err = KErrNone;
if (parameters & ScaleFactors) {
TRAP(err, m_player->SetScaleFactorL(m_scaleWidth, m_scaleHeight,
antialias));
if(KErrNone != err) {
TRACE("SetScaleFactorL (1) err %d", err);
setError(tr("Video display error"), err);
}
}
if (KErrNone == err) {
if (parameters & WindowHandle || parameters & WindowScreenRect) {
TRAP(err,
m_player->SetDisplayWindowL(m_wsSession, m_screenDevice,
*m_window,
m_videoScreenRect,
m_videoScreenRect));
}
if (KErrNone != err) {
TRACE("SetDisplayWindowL err %d", err);
setError(tr("Video display error"), err);
} else {
m_dsaActive = true;
if (parameters & ScaleFactors) {
TRAP(err, m_player->SetScaleFactorL(m_scaleWidth, m_scaleHeight,
antialias));
if (KErrNone != err) {
TRACE("SetScaleFactorL (2) err %d", err);
setError(tr("Video display error"), err);
}
}
}
}
}
TRACE_EXIT_0();
}
void MMF::DsaVideoPlayer::startDirectScreenAccess()
{
TRACE_CONTEXT(DsaVideoPlayer::startDirectScreenAccess, EVideoInternal);
TRACE_ENTRY("dsaActive %d", m_dsaActive);
int err = KErrNone;
if (!m_dsaActive) {
TRAP(err, m_player->StartDirectScreenAccessL());
if (KErrNone == err)
m_dsaActive = true;
else
setError(tr("Video display error"), err);
}
if (m_videoOutput)
m_videoOutput->dump();
TRACE_EXIT("error %d", err);
}
bool MMF::DsaVideoPlayer::stopDirectScreenAccess()
{
TRACE_CONTEXT(DsaVideoPlayer::stopDirectScreenAccess, EVideoInternal);
TRACE_ENTRY("dsaActive %d", m_dsaActive);
int err = KErrNone;
const bool dsaWasActive = m_dsaActive;
if (m_dsaActive) {
TRAP(err, m_player->StopDirectScreenAccessL());
if (KErrNone == err)
m_dsaActive = false;
else
setError(tr("Video display error"), err);
}
TRACE_EXIT("error %d", err);
return dsaWasActive;
}
QT_END_NAMESPACE