Merge "Merge remote-tracking branch 'origin/5.3' into 5.4" into refs/staging/5.4

This commit is contained in:
Sergio Ahumada
2014-09-26 15:44:56 +02:00
committed by The Qt Project
21 changed files with 213 additions and 161 deletions

View File

@@ -45,9 +45,6 @@
#include "qsoundeffect_qaudio_p.h"
#include <QtCore/qcoreapplication.h>
#include <QtCore/qthread.h>
#include <QtCore/qmutex.h>
#include <QtCore/qwaitcondition.h>
#include <QtCore/qiodevice.h>
//#include <QDebug>

View File

@@ -51,6 +51,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();
@@ -138,29 +162,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;
@@ -172,27 +173,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:
@@ -231,89 +214,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&)
{
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")] = 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;
};
}

View File

@@ -82,6 +82,8 @@ void QMediaNetworkPlaylistProviderPrivate::_q_handleParserError(QPlaylistFilePar
break;
}
parser.stop();
emit q->loadFailed(playlistError, errorMessage);
}

View File

@@ -760,7 +760,7 @@ qint64 QAlsaAudioInput::elapsedUSecs() const
if (deviceState == QAudio::StoppedState)
return 0;
return clockStamp.elapsed()*1000;
return clockStamp.elapsed() * qint64(1000);
}
void QAlsaAudioInput::reset()

View File

@@ -774,7 +774,7 @@ qint64 QAlsaAudioOutput::elapsedUSecs() const
if (deviceState == QAudio::StoppedState)
return 0;
return clockStamp.elapsed()*1000;
return clockStamp.elapsed() * qint64(1000);
}
void QAlsaAudioOutput::reset()

View File

@@ -474,7 +474,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)

View File

@@ -273,7 +273,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()

View File

@@ -684,7 +684,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()

View File

@@ -596,7 +596,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()

View File

@@ -186,7 +186,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

View File

@@ -172,7 +172,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

View File

@@ -538,6 +538,7 @@ void MmRendererMediaPlayerControl::play()
return;
}
m_stopEventsToIgnore = 0; // once playing, stop events must be proccessed
setState( QMediaPlayer::PlayingState);
}

View File

@@ -698,7 +698,7 @@ qint64 QWindowsAudioInput::elapsedUSecs() const
if (deviceState == QAudio::StoppedState)
return 0;
return timeStampOpened.elapsed()*1000;
return timeStampOpened.elapsed() * qint64(1000);
}
void QWindowsAudioInput::reset()

View File

@@ -674,7 +674,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

View File

@@ -236,7 +236,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);
@@ -246,9 +245,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);

View File

@@ -258,6 +258,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);
@@ -415,12 +416,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;
@@ -609,42 +613,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;
}
@@ -1502,8 +1503,11 @@ HRESULT MFPlayerSession::Invoke(IMFAsyncResult *pResult)
}
}
if (!m_closing)
if (!m_closing) {
emit sessionEvent(pEvent);
} else {
pEvent->Release();
}
return S_OK;
}
@@ -1626,9 +1630,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);
@@ -1699,6 +1700,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);
}
}
}

View File

@@ -155,6 +155,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)

View File

@@ -0,0 +1,2 @@
[playlist]
NumberOfEntries=100

View File

@@ -0,0 +1,27 @@
[playlist]
File1=http://test.host/path
Title1=First
Length1=-1
File2= http://test.host/path
Title2=Second
Length2=-1
File3=testfile
Title3=Third
Length3=-1
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

View File

@@ -0,0 +1,5 @@
[playlist]
X-GNOME-Title=totem-pl-file-example
NumberOfEntries=1
File1=http://test.host/path
Title1=Silence

View File

@@ -78,6 +78,7 @@ private slots:
void currentItem();
void saveAndLoad();
void loadM3uFile();
void loadPLSFile();
void playbackMode();
void playbackMode_data();
void shuffle();
@@ -348,8 +349,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());
@@ -359,8 +362,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());
@@ -372,7 +377,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());
@@ -382,9 +391,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());
@@ -398,12 +411,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);
@@ -420,10 +441,80 @@ 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 empty playlist
loadSpy.clear();
loadFailedSpy.clear();
testFileName = QFINDTESTDATA("testdata/empty.pls");
playlist.load(QUrl::fromLocalFile(testFileName));
QTRY_VERIFY(!loadSpy.isEmpty());
QVERIFY(loadFailedSpy.isEmpty());
QCOMPARE(playlist.error(), QMediaPlaylist::NoError);
QCOMPARE(playlist.mediaCount(), 0);
// 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(), 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
// (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());
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();
loadFailedSpy.clear();
playlist.load(QNetworkRequest(QUrl::fromLocalFile(QFINDTESTDATA("testdata/test.pls"))));
QTRY_VERIFY(!loadSpy.isEmpty());
QVERIFY(loadFailedSpy.isEmpty());
}