diff options
author | Qt Continuous Integration System <qt-info@nokia.com> | 2010-03-04 08:23:11 (GMT) |
---|---|---|
committer | Qt Continuous Integration System <qt-info@nokia.com> | 2010-03-04 08:23:11 (GMT) |
commit | b3ccc9b30c3a176021b6205193b8baa416e9e813 (patch) | |
tree | bc7ce3bc52c142c83dad59fbe71564ac01c49713 | |
parent | 2cb4b0a528a6d979a3edeb08611a6ac11cb54bd4 (diff) | |
parent | 5a3b9d3daf64ea686427478391d3773c5a1e024e (diff) | |
download | Qt-b3ccc9b30c3a176021b6205193b8baa416e9e813.zip Qt-b3ccc9b30c3a176021b6205193b8baa416e9e813.tar.gz Qt-b3ccc9b30c3a176021b6205193b8baa416e9e813.tar.bz2 |
Merge branch '4.7' of scm.dev.nokia.troll.no:qt/qt-multimedia-staging into 4.7-integration
* '4.7' of scm.dev.nokia.troll.no:qt/qt-multimedia-staging:
WaveDecoder; be more permissive in handling of wave file formats.
Debug media player status and media state changes.
Added playlist playback modes combo box to player demo
Added QMediaPlayer::StreamPlayback flag to query/select backend capable
-rw-r--r-- | demos/multimedia/player/player.cpp | 28 | ||||
-rw-r--r-- | demos/multimedia/player/player.h | 3 | ||||
-rw-r--r-- | src/multimedia/base/qmediaserviceprovider.cpp | 43 | ||||
-rw-r--r-- | src/multimedia/base/qmediaserviceprovider.h | 3 | ||||
-rw-r--r-- | src/multimedia/effects/wavedecoder_p.cpp | 21 | ||||
-rw-r--r-- | src/multimedia/effects/wavedecoder_p.h | 1 | ||||
-rw-r--r-- | src/multimedia/playback/qmediaplayer.cpp | 36 | ||||
-rw-r--r-- | src/multimedia/playback/qmediaplayer.h | 3 | ||||
-rw-r--r-- | tests/auto/qmediaserviceprovider/tst_qmediaserviceprovider.cpp | 72 |
9 files changed, 188 insertions, 22 deletions
diff --git a/demos/multimedia/player/player.cpp b/demos/multimedia/player/player.cpp index 49d18cb..af30a97 100644 --- a/demos/multimedia/player/player.cpp +++ b/demos/multimedia/player/player.cpp @@ -81,6 +81,22 @@ Player::Player(QWidget *parent) connect(playlistView, SIGNAL(activated(QModelIndex)), this, SLOT(jump(QModelIndex))); + playbackModeBox = new QComboBox; + playbackModeBox->addItem(tr("Linear"), + QVariant::fromValue<QMediaPlaylist::PlaybackMode>(QMediaPlaylist::Linear)); + playbackModeBox->addItem(tr("Loop"), + QVariant::fromValue<QMediaPlaylist::PlaybackMode>(QMediaPlaylist::Loop)); + playbackModeBox->addItem(tr("Random"), + QVariant::fromValue<QMediaPlaylist::PlaybackMode>(QMediaPlaylist::Random)); + playbackModeBox->addItem(tr("Current Item Once"), + QVariant::fromValue<QMediaPlaylist::PlaybackMode>(QMediaPlaylist::CurrentItemOnce)); + playbackModeBox->addItem(tr("Current Item In Loop"), + QVariant::fromValue<QMediaPlaylist::PlaybackMode>(QMediaPlaylist::CurrentItemInLoop)); + playbackModeBox->setCurrentIndex(0); + + connect(playbackModeBox, SIGNAL(activated(int)), SLOT(updatePlaybackMode())); + updatePlaybackMode(); + slider = new QSlider(Qt::Horizontal); slider->setRange(0, player->duration() / 1000); @@ -126,12 +142,16 @@ Player::Player(QWidget *parent) else colorButton->setEnabled(false); + QBoxLayout *playlistLayout = new QVBoxLayout; + playlistLayout->addWidget(playlistView); + playlistLayout->addWidget(playbackModeBox); + QBoxLayout *displayLayout = new QHBoxLayout; if (videoWidget) displayLayout->addWidget(videoWidget, 2); else displayLayout->addWidget(coverLabel, 2); - displayLayout->addWidget(playlistView); + displayLayout->addLayout(playlistLayout); QBoxLayout *controlLayout = new QHBoxLayout; controlLayout->setMargin(0); @@ -333,3 +353,9 @@ void Player::showColorDialog() } colorDialog->show(); } + +void Player::updatePlaybackMode() +{ + playlist->setPlaybackMode( + playbackModeBox->itemData(playbackModeBox->currentIndex()).value<QMediaPlaylist::PlaybackMode>()); +} diff --git a/demos/multimedia/player/player.h b/demos/multimedia/player/player.h index 1de8b1a..cda3eb9 100644 --- a/demos/multimedia/player/player.h +++ b/demos/multimedia/player/player.h @@ -57,6 +57,7 @@ class QAbstractItemView; class QLabel; class QModelIndex; class QSlider; +class QComboBox; class QMediaPlayer; class QVideoWidget; class PlaylistModel; @@ -87,6 +88,7 @@ private slots: void bufferingProgress(int progress); void showColorDialog(); + void updatePlaybackMode(); private: void setTrackInfo(const QString &info); @@ -97,6 +99,7 @@ private: QVideoWidget *videoWidget; QLabel *coverLabel; QSlider *slider; + QComboBox *playbackModeBox; PlaylistModel *playlistModel; QAbstractItemView *playlistView; QDialog *colorDialog; diff --git a/src/multimedia/base/qmediaserviceprovider.cpp b/src/multimedia/base/qmediaserviceprovider.cpp index d51d682..6e11079 100644 --- a/src/multimedia/base/qmediaserviceprovider.cpp +++ b/src/multimedia/base/qmediaserviceprovider.cpp @@ -102,6 +102,9 @@ public: \value RecordingSupport The service provides audio or video recording functions. + + \value StreamPlayback + The service is capable of playing QIODevice based streams. */ /*! @@ -396,14 +399,25 @@ public: QMediaServiceSupportedFormatsInterface *iface = qobject_cast<QMediaServiceSupportedFormatsInterface*>(obj); - //if low latency playback was asked, skip services known - //not to provide low latency playback - if (flags & QMediaPlayer::LowLatency) { + + if (flags) { QMediaServiceFeaturesInterface *iface = qobject_cast<QMediaServiceFeaturesInterface*>(obj); - if (iface && !(iface->supportedFeatures(serviceType) & QMediaServiceProviderHint::LowLatencyPlayback)) - continue; + if (iface) { + QMediaServiceProviderHint::Features features = iface->supportedFeatures(serviceType); + + //if low latency playback was asked, skip services known + //not to provide low latency playback + if ((flags & QMediaPlayer::LowLatency) && + !(features & QMediaServiceProviderHint::LowLatencyPlayback)) + continue; + + //the same for QIODevice based streams support + if ((flags & QMediaPlayer::StreamPlayback) && + !(features & QMediaServiceProviderHint::StreamPlayback)) + continue; + } } if (iface) @@ -434,14 +448,25 @@ public: QMediaServiceSupportedFormatsInterface *iface = qobject_cast<QMediaServiceSupportedFormatsInterface*>(obj); - // If low latency playback was asked for, skip MIME types from services known - // not to provide low latency playback + if (flags & QMediaPlayer::LowLatency) { QMediaServiceFeaturesInterface *iface = qobject_cast<QMediaServiceFeaturesInterface*>(obj); - if (iface && !(iface->supportedFeatures(serviceType) & QMediaServiceProviderHint::LowLatencyPlayback)) - continue; + if (iface) { + QMediaServiceProviderHint::Features features = iface->supportedFeatures(serviceType); + + // If low latency playback was asked for, skip MIME types from services known + // not to provide low latency playback + if ((flags & QMediaPlayer::LowLatency) && + !(features & QMediaServiceProviderHint::LowLatencyPlayback)) + continue; + + //the same for QIODevice based streams support + if ((flags & QMediaPlayer::StreamPlayback) && + !(features & QMediaServiceProviderHint::StreamPlayback)) + continue; + } } if (iface) { diff --git a/src/multimedia/base/qmediaserviceprovider.h b/src/multimedia/base/qmediaserviceprovider.h index 2ee0ae4..6e31493 100644 --- a/src/multimedia/base/qmediaserviceprovider.h +++ b/src/multimedia/base/qmediaserviceprovider.h @@ -64,7 +64,8 @@ public: enum Feature { LowLatencyPlayback = 0x01, - RecordingSupport = 0x02 + RecordingSupport = 0x02, + StreamPlayback = 0x04 }; Q_DECLARE_FLAGS(Features, Feature) diff --git a/src/multimedia/effects/wavedecoder_p.cpp b/src/multimedia/effects/wavedecoder_p.cpp index f2277ae..b534ded 100644 --- a/src/multimedia/effects/wavedecoder_p.cpp +++ b/src/multimedia/effects/wavedecoder_p.cpp @@ -55,7 +55,7 @@ WaveDecoder::WaveDecoder(QIODevice *s, QObject *parent): { open(QIODevice::ReadOnly | QIODevice::Unbuffered); - if (source->bytesAvailable() >= sizeof(CombinedHeader)) + if (source->bytesAvailable() >= qint64(sizeof(CombinedHeader) + sizeof(DATAHeader) + sizeof(quint16))) QTimer::singleShot(0, this, SLOT(handleData())); else connect(source, SIGNAL(readyRead()), SLOT(handleData())); @@ -105,7 +105,7 @@ qint64 WaveDecoder::writeData(const char *data, qint64 len) void WaveDecoder::handleData() { - if (source->bytesAvailable() < sizeof(CombinedHeader)) + if (source->bytesAvailable() < qint64(sizeof(CombinedHeader) + sizeof(DATAHeader) + sizeof(quint16))) return; source->disconnect(SIGNAL(readyRead()), this, SLOT(handleData())); @@ -114,12 +114,23 @@ void WaveDecoder::handleData() if (qstrncmp(header.riff.descriptor.id, "RIFF", 4) != 0 || qstrncmp(header.riff.type, "WAVE", 4) != 0 || qstrncmp(header.wave.descriptor.id, "fmt ", 4) != 0 || - (header.wave.audioFormat != 0 && header.wave.audioFormat != 1) || - qstrncmp(header.data.descriptor.id, "data", 4) != 0) { + (header.wave.audioFormat != 0 && header.wave.audioFormat != 1)) { emit invalidFormat(); } else { + DATAHeader dataHeader; + + if (qFromLittleEndian<quint32>(header.wave.descriptor.size) > sizeof(WAVEHeader)) { + // Extended data available + quint16 extraFormatBytes; + source->peek((char*)&extraFormatBytes, sizeof(quint16)); + extraFormatBytes = qFromLittleEndian<quint16>(extraFormatBytes); + source->read(sizeof(quint16) + extraFormatBytes); // dump it all + } + + source->read((char*)&dataHeader, sizeof(DATAHeader)); + int bps = qFromLittleEndian<quint16>(header.wave.bitsPerSample); format.setCodec(QLatin1String("audio/pcm")); @@ -129,7 +140,7 @@ void WaveDecoder::handleData() format.setSampleSize(bps); format.setChannels(qFromLittleEndian<quint16>(header.wave.numChannels)); - dataSize = qFromLittleEndian<quint32>(header.data.descriptor.size); + dataSize = qFromLittleEndian<quint32>(dataHeader.descriptor.size); haveFormat = true; connect(source, SIGNAL(readyRead()), SIGNAL(readyRead())); diff --git a/src/multimedia/effects/wavedecoder_p.h b/src/multimedia/effects/wavedecoder_p.h index 00aa14e..fa1f77e 100644 --- a/src/multimedia/effects/wavedecoder_p.h +++ b/src/multimedia/effects/wavedecoder_p.h @@ -116,7 +116,6 @@ private: { RIFFHeader riff; WAVEHeader wave; - DATAHeader data; }; bool haveFormat; diff --git a/src/multimedia/playback/qmediaplayer.cpp b/src/multimedia/playback/qmediaplayer.cpp index 27bff02..9466cad 100644 --- a/src/multimedia/playback/qmediaplayer.cpp +++ b/src/multimedia/playback/qmediaplayer.cpp @@ -43,6 +43,7 @@ #include <QtCore/qmetaobject.h> #include <QtCore/qtimer.h> #include <QtCore/qpointer.h> +#include <QtCore/qdebug.h> #include <QtMultimedia/qmediaplayer.h> @@ -55,6 +56,7 @@ #include <QtMultimedia/qvideowidget.h> #include <QtMultimedia/qgraphicsvideoitem.h> +//#define DEBUG_PLAYER_STATE QT_BEGIN_HEADER @@ -152,10 +154,16 @@ public: void _q_playlistDestroyed(); }; +#define ENUM_NAME(c,e,v) (c::staticMetaObject.enumerator(c::staticMetaObject.indexOfEnumerator(e)).valueToKey((v))) + void QMediaPlayerPrivate::_q_stateChanged(QMediaPlayer::State ps) { Q_Q(QMediaPlayer); +#ifdef DEBUG_PLAYER_STATE + qDebug() << "State changed:" << ENUM_NAME(QMediaPlayer, "State", ps) << (filterStates ? "(filtered)" : ""); +#endif + if (filterStates) return; @@ -183,6 +191,10 @@ void QMediaPlayerPrivate::_q_mediaStatusChanged(QMediaPlayer::MediaStatus status { Q_Q(QMediaPlayer); +#ifdef DEBUG_PLAYER_STATE + qDebug() << "MediaStatus changed:" << ENUM_NAME(QMediaPlayer, "MediaStatus", status); +#endif + switch (status) { case QMediaPlayer::StalledMedia: case QMediaPlayer::BufferingMedia: @@ -230,8 +242,12 @@ void QMediaPlayerPrivate::_q_updateMedia(const QMediaContent &media) state = control->state(); - if (state != currentState) + if (state != currentState) { +#ifdef DEBUG_PLAYER_STATE + qDebug() << "State changed:" << ENUM_NAME(QMediaPlayer, "State", state); +#endif emit q_func()->stateChanged(state); + } } void QMediaPlayerPrivate::_q_playlistDestroyed() @@ -243,10 +259,17 @@ void QMediaPlayerPrivate::_q_playlistDestroyed() static QMediaService *playerService(QMediaPlayer::Flags flags, QMediaServiceProvider *provider) { - if (flags && QMediaPlayer::LowLatency) + if (flags) { + QMediaServiceProviderHint::Features features = 0; + if (flags & QMediaPlayer::LowLatency) + features |= QMediaServiceProviderHint::LowLatencyPlayback; + + if (flags & QMediaPlayer::StreamPlayback) + features |= QMediaServiceProviderHint::StreamPlayback; + return provider->requestService(Q_MEDIASERVICE_MEDIAPLAYER, - QMediaServiceProviderHint(QMediaServiceProviderHint::LowLatencyPlayback)); - else + QMediaServiceProviderHint(features)); + } else return provider->requestService(Q_MEDIASERVICE_MEDIAPLAYER); } @@ -945,6 +968,11 @@ QStringList QMediaPlayer::supportedMimeTypes(Flags flags) The player is expected to be used with simple audio formats, but playback should start without significant delay. Such playback service can be used for beeps, ringtones, etc. + + \value StreamPlayback + The player is expected to play QIODevice based streams. + If passed to QMediaPlayer constructor, the service supporting + streams playback will be choosen. */ QT_END_NAMESPACE diff --git a/src/multimedia/playback/qmediaplayer.h b/src/multimedia/playback/qmediaplayer.h index 1b761ce..129b244 100644 --- a/src/multimedia/playback/qmediaplayer.h +++ b/src/multimedia/playback/qmediaplayer.h @@ -99,7 +99,8 @@ public: enum Flag { - LowLatency = 0x01 + LowLatency = 0x01, + StreamPlayback = 0x02 }; Q_DECLARE_FLAGS(Flags, Flag) diff --git a/tests/auto/qmediaserviceprovider/tst_qmediaserviceprovider.cpp b/tests/auto/qmediaserviceprovider/tst_qmediaserviceprovider.cpp index 9bca189..d839fe5 100644 --- a/tests/auto/qmediaserviceprovider/tst_qmediaserviceprovider.cpp +++ b/tests/auto/qmediaserviceprovider/tst_qmediaserviceprovider.cpp @@ -213,6 +213,57 @@ public: } }; +class MockServicePlugin4 : public QMediaServiceProviderPlugin, + public QMediaServiceSupportedFormatsInterface, + public QMediaServiceFeaturesInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaServiceSupportedFormatsInterface) + Q_INTERFACES(QMediaServiceFeaturesInterface) +public: + QStringList keys() const + { + return QStringList() << QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER); + } + + QMediaService* create(QString const& key) + { + if (keys().contains(key)) + return new MockMediaService("MockServicePlugin4"); + else + return 0; + } + + void release(QMediaService *service) + { + delete service; + } + + QtMultimedia::SupportEstimate hasSupport(const QString &mimeType, const QStringList& codecs) const + { + if (codecs.contains(QLatin1String("jpeg2000"))) + return QtMultimedia::NotSupported; + + if (supportedMimeTypes().contains(mimeType)) + return QtMultimedia::ProbablySupported; + + return QtMultimedia::MaybeSupported; + } + + QStringList supportedMimeTypes() const + { + return QStringList() << "video/mp4" << "video/quicktime"; + } + + QMediaServiceProviderHint::Features supportedFeatures(const QByteArray &service) const + { + if (service == QByteArray(Q_MEDIASERVICE_MEDIAPLAYER)) + return QMediaServiceProviderHint::StreamPlayback; + else + return 0; + } +}; + class MockMediaServiceProvider : public QMediaServiceProvider @@ -253,6 +304,7 @@ void tst_QMediaServiceProvider::initTestCase() plugins << new MockServicePlugin1; plugins << new MockServicePlugin2; plugins << new MockServicePlugin3; + plugins << new MockServicePlugin4; QMediaPluginLoader::setStaticPlugins(QLatin1String("/mediaservices"), plugins); } @@ -312,12 +364,32 @@ void tst_QMediaServiceProvider::testHasSupport() QCOMPARE(QMediaPlayer::hasSupport("audio/ogg"), QtMultimedia::ProbablySupported); QCOMPARE(QMediaPlayer::hasSupport("audio/wav"), QtMultimedia::ProbablySupported); + //test low latency flag support + QCOMPARE(QMediaPlayer::hasSupport("audio/wav", QStringList(), QMediaPlayer::LowLatency), + QtMultimedia::ProbablySupported); + //plugin1 probably supports audio/ogg, it checked because it doesn't provide features iface + QCOMPARE(QMediaPlayer::hasSupport("audio/ogg", QStringList(), QMediaPlayer::LowLatency), + QtMultimedia::ProbablySupported); + //Plugin4 is not checked here, sine it's known not support low latency + QCOMPARE(QMediaPlayer::hasSupport("video/quicktime", QStringList(), QMediaPlayer::LowLatency), + QtMultimedia::MaybeSupported); + + //test streaming flag support + QCOMPARE(QMediaPlayer::hasSupport("video/quicktime", QStringList(), QMediaPlayer::StreamPlayback), + QtMultimedia::ProbablySupported); + //Plugin2 is not checked here, sine it's known not support streaming + QCOMPARE(QMediaPlayer::hasSupport("audio/wav", QStringList(), QMediaPlayer::StreamPlayback), + QtMultimedia::MaybeSupported); + //ensure the correct media player plugin is choosen for mime type QMediaPlayer simplePlayer(0, QMediaPlayer::LowLatency); QCOMPARE(simplePlayer.service()->objectName(), QLatin1String("MockServicePlugin2")); QMediaPlayer mediaPlayer; QVERIFY(mediaPlayer.service()->objectName() != QLatin1String("MockServicePlugin2")); + + QMediaPlayer streamPlayer(0, QMediaPlayer::StreamPlayback); + QCOMPARE(streamPlayer.service()->objectName(), QLatin1String("MockServicePlugin4")); } void tst_QMediaServiceProvider::testSupportedMimeTypes() |