diff options
Diffstat (limited to 'src/plugins/qt7/mediaplayer')
-rw-r--r-- | src/plugins/qt7/mediaplayer/mediaplayer.pri | 16 | ||||
-rw-r--r-- | src/plugins/qt7/mediaplayer/qt7playercontrol.h | 109 | ||||
-rw-r--r-- | src/plugins/qt7/mediaplayer/qt7playercontrol.mm | 191 | ||||
-rw-r--r-- | src/plugins/qt7/mediaplayer/qt7playermetadata.h | 77 | ||||
-rw-r--r-- | src/plugins/qt7/mediaplayer/qt7playermetadata.mm | 260 | ||||
-rw-r--r-- | src/plugins/qt7/mediaplayer/qt7playerservice.h | 82 | ||||
-rw-r--r-- | src/plugins/qt7/mediaplayer/qt7playerservice.mm | 129 | ||||
-rw-r--r-- | src/plugins/qt7/mediaplayer/qt7playersession.h | 194 | ||||
-rw-r--r-- | src/plugins/qt7/mediaplayer/qt7playersession.mm | 751 |
9 files changed, 1809 insertions, 0 deletions
diff --git a/src/plugins/qt7/mediaplayer/mediaplayer.pri b/src/plugins/qt7/mediaplayer/mediaplayer.pri new file mode 100644 index 000000000..2edb1d2c7 --- /dev/null +++ b/src/plugins/qt7/mediaplayer/mediaplayer.pri @@ -0,0 +1,16 @@ +INCLUDEPATH += $$PWD + +DEFINES += QMEDIA_QT7_PLAYER + +HEADERS += \ + $$PWD/qt7playercontrol.h \ + $$PWD/qt7playermetadata.h \ + $$PWD/qt7playerservice.h \ + $$PWD/qt7playersession.h + +OBJECTIVE_SOURCES += \ + $$PWD/qt7playercontrol.mm \ + $$PWD/qt7playermetadata.mm \ + $$PWD/qt7playerservice.mm \ + $$PWD/qt7playersession.mm + diff --git a/src/plugins/qt7/mediaplayer/qt7playercontrol.h b/src/plugins/qt7/mediaplayer/qt7playercontrol.h new file mode 100644 index 000000000..064c0ccd3 --- /dev/null +++ b/src/plugins/qt7/mediaplayer/qt7playercontrol.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT7PLAYERCONTROL_H +#define QT7PLAYERCONTROL_H + +#include <QtCore/qobject.h> + +#include <qmediaplayercontrol.h> +#include <qmediaplayer.h> + +#include <QtGui/qmacdefines_mac.h> + + +QT_BEGIN_NAMESPACE + +class QT7PlayerSession; +class QT7PlayerService; +class QMediaPlaylist; +class QMediaPlaylistNavigator; + +class QT7PlayerControl : public QMediaPlayerControl +{ +Q_OBJECT +public: + QT7PlayerControl(QObject *parent = 0); + ~QT7PlayerControl(); + + void setSession(QT7PlayerSession *session); + + QMediaPlayer::State state() const; + QMediaPlayer::MediaStatus mediaStatus() const; + + QMediaContent media() const; + const QIODevice *mediaStream() const; + void setMedia(const QMediaContent &content, QIODevice *stream); + + qint64 position() const; + qint64 duration() const; + + int bufferStatus() const; + + int volume() const; + bool isMuted() const; + + bool isAudioAvailable() const; + bool isVideoAvailable() const; + + bool isSeekable() const; + QMediaTimeRange availablePlaybackRanges() const; + + qreal playbackRate() const; + void setPlaybackRate(qreal rate); + +public Q_SLOTS: + void setPosition(qint64 pos); + + void play(); + void pause(); + void stop(); + + void setVolume(int volume); + void setMuted(bool muted); + +private: + QT7PlayerSession *m_session; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qt7/mediaplayer/qt7playercontrol.mm b/src/plugins/qt7/mediaplayer/qt7playercontrol.mm new file mode 100644 index 000000000..ddfcc3570 --- /dev/null +++ b/src/plugins/qt7/mediaplayer/qt7playercontrol.mm @@ -0,0 +1,191 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qt7playercontrol.h" +#include "qt7playersession.h" + +#include <qmediaplaylistnavigator.h> + +#include <QtCore/qurl.h> +#include <QtCore/qdebug.h> + +QT_USE_NAMESPACE + +QT7PlayerControl::QT7PlayerControl(QObject *parent) + : QMediaPlayerControl(parent) +{ +} + +QT7PlayerControl::~QT7PlayerControl() +{ +} + +void QT7PlayerControl::setSession(QT7PlayerSession *session) +{ + m_session = session; + + connect(m_session, SIGNAL(positionChanged(qint64)), this, SIGNAL(positionChanged(qint64))); + connect(m_session, SIGNAL(durationChanged(qint64)), this, SIGNAL(durationChanged(qint64))); + connect(m_session, SIGNAL(stateChanged(QMediaPlayer::State)), + this, SIGNAL(stateChanged(QMediaPlayer::State))); + connect(m_session, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), + this, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus))); + connect(m_session, SIGNAL(volumeChanged(int)), this, SIGNAL(volumeChanged(int))); + connect(m_session, SIGNAL(mutedChanged(bool)), this, SIGNAL(mutedChanged(bool))); + connect(m_session, SIGNAL(audioAvailableChanged(bool)), this, SIGNAL(audioAvailableChanged(bool))); + connect(m_session, SIGNAL(videoAvailableChanged(bool)), this, SIGNAL(videoAvailableChanged(bool))); + connect(m_session, SIGNAL(error(int,QString)), this, SIGNAL(error(int,QString))); +} + +qint64 QT7PlayerControl::position() const +{ + return m_session->position(); +} + +qint64 QT7PlayerControl::duration() const +{ + return m_session->duration(); +} + +QMediaPlayer::State QT7PlayerControl::state() const +{ + return m_session->state(); +} + +QMediaPlayer::MediaStatus QT7PlayerControl::mediaStatus() const +{ + return m_session->mediaStatus(); +} + +int QT7PlayerControl::bufferStatus() const +{ + return m_session->bufferStatus(); +} + +int QT7PlayerControl::volume() const +{ + return m_session->volume(); +} + +bool QT7PlayerControl::isMuted() const +{ + return m_session->isMuted(); +} + +bool QT7PlayerControl::isSeekable() const +{ + return m_session->isSeekable(); +} + +QMediaTimeRange QT7PlayerControl::availablePlaybackRanges() const +{ + return m_session->availablePlaybackRanges(); +} + +qreal QT7PlayerControl::playbackRate() const +{ + return m_session->playbackRate(); +} + +void QT7PlayerControl::setPlaybackRate(qreal rate) +{ + m_session->setPlaybackRate(rate); +} + +void QT7PlayerControl::setPosition(qint64 pos) +{ + m_session->setPosition(pos); +} + +void QT7PlayerControl::play() +{ + m_session->play(); +} + +void QT7PlayerControl::pause() +{ + m_session->pause(); +} + +void QT7PlayerControl::stop() +{ + m_session->stop(); +} + +void QT7PlayerControl::setVolume(int volume) +{ + m_session->setVolume(volume); +} + +void QT7PlayerControl::setMuted(bool muted) +{ + m_session->setMuted(muted); +} + +QMediaContent QT7PlayerControl::media() const +{ + return m_session->media(); +} + +const QIODevice *QT7PlayerControl::mediaStream() const +{ + return m_session->mediaStream(); +} + +void QT7PlayerControl::setMedia(const QMediaContent &content, QIODevice *stream) +{ + m_session->setMedia(content, stream); + + emit mediaChanged(content); +} + +bool QT7PlayerControl::isAudioAvailable() const +{ + return m_session->isAudioAvailable(); +} + +bool QT7PlayerControl::isVideoAvailable() const +{ + return m_session->isVideoAvailable(); +} + + +#include "moc_qt7playercontrol.cpp" diff --git a/src/plugins/qt7/mediaplayer/qt7playermetadata.h b/src/plugins/qt7/mediaplayer/qt7playermetadata.h new file mode 100644 index 000000000..441ca07f6 --- /dev/null +++ b/src/plugins/qt7/mediaplayer/qt7playermetadata.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT7PLAYERMETADATACONTROL_H +#define QT7PLAYERMETADATACONTROL_H + +#include <qmetadatareadercontrol.h> + +QT_BEGIN_NAMESPACE + +class QT7PlayerSession; + +class QT7PlayerMetaDataControl : public QMetaDataReaderControl +{ + Q_OBJECT +public: + QT7PlayerMetaDataControl(QT7PlayerSession *session, QObject *parent); + virtual ~QT7PlayerMetaDataControl(); + + bool isMetaDataAvailable() const; + bool isWritable() const; + + QVariant metaData(QtMultimediaKit::MetaData key) const; + QList<QtMultimediaKit::MetaData> availableMetaData() const; + + QVariant extendedMetaData(const QString &key) const ; + QStringList availableExtendedMetaData() const; + +private slots: + void updateTags(); + +private: + QT7PlayerSession *m_session; + QMap<QtMultimediaKit::MetaData, QVariant> m_tags; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qt7/mediaplayer/qt7playermetadata.mm b/src/plugins/qt7/mediaplayer/qt7playermetadata.mm new file mode 100644 index 000000000..ec0d41cc2 --- /dev/null +++ b/src/plugins/qt7/mediaplayer/qt7playermetadata.mm @@ -0,0 +1,260 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qt7backend.h" +#include "qt7playermetadata.h" +#include "qt7playersession.h" +#include <QtCore/qvarlengtharray.h> + +#import <QTKit/QTMovie.h> + +#ifdef QUICKTIME_C_API_AVAILABLE + #include <QuickTime/QuickTime.h> + #undef check // avoid name clash; +#endif + +QT_USE_NAMESPACE + +QT7PlayerMetaDataControl::QT7PlayerMetaDataControl(QT7PlayerSession *session, QObject *parent) + :QMetaDataReaderControl(parent), m_session(session) +{ +} + +QT7PlayerMetaDataControl::~QT7PlayerMetaDataControl() +{ +} + +bool QT7PlayerMetaDataControl::isMetaDataAvailable() const +{ + return !m_tags.isEmpty(); +} + +bool QT7PlayerMetaDataControl::isWritable() const +{ + return false; +} + +QVariant QT7PlayerMetaDataControl::metaData(QtMultimediaKit::MetaData key) const +{ + return m_tags.value(key); +} + +QList<QtMultimediaKit::MetaData> QT7PlayerMetaDataControl::availableMetaData() const +{ + return m_tags.keys(); +} + +QVariant QT7PlayerMetaDataControl::extendedMetaData(const QString &key) const +{ + Q_UNUSED(key); + return QVariant(); +} + +QStringList QT7PlayerMetaDataControl::availableExtendedMetaData() const +{ + return QStringList(); +} + +#ifdef QUICKTIME_C_API_AVAILABLE + +static QString stripCopyRightSymbol(const QString &key) +{ + return key.right(key.length()-1); +} + +static QString convertQuickTimeKeyToUserKey(const QString &key) +{ + if (key == QLatin1String("com.apple.quicktime.displayname")) + return QLatin1String("nam"); + else if (key == QLatin1String("com.apple.quicktime.album")) + return QLatin1String("alb"); + else if (key == QLatin1String("com.apple.quicktime.artist")) + return QLatin1String("ART"); + else + return QLatin1String("???"); +} + +static OSStatus readMetaValue(QTMetaDataRef metaDataRef, QTMetaDataItem item, QTPropertyClass propClass, + QTPropertyID id, QTPropertyValuePtr *value, ByteCount *size) +{ + QTPropertyValueType type; + ByteCount propSize; + UInt32 propFlags; + OSStatus err = QTMetaDataGetItemPropertyInfo(metaDataRef, item, propClass, id, &type, &propSize, &propFlags); + + if (err == noErr) { + *value = malloc(propSize); + if (*value != 0) { + err = QTMetaDataGetItemProperty(metaDataRef, item, propClass, id, propSize, *value, size); + + if (err == noErr && (type == 'code' || type == 'itsk' || type == 'itlk')) { + // convert from native endian to big endian + OSTypePtr pType = (OSTypePtr)*value; + *pType = EndianU32_NtoB(*pType); + } + } + else + return -1; + } + + return err; +} + +static UInt32 getMetaType(QTMetaDataRef metaDataRef, QTMetaDataItem item) +{ + QTPropertyValuePtr value = 0; + ByteCount ignore = 0; + OSStatus err = readMetaValue( + metaDataRef, item, kPropertyClass_MetaDataItem, kQTMetaDataItemPropertyID_DataType, &value, &ignore); + + if (err == noErr) { + UInt32 type = *((UInt32 *) value); + if (value) + free(value); + return type; + } + + return 0; +} + +static QString cFStringToQString(CFStringRef str) +{ + if(!str) + return QString(); + CFIndex length = CFStringGetLength(str); + const UniChar *chars = CFStringGetCharactersPtr(str); + if (chars) + return QString(reinterpret_cast<const QChar *>(chars), length); + + QVarLengthArray<UniChar> buffer(length); + CFStringGetCharacters(str, CFRangeMake(0, length), buffer.data()); + return QString(reinterpret_cast<const QChar *>(buffer.constData()), length); +} + + +static QString getMetaValue(QTMetaDataRef metaDataRef, QTMetaDataItem item, SInt32 id) +{ + QTPropertyValuePtr value = 0; + ByteCount size = 0; + OSStatus err = readMetaValue(metaDataRef, item, kPropertyClass_MetaDataItem, id, &value, &size); + QString string; + + if (err == noErr) { + UInt32 dataType = getMetaType(metaDataRef, item); + switch (dataType){ + case kQTMetaDataTypeUTF8: + case kQTMetaDataTypeMacEncodedText: + string = cFStringToQString(CFStringCreateWithBytes(0, (UInt8*)value, size, kCFStringEncodingUTF8, false)); + break; + case kQTMetaDataTypeUTF16BE: + string = cFStringToQString(CFStringCreateWithBytes(0, (UInt8*)value, size, kCFStringEncodingUTF16BE, false)); + break; + default: + break; + } + + if (value) + free(value); + } + + return string; +} + + +static void readFormattedData(QTMetaDataRef metaDataRef, OSType format, QMultiMap<QString, QString> &result) +{ + QTMetaDataItem item = kQTMetaDataItemUninitialized; + OSStatus err = QTMetaDataGetNextItem(metaDataRef, format, item, kQTMetaDataKeyFormatWildcard, 0, 0, &item); + while (err == noErr){ + QString key = getMetaValue(metaDataRef, item, kQTMetaDataItemPropertyID_Key); + if (format == kQTMetaDataStorageFormatQuickTime) + key = convertQuickTimeKeyToUserKey(key); + else + key = stripCopyRightSymbol(key); + + if (!result.contains(key)){ + QString val = getMetaValue(metaDataRef, item, kQTMetaDataItemPropertyID_Value); + result.insert(key, val); + } + err = QTMetaDataGetNextItem(metaDataRef, format, item, kQTMetaDataKeyFormatWildcard, 0, 0, &item); + } +} +#endif + + +void QT7PlayerMetaDataControl::updateTags() +{ + bool wasEmpty = m_tags.isEmpty(); + m_tags.clear(); + + QTMovie *movie = (QTMovie*)m_session->movie(); + + if (movie) { + QMultiMap<QString, QString> metaMap; + +#ifdef QUICKTIME_C_API_AVAILABLE + QTMetaDataRef metaDataRef; + OSStatus err = QTCopyMovieMetaData([movie quickTimeMovie], &metaDataRef); + if (err == noErr) { + readFormattedData(metaDataRef, kQTMetaDataStorageFormatUserData, metaMap); + readFormattedData(metaDataRef, kQTMetaDataStorageFormatQuickTime, metaMap); + readFormattedData(metaDataRef, kQTMetaDataStorageFormatiTunes, metaMap); + } +#else + AutoReleasePool pool; + NSString *name = [movie attributeForKey:@"QTMovieDisplayNameAttribute"]; + metaMap.insert(QLatin1String("nam"), QString::fromUtf8([name UTF8String])); +#endif // QUICKTIME_C_API_AVAILABLE + + m_tags.insert(QtMultimediaKit::AlbumArtist, metaMap.value(QLatin1String("ART"))); + m_tags.insert(QtMultimediaKit::AlbumTitle, metaMap.value(QLatin1String("alb"))); + m_tags.insert(QtMultimediaKit::Title, metaMap.value(QLatin1String("nam"))); + m_tags.insert(QtMultimediaKit::Date, metaMap.value(QLatin1String("day"))); + m_tags.insert(QtMultimediaKit::Genre, metaMap.value(QLatin1String("gnre"))); + m_tags.insert(QtMultimediaKit::TrackNumber, metaMap.value(QLatin1String("trk"))); + m_tags.insert(QtMultimediaKit::Description, metaMap.value(QLatin1String("des"))); + } + + if (!wasEmpty || !m_tags.isEmpty()) + emit metaDataChanged(); +} + +#include "moc_qt7playermetadata.cpp" diff --git a/src/plugins/qt7/mediaplayer/qt7playerservice.h b/src/plugins/qt7/mediaplayer/qt7playerservice.h new file mode 100644 index 000000000..65415f0a9 --- /dev/null +++ b/src/plugins/qt7/mediaplayer/qt7playerservice.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT7PLAYERSERVICE_H +#define QT7PLAYERSERVICE_H + +#include <QtCore/qobject.h> +#include <QtCore/qset.h> +#include <qmediaservice.h> + + +QT_BEGIN_NAMESPACE +class QMediaMetaData; +class QMediaPlayerControl; +class QMediaPlaylist; +class QMediaPlaylistNavigator; +class QT7PlayerControl; +class QT7PlayerMetaDataControl; +class QT7VideoWindowControl; +class QT7VideoWidgetControl; +class QT7VideoRendererControl; +class QT7VideoOutput; +class QT7PlayerSession; + +class QT7PlayerService : public QMediaService +{ +Q_OBJECT +public: + QT7PlayerService(QObject *parent = 0); + ~QT7PlayerService(); + + QMediaControl* requestControl(const char *name); + void releaseControl(QMediaControl *control); + +private: + QT7PlayerSession *m_session; + QT7PlayerControl *m_control; + QMediaControl * m_videoOutput; + QT7PlayerMetaDataControl *m_playerMetaDataControl; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qt7/mediaplayer/qt7playerservice.mm b/src/plugins/qt7/mediaplayer/qt7playerservice.mm new file mode 100644 index 000000000..39d06a4f3 --- /dev/null +++ b/src/plugins/qt7/mediaplayer/qt7playerservice.mm @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qvariant.h> +#include <QtCore/qdebug.h> +#include <QtGui/qwidget.h> + +#include "qt7backend.h" +#include "qt7playerservice.h" +#include "qt7playercontrol.h" +#include "qt7playersession.h" +#include "qt7videooutput.h" +#include "qt7movieviewoutput.h" +#include "qt7movieviewrenderer.h" +#include "qt7movierenderer.h" +#include "qt7movievideowidget.h" +#include "qt7playermetadata.h" + +#include <qmediaplaylistnavigator.h> +#include <qmediaplaylist.h> + +QT_USE_NAMESPACE + +QT7PlayerService::QT7PlayerService(QObject *parent): + QMediaService(parent), + m_videoOutput(0) +{ + m_session = new QT7PlayerSession(this); + + m_control = new QT7PlayerControl(this); + m_control->setSession(m_session); + + m_playerMetaDataControl = new QT7PlayerMetaDataControl(m_session, this); + connect(m_control, SIGNAL(mediaChanged(QMediaContent)), m_playerMetaDataControl, SLOT(updateTags())); +} + +QT7PlayerService::~QT7PlayerService() +{ +} + +QMediaControl *QT7PlayerService::requestControl(const char *name) +{ + if (qstrcmp(name, QMediaPlayerControl_iid) == 0) + return m_control; + + if (qstrcmp(name, QMetaDataReaderControl_iid) == 0) + return m_playerMetaDataControl; + +#ifndef QT_NO_OPENGL + if (!m_videoOutput) { + if (qstrcmp(name, QVideoWindowControl_iid) == 0) { +#if defined(QT_MAC_USE_COCOA) + m_videoOutput = new QT7MovieViewOutput(this); +#endif + } + + if (qstrcmp(name, QVideoRendererControl_iid) == 0) { +#ifdef QUICKTIME_C_API_AVAILABLE + m_videoOutput = new QT7MovieRenderer(this); +#else + m_videoOutput = new QT7MovieViewRenderer(this); +#endif + } + + if (qstrcmp(name, QVideoWidgetControl_iid) == 0) { +#ifdef QUICKTIME_C_API_AVAILABLE + m_videoOutput = new QT7MovieVideoWidget(this); +#endif + } + + if (m_videoOutput) { + QT7VideoOutput *videoOutput = qobject_cast<QT7VideoOutput*>(m_videoOutput); + m_session->setVideoOutput(videoOutput); + return m_videoOutput; + } + } +#endif // !defined(QT_NO_OPENGL) + + return 0; +} + +void QT7PlayerService::releaseControl(QMediaControl *control) +{ + if (m_videoOutput == control) { + m_videoOutput = 0; + m_session->setVideoOutput(0); + delete control; + } +} + +#include "moc_qt7playerservice.cpp" diff --git a/src/plugins/qt7/mediaplayer/qt7playersession.h b/src/plugins/qt7/mediaplayer/qt7playersession.h new file mode 100644 index 000000000..0b18748a4 --- /dev/null +++ b/src/plugins/qt7/mediaplayer/qt7playersession.h @@ -0,0 +1,194 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT7PLAYERSESSION_H +#define QT7PLAYERSESSION_H + +#include <QtCore/qobject.h> +#include <QtCore/qbytearray.h> +#include <QtCore/qset.h> +#include <QtCore/qresource.h> + +#include <qmediaplayercontrol.h> +#include <qmediaplayer.h> + +#include <QtGui/qmacdefines_mac.h> + + +QT_BEGIN_NAMESPACE + +class QT7PlayerControl; +class QMediaPlaylist; +class QMediaPlaylistNavigator; +class QT7VideoOutput; +class QT7PlayerSession; +class QT7PlayerService; + + +class QT7PlayerSession : public QObject +{ + Q_OBJECT +public: + QT7PlayerSession(QObject *parent = 0); + ~QT7PlayerSession(); + + void *movie() const; + + void setControl(QT7PlayerControl *control); + + void setVideoOutput(QT7VideoOutput *output); + + QMediaPlayer::State state() const; + QMediaPlayer::MediaStatus mediaStatus() const; + + QMediaContent media() const; + const QIODevice *mediaStream() const; + void setMedia(const QMediaContent &content, QIODevice *stream); + + qint64 position() const; + qint64 duration() const; + + int bufferStatus() const; + + int volume() const; + bool isMuted() const; + + bool isAudioAvailable() const; + bool isVideoAvailable() const; + + bool isSeekable() const; + QMediaTimeRange availablePlaybackRanges() const; + + qreal playbackRate() const; + +public slots: + void setPlaybackRate(qreal rate); + + void setPosition(qint64 pos); + + void play(); + void pause(); + void stop(); + + void setVolume(int volume); + void setMuted(bool muted); + + void processEOS(); + void processLoadStateChange(); + void processVolumeChange(); + void processNaturalSizeChange(); + void processPositionChange(); + +signals: + void positionChanged(qint64 position); + void durationChanged(qint64 duration); + void stateChanged(QMediaPlayer::State newState); + void mediaStatusChanged(QMediaPlayer::MediaStatus status); + void volumeChanged(int volume); + void mutedChanged(bool muted); + void audioAvailableChanged(bool audioAvailable); + void videoAvailableChanged(bool videoAvailable); + void error(int error, const QString &errorString); + +private: + class ResourceHandler { + public: + ResourceHandler():resource(0) {} + ~ResourceHandler() { clear(); } + void setResourceFile(const QString &file) { + if (resource) { + if (resource->fileName() == file) + return; + delete resource; + rawData.clear(); + } + resource = new QResource(file); + } + bool isValid() const { return resource && resource->isValid() && resource->data() != 0; } + const uchar *data() { + if (!isValid()) + return 0; + if (resource->isCompressed()) { + if (rawData.size() == 0) + rawData = qUncompress(resource->data(), resource->size()); + return (const uchar *)rawData.constData(); + } + return resource->data(); + } + qint64 size() { + if (data() == 0) + return 0; + return resource->isCompressed() ? rawData.size() : resource->size(); + } + void clear() { + delete resource; + rawData.clear(); + } + QResource *resource; + QByteArray rawData; + }; + + void openMovie(bool tryAsync); + + void *m_QTMovie; + void *m_movieObserver; + + QMediaPlayer::State m_state; + QMediaPlayer::MediaStatus m_mediaStatus; + QIODevice *m_mediaStream; + QMediaContent m_resources; + ResourceHandler m_resourceHandler; + + QT7VideoOutput * m_videoOutput; + + bool m_muted; + bool m_tryingAsync; + int m_volume; + qreal m_rate; + + qint64 m_duration; + bool m_videoAvailable; + bool m_audioAvailable; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qt7/mediaplayer/qt7playersession.mm b/src/plugins/qt7/mediaplayer/qt7playersession.mm new file mode 100644 index 000000000..c4eef5c9d --- /dev/null +++ b/src/plugins/qt7/mediaplayer/qt7playersession.mm @@ -0,0 +1,751 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#import <QTKit/QTDataReference.h> +#import <QTKit/QTMovie.h> + +#include "qt7backend.h" + +#include "qt7playersession.h" +#include "qt7playercontrol.h" +#include "qt7videooutput.h" + +#include <QtNetwork/qnetworkcookie.h> +#include <qmediaplaylistnavigator.h> + +#include <CoreFoundation/CoreFoundation.h> +#include <Foundation/Foundation.h> + +#include <QtCore/qdatetime.h> +#include <QtCore/qurl.h> + +#include <QtCore/qdebug.h> + +QT_USE_NAMESPACE + +//#define QT_DEBUG_QT7 + +@interface QTMovieObserver : NSObject +{ +@private + QT7PlayerSession *m_session; + QTMovie *m_movie; +} + +- (QTMovieObserver *) initWithPlayerSession:(QT7PlayerSession*)session; +- (void) setMovie:(QTMovie *)movie; +- (void) processEOS:(NSNotification *)notification; +- (void) processLoadStateChange:(NSNotification *)notification; +- (void) processVolumeChange:(NSNotification *)notification; +- (void) processNaturalSizeChange :(NSNotification *)notification; +- (void) processPositionChange :(NSNotification *)notification; +@end + +@implementation QTMovieObserver + +- (QTMovieObserver *) initWithPlayerSession:(QT7PlayerSession*)session +{ + if (!(self = [super init])) + return nil; + + self->m_session = session; + return self; +} + +- (void) setMovie:(QTMovie *)movie +{ + if (m_movie == movie) + return; + + if (m_movie) { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [m_movie release]; + } + + m_movie = movie; + + if (movie) { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(processEOS:) + name:QTMovieDidEndNotification + object:m_movie]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(processLoadStateChange:) + name:QTMovieLoadStateDidChangeNotification + object:m_movie]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(processVolumeChange:) + name:QTMovieVolumeDidChangeNotification + object:m_movie]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(processPositionChange:) + name:QTMovieTimeDidChangeNotification + object:m_movie]; + + if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_6) { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(processNaturalSizeChange:) + name:@"QTMovieNaturalSizeDidChangeNotification" + object:m_movie]; + + } + else { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(processNaturalSizeChange:) + name:QTMovieEditedNotification + object:m_movie]; + } + + [movie retain]; + } +} + +- (void) processEOS:(NSNotification *)notification +{ + Q_UNUSED(notification); + QMetaObject::invokeMethod(m_session, "processEOS", Qt::AutoConnection); +} + +- (void) processLoadStateChange:(NSNotification *)notification +{ + Q_UNUSED(notification); + QMetaObject::invokeMethod(m_session, "processLoadStateChange", Qt::AutoConnection); +} + +- (void) processVolumeChange:(NSNotification *)notification +{ + Q_UNUSED(notification); + QMetaObject::invokeMethod(m_session, "processVolumeChange", Qt::AutoConnection); +} + +- (void) processNaturalSizeChange :(NSNotification *)notification +{ + Q_UNUSED(notification); + QMetaObject::invokeMethod(m_session, "processNaturalSizeChange", Qt::AutoConnection); +} + +- (void) processPositionChange :(NSNotification *)notification +{ + Q_UNUSED(notification); + QMetaObject::invokeMethod(m_session, "processPositionChange", Qt::AutoConnection); +} + +@end + +static inline NSString *qString2CFStringRef(const QString &string) +{ + return [NSString stringWithCharacters:reinterpret_cast<const UniChar *>(string.unicode()) length:string.length()]; +} + +QT7PlayerSession::QT7PlayerSession(QObject *parent) + : QObject(parent) + , m_QTMovie(0) + , m_state(QMediaPlayer::StoppedState) + , m_mediaStatus(QMediaPlayer::NoMedia) + , m_mediaStream(0) + , m_videoOutput(0) + , m_muted(false) + , m_tryingAsync(false) + , m_volume(100) + , m_rate(1.0) + , m_duration(0) + , m_videoAvailable(false) + , m_audioAvailable(false) +{ + m_movieObserver = [[QTMovieObserver alloc] initWithPlayerSession:this]; +} + +QT7PlayerSession::~QT7PlayerSession() +{ + if (m_videoOutput) + m_videoOutput->setMovie(0); + + [(QTMovieObserver*)m_movieObserver setMovie:nil]; + [(QTMovieObserver*)m_movieObserver release]; + [(QTMovie*)m_QTMovie release]; +} + +void *QT7PlayerSession::movie() const +{ + return m_QTMovie; +} + +void QT7PlayerSession::setVideoOutput(QT7VideoOutput *output) +{ + if (m_videoOutput == output) + return; + + if (m_videoOutput) + m_videoOutput->setMovie(0); + + m_videoOutput = output; + + if (m_videoOutput && m_state != QMediaPlayer::StoppedState) + m_videoOutput->setMovie(m_QTMovie); +} + +qint64 QT7PlayerSession::position() const +{ + if (!m_QTMovie) + return 0; + + QTTime qtTime = [(QTMovie*)m_QTMovie currentTime]; + + return static_cast<quint64>(float(qtTime.timeValue) / float(qtTime.timeScale) * 1000.0f); +} + +qint64 QT7PlayerSession::duration() const +{ + if (!m_QTMovie) + return 0; + + QTTime qtTime = [(QTMovie*)m_QTMovie duration]; + + return static_cast<quint64>(float(qtTime.timeValue) / float(qtTime.timeScale) * 1000.0f); +} + +QMediaPlayer::State QT7PlayerSession::state() const +{ + return m_state; +} + +QMediaPlayer::MediaStatus QT7PlayerSession::mediaStatus() const +{ + return m_mediaStatus; +} + +int QT7PlayerSession::bufferStatus() const +{ + return 100; +} + +int QT7PlayerSession::volume() const +{ + return m_volume; +} + +bool QT7PlayerSession::isMuted() const +{ + return m_muted; +} + +bool QT7PlayerSession::isSeekable() const +{ + return true; +} + +#ifndef QUICKTIME_C_API_AVAILABLE +@interface QTMovie(QtExtensions) +- (NSArray*)loadedRanges; +- (QTTime)maxTimeLoaded; +@end +#endif + +QMediaTimeRange QT7PlayerSession::availablePlaybackRanges() const +{ + QTMovie *movie = (QTMovie*)m_QTMovie; +#ifndef QUICKTIME_C_API_AVAILABLE + AutoReleasePool pool; + if ([movie respondsToSelector:@selector(loadedRanges)]) { + QMediaTimeRange rc; + NSArray *r = [movie loadedRanges]; + for (NSValue *tr in r) { + QTTimeRange timeRange = [tr QTTimeRangeValue]; + qint64 startTime = qint64(float(timeRange.time.timeValue) / timeRange.time.timeScale * 1000.0); + rc.addInterval(startTime, startTime + qint64(float(timeRange.duration.timeValue) / timeRange.duration.timeScale * 1000.0)); + } + return rc; + } + else if ([movie respondsToSelector:@selector(maxTimeLoaded)]) { + QTTime loadedTime = [movie maxTimeLoaded]; + return QMediaTimeRange(0, qint64(float(loadedTime.timeValue) / loadedTime.timeScale * 1000.0)); + } +#else + TimeValue loadedTime; + TimeScale scale; + Movie m = [movie quickTimeMovie]; + if (GetMaxLoadedTimeInMovie(m, &loadedTime) == noErr) { + scale = GetMovieTimeScale(m); + return QMediaTimeRange(0, qint64(float(loadedTime) / scale * 1000.0f)); + } +#endif + return QMediaTimeRange(0, duration()); +} + +qreal QT7PlayerSession::playbackRate() const +{ + return m_rate; +} + +void QT7PlayerSession::setPlaybackRate(qreal rate) +{ + if (qFuzzyCompare(m_rate, rate)) + return; + + m_rate = rate; + + if (m_QTMovie != 0 && m_state == QMediaPlayer::PlayingState) { + AutoReleasePool pool; + float preferredRate = [[(QTMovie*)m_QTMovie attributeForKey:@"QTMoviePreferredRateAttribute"] floatValue]; + [(QTMovie*)m_QTMovie setRate:preferredRate * m_rate]; + } +} + +void QT7PlayerSession::setPosition(qint64 pos) +{ + if ( !isSeekable() || pos == position()) + return; + + if (duration() > 0) + pos = qMin(pos, duration()); + + QTTime newQTTime = [(QTMovie*)m_QTMovie currentTime]; + newQTTime.timeValue = (pos / 1000.0f) * newQTTime.timeScale; + [(QTMovie*)m_QTMovie setCurrentTime:newQTTime]; + + //reset the EndOfMedia status position is changed after playback is finished + if (m_mediaStatus == QMediaPlayer::EndOfMedia) + processLoadStateChange(); +} + +void QT7PlayerSession::play() +{ + if (m_state == QMediaPlayer::PlayingState) + return; + + m_state = QMediaPlayer::PlayingState; + + if (m_videoOutput) + m_videoOutput->setMovie(m_QTMovie); + + //reset the EndOfMedia status if the same file is played again + if (m_mediaStatus == QMediaPlayer::EndOfMedia) + processLoadStateChange(); + + AutoReleasePool pool; + float preferredRate = [[(QTMovie*)m_QTMovie attributeForKey:@"QTMoviePreferredRateAttribute"] floatValue]; + [(QTMovie*)m_QTMovie setRate:preferredRate * m_rate]; + + processLoadStateChange(); + emit stateChanged(m_state); +} + +void QT7PlayerSession::pause() +{ + if (m_state == QMediaPlayer::PausedState) + return; + + m_state = QMediaPlayer::PausedState; + + if (m_videoOutput) + m_videoOutput->setMovie(m_QTMovie); + + //reset the EndOfMedia status if the same file is played again + if (m_mediaStatus == QMediaPlayer::EndOfMedia) + processLoadStateChange(); + + [(QTMovie*)m_QTMovie setRate:0]; + + processLoadStateChange(); + emit stateChanged(m_state); +} + +void QT7PlayerSession::stop() +{ + if (m_state == QMediaPlayer::StoppedState) + return; + + m_state = QMediaPlayer::StoppedState; + + [(QTMovie*)m_QTMovie setRate:0]; + setPosition(0); + + if (m_videoOutput) + m_videoOutput->setMovie(0); + + processLoadStateChange(); + emit stateChanged(m_state); + emit positionChanged(position()); +} + +void QT7PlayerSession::setVolume(int volume) +{ + if (m_volume == volume) + return; + + m_volume = volume; + + if (m_QTMovie != 0) + [(QTMovie*)m_QTMovie setVolume:m_volume / 100.0f]; + + emit volumeChanged(m_volume); +} + +void QT7PlayerSession::setMuted(bool muted) +{ + if (m_muted == muted) + return; + + m_muted = muted; + + if (m_QTMovie != 0) + [(QTMovie*)m_QTMovie setMuted:m_muted]; + + emit mutedChanged(muted); +} + +QMediaContent QT7PlayerSession::media() const +{ + return m_resources; +} + +const QIODevice *QT7PlayerSession::mediaStream() const +{ + return m_mediaStream; +} + +void QT7PlayerSession::setMedia(const QMediaContent &content, QIODevice *stream) +{ + AutoReleasePool pool; + +#ifdef QT_DEBUG_QT7 + qDebug() << Q_FUNC_INFO << content.canonicalUrl(); +#endif + + if (m_QTMovie) { + [(QTMovieObserver*)m_movieObserver setMovie:nil]; + + if (m_videoOutput) + m_videoOutput->setMovie(0); + + [(QTMovie*)m_QTMovie release]; + m_QTMovie = 0; + m_resourceHandler.clear(); + } + + m_resources = content; + m_mediaStream = stream; + QMediaPlayer::MediaStatus oldMediaStatus = m_mediaStatus; + + if (content.isNull()) { + m_mediaStatus = QMediaPlayer::NoMedia; + if (m_state != QMediaPlayer::StoppedState) + emit stateChanged(m_state = QMediaPlayer::StoppedState); + + if (m_mediaStatus != oldMediaStatus) + emit mediaStatusChanged(m_mediaStatus); + emit positionChanged(position()); + return; + } + + m_mediaStatus = QMediaPlayer::LoadingMedia; + if (m_mediaStatus != oldMediaStatus) + emit mediaStatusChanged(m_mediaStatus); + + QNetworkRequest request = content.canonicalResource().request(); + + QVariant cookies = request.header(QNetworkRequest::CookieHeader); + if (cookies.isValid()) { + NSHTTPCookieStorage *store = [NSHTTPCookieStorage sharedHTTPCookieStorage]; + QList<QNetworkCookie> cookieList = cookies.value<QList<QNetworkCookie> >(); + + foreach (const QNetworkCookie &requestCookie, cookieList) { + NSMutableDictionary *p = [NSMutableDictionary dictionaryWithObjectsAndKeys: + qString2CFStringRef(requestCookie.name()), NSHTTPCookieName, + qString2CFStringRef(requestCookie.value()), NSHTTPCookieValue, + qString2CFStringRef(requestCookie.domain()), NSHTTPCookieDomain, + qString2CFStringRef(requestCookie.path()), NSHTTPCookiePath, + nil + ]; + if (requestCookie.isSessionCookie()) + [p setObject:[NSString stringWithUTF8String:"TRUE"] forKey:NSHTTPCookieDiscard]; + else + [p setObject:[NSDate dateWithTimeIntervalSince1970:requestCookie.expirationDate().toTime_t()] forKey:NSHTTPCookieExpires]; + + [store setCookie:[NSHTTPCookie cookieWithProperties:p]]; + } + } + + // Attempt multiple times to open the movie. + // First try - attempt open in async mode + openMovie(true); + + emit positionChanged(position()); +} + +void QT7PlayerSession::openMovie(bool tryAsync) +{ + QUrl requestUrl = m_resources.canonicalResource().request().url(); + if (requestUrl.scheme().isEmpty()) + requestUrl.setScheme(QLatin1String("file")); + +#ifdef QT_DEBUG_QT7 + qDebug() << Q_FUNC_INFO << requestUrl; +#endif + + NSError *err = 0; + NSString *urlString = [NSString stringWithUTF8String:requestUrl.toEncoded().constData()]; + + NSMutableDictionary *attr = [NSMutableDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithBool:YES], QTMovieOpenAsyncOKAttribute, + [NSNumber numberWithBool:YES], QTMovieIsActiveAttribute, + [NSNumber numberWithBool:YES], QTMovieResolveDataRefsAttribute, + [NSNumber numberWithBool:YES], QTMovieDontInteractWithUserAttribute, + nil]; + + + if (requestUrl.scheme() == QLatin1String("qrc")) { + // Load from Qt resource + m_resourceHandler.setResourceFile(QLatin1Char(':') + requestUrl.path()); + if (!m_resourceHandler.isValid()) { + emit error(QMediaPlayer::FormatError, tr("Attempting to play invalid Qt resource")); + return; + } + + CFDataRef resourceData = + CFDataCreateWithBytesNoCopy(0, m_resourceHandler.data(), m_resourceHandler.size(), kCFAllocatorNull); + + QTDataReference *dataReference = + [QTDataReference dataReferenceWithReferenceToData:(NSData*)resourceData + name:qString2CFStringRef(requestUrl.path()) + MIMEType:nil]; + + [attr setObject:dataReference forKey:QTMovieDataReferenceAttribute]; + + CFRelease(resourceData); + } else { + [attr setObject:[NSURL URLWithString:urlString] forKey:QTMovieURLAttribute]; + } + + if (tryAsync && QSysInfo::MacintoshVersion >= QSysInfo::MV_10_6) { + [attr setObject:[NSNumber numberWithBool:YES] forKey:@"QTMovieOpenAsyncRequiredAttribute"]; +// XXX: This is disabled for now. causes some problems with video playback for some formats +// [attr setObject:[NSNumber numberWithBool:YES] forKey:@"QTMovieOpenForPlaybackAttribute"]; + m_tryingAsync = true; + } + else + m_tryingAsync = false; + + m_QTMovie = [QTMovie movieWithAttributes:attr error:&err]; + if (err != nil) { + // First attempt to test for inability to perform async +// if ([err code] == QTErrorMovieOpeningCannotBeAsynchronous) { XXX: error code unknown! + if (m_tryingAsync) { + m_tryingAsync = false; + err = nil; + [attr removeObjectForKey:@"QTMovieOpenAsyncRequiredAttribute"]; + m_QTMovie = [QTMovie movieWithAttributes:attr error:&err]; + } + } + + if (err != nil) { + m_QTMovie = 0; + QString description = QString::fromUtf8([[err localizedDescription] UTF8String]); + emit error(QMediaPlayer::FormatError, description); + +#ifdef QT_DEBUG_QT7 + qDebug() << Q_FUNC_INFO << description; +#endif + } + else { + [(QTMovie*)m_QTMovie retain]; + + [(QTMovieObserver*)m_movieObserver setMovie:(QTMovie*)m_QTMovie]; + + if (m_state != QMediaPlayer::StoppedState && m_videoOutput) + m_videoOutput->setMovie(m_QTMovie); + + processLoadStateChange(); + + [(QTMovie*)m_QTMovie setMuted:m_muted]; + [(QTMovie*)m_QTMovie setVolume:m_volume / 100.0f]; + } +} + +bool QT7PlayerSession::isAudioAvailable() const +{ + if (!m_QTMovie) + return false; + + AutoReleasePool pool; + return [[(QTMovie*)m_QTMovie attributeForKey:@"QTMovieHasAudioAttribute"] boolValue] == YES; +} + +bool QT7PlayerSession::isVideoAvailable() const +{ + if (!m_QTMovie) + return false; + + AutoReleasePool pool; + return [[(QTMovie*)m_QTMovie attributeForKey:@"QTMovieHasVideoAttribute"] boolValue] == YES; +} + +void QT7PlayerSession::processEOS() +{ +#ifdef QT_DEBUG_QT7 + qDebug() << Q_FUNC_INFO; +#endif + emit positionChanged(position()); + m_mediaStatus = QMediaPlayer::EndOfMedia; + if (m_videoOutput) + m_videoOutput->setMovie(0); + emit stateChanged(m_state = QMediaPlayer::StoppedState); + emit mediaStatusChanged(m_mediaStatus); +} + +void QT7PlayerSession::processLoadStateChange() +{ + if (!m_QTMovie) + return; + + AutoReleasePool pool; + + long state = [[(QTMovie*)m_QTMovie attributeForKey:QTMovieLoadStateAttribute] longValue]; + +#ifdef QT_DEBUG_QT7 + qDebug() << Q_FUNC_INFO << state; +#endif + +#ifndef QUICKTIME_C_API_AVAILABLE + enum { + kMovieLoadStateError = -1L, + kMovieLoadStateLoading = 1000, + kMovieLoadStateLoaded = 2000, + kMovieLoadStatePlayable = 10000, + kMovieLoadStatePlaythroughOK = 20000, + kMovieLoadStateComplete = 100000 + }; +#endif + + if (state == kMovieLoadStateError) { + if (m_tryingAsync) { + NSError *error = [(QTMovie*)m_QTMovie attributeForKey:@"QTMovieLoadStateErrorAttribute"]; + if ([error code] == componentNotThreadSafeErr) { + // Last Async check, try again with no such flag + openMovie(false); + } + } + else { + if (m_videoOutput) + m_videoOutput->setMovie(0); + + emit error(QMediaPlayer::FormatError, tr("Failed to load media")); + emit mediaStatusChanged(m_mediaStatus = QMediaPlayer::InvalidMedia); + emit stateChanged(m_state = QMediaPlayer::StoppedState); + } + + return; + } + + QMediaPlayer::MediaStatus newStatus = QMediaPlayer::NoMedia; + bool isPlaying = (m_state != QMediaPlayer::StoppedState); + + if (state >= kMovieLoadStatePlaythroughOK) { + newStatus = isPlaying ? QMediaPlayer::BufferedMedia : QMediaPlayer::LoadedMedia; + } else if (state >= kMovieLoadStatePlayable) + newStatus = isPlaying ? QMediaPlayer::BufferingMedia : QMediaPlayer::LoadingMedia; + else if (state >= kMovieLoadStateLoading) { + if (!isPlaying) + newStatus = QMediaPlayer::LoadingMedia; + else if (m_mediaStatus >= QMediaPlayer::LoadedMedia) + newStatus = QMediaPlayer::StalledMedia; + else + newStatus = QMediaPlayer::LoadingMedia; + } + + if (state >= kMovieLoadStatePlayable && + m_state == QMediaPlayer::PlayingState && + [(QTMovie*)m_QTMovie rate] == 0) { + + float preferredRate = [[(QTMovie*)m_QTMovie attributeForKey:@"QTMoviePreferredRateAttribute"] floatValue]; + + [(QTMovie*)m_QTMovie setRate:preferredRate * m_rate]; + } + + if (state >= kMovieLoadStateLoaded) { + qint64 currentDuration = duration(); + if (m_duration != currentDuration) + emit durationChanged(m_duration = currentDuration); + + if (m_audioAvailable != isAudioAvailable()) + emit audioAvailableChanged(m_audioAvailable = !m_audioAvailable); + + if (m_videoAvailable != isVideoAvailable()) + emit videoAvailableChanged(m_videoAvailable = !m_videoAvailable); + } + + if (newStatus != m_mediaStatus) + emit mediaStatusChanged(m_mediaStatus = newStatus); +} + +void QT7PlayerSession::processVolumeChange() +{ + if (!m_QTMovie) + return; + + int newVolume = qRound(100.0f * [((QTMovie*)m_QTMovie) volume]); + + if (newVolume != m_volume) { + emit volumeChanged(m_volume = newVolume); + } +} + +void QT7PlayerSession::processNaturalSizeChange() +{ + AutoReleasePool pool; + NSSize size = [[(QTMovie*)m_QTMovie attributeForKey:@"QTMovieNaturalSizeAttribute"] sizeValue]; +#ifdef QT_DEBUG_QT7 + qDebug() << Q_FUNC_INFO << QSize(size.width, size.height); +#endif + + if (m_videoOutput) + m_videoOutput->updateNaturalSize(QSize(size.width, size.height)); +} + +void QT7PlayerSession::processPositionChange() +{ + emit positionChanged(position()); +} + +#include "moc_qt7playersession.cpp" |