From b6e9d52b0bcb263751542efe7f7e7379e0a7ee9f Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Fri, 29 Aug 2014 11:33:37 +0200 Subject: [PATCH 01/10] Bump version Change-Id: I123f7fd8e2f88b36a69d3d5713f3b6390db610bc --- .qmake.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.qmake.conf b/.qmake.conf index 60effa7d..8c368751 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -1,4 +1,4 @@ load(qt_build_config) CONFIG += qt_example_installs -MODULE_VERSION = 5.3.2 +MODULE_VERSION = 5.3.3 From 006cdeee92b0ecc292cfba7871fd1dafaff4c05d Mon Sep 17 00:00:00 2001 From: Bernd Weimer Date: Wed, 3 Sep 2014 13:46:36 +0200 Subject: [PATCH 02/10] QNX: Fix end of media notification When auto-play is on, EndOfMedia would not be emitted. This is due to a workaround for mmrenderer, that wrongly ignored stop events. Once media is played stop events will always have to be processed. Change-Id: I1cfd665bb06638ee3c86807aecc51e78f9baa938 Reviewed-by: Rafael Roquetto --- src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp b/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp index abb68278..66d64935 100644 --- a/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp +++ b/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp @@ -546,6 +546,7 @@ void MmRendererMediaPlayerControl::play() return; } + m_stopEventsToIgnore = 0; // once playing, stop events must be proccessed setState( QMediaPlayer::PlayingState); } From 18d6560db15d8f65b221717b9a769fd0f00cec35 Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Wed, 3 Sep 2014 14:45:50 +0200 Subject: [PATCH 03/10] Fix integer overflow in several audio plugins. Task-number: QTBUG-40804 Change-Id: If006cb7db319bb6fda4ce7eb4f907e897b5d9efa Reviewed-by: Christian Stromme --- src/plugins/alsa/qalsaaudioinput.cpp | 2 +- src/plugins/alsa/qalsaaudiooutput.cpp | 2 +- src/plugins/opensles/qopenslesaudioinput.cpp | 2 +- src/plugins/opensles/qopenslesaudiooutput.cpp | 2 +- src/plugins/pulseaudio/qaudioinput_pulse.cpp | 2 +- src/plugins/pulseaudio/qaudiooutput_pulse.cpp | 2 +- src/plugins/qnx-audio/audio/qnxaudioinput.cpp | 2 +- src/plugins/qnx-audio/audio/qnxaudiooutput.cpp | 2 +- src/plugins/windowsaudio/qwindowsaudioinput.cpp | 2 +- src/plugins/windowsaudio/qwindowsaudiooutput.cpp | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/plugins/alsa/qalsaaudioinput.cpp b/src/plugins/alsa/qalsaaudioinput.cpp index e01f2d70..c66fdb7f 100644 --- a/src/plugins/alsa/qalsaaudioinput.cpp +++ b/src/plugins/alsa/qalsaaudioinput.cpp @@ -768,7 +768,7 @@ qint64 QAlsaAudioInput::elapsedUSecs() const if (deviceState == QAudio::StoppedState) return 0; - return clockStamp.elapsed()*1000; + return clockStamp.elapsed() * qint64(1000); } void QAlsaAudioInput::reset() diff --git a/src/plugins/alsa/qalsaaudiooutput.cpp b/src/plugins/alsa/qalsaaudiooutput.cpp index c8d709cf..da25a885 100644 --- a/src/plugins/alsa/qalsaaudiooutput.cpp +++ b/src/plugins/alsa/qalsaaudiooutput.cpp @@ -782,7 +782,7 @@ qint64 QAlsaAudioOutput::elapsedUSecs() const if (deviceState == QAudio::StoppedState) return 0; - return clockStamp.elapsed()*1000; + return clockStamp.elapsed() * qint64(1000); } void QAlsaAudioOutput::reset() diff --git a/src/plugins/opensles/qopenslesaudioinput.cpp b/src/plugins/opensles/qopenslesaudioinput.cpp index ac980188..98ddea73 100644 --- a/src/plugins/opensles/qopenslesaudioinput.cpp +++ b/src/plugins/opensles/qopenslesaudioinput.cpp @@ -482,7 +482,7 @@ qint64 QOpenSLESAudioInput::elapsedUSecs() const if (m_deviceState == QAudio::StoppedState) return 0; - return m_clockStamp.elapsed() * 1000; + return m_clockStamp.elapsed() * qint64(1000); } void QOpenSLESAudioInput::setVolume(qreal vol) diff --git a/src/plugins/opensles/qopenslesaudiooutput.cpp b/src/plugins/opensles/qopenslesaudiooutput.cpp index 9c62852d..5457abaf 100644 --- a/src/plugins/opensles/qopenslesaudiooutput.cpp +++ b/src/plugins/opensles/qopenslesaudiooutput.cpp @@ -290,7 +290,7 @@ qint64 QOpenSLESAudioOutput::elapsedUSecs() const if (m_state == QAudio::StoppedState) return 0; - return m_clockStamp.elapsed() * 1000; + return m_clockStamp.elapsed() * qint64(1000); } void QOpenSLESAudioOutput::reset() diff --git a/src/plugins/pulseaudio/qaudioinput_pulse.cpp b/src/plugins/pulseaudio/qaudioinput_pulse.cpp index 89dc0861..b34d7542 100644 --- a/src/plugins/pulseaudio/qaudioinput_pulse.cpp +++ b/src/plugins/pulseaudio/qaudioinput_pulse.cpp @@ -692,7 +692,7 @@ qint64 QPulseAudioInput::elapsedUSecs() const if (m_deviceState == QAudio::StoppedState) return 0; - return m_clockStamp.elapsed() * 1000; + return m_clockStamp.elapsed() * qint64(1000); } void QPulseAudioInput::reset() diff --git a/src/plugins/pulseaudio/qaudiooutput_pulse.cpp b/src/plugins/pulseaudio/qaudiooutput_pulse.cpp index 64a08066..b2046330 100644 --- a/src/plugins/pulseaudio/qaudiooutput_pulse.cpp +++ b/src/plugins/pulseaudio/qaudiooutput_pulse.cpp @@ -591,7 +591,7 @@ qint64 QPulseAudioOutput::elapsedUSecs() const if (m_deviceState == QAudio::StoppedState) return 0; - return m_clockStamp.elapsed() * 1000; + return m_clockStamp.elapsed() * qint64(1000); } void QPulseAudioOutput::reset() diff --git a/src/plugins/qnx-audio/audio/qnxaudioinput.cpp b/src/plugins/qnx-audio/audio/qnxaudioinput.cpp index eb806459..2c5956bd 100644 --- a/src/plugins/qnx-audio/audio/qnxaudioinput.cpp +++ b/src/plugins/qnx-audio/audio/qnxaudioinput.cpp @@ -194,7 +194,7 @@ qint64 QnxAudioInput::elapsedUSecs() const if (m_state == QAudio::StoppedState) return 0; - return m_clockStamp.elapsed() * 1000; + return m_clockStamp.elapsed() * qint64(1000); } QAudio::Error QnxAudioInput::error() const diff --git a/src/plugins/qnx-audio/audio/qnxaudiooutput.cpp b/src/plugins/qnx-audio/audio/qnxaudiooutput.cpp index 4a82e93b..c12f3abb 100644 --- a/src/plugins/qnx-audio/audio/qnxaudiooutput.cpp +++ b/src/plugins/qnx-audio/audio/qnxaudiooutput.cpp @@ -180,7 +180,7 @@ qint64 QnxAudioOutput::elapsedUSecs() const if (m_state == QAudio::StoppedState) return 0; else - return m_startTimeStamp.elapsed() * 1000; + return m_startTimeStamp.elapsed() * qint64(1000); } QAudio::Error QnxAudioOutput::error() const diff --git a/src/plugins/windowsaudio/qwindowsaudioinput.cpp b/src/plugins/windowsaudio/qwindowsaudioinput.cpp index 26f0641b..e55f3ab6 100644 --- a/src/plugins/windowsaudio/qwindowsaudioinput.cpp +++ b/src/plugins/windowsaudio/qwindowsaudioinput.cpp @@ -706,7 +706,7 @@ qint64 QWindowsAudioInput::elapsedUSecs() const if (deviceState == QAudio::StoppedState) return 0; - return timeStampOpened.elapsed()*1000; + return timeStampOpened.elapsed() * qint64(1000); } void QWindowsAudioInput::reset() diff --git a/src/plugins/windowsaudio/qwindowsaudiooutput.cpp b/src/plugins/windowsaudio/qwindowsaudiooutput.cpp index 1c8882ee..360441ad 100644 --- a/src/plugins/windowsaudio/qwindowsaudiooutput.cpp +++ b/src/plugins/windowsaudio/qwindowsaudiooutput.cpp @@ -682,7 +682,7 @@ qint64 QWindowsAudioOutput::elapsedUSecs() const if (deviceState == QAudio::StoppedState) return 0; - return timeStampOpened.elapsed()*1000; + return timeStampOpened.elapsed() * qint64(1000); } QAudio::Error QWindowsAudioOutput::error() const From 973ae5e0f60d335d1b22f9a2418fe50839d50322 Mon Sep 17 00:00:00 2001 From: Andres Gomez Date: Wed, 30 Jul 2014 17:34:16 +0300 Subject: [PATCH 04/10] QMediaNetworkPlaylistProvider: Upon error parsing, stop parsing. When an error is found parsing a playlist, stop parsing. This will also prevent the emission of the "loaded" signal when the parser finishes. Task-number: QTBUG-40513 Change-Id: Ia814864d0d546806219993f0b727761d5d4e7903 Reviewed-by: Yoann Lopes --- .../qmedianetworkplaylistprovider.cpp | 2 + .../unit/qmediaplaylist/testdata/test.pls | 10 +++ .../testdata/totem-pl-example.pls | 5 ++ .../unit/qmediaplaylist/testdata/trash.pls | 2 + .../qmediaplaylist/tst_qmediaplaylist.cpp | 75 ++++++++++++++++++- 5 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 tests/auto/unit/qmediaplaylist/testdata/test.pls create mode 100644 tests/auto/unit/qmediaplaylist/testdata/totem-pl-example.pls create mode 100644 tests/auto/unit/qmediaplaylist/testdata/trash.pls diff --git a/src/multimedia/playback/qmedianetworkplaylistprovider.cpp b/src/multimedia/playback/qmedianetworkplaylistprovider.cpp index a8d8c4b0..9bbd7f3a 100644 --- a/src/multimedia/playback/qmedianetworkplaylistprovider.cpp +++ b/src/multimedia/playback/qmedianetworkplaylistprovider.cpp @@ -90,6 +90,8 @@ void QMediaNetworkPlaylistProviderPrivate::_q_handleParserError(QPlaylistFilePar break; } + parser.stop(); + emit q->loadFailed(playlistError, errorMessage); } diff --git a/tests/auto/unit/qmediaplaylist/testdata/test.pls b/tests/auto/unit/qmediaplaylist/testdata/test.pls new file mode 100644 index 00000000..1b66c3ab --- /dev/null +++ b/tests/auto/unit/qmediaplaylist/testdata/test.pls @@ -0,0 +1,10 @@ +[playlist] + +File1=http://test.host/path +Title1=First +Length1=-1 +File2= http://test.host/path +Title2=Second +Length2=-1 + +NumberOfEntries=2 diff --git a/tests/auto/unit/qmediaplaylist/testdata/totem-pl-example.pls b/tests/auto/unit/qmediaplaylist/testdata/totem-pl-example.pls new file mode 100644 index 00000000..385fe2a3 --- /dev/null +++ b/tests/auto/unit/qmediaplaylist/testdata/totem-pl-example.pls @@ -0,0 +1,5 @@ +[playlist] +X-GNOME-Title=totem-pl-file-example +NumberOfEntries=1 +File1=http://test.host/path +Title1=Silence diff --git a/tests/auto/unit/qmediaplaylist/testdata/trash.pls b/tests/auto/unit/qmediaplaylist/testdata/trash.pls new file mode 100644 index 00000000..639c22b0 --- /dev/null +++ b/tests/auto/unit/qmediaplaylist/testdata/trash.pls @@ -0,0 +1,2 @@ +[playlist] +NumberOfEntries=100 diff --git a/tests/auto/unit/qmediaplaylist/tst_qmediaplaylist.cpp b/tests/auto/unit/qmediaplaylist/tst_qmediaplaylist.cpp index 7aa8d7a5..63b84b5e 100644 --- a/tests/auto/unit/qmediaplaylist/tst_qmediaplaylist.cpp +++ b/tests/auto/unit/qmediaplaylist/tst_qmediaplaylist.cpp @@ -86,6 +86,7 @@ private slots: void currentItem(); void saveAndLoad(); void loadM3uFile(); + void loadPLSFile(); void playbackMode(); void playbackMode_data(); void shuffle(); @@ -356,8 +357,10 @@ void tst_QMediaPlaylist::saveAndLoad() QVERIFY(playlist.error() == QMediaPlaylist::FormatNotSupportedError); QVERIFY(!playlist.errorString().isEmpty()); + QSignalSpy loadedSignal(&playlist, SIGNAL(loaded())); QSignalSpy errorSignal(&playlist, SIGNAL(loadFailed())); playlist.load(&buffer, "unsupported_format"); + QTRY_VERIFY(loadedSignal.isEmpty()); QCOMPARE(errorSignal.size(), 1); QVERIFY(playlist.error() != QMediaPlaylist::NoError); QVERIFY(!playlist.errorString().isEmpty()); @@ -367,8 +370,10 @@ void tst_QMediaPlaylist::saveAndLoad() QVERIFY(playlist.error() != QMediaPlaylist::NoError); QVERIFY(!playlist.errorString().isEmpty()); + loadedSignal.clear(); errorSignal.clear(); playlist.load(QUrl::fromLocalFile(QLatin1String("tmp.unsupported_format")), "unsupported_format"); + QTRY_VERIFY(loadedSignal.isEmpty()); QCOMPARE(errorSignal.size(), 1); QVERIFY(playlist.error() == QMediaPlaylist::FormatNotSupportedError); QVERIFY(!playlist.errorString().isEmpty()); @@ -380,7 +385,11 @@ void tst_QMediaPlaylist::saveAndLoad() buffer.seek(0); QMediaPlaylist playlist2; + QSignalSpy loadedSignal2(&playlist2, SIGNAL(loaded())); + QSignalSpy errorSignal2(&playlist2, SIGNAL(loadFailed())); playlist2.load(&buffer, "m3u"); + QCOMPARE(loadedSignal2.size(), 1); + QTRY_VERIFY(errorSignal2.isEmpty()); QCOMPARE(playlist.error(), QMediaPlaylist::NoError); QCOMPARE(playlist.mediaCount(), playlist2.mediaCount()); @@ -390,9 +399,13 @@ void tst_QMediaPlaylist::saveAndLoad() res = playlist.save(QUrl::fromLocalFile(QLatin1String("tmp.m3u")), "m3u"); QVERIFY(res); + loadedSignal2.clear(); + errorSignal2.clear(); playlist2.clear(); QVERIFY(playlist2.isEmpty()); playlist2.load(QUrl::fromLocalFile(QLatin1String("tmp.m3u")), "m3u"); + QCOMPARE(loadedSignal2.size(), 1); + QTRY_VERIFY(errorSignal2.isEmpty()); QCOMPARE(playlist.error(), QMediaPlaylist::NoError); QCOMPARE(playlist.mediaCount(), playlist2.mediaCount()); @@ -406,12 +419,20 @@ void tst_QMediaPlaylist::loadM3uFile() QMediaPlaylist playlist; // Try to load playlist that does not exist in the testdata folder + QSignalSpy loadSpy(&playlist, SIGNAL(loaded())); + QSignalSpy loadFailedSpy(&playlist, SIGNAL(loadFailed())); QString testFileName = QFINDTESTDATA("testdata"); playlist.load(QUrl::fromLocalFile(testFileName + "/missing_file.m3u")); + QTRY_VERIFY(loadSpy.isEmpty()); + QVERIFY(!loadFailedSpy.isEmpty()); QVERIFY(playlist.error() != QMediaPlaylist::NoError); + loadSpy.clear(); + loadFailedSpy.clear(); testFileName = QFINDTESTDATA("testdata/test.m3u"); playlist.load(QUrl::fromLocalFile(testFileName)); + QTRY_VERIFY(!loadSpy.isEmpty()); + QVERIFY(loadFailedSpy.isEmpty()); QCOMPARE(playlist.error(), QMediaPlaylist::NoError); QCOMPARE(playlist.mediaCount(), 7); @@ -428,10 +449,62 @@ void tst_QMediaPlaylist::loadM3uFile() //ensure #2 suffix is not stripped from path testFileName = QFINDTESTDATA("testdata/testfile2#suffix"); QCOMPARE(playlist.media(6).canonicalUrl(), QUrl::fromLocalFile(testFileName)); + // check ability to load from QNetworkRequest + loadSpy.clear(); + loadFailedSpy.clear(); + playlist.load(QNetworkRequest(QUrl::fromLocalFile(QFINDTESTDATA("testdata/test.m3u")))); + QTRY_VERIFY(!loadSpy.isEmpty()); + QVERIFY(loadFailedSpy.isEmpty()); +} + +void tst_QMediaPlaylist::loadPLSFile() +{ + QMediaPlaylist playlist; + + // Try to load playlist that does not exist in the testdata folder QSignalSpy loadSpy(&playlist, SIGNAL(loaded())); QSignalSpy loadFailedSpy(&playlist, SIGNAL(loadFailed())); - playlist.load(QNetworkRequest(QUrl::fromLocalFile(QFINDTESTDATA("testdata/test.m3u")))); + QString testFileName = QFINDTESTDATA("testdata"); + playlist.load(QUrl::fromLocalFile(testFileName + "/missing_file.pls")); + QTRY_VERIFY(loadSpy.isEmpty()); + QVERIFY(!loadFailedSpy.isEmpty()); + QVERIFY(playlist.error() != QMediaPlaylist::NoError); + + // Try to load bogus playlist + loadSpy.clear(); + loadFailedSpy.clear(); + testFileName = QFINDTESTDATA("testdata/trash.pls"); + playlist.load(QUrl::fromLocalFile(testFileName)); + QTRY_VERIFY(loadSpy.isEmpty()); + QVERIFY(!loadFailedSpy.isEmpty()); + QVERIFY(playlist.error() == QMediaPlaylist::FormatError); + + // Try to load regular playlist + loadSpy.clear(); + loadFailedSpy.clear(); + testFileName = QFINDTESTDATA("testdata/test.pls"); + playlist.load(QUrl::fromLocalFile(testFileName)); + QTRY_VERIFY(!loadSpy.isEmpty()); + QVERIFY(loadFailedSpy.isEmpty()); + QCOMPARE(playlist.error(), QMediaPlaylist::NoError); + QCOMPARE(playlist.mediaCount(), 2); + QCOMPARE(playlist.media(0).canonicalUrl(), QUrl(QLatin1String("http://test.host/path"))); + QCOMPARE(playlist.media(1).canonicalUrl(), QUrl(QLatin1String("http://test.host/path"))); + + // Try to load a totem-pl generated playlist + loadSpy.clear(); + loadFailedSpy.clear(); + testFileName = QFINDTESTDATA("testdata/totem-pl-example.pls"); + playlist.load(QUrl::fromLocalFile(testFileName)); + QTRY_VERIFY(loadSpy.isEmpty()); + QVERIFY(!loadFailedSpy.isEmpty()); + QVERIFY(playlist.error() == QMediaPlaylist::FormatError); + + // check ability to load from QNetworkRequest + loadSpy.clear(); + loadFailedSpy.clear(); + playlist.load(QNetworkRequest(QUrl::fromLocalFile(QFINDTESTDATA("testdata/test.pls")))); QTRY_VERIFY(!loadSpy.isEmpty()); QVERIFY(loadFailedSpy.isEmpty()); } From e26483c106cd1408b768f18f5d0edfd83c78f5bf Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Wed, 27 Aug 2014 16:25:40 +0200 Subject: [PATCH 05/10] Fix URL handling in PLS parser. Make sure relative paths are resolved to a full path. Task-number: QTBUG-40515 Change-Id: Ideb83fc3a3c4a74c84917a22e3c30162d7b6158a Reviewed-by: Christian Stromme --- .../playback/playlistfileparser.cpp | 51 ++++++++++--------- .../unit/qmediaplaylist/testdata/test.pls | 19 ++++++- .../qmediaplaylist/tst_qmediaplaylist.cpp | 14 ++++- 3 files changed, 57 insertions(+), 27 deletions(-) diff --git a/src/multimedia/playback/playlistfileparser.cpp b/src/multimedia/playback/playlistfileparser.cpp index 1254d613..97c551c9 100644 --- a/src/multimedia/playback/playlistfileparser.cpp +++ b/src/multimedia/playback/playlistfileparser.cpp @@ -59,6 +59,30 @@ public: virtual void parseLine(int lineIndex, const QString& line, const QUrl& root) = 0; +protected: + QUrl expandToFullPath(const QUrl &root, const QString &line) + { + // On Linux, backslashes are not converted to forward slashes :/ + if (line.startsWith(QLatin1String("//")) || line.startsWith(QLatin1String("\\\\"))) { + // Network share paths are not resolved + return QUrl::fromLocalFile(line); + } + + QUrl url(line); + if (url.scheme().isEmpty()) { + // Resolve it relative to root + if (root.isLocalFile()) + return root.resolved(QUrl::fromLocalFile(line)); + else + return root.resolved(url); + } else if (url.scheme().length() == 1) { + // Assume it's a drive letter for a Windows path + url = QUrl::fromLocalFile(line); + } + + return url; + } + Q_SIGNALS: void newItem(const QVariant& content); void finished(); @@ -146,29 +170,6 @@ public: return -1; } - QUrl expandToFullPath(const QUrl& root, const QString& line) - { - // On Linux, backslashes are not converted to forward slashes :/ - if (line.startsWith(QLatin1String("//")) || line.startsWith(QLatin1String("\\\\"))) { - // Network share paths are not resolved - return QUrl::fromLocalFile(line); - } - - QUrl url(line); - if (url.scheme().isEmpty()) { - // Resolve it relative to root - if (root.isLocalFile()) - return root.resolved(QUrl::fromLocalFile(line)); - else - return root.resolved(url); - } else if (url.scheme().length() == 1) { - // Assume it's a drive letter for a Windows path - url = QUrl::fromLocalFile(line); - } - - return url; - } - private: bool m_extendedFormat; QVariantMap m_extraInfo; @@ -249,7 +250,7 @@ Version=2 m_readFlags |= int(flag); } - void parseLine(int lineIndex, const QString& line, const QUrl&) + void parseLine(int lineIndex, const QString &line, const QUrl &root) { switch (m_state) { case Header: @@ -260,7 +261,7 @@ Version=2 break; case Track: if (!containsFlag(FileRead) && line.startsWith(m_fileName)) { - m_item[QLatin1String("url")] = getValue(lineIndex, line); + m_item[QLatin1String("url")] = expandToFullPath(root, getValue(lineIndex, line)); setFlag(FileRead); } else if (!containsFlag(TitleRead) && line.startsWith(m_titleName)) { m_item[QMediaMetaData::Title] = getValue(lineIndex, line); diff --git a/tests/auto/unit/qmediaplaylist/testdata/test.pls b/tests/auto/unit/qmediaplaylist/testdata/test.pls index 1b66c3ab..18832b10 100644 --- a/tests/auto/unit/qmediaplaylist/testdata/test.pls +++ b/tests/auto/unit/qmediaplaylist/testdata/test.pls @@ -6,5 +6,22 @@ Length1=-1 File2= http://test.host/path Title2=Second Length2=-1 +File3=testfile +Title3=Third +Length3=-1 -NumberOfEntries=2 + + +File4=testdir/testfile +Title4=Fourth +Length4=-1 +File5=/testdir/testfile +Title5=Fifth +Length5=-1 +File6=file://path/name#suffix +Title6=Sixth +Length6=-1 +File7=testfile2#suffix +Title7=Seventh +Length7=-1 +NumberOfEntries=7 diff --git a/tests/auto/unit/qmediaplaylist/tst_qmediaplaylist.cpp b/tests/auto/unit/qmediaplaylist/tst_qmediaplaylist.cpp index 63b84b5e..748bcd30 100644 --- a/tests/auto/unit/qmediaplaylist/tst_qmediaplaylist.cpp +++ b/tests/auto/unit/qmediaplaylist/tst_qmediaplaylist.cpp @@ -488,9 +488,21 @@ void tst_QMediaPlaylist::loadPLSFile() QTRY_VERIFY(!loadSpy.isEmpty()); QVERIFY(loadFailedSpy.isEmpty()); QCOMPARE(playlist.error(), QMediaPlaylist::NoError); - QCOMPARE(playlist.mediaCount(), 2); + QCOMPARE(playlist.mediaCount(), 7); + QCOMPARE(playlist.media(0).canonicalUrl(), QUrl(QLatin1String("http://test.host/path"))); QCOMPARE(playlist.media(1).canonicalUrl(), QUrl(QLatin1String("http://test.host/path"))); + testFileName = QFINDTESTDATA("testdata/testfile"); + QCOMPARE(playlist.media(2).canonicalUrl(), + QUrl::fromLocalFile(testFileName)); + testFileName = QFINDTESTDATA("testdata"); + QCOMPARE(playlist.media(3).canonicalUrl(), + QUrl::fromLocalFile(testFileName + "/testdir/testfile")); + QCOMPARE(playlist.media(4).canonicalUrl(), QUrl(QLatin1String("file:///testdir/testfile"))); + QCOMPARE(playlist.media(5).canonicalUrl(), QUrl(QLatin1String("file://path/name#suffix"))); + //ensure #2 suffix is not stripped from path + testFileName = QFINDTESTDATA("testdata/testfile2#suffix"); + QCOMPARE(playlist.media(6).canonicalUrl(), QUrl::fromLocalFile(testFileName)); // Try to load a totem-pl generated playlist loadSpy.clear(); From 90fd3ac39999389fd898dd43210f8af95adb5493 Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Tue, 9 Sep 2014 14:59:06 +0200 Subject: [PATCH 06/10] WMF: fix start time of QAudioProbe's buffers. Task-number: QTBUG-40954 Change-Id: Icd1d144dcff3a3191432722da44a263ca286dbb6 Reviewed-by: Christian Stromme --- src/plugins/wmf/samplegrabber.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/plugins/wmf/samplegrabber.cpp b/src/plugins/wmf/samplegrabber.cpp index e4ead539..41ff8d79 100644 --- a/src/plugins/wmf/samplegrabber.cpp +++ b/src/plugins/wmf/samplegrabber.cpp @@ -163,6 +163,9 @@ STDMETHODIMP AudioSampleGrabberCallback::OnProcessSample(REFGUID guidMajorMediaT if (llSampleTime == _I64_MAX) { // Set default QAudioBuffer start time llSampleTime = -1; + } else { + // WMF uses 100-nanosecond units, Qt uses microseconds + llSampleTime /= 10; } foreach (MFAudioProbeControl* probe, m_audioProbes) From 4c5aec9bb6fd95a65544aa433f1357320132ae9f Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Thu, 28 Aug 2014 16:00:15 +0200 Subject: [PATCH 07/10] Make PLS parser more permissive. The PLS format is not clearly specified, some rules are just assumed and files don't always respect them. We now only look for 'File' entries, since that's the only thing we actually use. We ignore the Version, NumberOfEntries, Title, Length and any other unrecognized tags. Task-number: QTBUG-40515 Change-Id: I9c176b7b68fd1441abbd50364f88994ad5d6236f Reviewed-by: Christian Stromme --- .../playback/playlistfileparser.cpp | 106 ++---------------- .../testdata/{trash.pls => empty.pls} | 0 .../qmediaplaylist/tst_qmediaplaylist.cpp | 22 ++-- 3 files changed, 26 insertions(+), 102 deletions(-) rename tests/auto/unit/qmediaplaylist/testdata/{trash.pls => empty.pls} (100%) diff --git a/src/multimedia/playback/playlistfileparser.cpp b/src/multimedia/playback/playlistfileparser.cpp index 97c551c9..374d3fa0 100644 --- a/src/multimedia/playback/playlistfileparser.cpp +++ b/src/multimedia/playback/playlistfileparser.cpp @@ -181,27 +181,9 @@ class PLSParser : public ParserBase public: PLSParser(QObject *parent) : ParserBase(parent) - , m_state(Header) - , m_count(0) - , m_readFlags(0) { } - enum ReadFlags - { - FileRead = 0x1, - TitleRead = 0x2, - LengthRead = 0x4, - All = FileRead | TitleRead | LengthRead - }; - - enum State - { - Header, - Track, - Footer - }; - /* * The format is essentially that of an INI file structured as follows: @@ -240,89 +222,25 @@ NumberOfEntries=2 Version=2 */ - inline bool containsFlag(const ReadFlags& flag) + void parseLine(int, const QString &line, const QUrl &root) { - return (m_readFlags & int(flag)) == flag; + // We ignore everything but 'File' entries, since that's the only thing we care about. + if (!line.startsWith(QLatin1String("File"))) + return; + + QString value = getValue(line); + if (value.isEmpty()) + return; + + emit newItem(expandToFullPath(root, value)); } - inline void setFlag(const ReadFlags& flag) - { - m_readFlags |= int(flag); - } - - void parseLine(int lineIndex, const QString &line, const QUrl &root) - { - switch (m_state) { - case Header: - if (line == QLatin1String("[playlist]")) { - m_state = Track; - setCount(1); - } - break; - case Track: - if (!containsFlag(FileRead) && line.startsWith(m_fileName)) { - m_item[QLatin1String("url")] = expandToFullPath(root, getValue(lineIndex, line)); - setFlag(FileRead); - } else if (!containsFlag(TitleRead) && line.startsWith(m_titleName)) { - m_item[QMediaMetaData::Title] = getValue(lineIndex, line); - setFlag(TitleRead); - } else if (!containsFlag(LengthRead) && line.startsWith(m_lengthName)) { - //convert from seconds to miliseconds - int length = getValue(lineIndex, line).toInt(); - if (length > 0) - m_item[QMediaMetaData::Duration] = length * 1000; - setFlag(LengthRead); - } else if (line.startsWith(QLatin1String("NumberOfEntries"))) { - m_state = Footer; - int entries = getValue(lineIndex, line).toInt(); - int count = m_readFlags == 0 ? (m_count - 1) : m_count; - if (entries != count) { - emit error(QPlaylistFileParser::FormatError, tr("Error parsing playlist: %1, expected count = %2"). - arg(line, QString::number(count))); - } - break; - } - if (m_readFlags == int(All)) { - emit newItem(m_item); - setCount(m_count + 1); - } - break; - case Footer: - if (line.startsWith(QLatin1String("Version"))) { - int version = getValue(lineIndex, line).toInt(); - if (version != 2) - emit error(QPlaylistFileParser::FormatError, QString(tr("Error parsing playlist at line[%1], expected version = 2")).arg(line)); - } - break; - } - } - - QString getValue(int lineIndex, const QString& line) { + QString getValue(const QString& line) { int start = line.indexOf('='); - if (start < 0) { - emit error(QPlaylistFileParser::FormatError, QString(tr("Error parsing playlist at line[%1]:%2")).arg(QString::number(lineIndex), line)); + if (start < 0) return QString(); - } return line.midRef(start + 1).trimmed().toString(); } - - void setCount(int count) { - m_count = count; - m_fileName = QStringLiteral("File%1").arg(count); - m_titleName = QStringLiteral("Title%1").arg(count); - m_lengthName = QStringLiteral("Length%1").arg(count); - m_item.clear(); - m_readFlags = 0; - } - -private: - State m_state; - int m_count; - QString m_titleName; - QString m_fileName; - QString m_lengthName; - QVariantMap m_item; - int m_readFlags; }; } diff --git a/tests/auto/unit/qmediaplaylist/testdata/trash.pls b/tests/auto/unit/qmediaplaylist/testdata/empty.pls similarity index 100% rename from tests/auto/unit/qmediaplaylist/testdata/trash.pls rename to tests/auto/unit/qmediaplaylist/testdata/empty.pls diff --git a/tests/auto/unit/qmediaplaylist/tst_qmediaplaylist.cpp b/tests/auto/unit/qmediaplaylist/tst_qmediaplaylist.cpp index 748bcd30..82b7bdaf 100644 --- a/tests/auto/unit/qmediaplaylist/tst_qmediaplaylist.cpp +++ b/tests/auto/unit/qmediaplaylist/tst_qmediaplaylist.cpp @@ -471,14 +471,15 @@ void tst_QMediaPlaylist::loadPLSFile() QVERIFY(!loadFailedSpy.isEmpty()); QVERIFY(playlist.error() != QMediaPlaylist::NoError); - // Try to load bogus playlist + // Try to load empty playlist loadSpy.clear(); loadFailedSpy.clear(); - testFileName = QFINDTESTDATA("testdata/trash.pls"); + testFileName = QFINDTESTDATA("testdata/empty.pls"); playlist.load(QUrl::fromLocalFile(testFileName)); - QTRY_VERIFY(loadSpy.isEmpty()); - QVERIFY(!loadFailedSpy.isEmpty()); - QVERIFY(playlist.error() == QMediaPlaylist::FormatError); + QTRY_VERIFY(!loadSpy.isEmpty()); + QVERIFY(loadFailedSpy.isEmpty()); + QCOMPARE(playlist.error(), QMediaPlaylist::NoError); + QCOMPARE(playlist.mediaCount(), 0); // Try to load regular playlist loadSpy.clear(); @@ -505,13 +506,18 @@ void tst_QMediaPlaylist::loadPLSFile() QCOMPARE(playlist.media(6).canonicalUrl(), QUrl::fromLocalFile(testFileName)); // Try to load a totem-pl generated playlist + // (Format doesn't respect the spec) loadSpy.clear(); loadFailedSpy.clear(); + playlist.clear(); testFileName = QFINDTESTDATA("testdata/totem-pl-example.pls"); playlist.load(QUrl::fromLocalFile(testFileName)); - QTRY_VERIFY(loadSpy.isEmpty()); - QVERIFY(!loadFailedSpy.isEmpty()); - QVERIFY(playlist.error() == QMediaPlaylist::FormatError); + QTRY_VERIFY(!loadSpy.isEmpty()); + QVERIFY(loadFailedSpy.isEmpty()); + QCOMPARE(playlist.error(), QMediaPlaylist::NoError); + QCOMPARE(playlist.mediaCount(), 1); + QCOMPARE(playlist.media(0).canonicalUrl(), QUrl(QLatin1String("http://test.host/path"))); + // check ability to load from QNetworkRequest loadSpy.clear(); From 5be252432804ebf50992c266dad9c93bd039ed41 Mon Sep 17 00:00:00 2001 From: Nodir Temirkhodjaev Date: Fri, 5 Sep 2014 16:29:41 +0500 Subject: [PATCH 08/10] WMF: fix memory leaks. Release requested interfaces. Task-number: QTBUG-32481 Change-Id: I846981f6a7a7ea77588b9322fc41e05e583bdb15 Reviewed-by: Wouter Huysentruit Reviewed-by: Alex Blasche Reviewed-by: Jeff Tranter Reviewed-by: Allan Sandfeld Jensen --- .../wmf/decoder/mfaudiodecodercontrol.cpp | 3 +- src/plugins/wmf/player/mfplayersession.cpp | 56 ++++++++++--------- 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/src/plugins/wmf/decoder/mfaudiodecodercontrol.cpp b/src/plugins/wmf/decoder/mfaudiodecodercontrol.cpp index 22eb1a09..d9122e5d 100644 --- a/src/plugins/wmf/decoder/mfaudiodecodercontrol.cpp +++ b/src/plugins/wmf/decoder/mfaudiodecodercontrol.cpp @@ -244,7 +244,6 @@ void MFAudioDecoderControl::handleMediaSourceReady() } if (m_sourceResolver->mediaSource()) { - IMFPresentationDescriptor *pd = 0; if (mediaType && m_resampler) { HRESULT hr = S_OK; hr = m_resampler->SetInputType(m_mfInputStreamID, mediaType, 0); @@ -254,9 +253,11 @@ void MFAudioDecoderControl::handleMediaSourceReady() qWarning() << "MFAudioDecoderControl: failed to SetInputType of resampler" << hr; } } + IMFPresentationDescriptor *pd; if (SUCCEEDED(m_sourceResolver->mediaSource()->CreatePresentationDescriptor(&pd))) { UINT64 duration = 0; pd->GetUINT64(MF_PD_DURATION, &duration); + pd->Release(); duration /= 10000; if (m_duration != qint64(duration)) { m_duration = qint64(duration); diff --git a/src/plugins/wmf/player/mfplayersession.cpp b/src/plugins/wmf/player/mfplayersession.cpp index 09c5a8c5..4b83e722 100644 --- a/src/plugins/wmf/player/mfplayersession.cpp +++ b/src/plugins/wmf/player/mfplayersession.cpp @@ -266,6 +266,7 @@ void MFPlayerSession::handleMediaSourceReady() //convert from 100 nanosecond to milisecond emit durationUpdate(qint64(m_duration / 10000)); setupPlaybackTopology(mediaSource, sourcePD); + sourcePD->Release(); } else { changeStatus(QMediaPlayer::InvalidMedia); emit error(QMediaPlayer::ResourceError, tr("Cannot create presentation descriptor."), true); @@ -423,12 +424,15 @@ IMFTopologyNode* MFPlayerSession::addOutputNode(IMFStreamDescriptor *streamDesc, if (SUCCEEDED(hr)) { hr = node->SetUINT32(MF_TOPONODE_STREAMID, sinkID); if (SUCCEEDED(hr)) { - if (SUCCEEDED(topology->AddNode(node))) + if (SUCCEEDED(topology->AddNode(node))) { + handler->Release(); return node; + } } } } } + handler->Release(); } node->Release(); return NULL; @@ -617,42 +621,39 @@ HRESULT BindOutputNode(IMFTopologyNode *pNode) // Sets the IMFStreamSink pointers on all of the output nodes in a topology. HRESULT BindOutputNodes(IMFTopology *pTopology) { - DWORD cNodes = 0; - - IMFCollection *collection = NULL; - IUnknown *element = NULL; - IMFTopologyNode *node = NULL; + IMFCollection *collection; // Get the collection of output nodes. HRESULT hr = pTopology->GetOutputNodeCollection(&collection); // Enumerate all of the nodes in the collection. - if (SUCCEEDED(hr)) + if (SUCCEEDED(hr)) { + DWORD cNodes; hr = collection->GetElementCount(&cNodes); - if (SUCCEEDED(hr)) { - for (DWORD i = 0; i < cNodes; i++) { - hr = collection->GetElement(i, &element); - if (FAILED(hr)) - break; + if (SUCCEEDED(hr)) { + for (DWORD i = 0; i < cNodes; i++) { + IUnknown *element; + hr = collection->GetElement(i, &element); + if (FAILED(hr)) + break; - hr = element->QueryInterface(IID_IMFTopologyNode, (void**)&node); - if (FAILED(hr)) - break; + IMFTopologyNode *node; + hr = element->QueryInterface(IID_IMFTopologyNode, (void**)&node); + element->Release(); + if (FAILED(hr)) + break; - // Bind this node. - hr = BindOutputNode(node); - if (FAILED(hr)) - break; + // Bind this node. + hr = BindOutputNode(node); + node->Release(); + if (FAILED(hr)) + break; + } } + collection->Release(); } - if (collection) - collection->Release(); - if (element) - element->Release(); - if (node) - node->Release(); return hr; } @@ -1510,8 +1511,11 @@ HRESULT MFPlayerSession::Invoke(IMFAsyncResult *pResult) } } - if (!m_closing) + if (!m_closing) { emit sessionEvent(pEvent); + } else { + pEvent->Release(); + } return S_OK; } From 569dd64083f3d54515db97f6333d59cbab21f528 Mon Sep 17 00:00:00 2001 From: Nodir Temirkhodjaev Date: Sat, 30 Aug 2014 16:41:30 +0500 Subject: [PATCH 09/10] WMF: fix initializing of media player's volume. According to the docs, MESessionTopologyStatus with status == MF_TOPOSTATUS_READY should be the correct place for the GetService call. Change-Id: I7fdbedbe43b2191b35b95c7fd9c86940f58daff7 Reviewed-by: Wouter Huysentruit Reviewed-by: Yoann Lopes --- src/plugins/wmf/player/mfplayersession.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/wmf/player/mfplayersession.cpp b/src/plugins/wmf/player/mfplayersession.cpp index 4b83e722..0de0bdfd 100644 --- a/src/plugins/wmf/player/mfplayersession.cpp +++ b/src/plugins/wmf/player/mfplayersession.cpp @@ -1638,9 +1638,6 @@ void MFPlayerSession::handleSessionEvent(IMFMediaEvent *sessionEvent) } } - if (SUCCEEDED(MFGetService(m_session, MR_STREAM_VOLUME_SERVICE, IID_PPV_ARGS(&m_volumeControl)))) - setVolumeInternal(m_muted ? 0 : m_volume); - DWORD dwCharacteristics = 0; m_sourceResolver->mediaSource()->GetCharacteristics(&dwCharacteristics); emit seekableUpdate(MFMEDIASOURCE_CAN_SEEK & dwCharacteristics); @@ -1711,6 +1708,9 @@ void MFPlayerSession::handleSessionEvent(IMFMediaEvent *sessionEvent) } } MFGetService(m_session, MFNETSOURCE_STATISTICS_SERVICE, IID_PPV_ARGS(&m_netsourceStatistics)); + + if (SUCCEEDED(MFGetService(m_session, MR_STREAM_VOLUME_SERVICE, IID_PPV_ARGS(&m_volumeControl)))) + setVolumeInternal(m_muted ? 0 : m_volume); } } } From e195b7fc05d62cce626693a8d791e58466dd3ac7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Str=C3=B8mme?= Date: Wed, 10 Sep 2014 10:49:08 +0200 Subject: [PATCH 10/10] Remove unused includes Change-Id: Ibbce6e9135649d5dce0522320197dbbd0a92b3b9 Reviewed-by: Yoann Lopes --- src/multimedia/audio/qsoundeffect_qaudio_p.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/multimedia/audio/qsoundeffect_qaudio_p.cpp b/src/multimedia/audio/qsoundeffect_qaudio_p.cpp index 2b4359cc..56166ea3 100644 --- a/src/multimedia/audio/qsoundeffect_qaudio_p.cpp +++ b/src/multimedia/audio/qsoundeffect_qaudio_p.cpp @@ -53,9 +53,6 @@ #include "qsoundeffect_qaudio_p.h" #include -#include -#include -#include #include //#include