src/3rdparty/phonon/mmf/abstractvideoplayer.cpp
changeset 19 fcece45ef507
child 14 c0432d11811c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/3rdparty/phonon/mmf/abstractvideoplayer.cpp	Mon May 03 13:17:34 2010 +0300
@@ -0,0 +1,490 @@
+/*  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 <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <QUrl>
+#include <QTimer>
+#include <QWidget>
+
+#include <coemain.h>    // for CCoeEnv
+
+#include "abstractvideoplayer.h"
+#include "utils.h"
+
+#ifndef QT_NO_DEBUG
+#include "objectdump.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+using namespace Phonon;
+using namespace Phonon::MMF;
+
+/*! \class MMF::AbstractVideoPlayer
+  \internal
+*/
+
+//-----------------------------------------------------------------------------
+// Constructor / destructor
+//-----------------------------------------------------------------------------
+
+MMF::AbstractVideoPlayer::AbstractVideoPlayer(MediaObject *parent, const AbstractPlayer *player)
+    :   AbstractMediaPlayer(parent, player)
+    ,   m_wsSession(CCoeEnv::Static()->WsSession())
+    ,   m_screenDevice(*CCoeEnv::Static()->ScreenDevice())
+    ,   m_window(0)
+    ,   m_scaleWidth(1.0)
+    ,   m_scaleHeight(1.0)
+    ,   m_totalTime(0)
+{
+
+}
+
+void MMF::AbstractVideoPlayer::construct()
+{
+    TRACE_CONTEXT(AbstractVideoPlayer::AbstractVideoPlayer, EVideoApi);
+    TRACE_ENTRY_0();
+
+    if (m_videoOutput) {
+        initVideoOutput();
+        m_window = m_videoOutput->videoWindow();
+    }
+
+    createPlayer();
+
+    TRACE_EXIT_0();
+}
+
+MMF::AbstractVideoPlayer::~AbstractVideoPlayer()
+{
+    TRACE_CONTEXT(AbstractVideoPlayer::~AbstractVideoPlayer, EVideoApi);
+    TRACE_ENTRY_0();
+
+    // QObject destructor removes all signal-slot connections involving this
+    // object, so we do not need to disconnect from m_videoOutput here.
+
+    TRACE_EXIT_0();
+}
+
+CVideoPlayerUtility* MMF::AbstractVideoPlayer::nativePlayer() const
+{
+    return m_player.data();
+}
+
+//-----------------------------------------------------------------------------
+// Public API
+//-----------------------------------------------------------------------------
+
+void MMF::AbstractVideoPlayer::doPlay()
+{
+    TRACE_CONTEXT(AbstractVideoPlayer::doPlay, EVideoApi);
+
+    handlePendingParametersChanged();
+
+    m_player->Play();
+}
+
+void MMF::AbstractVideoPlayer::doPause()
+{
+    TRACE_CONTEXT(AbstractVideoPlayer::doPause, EVideoApi);
+
+    TRAPD(err, m_player->PauseL());
+    if (KErrNone != err && state() != ErrorState) {
+        TRACE("PauseL error %d", err);
+        setError(tr("Pause failed"), err);
+    }
+}
+
+void MMF::AbstractVideoPlayer::doStop()
+{
+    m_player->Stop();
+}
+
+void MMF::AbstractVideoPlayer::doSeek(qint64 ms)
+{
+    TRACE_CONTEXT(AbstractVideoPlayer::doSeek, EVideoApi);
+
+    TRAPD(err, m_player->SetPositionL(TTimeIntervalMicroSeconds(ms * 1000)));
+
+    if (KErrNone != err)
+        setError(tr("Seek failed"), err);
+}
+
+int MMF::AbstractVideoPlayer::setDeviceVolume(int mmfVolume)
+{
+    TRAPD(err, m_player->SetVolumeL(mmfVolume));
+    return err;
+}
+
+int MMF::AbstractVideoPlayer::openFile(RFile &file)
+{
+    TRAPD(err, m_player->OpenFileL(file));
+    return err;
+}
+
+int MMF::AbstractVideoPlayer::openUrl(const QString &url)
+{
+    TRAPD(err, m_player->OpenUrlL(qt_QString2TPtrC(url)));
+    return err;
+}
+
+int MMF::AbstractVideoPlayer::bufferStatus() const
+{
+    int result = 0;
+    TRAP_IGNORE(m_player->GetVideoLoadingProgressL(result));
+    return result;
+}
+
+void MMF::AbstractVideoPlayer::close()
+{
+    m_player->Close();
+}
+
+bool MMF::AbstractVideoPlayer::hasVideo() const
+{
+    return true;
+}
+
+qint64 MMF::AbstractVideoPlayer::currentTime() const
+{
+    TRACE_CONTEXT(AbstractVideoPlayer::currentTime, EVideoApi);
+
+    TTimeIntervalMicroSeconds us;
+    TRAPD(err, us = m_player->PositionL())
+
+    qint64 result = 0;
+
+    if (KErrNone == err) {
+        result = toMilliSeconds(us);
+    } else {
+        TRACE("PositionL error %d", err);
+
+        // If we don't cast away constness here, we simply have to ignore
+        // the error.
+        const_cast<AbstractVideoPlayer*>(this)->setError(tr("Getting position failed"), err);
+    }
+
+    return result;
+}
+
+qint64 MMF::AbstractVideoPlayer::totalTime() const
+{
+    return m_totalTime;
+}
+
+
+//-----------------------------------------------------------------------------
+// Public slots
+//-----------------------------------------------------------------------------
+
+void MMF::AbstractVideoPlayer::videoWindowChanged()
+{
+    TRACE_CONTEXT(AbstractVideoPlayer::videoOutputRegionChanged, EVideoInternal);
+    TRACE_ENTRY("state %d", state());
+
+    m_window = m_videoOutput ? m_videoOutput->videoWindow() : 0;
+
+    handleVideoWindowChanged();
+
+    TRACE_EXIT_0();
+}
+
+void MMF::AbstractVideoPlayer::aspectRatioChanged()
+{
+    TRACE_CONTEXT(AbstractVideoPlayer::aspectRatioChanged, EVideoInternal);
+    TRACE_ENTRY("state %d aspectRatio %d", state());
+
+    updateScaleFactors(m_videoOutput->videoWindowSize());
+
+    TRACE_EXIT_0();
+}
+
+void MMF::AbstractVideoPlayer::scaleModeChanged()
+{
+    TRACE_CONTEXT(AbstractVideoPlayer::scaleModeChanged, EVideoInternal);
+    TRACE_ENTRY("state %d", state());
+
+    updateScaleFactors(m_videoOutput->videoWindowSize());
+
+    TRACE_EXIT_0();
+}
+
+
+//-----------------------------------------------------------------------------
+// MVideoPlayerUtilityObserver callbacks
+//-----------------------------------------------------------------------------
+
+void MMF::AbstractVideoPlayer::MvpuoOpenComplete(TInt aError)
+{
+    TRACE_CONTEXT(AbstractVideoPlayer::MvpuoOpenComplete, EVideoApi);
+    TRACE_ENTRY("state %d error %d", state(), aError);
+
+    __ASSERT_ALWAYS(LoadingState == state(), Utils::panic(InvalidStatePanic));
+
+    if (KErrNone == aError)
+        m_player->Prepare();
+    else
+        setError(tr("Opening clip failed"), aError);
+
+    TRACE_EXIT_0();
+}
+
+void MMF::AbstractVideoPlayer::MvpuoPrepareComplete(TInt aError)
+{
+    TRACE_CONTEXT(AbstractVideoPlayer::MvpuoPrepareComplete, EVideoApi);
+    TRACE_ENTRY("state %d error %d", state(), aError);
+
+    __ASSERT_ALWAYS(LoadingState == state(), Utils::panic(InvalidStatePanic));
+
+    TRAPD(err, getVideoClipParametersL(aError));
+
+    if (KErrNone == err) {
+        maxVolumeChanged(m_player->MaxVolume());
+
+        if (m_videoOutput)
+            m_videoOutput->setVideoSize(m_videoFrameSize);
+
+        prepareCompleted();
+        handlePendingParametersChanged();
+
+        emit totalTimeChanged(totalTime());
+        changeState(StoppedState);
+    } else {
+        setError(tr("Buffering clip failed"), err);
+    }
+
+    TRACE_EXIT_0();
+}
+
+void MMF::AbstractVideoPlayer::getVideoClipParametersL(TInt aError)
+{
+    User::LeaveIfError(aError);
+
+    // Get frame size
+    TSize size;
+    m_player->VideoFrameSizeL(size);
+    m_videoFrameSize = QSize(size.iWidth, size.iHeight);
+
+    // Get duration
+    m_totalTime = toMilliSeconds(m_player->DurationL());
+}
+
+
+void MMF::AbstractVideoPlayer::MvpuoFrameReady(CFbsBitmap &aFrame, TInt aError)
+{
+    TRACE_CONTEXT(AbstractVideoPlayer::MvpuoFrameReady, EVideoApi);
+    TRACE_ENTRY("state %d error %d", state(), aError);
+
+    Q_UNUSED(aFrame);
+    Q_UNUSED(aError);   // suppress warnings in release builds
+
+    TRACE_EXIT_0();
+}
+
+void MMF::AbstractVideoPlayer::MvpuoPlayComplete(TInt aError)
+{
+    TRACE_CONTEXT(AbstractVideoPlayer::MvpuoPlayComplete, EVideoApi)
+    TRACE_ENTRY("state %d error %d", state(), aError);
+
+    // Call base class function which handles end of playback for both
+    // audio and video clips.
+    playbackComplete(aError);
+
+    TRACE_EXIT_0();
+}
+
+void MMF::AbstractVideoPlayer::MvpuoEvent(const TMMFEvent &aEvent)
+{
+    TRACE_CONTEXT(AbstractVideoPlayer::MvpuoEvent, EVideoApi);
+    TRACE_ENTRY("state %d", state());
+
+    Q_UNUSED(aEvent);
+
+    TRACE_EXIT_0();
+}
+
+
+//-----------------------------------------------------------------------------
+// MVideoLoadingObserver callbacks
+//-----------------------------------------------------------------------------
+
+void MMF::AbstractVideoPlayer::MvloLoadingStarted()
+{
+    bufferingStarted();
+}
+
+void MMF::AbstractVideoPlayer::MvloLoadingComplete()
+{
+    bufferingComplete();
+}
+
+
+//-----------------------------------------------------------------------------
+// Video window updates
+//-----------------------------------------------------------------------------
+
+void MMF::AbstractVideoPlayer::videoOutputChanged()
+{
+    TRACE_CONTEXT(AbstractVideoPlayer::videoOutputChanged, EVideoInternal);
+    TRACE_ENTRY_0();
+
+    if (m_videoOutput)
+        initVideoOutput();
+
+    videoWindowChanged();
+
+    TRACE_EXIT_0();
+}
+
+void MMF::AbstractVideoPlayer::initVideoOutput()
+{
+    bool connected = connect(
+        m_videoOutput, SIGNAL(videoWindowChanged()),
+        this, SLOT(videoWindowChanged())
+    );
+    Q_ASSERT(connected);
+
+    connected = connect(
+        m_videoOutput, SIGNAL(aspectRatioChanged()),
+        this, SLOT(aspectRatioChanged())
+    );
+    Q_ASSERT(connected);
+
+    connected = connect(
+        m_videoOutput, SIGNAL(scaleModeChanged()),
+        this, SLOT(scaleModeChanged())
+    );
+    Q_ASSERT(connected);
+
+    // Suppress warnings in release builds
+    Q_UNUSED(connected);
+
+    // Do these after all connections are complete, to ensure
+    // that any signals generated get to their destinations.
+    m_videoOutput->winId();
+    m_videoOutput->setVideoSize(m_videoFrameSize);
+}
+
+// Helper function for aspect ratio / scale mode handling
+QSize scaleToAspect(const QSize &srcRect, int aspectWidth, int aspectHeight)
+{
+    const qreal aspectRatio = qreal(aspectWidth) / aspectHeight;
+
+    int width = srcRect.width();
+    int height = srcRect.width() / aspectRatio;
+    if (height > srcRect.height()){
+        height = srcRect.height();
+        width = srcRect.height() * aspectRatio;
+    }
+    return QSize(width, height);
+}
+
+void MMF::AbstractVideoPlayer::updateScaleFactors(const QSize &windowSize, bool apply)
+{
+    if (m_videoFrameSize.isValid()) {
+        QRect videoRect;
+
+        // Calculate size of smallest rect which contains video frame size
+        // and conforms to aspect ratio
+        switch (m_videoOutput->aspectRatio()) {
+        case Phonon::VideoWidget::AspectRatioAuto:
+            videoRect.setSize(m_videoFrameSize);
+            break;
+
+        case Phonon::VideoWidget::AspectRatioWidget:
+            videoRect.setSize(windowSize);
+            break;
+
+        case Phonon::VideoWidget::AspectRatio4_3:
+            videoRect.setSize(scaleToAspect(m_videoFrameSize, 4, 3));
+            break;
+
+        case Phonon::VideoWidget::AspectRatio16_9:
+            videoRect.setSize(scaleToAspect(m_videoFrameSize, 16, 9));
+            break;
+        }
+
+        // Scale to fill the window width
+        const int windowWidth = windowSize.width();
+        const int windowHeight = windowSize.height();
+        const qreal windowScaleFactor = qreal(windowWidth) / videoRect.width();
+        int videoWidth = windowWidth;
+        int videoHeight = videoRect.height() * windowScaleFactor;
+
+        const qreal windowToVideoHeightRatio = qreal(windowHeight) / videoHeight;
+
+        switch (m_videoOutput->scaleMode()) {
+        case Phonon::VideoWidget::ScaleAndCrop:
+            if (videoHeight < windowHeight) {
+                videoWidth *= windowToVideoHeightRatio;
+                videoHeight = windowHeight;
+            }
+            break;
+        case Phonon::VideoWidget::FitInView:
+        default:
+            if (videoHeight > windowHeight) {
+                videoWidth *= windowToVideoHeightRatio;
+                videoHeight = windowHeight;
+            }
+            break;
+        }
+
+        // Calculate scale factors
+        m_scaleWidth = 100.0f * videoWidth / m_videoFrameSize.width();
+        m_scaleHeight = 100.0f * videoHeight / m_videoFrameSize.height();
+
+        if (apply)
+            parametersChanged(ScaleFactors);
+    }
+}
+
+void MMF::AbstractVideoPlayer::parametersChanged(VideoParameters parameters)
+{
+    if (state() == LoadingState)
+        m_pendingChanges |= parameters;
+    else
+        handleParametersChanged(parameters);
+}
+
+void MMF::AbstractVideoPlayer::handlePendingParametersChanged()
+{
+    if (m_pendingChanges)
+        handleParametersChanged(m_pendingChanges);
+    m_pendingChanges = 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Metadata
+//-----------------------------------------------------------------------------
+
+int MMF::AbstractVideoPlayer::numberOfMetaDataEntries() const
+{
+    int numberOfEntries = 0;
+    TRAP_IGNORE(numberOfEntries = m_player->NumberOfMetaDataEntriesL());
+    return numberOfEntries;
+}
+
+QPair<QString, QString> MMF::AbstractVideoPlayer::metaDataEntry(int index) const
+{
+    CMMFMetaDataEntry *entry = 0;
+    QT_TRAP_THROWING(entry = m_player->MetaDataEntryL(index));
+    return QPair<QString, QString>(qt_TDesC2QString(entry->Name()), qt_TDesC2QString(entry->Value()));
+}
+
+QT_END_NAMESPACE
+