diff options
author | Liang Qi <liang.qi@qt.io> | 2018-01-06 20:21:19 +0100 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2018-01-06 20:21:19 +0100 |
commit | 82621148de82d63a562163a72598e15ed98797a8 (patch) | |
tree | 030d345ad4a4ae612995949bbbeec66b36e69854 | |
parent | 2fc515ea1eaa0f7ffb56c4dadee560095c3374bd (diff) | |
parent | 7a3b8907060123fe5d487d4c9ba3a1e222f468bb (diff) | |
download | qtmultimedia-82621148de82d63a562163a72598e15ed98797a8.tar.gz |
Merge remote-tracking branch 'origin/5.10' into dev
Conflicts:
.qmake.conf
Change-Id: I5acdc7e0bd3729b80522dfff0f388cf2507fb111
46 files changed, 484 insertions, 278 deletions
diff --git a/dist/changes-5.10.0 b/dist/changes-5.10.0 new file mode 100644 index 000000000..cbdb75b09 --- /dev/null +++ b/dist/changes-5.10.0 @@ -0,0 +1,41 @@ +Qt 5.10 introduces many new features and improvements as well as bugfixes +over the 5.9.x series. For more details, refer to the online documentation +included in this distribution. The documentation is also available online: + +http://doc.qt.io/qt-5/index.html + +The Qt version 5.10 series is binary compatible with the 5.9.x series. +Applications compiled for 5.9 will continue to run with 5.10. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Qt 5.10.0 Changes * +**************************************************************************** + + - [QTBUG-57045] Fixed crash when calling pause in the onPositionChanged + handler. + +**************************************************************************** +* Platform Specific Changes * +**************************************************************************** + +QNX +--- + - Added support for setting audio roles. + +Linux +----- + - [QTBUG-62621] Unsupported audio formats in PulseAudio will now be rejected + instead of being played incorrectly. + - [QTBUG-63427] QSoundEffect with PulseAudio now supports 24 bit samples. + +Windows +------- + - Added support for QMediaMetaData::Orientation. diff --git a/dist/changes-5.9.3 b/dist/changes-5.9.3 new file mode 100644 index 000000000..568224232 --- /dev/null +++ b/dist/changes-5.9.3 @@ -0,0 +1,58 @@ +Qt 5.9.3 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.9.0. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +http://doc.qt.io/qt-5/index.html + +The Qt version 5.9 series is binary compatible with the 5.8.x series. +Applications compiled for 5.8 will continue to run with 5.9. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Qt 5.9.3 Changes * +**************************************************************************** + +QtMultimedia +------------ + +- [QTBUG-53268] Fixed regression that caused relevant properties of the surface + format to be discarded when the video node was created. +- [QTBUG-62255] Fixed loading of remote m3u files. + +**************************************************************************** +* Platform Specific Changes * +**************************************************************************** + +Linux +----- + +- [QTBUG-62789] Fixed memory leak in QGstreamerAudioDecoderSession. +- [QTBUG-62245] Fixed input query in V4L code to correctly detect all cameras. +- Fixed memory leak in CameraBinImageCapture. + +QNX +--- + +- Switched to mmr_event_t based metadata retrieval, as PPS based retrieval is no + longer supported by Multimedia for QNX 7.0.0. + + +Android +------- + +- [QTBUG-51213] The scan line for the video surface format is now correctly + set to bottom-up. + +WinRT +----- + +- [QTBUG-63308] Added permission check for the camera. diff --git a/examples/multimedia/audiodecoder/audiodecoder.cpp b/examples/multimedia/audiodecoder/audiodecoder.cpp index 5145d529e..86904f7c9 100644 --- a/examples/multimedia/audiodecoder/audiodecoder.cpp +++ b/examples/multimedia/audiodecoder/audiodecoder.cpp @@ -67,15 +67,23 @@ AudioDecoder::AudioDecoder(bool isPlayback, bool isDelete) format.setSampleType(QAudioFormat::SignedInt); m_decoder.setAudioFormat(format); - connect(&m_decoder, SIGNAL(bufferReady()), this, SLOT(bufferReady())); - connect(&m_decoder, SIGNAL(error(QAudioDecoder::Error)), this, SLOT(error(QAudioDecoder::Error))); - connect(&m_decoder, SIGNAL(stateChanged(QAudioDecoder::State)), this, SLOT(stateChanged(QAudioDecoder::State))); - connect(&m_decoder, SIGNAL(finished()), this, SLOT(finished())); - connect(&m_decoder, SIGNAL(positionChanged(qint64)), this, SLOT(updateProgress())); - connect(&m_decoder, SIGNAL(durationChanged(qint64)), this, SLOT(updateProgress())); - - connect(&m_soundEffect, SIGNAL(statusChanged()), this, SLOT(playbackStatusChanged())); - connect(&m_soundEffect, SIGNAL(playingChanged()), this, SLOT(playingChanged())); + connect(&m_decoder, &QAudioDecoder::bufferReady, + this, &AudioDecoder::bufferReady); + connect(&m_decoder, QOverload<QAudioDecoder::Error>::of(&QAudioDecoder::error), + this, QOverload<QAudioDecoder::Error>::of(&AudioDecoder::error)); + connect(&m_decoder, &QAudioDecoder::stateChanged, + this, &AudioDecoder::stateChanged); + connect(&m_decoder, &QAudioDecoder::finished, + this, &AudioDecoder::finished); + connect(&m_decoder, &QAudioDecoder::positionChanged, + this, &AudioDecoder::updateProgress); + connect(&m_decoder, &QAudioDecoder::durationChanged, + this, &AudioDecoder::updateProgress); + + connect(&m_soundEffect, &QSoundEffect::statusChanged, + this, &AudioDecoder::playbackStatusChanged); + connect(&m_soundEffect, &QSoundEffect::playingChanged, + this, &AudioDecoder::playingChanged); m_progress = -1.0; } diff --git a/examples/multimedia/audiodecoder/main.cpp b/examples/multimedia/audiodecoder/main.cpp index 2b4b9dab4..c0947b83f 100644 --- a/examples/multimedia/audiodecoder/main.cpp +++ b/examples/multimedia/audiodecoder/main.cpp @@ -95,7 +95,8 @@ int main(int argc, char *argv[]) targetFile.setFile(sourceFile.dir().absoluteFilePath("out.wav")); AudioDecoder decoder(isPlayback, isDelete); - QObject::connect(&decoder, SIGNAL(done()), &app, SLOT(quit())); + QObject::connect(&decoder, &AudioDecoder::done, + &app, &QCoreApplication::quit); decoder.setSourceFilename(sourceFile.absoluteFilePath()); decoder.setTargetFilename(targetFile.absoluteFilePath()); decoder.start(); diff --git a/examples/multimedia/audiorecorder/audiorecorder.cpp b/examples/multimedia/audiorecorder/audiorecorder.cpp index 312b2d2aa..9dd3368e0 100644 --- a/examples/multimedia/audiorecorder/audiorecorder.cpp +++ b/examples/multimedia/audiorecorder/audiorecorder.cpp @@ -58,6 +58,7 @@ #include <QDir> #include <QFileDialog> #include <QMediaRecorder> +#include <QStandardPaths> static qreal getPeakValue(const QAudioFormat &format); static QVector<qreal> getBufferLevels(const QAudioBuffer &buffer); @@ -221,7 +222,17 @@ void AudioRecorder::togglePause() void AudioRecorder::setOutputLocation() { +#ifdef Q_OS_WINRT + // UWP does not allow to store outside the sandbox + const QString cacheDir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation); + if (!QDir().mkpath(cacheDir)) { + qWarning() << "Failed to create cache directory"; + return; + } + QString fileName = cacheDir + QLatin1String("/output.wav"); +#else QString fileName = QFileDialog::getSaveFileName(); +#endif m_audioRecorder->setOutputLocation(QUrl::fromLocalFile(fileName)); m_outputLocationSet = true; } diff --git a/examples/multimedia/declarative-camera/qmlcamera.cpp b/examples/multimedia/declarative-camera/qmlcamera.cpp index 1118e0dc0..edffe6bb0 100644 --- a/examples/multimedia/declarative-camera/qmlcamera.cpp +++ b/examples/multimedia/declarative-camera/qmlcamera.cpp @@ -59,7 +59,8 @@ int main(int argc, char* argv[]) view.setResizeMode(QQuickView::SizeRootObjectToView); // Qt.quit() called in embedded .qml by default only emits // quit() signal, so do this (optionally use Qt.exit()). - QObject::connect(view.engine(), SIGNAL(quit()), qApp, SLOT(quit())); + QObject::connect(view.engine(), &QQmlEngine::quit, + qApp, &QGuiApplication::quit); view.setSource(QUrl("qrc:///declarative-camera.qml")); view.resize(800, 480); view.show(); diff --git a/examples/multimedia/radio/radio.cpp b/examples/multimedia/radio/radio.cpp index c6bac969a..f4c9f5531 100644 --- a/examples/multimedia/radio/radio.cpp +++ b/examples/multimedia/radio/radio.cpp @@ -53,7 +53,8 @@ Radio::Radio() { radio = new QRadioTuner; - connect(radio, SIGNAL(error(QRadioTuner::Error)), this, SLOT(error(QRadioTuner::Error))); + connect(radio, QOverload<QRadioTuner::Error>::of(&QRadioTuner::error), + this, QOverload<QRadioTuner::Error>::of(&Radio::error)); if (radio->isBandSupported(QRadioTuner::FM)) radio->setBand(QRadioTuner::FM); @@ -68,7 +69,8 @@ Radio::Radio() freq = new QLabel; freq->setText(QString("%1 kHz").arg(radio->frequency()/1000)); topBar->addWidget(freq); - connect(radio, SIGNAL(frequencyChanged(int)), SLOT(freqChanged(int))); + connect(radio, &QRadioTuner::frequencyChanged, + this, &Radio::freqChanged); signal = new QLabel; if (radio->isAvailable()) @@ -76,34 +78,40 @@ Radio::Radio() else signal->setText(tr("No radio found")); topBar->addWidget(signal); - connect(radio, SIGNAL(signalStrengthChanged(int)), SLOT(signalChanged(int))); + connect(radio, &QRadioTuner::signalStrengthChanged, + this, &Radio::signalChanged); volumeSlider = new QSlider(Qt::Vertical,this); volumeSlider->setRange(0, 100); volumeSlider->setValue(50); - connect(volumeSlider, SIGNAL(valueChanged(int)), SLOT(updateVolume(int))); + connect(volumeSlider, &QSlider::valueChanged, + this, &Radio::updateVolume); topBar->addWidget(volumeSlider); layout->addLayout(buttonBar); searchLeft = new QPushButton; searchLeft->setText(tr("scan Down")); - connect(searchLeft, SIGNAL(clicked()), SLOT(searchDown())); + connect(searchLeft, &QPushButton::clicked, + this, &Radio::searchDown); buttonBar->addWidget(searchLeft); left = new QPushButton; left->setText(tr("Freq Down")); - connect(left, SIGNAL(clicked()), SLOT(freqDown())); + connect(left, &QPushButton::clicked, + this, &Radio::freqDown); buttonBar->addWidget(left); right = new QPushButton; - connect(right, SIGNAL(clicked()), SLOT(freqUp())); + connect(right, &QPushButton::clicked, + this, &Radio::freqUp); right->setText(tr("Freq Up")); buttonBar->addWidget(right); searchRight = new QPushButton; searchRight->setText(tr("scan Up")); - connect(searchRight, SIGNAL(clicked()), SLOT(searchUp())); + connect(searchRight, &QPushButton::clicked, + this, &Radio::searchUp); buttonBar->addWidget(searchRight); window->setLayout(layout); diff --git a/examples/multimedia/spectrum/app/engine.cpp b/examples/multimedia/spectrum/app/engine.cpp index eb289ca6c..7e11d012b 100644 --- a/examples/multimedia/spectrum/app/engine.cpp +++ b/examples/multimedia/spectrum/app/engine.cpp @@ -108,10 +108,8 @@ Engine::Engine(QObject *parent) { qRegisterMetaType<FrequencySpectrum>("FrequencySpectrum"); qRegisterMetaType<WindowFunction>("WindowFunction"); - CHECKED_CONNECT(&m_spectrumAnalyser, - SIGNAL(spectrumChanged(FrequencySpectrum)), - this, - SLOT(spectrumChanged(FrequencySpectrum))); + connect(&m_spectrumAnalyser, QOverload<const FrequencySpectrum&>::of(&SpectrumAnalyser::spectrumChanged), + this, QOverload<const FrequencySpectrum&>::of(&Engine::spectrumChanged)); // This code might misinterpret things like "-something -category". But // it's unlikely that that needs to be supported so we'll let it go. @@ -243,16 +241,17 @@ void Engine::startRecording() setRecordPosition(0, true); stopPlayback(); m_mode = QAudio::AudioInput; - CHECKED_CONNECT(m_audioInput, SIGNAL(stateChanged(QAudio::State)), - this, SLOT(audioStateChanged(QAudio::State))); - CHECKED_CONNECT(m_audioInput, SIGNAL(notify()), - this, SLOT(audioNotify())); + connect(m_audioInput, &QAudioInput::stateChanged, + this, &Engine::audioStateChanged); + connect(m_audioInput, &QAudioInput::notify, + this, &Engine::audioNotify); + m_count = 0; m_dataLength = 0; emit dataLengthChanged(0); m_audioInputIODevice = m_audioInput->start(); - CHECKED_CONNECT(m_audioInputIODevice, SIGNAL(readyRead()), - this, SLOT(audioDataReady())); + connect(m_audioInputIODevice, &QIODevice::readyRead, + this, &Engine::audioDataReady); } } } @@ -275,10 +274,11 @@ void Engine::startPlayback() setPlayPosition(0, true); stopRecording(); m_mode = QAudio::AudioOutput; - CHECKED_CONNECT(m_audioOutput, SIGNAL(stateChanged(QAudio::State)), - this, SLOT(audioStateChanged(QAudio::State))); - CHECKED_CONNECT(m_audioOutput, SIGNAL(notify()), - this, SLOT(audioNotify())); + connect(m_audioOutput, &QAudioOutput::stateChanged, + this, &Engine::audioStateChanged); + connect(m_audioOutput, &QAudioOutput::notify, + this, &Engine::audioNotify); + m_count = 0; if (m_file) { m_file->seek(0); diff --git a/examples/multimedia/spectrum/app/levelmeter.cpp b/examples/multimedia/spectrum/app/levelmeter.cpp index a2741d23f..1c720905c 100644 --- a/examples/multimedia/spectrum/app/levelmeter.cpp +++ b/examples/multimedia/spectrum/app/levelmeter.cpp @@ -77,7 +77,8 @@ LevelMeter::LevelMeter(QWidget *parent) setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); setMinimumWidth(30); - connect(m_redrawTimer, SIGNAL(timeout()), this, SLOT(redrawTimerExpired())); + connect(m_redrawTimer, &QTimer::timeout, + this, &LevelMeter::redrawTimerExpired); m_redrawTimer->start(RedrawInterval); } diff --git a/examples/multimedia/spectrum/app/mainwidget.cpp b/examples/multimedia/spectrum/app/mainwidget.cpp index 6585fec94..945313f32 100644 --- a/examples/multimedia/spectrum/app/mainwidget.cpp +++ b/examples/multimedia/spectrum/app/mainwidget.cpp @@ -339,62 +339,62 @@ void MainWidget::createUi() void MainWidget::connectUi() { - CHECKED_CONNECT(m_recordButton, SIGNAL(clicked()), - m_engine, SLOT(startRecording())); + connect(m_recordButton, &QPushButton::clicked, + m_engine, &Engine::startRecording); - CHECKED_CONNECT(m_pauseButton, SIGNAL(clicked()), - m_engine, SLOT(suspend())); + connect(m_pauseButton, &QPushButton::clicked, + m_engine, &Engine::suspend); - CHECKED_CONNECT(m_playButton, SIGNAL(clicked()), - m_engine, SLOT(startPlayback())); + connect(m_playButton, &QPushButton::clicked, + m_engine, &Engine::startPlayback); - CHECKED_CONNECT(m_settingsButton, SIGNAL(clicked()), - this, SLOT(showSettingsDialog())); + connect(m_settingsButton, &QPushButton::clicked, + this, &MainWidget::showSettingsDialog); - CHECKED_CONNECT(m_engine, SIGNAL(stateChanged(QAudio::Mode,QAudio::State)), - this, SLOT(stateChanged(QAudio::Mode,QAudio::State))); + connect(m_engine, &Engine::stateChanged, + this, &MainWidget::stateChanged); - CHECKED_CONNECT(m_engine, SIGNAL(formatChanged(const QAudioFormat &)), - this, SLOT(formatChanged(const QAudioFormat &))); + connect(m_engine, &Engine::formatChanged, + this, &MainWidget::formatChanged); m_progressBar->bufferLengthChanged(m_engine->bufferLength()); - CHECKED_CONNECT(m_engine, SIGNAL(bufferLengthChanged(qint64)), - this, SLOT(bufferLengthChanged(qint64))); + connect(m_engine, &Engine::bufferLengthChanged, + this, &MainWidget::bufferLengthChanged); - CHECKED_CONNECT(m_engine, SIGNAL(dataLengthChanged(qint64)), - this, SLOT(updateButtonStates())); + connect(m_engine, &Engine::dataLengthChanged, + this, &MainWidget::updateButtonStates); - CHECKED_CONNECT(m_engine, SIGNAL(recordPositionChanged(qint64)), - m_progressBar, SLOT(recordPositionChanged(qint64))); + connect(m_engine, &Engine::recordPositionChanged, + m_progressBar, &ProgressBar::recordPositionChanged); - CHECKED_CONNECT(m_engine, SIGNAL(playPositionChanged(qint64)), - m_progressBar, SLOT(playPositionChanged(qint64))); + connect(m_engine, &Engine::playPositionChanged, + m_progressBar, &ProgressBar::playPositionChanged); - CHECKED_CONNECT(m_engine, SIGNAL(recordPositionChanged(qint64)), - this, SLOT(audioPositionChanged(qint64))); + connect(m_engine, &Engine::recordPositionChanged, + this, &MainWidget::audioPositionChanged); - CHECKED_CONNECT(m_engine, SIGNAL(playPositionChanged(qint64)), - this, SLOT(audioPositionChanged(qint64))); + connect(m_engine, &Engine::playPositionChanged, + this, &MainWidget::audioPositionChanged); - CHECKED_CONNECT(m_engine, SIGNAL(levelChanged(qreal, qreal, int)), - m_levelMeter, SLOT(levelChanged(qreal, qreal, int))); + connect(m_engine, &Engine::levelChanged, + m_levelMeter, &LevelMeter::levelChanged); - CHECKED_CONNECT(m_engine, SIGNAL(spectrumChanged(qint64, qint64, const FrequencySpectrum &)), - this, SLOT(spectrumChanged(qint64, qint64, const FrequencySpectrum &))); + connect(m_engine, QOverload<qint64, qint64, const FrequencySpectrum&>::of(&Engine::spectrumChanged), + this, QOverload<qint64, qint64, const FrequencySpectrum&>::of(&MainWidget::spectrumChanged)); - CHECKED_CONNECT(m_engine, SIGNAL(infoMessage(QString, int)), - this, SLOT(infoMessage(QString, int))); + connect(m_engine, &Engine::infoMessage, + this, &MainWidget::infoMessage); - CHECKED_CONNECT(m_engine, SIGNAL(errorMessage(QString, QString)), - this, SLOT(errorMessage(QString, QString))); + connect(m_engine, &Engine::errorMessage, + this, &MainWidget::errorMessage); - CHECKED_CONNECT(m_spectrograph, SIGNAL(infoMessage(QString, int)), - this, SLOT(infoMessage(QString, int))); + connect(m_spectrograph, &Spectrograph::infoMessage, + this, &MainWidget::infoMessage); #ifndef DISABLE_WAVEFORM - CHECKED_CONNECT(m_engine, SIGNAL(bufferChanged(qint64, qint64, const QByteArray &)), - m_waveform, SLOT(bufferChanged(qint64, qint64, const QByteArray &))); + connect(m_engine, &Engine::bufferChanged, + m_waveform, &Waveform::bufferChanged); #endif } @@ -410,9 +410,9 @@ void MainWidget::createMenus() m_generateToneAction->setCheckable(true); m_recordAction->setCheckable(true); - connect(m_loadFileAction, SIGNAL(triggered(bool)), this, SLOT(showFileDialog())); - connect(m_generateToneAction, SIGNAL(triggered(bool)), this, SLOT(showToneGeneratorDialog())); - connect(m_recordAction, SIGNAL(triggered(bool)), this, SLOT(initializeRecord())); + connect(m_loadFileAction, &QAction::triggered, this, &MainWidget::showFileDialog); + connect(m_generateToneAction, &QAction::triggered, this, &MainWidget::showToneGeneratorDialog); + connect(m_recordAction, &QAction::triggered, this, &MainWidget::initializeRecord); } void MainWidget::updateButtonStates() diff --git a/examples/multimedia/spectrum/app/settingsdialog.cpp b/examples/multimedia/spectrum/app/settingsdialog.cpp index 109817cd2..f1723077e 100644 --- a/examples/multimedia/spectrum/app/settingsdialog.cpp +++ b/examples/multimedia/spectrum/app/settingsdialog.cpp @@ -114,12 +114,12 @@ SettingsDialog::SettingsDialog( windowFunctionLayout.take(); // ownership transferred to dialogLayout // Connect - CHECKED_CONNECT(m_inputDeviceComboBox, SIGNAL(activated(int)), - this, SLOT(inputDeviceChanged(int))); - CHECKED_CONNECT(m_outputDeviceComboBox, SIGNAL(activated(int)), - this, SLOT(outputDeviceChanged(int))); - CHECKED_CONNECT(m_windowFunctionComboBox, SIGNAL(activated(int)), - this, SLOT(windowFunctionChanged(int))); + connect(m_inputDeviceComboBox, QOverload<int>::of(&QComboBox::activated), + this, &SettingsDialog::inputDeviceChanged); + connect(m_outputDeviceComboBox, QOverload<int>::of(&QComboBox::activated), + this, &SettingsDialog::outputDeviceChanged); + connect(m_windowFunctionComboBox, QOverload<int>::of(&QComboBox::activated), + this, &SettingsDialog::windowFunctionChanged); // Add standard buttons to layout QDialogButtonBox *buttonBox = new QDialogButtonBox(this); @@ -127,10 +127,10 @@ SettingsDialog::SettingsDialog( dialogLayout->addWidget(buttonBox); // Connect standard buttons - CHECKED_CONNECT(buttonBox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), - this, SLOT(accept())); - CHECKED_CONNECT(buttonBox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), - this, SLOT(reject())); + connect(buttonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, + this, &SettingsDialog::accept); + connect(buttonBox->button(QDialogButtonBox::Cancel), &QPushButton::clicked, + this, &SettingsDialog::reject); setLayout(dialogLayout); } diff --git a/examples/multimedia/spectrum/app/spectrum.h b/examples/multimedia/spectrum/app/spectrum.h index 1d0eedeff..aea9ce7c5 100644 --- a/examples/multimedia/spectrum/app/spectrum.h +++ b/examples/multimedia/spectrum/app/spectrum.h @@ -130,22 +130,6 @@ struct SweptTone qreal amplitude; }; - -//----------------------------------------------------------------------------- -// Macros -//----------------------------------------------------------------------------- - -// Macro which connects a signal to a slot, and which causes application to -// abort if the connection fails. This is intended to catch programming errors -// such as mis-typing a signal or slot name. It is necessary to write our own -// macro to do this - the following idiom -// Q_ASSERT(connect(source, signal, receiver, slot)); -// will not work because Q_ASSERT compiles to a no-op in release builds. - -#define CHECKED_CONNECT(source, signal, receiver, slot) \ - if (!connect(source, signal, receiver, slot)) \ - qt_assert_x(Q_FUNC_INFO, "CHECKED_CONNECT failed", __FILE__, __LINE__); - // Handle some dependencies between macros defined in the .pro file #ifdef DISABLE_WAVEFORM diff --git a/examples/multimedia/spectrum/app/spectrumanalyser.cpp b/examples/multimedia/spectrum/app/spectrumanalyser.cpp index 466c67188..ee024147f 100644 --- a/examples/multimedia/spectrum/app/spectrumanalyser.cpp +++ b/examples/multimedia/spectrum/app/spectrumanalyser.cpp @@ -172,8 +172,8 @@ SpectrumAnalyser::SpectrumAnalyser(QObject *parent) , m_count(0) #endif { - CHECKED_CONNECT(m_thread, SIGNAL(calculationComplete(FrequencySpectrum)), - this, SLOT(calculationComplete(FrequencySpectrum))); + connect(m_thread, &SpectrumAnalyserThread::calculationComplete, + this, &SpectrumAnalyser::calculationComplete); } SpectrumAnalyser::~SpectrumAnalyser() diff --git a/examples/multimedia/spectrum/app/tonegeneratordialog.cpp b/examples/multimedia/spectrum/app/tonegeneratordialog.cpp index 55f998417..76fe5d2e3 100644 --- a/examples/multimedia/spectrum/app/tonegeneratordialog.cpp +++ b/examples/multimedia/spectrum/app/tonegeneratordialog.cpp @@ -106,12 +106,12 @@ ToneGeneratorDialog::ToneGeneratorDialog(QWidget *parent) dialogLayout->addWidget(m_toneGeneratorControl); // Connect - CHECKED_CONNECT(m_toneGeneratorSweepCheckBox, SIGNAL(toggled(bool)), - this, SLOT(frequencySweepEnabled(bool))); - CHECKED_CONNECT(m_frequencySlider, SIGNAL(valueChanged(int)), - m_frequencySpinBox, SLOT(setValue(int))); - CHECKED_CONNECT(m_frequencySpinBox, SIGNAL(valueChanged(int)), - m_frequencySlider, SLOT(setValue(int))); + connect(m_toneGeneratorSweepCheckBox, &QCheckBox::toggled, + this, &ToneGeneratorDialog::frequencySweepEnabled); + connect(m_frequencySlider, &QSlider::valueChanged, + m_frequencySpinBox, &QSpinBox::setValue); + connect(m_frequencySpinBox, QOverload<int>::of(&QSpinBox::valueChanged), + m_frequencySlider, &QSlider::setValue); // Add standard buttons to layout QDialogButtonBox *buttonBox = new QDialogButtonBox(this); @@ -119,10 +119,10 @@ ToneGeneratorDialog::ToneGeneratorDialog(QWidget *parent) dialogLayout->addWidget(buttonBox); // Connect standard buttons - CHECKED_CONNECT(buttonBox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), - this, SLOT(accept())); - CHECKED_CONNECT(buttonBox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), - this, SLOT(reject())); + connect(buttonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, + this, &ToneGeneratorDialog::accept); + connect(buttonBox->button(QDialogButtonBox::Cancel), &QPushButton::clicked, + this, &ToneGeneratorDialog::reject); setLayout(dialogLayout); } diff --git a/examples/multimedia/video/qmlvideo/main.cpp b/examples/multimedia/video/qmlvideo/main.cpp index a09ea534e..e288c0ae4 100644 --- a/examples/multimedia/video/qmlvideo/main.cpp +++ b/examples/multimedia/video/qmlvideo/main.cpp @@ -122,7 +122,7 @@ int main(int argc, char *argv[]) QQuickView viewer; viewer.setSource(QUrl("qrc:///qml/qmlvideo/main.qml")); - QObject::connect(viewer.engine(), SIGNAL(quit()), &viewer, SLOT(close())); + QObject::connect(viewer.engine(), &QQmlEngine::quit, &viewer, &QQuickView::close); QQuickItem *rootObject = viewer.rootObject(); rootObject->setProperty("source1", url1); diff --git a/examples/multimedia/video/qmlvideofx/qmlapplicationviewer/qmlapplicationviewer.cpp b/examples/multimedia/video/qmlvideofx/qmlapplicationviewer/qmlapplicationviewer.cpp index 33cead8e0..27102b0c5 100644 --- a/examples/multimedia/video/qmlvideofx/qmlapplicationviewer/qmlapplicationviewer.cpp +++ b/examples/multimedia/video/qmlvideofx/qmlapplicationviewer/qmlapplicationviewer.cpp @@ -90,7 +90,7 @@ QmlApplicationViewer::QmlApplicationViewer(QWindow *parent) : QQuickView(parent) , d(new QmlApplicationViewerPrivate(this)) { - connect(engine(), SIGNAL(quit()), QCoreApplication::instance(), SLOT(quit())); + connect(engine(), &QQmlEngine::quit, QCoreApplication::instance(), &QCoreApplication::quit); setResizeMode(QQuickView::SizeRootObjectToView); } @@ -98,7 +98,7 @@ QmlApplicationViewer::QmlApplicationViewer(QQuickView *view, QWindow *parent) : QQuickView(parent) , d(new QmlApplicationViewerPrivate(view)) { - connect(view->engine(), SIGNAL(quit()), QCoreApplication::instance(), SLOT(quit())); + connect(view->engine(), &QQmlEngine::quit, QCoreApplication::instance(), &QCoreApplication::quit); view->setResizeMode(QQuickView::SizeRootObjectToView); } diff --git a/examples/multimedia/video/snippets/frequencymonitor/frequencymonitor.cpp b/examples/multimedia/video/snippets/frequencymonitor/frequencymonitor.cpp index fb31c7b1e..d611497fe 100644 --- a/examples/multimedia/video/snippets/frequencymonitor/frequencymonitor.cpp +++ b/examples/multimedia/video/snippets/frequencymonitor/frequencymonitor.cpp @@ -105,18 +105,18 @@ FrequencyMonitorPrivate::FrequencyMonitorPrivate(FrequencyMonitor *parent) , m_stalledTimer(new QTimer(this)) { m_instantaneousElapsed.start(); - connect(m_averageTimer, SIGNAL(timeout()), - this, SLOT(calculateAverageFrequency())); + connect(m_averageTimer, &QTimer::timeout, + this, &FrequencyMonitorPrivate::calculateAverageFrequency); if (DefaultSamplingInterval) m_averageTimer->start(DefaultSamplingInterval); m_averageElapsed.start(); - connect(m_traceTimer, SIGNAL(timeout()), - q_ptr, SLOT(trace())); + connect(m_traceTimer, &QTimer::timeout, + q_ptr, &FrequencyMonitor::trace); if (DefaultTraceInterval) m_traceTimer->start(DefaultTraceInterval); m_stalledTimer->setSingleShot(true); - connect(m_stalledTimer, SIGNAL(timeout()), - this, SLOT(stalled())); + connect(m_stalledTimer, &QTimer::timeout, + this, &FrequencyMonitorPrivate::stalled); } void FrequencyMonitorPrivate::calculateInstantaneousFrequency() diff --git a/examples/multimediawidgets/customvideosurface/customvideoitem/videoplayer.cpp b/examples/multimediawidgets/customvideosurface/customvideoitem/videoplayer.cpp index 7da566a20..60b93a116 100644 --- a/examples/multimediawidgets/customvideosurface/customvideoitem/videoplayer.cpp +++ b/examples/multimediawidgets/customvideosurface/customvideoitem/videoplayer.cpp @@ -80,24 +80,25 @@ VideoPlayer::VideoPlayer(QWidget *parent) rotateSlider->setRange(-180, 180); rotateSlider->setValue(0); - connect(rotateSlider, SIGNAL(valueChanged(int)), - this, SLOT(rotateVideo(int))); + connect(rotateSlider, &QSlider::valueChanged, + this, &VideoPlayer::rotateVideo); QAbstractButton *openButton = new QPushButton(tr("Open...")); - connect(openButton, SIGNAL(clicked()), this, SLOT(openFile())); + connect(openButton, &QAbstractButton::clicked, + this, &VideoPlayer::openFile); playButton = new QPushButton; playButton->setEnabled(false); playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay)); - connect(playButton, SIGNAL(clicked()), - this, SLOT(play())); + connect(playButton, &QAbstractButton::clicked, + this, &VideoPlayer::play); positionSlider = new QSlider(Qt::Horizontal); positionSlider->setRange(0, 0); - connect(positionSlider, SIGNAL(sliderMoved(int)), - this, SLOT(setPosition(int))); + connect(positionSlider, &QSlider::sliderMoved, + this, &VideoPlayer::setPosition); QBoxLayout *controlLayout = new QHBoxLayout; controlLayout->setMargin(0); @@ -113,10 +114,10 @@ VideoPlayer::VideoPlayer(QWidget *parent) setLayout(layout); mediaPlayer.setVideoOutput(videoItem); - connect(&mediaPlayer, SIGNAL(stateChanged(QMediaPlayer::State)), - this, SLOT(mediaStateChanged(QMediaPlayer::State))); - connect(&mediaPlayer, SIGNAL(positionChanged(qint64)), this, SLOT(positionChanged(qint64))); - connect(&mediaPlayer, SIGNAL(durationChanged(qint64)), this, SLOT(durationChanged(qint64))); + connect(&mediaPlayer, &QMediaPlayer::stateChanged, + this, &VideoPlayer::mediaStateChanged); + connect(&mediaPlayer, &QMediaPlayer::positionChanged, this, &VideoPlayer::positionChanged); + connect(&mediaPlayer, &QMediaPlayer::durationChanged, this, &VideoPlayer::durationChanged); } VideoPlayer::~VideoPlayer() diff --git a/examples/multimediawidgets/customvideosurface/customvideowidget/videoplayer.cpp b/examples/multimediawidgets/customvideosurface/customvideowidget/videoplayer.cpp index 7d0759c35..7730f8140 100644 --- a/examples/multimediawidgets/customvideosurface/customvideowidget/videoplayer.cpp +++ b/examples/multimediawidgets/customvideosurface/customvideowidget/videoplayer.cpp @@ -64,20 +64,21 @@ VideoPlayer::VideoPlayer(QWidget *parent) VideoWidget *videoWidget = new VideoWidget; QAbstractButton *openButton = new QPushButton(tr("Open...")); - connect(openButton, SIGNAL(clicked()), this, SLOT(openFile())); + connect(openButton, &QAbstractButton::clicked, + this, &VideoPlayer::openFile); playButton = new QPushButton; playButton->setEnabled(false); playButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay)); - connect(playButton, SIGNAL(clicked()), - this, SLOT(play())); + connect(playButton, &QAbstractButton::clicked, + this, &VideoPlayer::play); positionSlider = new QSlider(Qt::Horizontal); positionSlider->setRange(0, 0); - connect(positionSlider, SIGNAL(sliderMoved(int)), - this, SLOT(setPosition(int))); + connect(positionSlider, &QSlider::sliderMoved, + this, &VideoPlayer::setPosition); QBoxLayout *controlLayout = new QHBoxLayout; controlLayout->setMargin(0); @@ -92,10 +93,10 @@ VideoPlayer::VideoPlayer(QWidget *parent) setLayout(layout); mediaPlayer.setVideoOutput(videoWidget->videoSurface()); - connect(&mediaPlayer, SIGNAL(stateChanged(QMediaPlayer::State)), - this, SLOT(mediaStateChanged(QMediaPlayer::State))); - connect(&mediaPlayer, SIGNAL(positionChanged(qint64)), this, SLOT(positionChanged(qint64))); - connect(&mediaPlayer, SIGNAL(durationChanged(qint64)), this, SLOT(durationChanged(qint64))); + connect(&mediaPlayer, &QMediaPlayer::stateChanged, + this, &VideoPlayer::mediaStateChanged); + connect(&mediaPlayer, &QMediaPlayer::positionChanged, this, &VideoPlayer::positionChanged); + connect(&mediaPlayer, &QMediaPlayer::durationChanged, this, &VideoPlayer::durationChanged); } VideoPlayer::~VideoPlayer() diff --git a/src/gsttools/qgstreamervideoinputdevicecontrol.cpp b/src/gsttools/qgstreamervideoinputdevicecontrol.cpp index 2f08575aa..86e6772b7 100644 --- a/src/gsttools/qgstreamervideoinputdevicecontrol.cpp +++ b/src/gsttools/qgstreamervideoinputdevicecontrol.cpp @@ -90,9 +90,8 @@ int QGstreamerVideoInputDeviceControl::selectedDevice() const void QGstreamerVideoInputDeviceControl::setSelectedDevice(int index) { - if (index != m_selectedDevice) { - m_selectedDevice = index; - emit selectedDeviceChanged(index); - emit selectedDeviceChanged(deviceName(index)); - } + // Always update selected device and proxy it to clients + m_selectedDevice = index; + emit selectedDeviceChanged(index); + emit selectedDeviceChanged(deviceName(index)); } diff --git a/src/multimedia/audio/qsamplecache_p.cpp b/src/multimedia/audio/qsamplecache_p.cpp index 487346832..c76f51899 100644 --- a/src/multimedia/audio/qsamplecache_p.cpp +++ b/src/multimedia/audio/qsamplecache_p.cpp @@ -140,8 +140,11 @@ void QSampleCache::loadingRelease() QMutexLocker locker(&m_loadingMutex); m_loadingRefCount--; if (m_loadingRefCount == 0) { - if (m_loadingThread.isRunning()) + if (m_loadingThread.isRunning()) { + m_networkAccessManager->deleteLater(); + m_networkAccessManager = nullptr; m_loadingThread.exit(); + } } } diff --git a/src/multimedia/audio/qsoundeffect_pulse_p.cpp b/src/multimedia/audio/qsoundeffect_pulse_p.cpp index bf647ea1f..a86f22872 100644 --- a/src/multimedia/audio/qsoundeffect_pulse_p.cpp +++ b/src/multimedia/audio/qsoundeffect_pulse_p.cpp @@ -535,31 +535,34 @@ void QSoundEffectPrivate::setLoopCount(int loopCount) qreal QSoundEffectPrivate::volume() const { - QReadLocker locker(&m_volumeLock); + QMutexLocker locker(&m_volumeLock); return m_volume; } void QSoundEffectPrivate::setVolume(qreal volume) { - QWriteLocker locker(&m_volumeLock); + QMutexLocker locker(&m_volumeLock); if (qFuzzyCompare(m_volume, volume)) return; m_volume = qBound(qreal(0), volume, qreal(1)); + locker.unlock(); emit volumeChanged(); } bool QSoundEffectPrivate::isMuted() const { - QReadLocker locker(&m_volumeLock); + QMutexLocker locker(&m_volumeLock); return m_muted; } void QSoundEffectPrivate::setMuted(bool muted) { - QWriteLocker locker(&m_volumeLock); + m_volumeLock.lock(); m_muted = muted; + m_volumeLock.unlock(); + emit mutedChanged(); } @@ -884,7 +887,7 @@ int QSoundEffectPrivate::writeToStream(const void *data, int size) if (size < 1) return 0; - m_volumeLock.lockForRead(); + m_volumeLock.lock(); qreal volume = m_muted ? 0 : m_volume; m_volumeLock.unlock(); pa_free_cb_t writeDoneCb = stream_write_done_callback; diff --git a/src/multimedia/audio/qsoundeffect_pulse_p.h b/src/multimedia/audio/qsoundeffect_pulse_p.h index 7be88c55a..268a99326 100644 --- a/src/multimedia/audio/qsoundeffect_pulse_p.h +++ b/src/multimedia/audio/qsoundeffect_pulse_p.h @@ -56,7 +56,7 @@ #include <QtCore/qobject.h> #include <QtCore/qdatetime.h> -#include <QtCore/qreadwritelock.h> +#include <QtCore/qmutex.h> #include <qmediaplayer.h> #include <pulse/pulseaudio.h> #include "qsamplecache_p.h" @@ -175,7 +175,8 @@ private: bool m_resourcesAvailable; - mutable QReadWriteLock m_volumeLock; + // Protects volume while PuseAudio is accessing it + mutable QMutex m_volumeLock; QMediaPlayerResourceSetInterface *m_resources; }; diff --git a/src/multimedia/doc/qtmultimedia.qdocconf b/src/multimedia/doc/qtmultimedia.qdocconf index e3d3827c5..074fcb75e 100644 --- a/src/multimedia/doc/qtmultimedia.qdocconf +++ b/src/multimedia/doc/qtmultimedia.qdocconf @@ -43,6 +43,9 @@ qhp.QtMultimedia.subprojects.examples.sortPages = true exampledirs += ../../../examples \ snippets +manifestmeta.highlighted.names = "QtMultimedia/QML Video Shader Effects Example" \ + "QtMultimedia/Media Player Example" + headerdirs += ../.. imagedirs += src/images \ diff --git a/src/multimedia/playback/qmediaplayer.cpp b/src/multimedia/playback/qmediaplayer.cpp index 52fa6e68e..01c91babc 100644 --- a/src/multimedia/playback/qmediaplayer.cpp +++ b/src/multimedia/playback/qmediaplayer.cpp @@ -732,7 +732,17 @@ void QMediaPlayer::setNetworkConfigurations(const QList<QNetworkConfiguration> & QMediaPlayer::State QMediaPlayer::state() const { - return d_func()->state; + Q_D(const QMediaPlayer); + + // In case if EndOfMedia status is already received + // but state is not. + if (d->control != 0 + && d->status == QMediaPlayer::EndOfMedia + && d->state != d->control->state()) { + return d->control->state(); + } + + return d->state; } QMediaPlayer::MediaStatus QMediaPlayer::mediaStatus() const diff --git a/src/multimediawidgets/qpaintervideosurface.cpp b/src/multimediawidgets/qpaintervideosurface.cpp index 6e93e150d..0147690e1 100644 --- a/src/multimediawidgets/qpaintervideosurface.cpp +++ b/src/multimediawidgets/qpaintervideosurface.cpp @@ -1254,8 +1254,8 @@ QAbstractVideoSurface::Error QVideoSurfaceGlslPainter::paint( if (scissorTestEnabled) glEnable(GL_SCISSOR_TEST); - const int width = QOpenGLContext::currentContext()->surface()->size().width(); - const int height = QOpenGLContext::currentContext()->surface()->size().height(); + const int width = painter->viewport().width(); + const int height = painter->viewport().height(); const QTransform transform = painter->deviceTransform(); diff --git a/src/plugins/alsa/qalsaaudiooutput.cpp b/src/plugins/alsa/qalsaaudiooutput.cpp index cd97ae85b..ddbe04de9 100644 --- a/src/plugins/alsa/qalsaaudiooutput.cpp +++ b/src/plugins/alsa/qalsaaudiooutput.cpp @@ -316,9 +316,6 @@ bool QAlsaAudioOutput::open() return false; } - if (!QAlsaAudioDeviceInfo::availableDevices(QAudio::AudioOutput).contains(m_device)) - return false; - QString dev; #if SND_LIB_VERSION < 0x1000e // 1.0.14 if (m_device != "default") diff --git a/src/plugins/android/src/common/qandroidvideooutput.cpp b/src/plugins/android/src/common/qandroidvideooutput.cpp index eb41d4a8e..b425b9d89 100644 --- a/src/plugins/android/src/common/qandroidvideooutput.cpp +++ b/src/plugins/android/src/common/qandroidvideooutput.cpp @@ -324,7 +324,6 @@ void QAndroidTextureVideoOutput::onFrameAvailable() if (!m_surface->isActive()) { QVideoSurfaceFormat format(frame.size(), frame.pixelFormat(), QAbstractVideoBuffer::GLTextureHandle); - format.setScanLineDirection(QVideoSurfaceFormat::BottomToTop); m_surface->start(format); } diff --git a/src/plugins/avfoundation/camera/avfcamerasession.mm b/src/plugins/avfoundation/camera/avfcamerasession.mm index 0b7c0e9d8..8e3436d39 100644 --- a/src/plugins/avfoundation/camera/avfcamerasession.mm +++ b/src/plugins/avfoundation/camera/avfcamerasession.mm @@ -234,7 +234,7 @@ void AVFCameraSession::updateCameraDevices() break; case AVCaptureDevicePositionFront: info.position = QCamera::FrontFace; - info.orientation = 270; + info.orientation = 90; break; default: info.position = QCamera::UnspecifiedPosition; diff --git a/src/plugins/common/evr/evrcustompresenter.cpp b/src/plugins/common/evr/evrcustompresenter.cpp index 958204079..b07dbe719 100644 --- a/src/plugins/common/evr/evrcustompresenter.cpp +++ b/src/plugins/common/evr/evrcustompresenter.cpp @@ -1350,13 +1350,6 @@ HRESULT EVRCustomPresenter::createOptimalVideoType(IMFMediaType *proposedType, I // Modify the new type. - // Set the pixel aspect ratio (PAR) to 1:1 (see assumption #1, above) - // The ratio is packed in a single UINT64. A helper function is normally available for - // that (MFSetAttributeRatio) but it's not correctly defined in MinGW 4.9.1. - hr = mtOptimal->SetUINT64(MF_MT_PIXEL_ASPECT_RATIO, (((UINT64) 1) << 32) | ((UINT64) 1)); - if (FAILED(hr)) - goto done; - hr = proposedType->GetUINT64(MF_MT_FRAME_SIZE, &size); width = int(HI32(size)); height = int(LO32(size)); diff --git a/src/plugins/common/evr/evrd3dpresentengine.cpp b/src/plugins/common/evr/evrd3dpresentengine.cpp index fd9ccdef1..54403faba 100644 --- a/src/plugins/common/evr/evrd3dpresentengine.cpp +++ b/src/plugins/common/evr/evrd3dpresentengine.cpp @@ -47,6 +47,7 @@ #include <QDebug> #include <qthread.h> #include <private/qmediaopenglhelper_p.h> +#include <QOffscreenSurface> #ifdef MAYBE_ANGLE # include <qguiapplication.h> @@ -128,11 +129,65 @@ class OpenGLResources : public QObject { public: OpenGLResources() - : egl(new EGLWrapper) - , eglDisplay(0) - , eglSurface(0) - , glTexture(0) - {} + : m_egl(new EGLWrapper) + , m_eglDisplay(nullptr) + , m_eglSurface(nullptr) + , m_glTexture(0) + , m_glContext(QOpenGLContext::currentContext()) + { + Q_ASSERT(m_glContext); + } + + unsigned int glTexture() const + { + return m_glTexture; + } + + bool createTexture(const QVideoSurfaceFormat &format, IDirect3DDevice9Ex *device, + IDirect3DTexture9 **texture) + { + if (!m_glContext) + return false; + + m_glContext->functions()->glGenTextures(1, &m_glTexture); + QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface(); + m_eglDisplay = static_cast<EGLDisplay*>( + nativeInterface->nativeResourceForContext("eglDisplay", m_glContext)); + EGLConfig *eglConfig = static_cast<EGLConfig*>( + nativeInterface->nativeResourceForContext("eglConfig", m_glContext)); + + const bool hasAlpha = m_glContext->format().hasAlpha(); + + EGLint attribs[] = { + EGL_WIDTH, format.frameWidth(), + EGL_HEIGHT, format.frameHeight(), + EGL_TEXTURE_FORMAT, (hasAlpha ? EGL_TEXTURE_RGBA : EGL_TEXTURE_RGB), + EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, + EGL_NONE + }; + + m_eglSurface = m_egl->createPbufferSurface(m_eglDisplay, eglConfig, attribs); + + HANDLE share_handle = 0; + PFNEGLQUERYSURFACEPOINTERANGLEPROC eglQuerySurfacePointerANGLE = + reinterpret_cast<PFNEGLQUERYSURFACEPOINTERANGLEPROC>( + m_egl->getProcAddress("eglQuerySurfacePointerANGLE")); + Q_ASSERT(eglQuerySurfacePointerANGLE); + eglQuerySurfacePointerANGLE( + m_eglDisplay, + m_eglSurface, + EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, &share_handle); + + device->CreateTexture(format.frameWidth(), format.frameHeight(), 1, + D3DUSAGE_RENDERTARGET, + (hasAlpha ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8), + D3DPOOL_DEFAULT, texture, &share_handle); + + m_glContext->functions()->glBindTexture(GL_TEXTURE_2D, m_glTexture); + m_egl->bindTexImage(m_eglDisplay, m_eglSurface, EGL_BACK_BUFFER); + + return texture != NULL; + } void release() { @@ -142,24 +197,32 @@ public: deleteLater(); } - EGLWrapper *egl; - EGLDisplay *eglDisplay; - EGLSurface eglSurface; - unsigned int glTexture; - private: + EGLWrapper *m_egl; + EGLDisplay *m_eglDisplay; + EGLSurface m_eglSurface; + unsigned int m_glTexture; + QOpenGLContext *m_glContext; + ~OpenGLResources() { - Q_ASSERT(QOpenGLContext::currentContext() != NULL); + QScopedPointer<QOffscreenSurface> surface; + if (m_glContext != QOpenGLContext::currentContext()) { + surface.reset(new QOffscreenSurface); + surface->create(); + m_glContext->makeCurrent(surface.data()); + } - if (eglSurface && egl) { - egl->releaseTexImage(eglDisplay, eglSurface, EGL_BACK_BUFFER); - egl->destroySurface(eglDisplay, eglSurface); + if (m_eglSurface && m_egl) { + m_egl->releaseTexImage(m_eglDisplay, m_eglSurface, EGL_BACK_BUFFER); + m_egl->destroySurface(m_eglDisplay, m_eglSurface); } - if (glTexture) - QOpenGLContext::currentContext()->functions()->glDeleteTextures(1, &glTexture); + if (m_glTexture) + m_glContext->functions()->glDeleteTextures(1, &m_glTexture); - delete egl; + delete m_egl; + if (surface) + m_glContext->doneCurrent(); } }; @@ -257,9 +320,9 @@ QVariant IMFSampleVideoBuffer::handle() const if (handleType() != GLTextureHandle) return handle; - if (m_engine->m_glResources && (m_textureUpdated || m_engine->updateTexture(m_surface))) { + if (m_textureUpdated || m_engine->updateTexture(m_surface)) { m_textureUpdated = true; - handle = QVariant::fromValue<unsigned int>(m_engine->m_glResources->glTexture); + handle = QVariant::fromValue<unsigned int>(m_engine->m_glResources->glTexture()); } #endif @@ -518,6 +581,10 @@ done: : qt_evr_pixelFormatFromD3DFormat(d3dFormat), m_useTextureRendering ? QAbstractVideoBuffer::GLTextureHandle : QAbstractVideoBuffer::NoHandle); + UINT32 horizontal = 1, vertical = 1; + hr = MFGetAttributeRatio(format, MF_MT_PIXEL_ASPECT_RATIO, &horizontal, &vertical); + if (SUCCEEDED(hr)) + m_surfaceFormat.setPixelAspectRatio(horizontal, vertical); } else { releaseResources(); } @@ -553,61 +620,11 @@ QVideoFrame D3DPresentEngine::makeVideoFrame(IMFSample *sample) bool D3DPresentEngine::createRenderTexture() { - if (m_texture) - return true; - - Q_ASSERT(QOpenGLContext::currentContext() != NULL); - - if (!m_glResources) - m_glResources = new OpenGLResources; - - QOpenGLContext *currentContext = QOpenGLContext::currentContext(); - if (!currentContext) - return false; - - QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface(); - m_glResources->eglDisplay = static_cast<EGLDisplay*>( - nativeInterface->nativeResourceForContext("eglDisplay", currentContext)); - EGLConfig *eglConfig = static_cast<EGLConfig*>( - nativeInterface->nativeResourceForContext("eglConfig", currentContext)); - - currentContext->functions()->glGenTextures(1, &m_glResources->glTexture); - - bool hasAlpha = currentContext->format().hasAlpha(); - - EGLint attribs[] = { - EGL_WIDTH, m_surfaceFormat.frameWidth(), - EGL_HEIGHT, m_surfaceFormat.frameHeight(), - EGL_TEXTURE_FORMAT, hasAlpha ? EGL_TEXTURE_RGBA : EGL_TEXTURE_RGB, - EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, - EGL_NONE - }; - - EGLSurface pbuffer = m_glResources->egl->createPbufferSurface(m_glResources->eglDisplay, eglConfig, attribs); - - HANDLE share_handle = 0; - PFNEGLQUERYSURFACEPOINTERANGLEPROC eglQuerySurfacePointerANGLE = - reinterpret_cast<PFNEGLQUERYSURFACEPOINTERANGLEPROC>(m_glResources->egl->getProcAddress("eglQuerySurfacePointerANGLE")); - Q_ASSERT(eglQuerySurfacePointerANGLE); - eglQuerySurfacePointerANGLE( - m_glResources->eglDisplay, - pbuffer, - EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, &share_handle); - - - m_device->CreateTexture(m_surfaceFormat.frameWidth(), m_surfaceFormat.frameHeight(), 1, - D3DUSAGE_RENDERTARGET, - hasAlpha ? D3DFMT_A8R8G8B8 : D3DFMT_X8R8G8B8, - D3DPOOL_DEFAULT, - &m_texture, - &share_handle); - - m_glResources->eglSurface = pbuffer; - - QOpenGLContext::currentContext()->functions()->glBindTexture(GL_TEXTURE_2D, m_glResources->glTexture); - m_glResources->egl->bindTexImage(m_glResources->eglDisplay, m_glResources->eglSurface, EGL_BACK_BUFFER); + if (m_glResources) + m_glResources->release(); - return m_texture != NULL; + m_glResources = new OpenGLResources; + return m_glResources->createTexture(m_surfaceFormat, m_device, &m_texture); } bool D3DPresentEngine::updateTexture(IDirect3DSurface9 *src) diff --git a/src/plugins/directshow/camera/dscamerasession.cpp b/src/plugins/directshow/camera/dscamerasession.cpp index 195712057..6590afeb9 100644 --- a/src/plugins/directshow/camera/dscamerasession.cpp +++ b/src/plugins/directshow/camera/dscamerasession.cpp @@ -815,8 +815,8 @@ bool DSCameraSession::configurePreviewFormat() return false; } - // Set sample grabber format (always RGB32) - static const AM_MEDIA_TYPE grabberFormat { MEDIATYPE_Video, MEDIASUBTYPE_RGB32, 0, 0, 0, FORMAT_VideoInfo, nullptr, 0, nullptr}; + // Set sample grabber format + static const AM_MEDIA_TYPE grabberFormat { MEDIATYPE_Video, MEDIASUBTYPE_ARGB32, 0, 0, 0, FORMAT_VideoInfo, nullptr, 0, nullptr}; if (!m_previewSampleGrabber->setMediaType(&grabberFormat)) return false; diff --git a/src/plugins/directshow/dsserviceplugin.cpp b/src/plugins/directshow/dsserviceplugin.cpp index 51be7e500..cb4f0cdf9 100644 --- a/src/plugins/directshow/dsserviceplugin.cpp +++ b/src/plugins/directshow/dsserviceplugin.cpp @@ -123,7 +123,9 @@ QMediaServiceProviderHint::Features DSServicePlugin::supportedFeatures( QByteArray DSServicePlugin::defaultDevice(const QByteArray &service) const { if (service == Q_MEDIASERVICE_CAMERA) { + addRefCount(); const QList<DSVideoDeviceInfo> &devs = DSVideoDeviceControl::availableDevices(); + releaseRefCount(); if (!devs.isEmpty()) return devs.first().first; } @@ -135,7 +137,9 @@ QList<QByteArray> DSServicePlugin::devices(const QByteArray &service) const QList<QByteArray> result; if (service == Q_MEDIASERVICE_CAMERA) { + addRefCount(); const QList<DSVideoDeviceInfo> &devs = DSVideoDeviceControl::availableDevices(); + releaseRefCount(); for (const DSVideoDeviceInfo &info : devs) result.append(info.first); } @@ -146,7 +150,9 @@ QList<QByteArray> DSServicePlugin::devices(const QByteArray &service) const QString DSServicePlugin::deviceDescription(const QByteArray &service, const QByteArray &device) { if (service == Q_MEDIASERVICE_CAMERA) { + addRefCount(); const QList<DSVideoDeviceInfo> &devs = DSVideoDeviceControl::availableDevices(); + releaseRefCount(); for (const DSVideoDeviceInfo &info : devs) { if (info.first == device) return info.second; diff --git a/src/plugins/directshow/player/directshowplayerservice.cpp b/src/plugins/directshow/player/directshowplayerservice.cpp index 8ee5d67a1..2218ca5ed 100644 --- a/src/plugins/directshow/player/directshowplayerservice.cpp +++ b/src/plugins/directshow/player/directshowplayerservice.cpp @@ -318,18 +318,15 @@ void DirectShowPlayerService::load(const QMediaContent &media, QIODevice *stream m_graphStatus = InvalidMedia; m_error = QMediaPlayer::ResourceError; } else { - // {36b73882-c2c8-11cf-8b46-00805f6cef60} - static const GUID iid_IFilterGraph2 = { - 0x36b73882, 0xc2c8, 0x11cf, {0x8b, 0x46, 0x00, 0x80, 0x5f, 0x6c, 0xef, 0x60} }; m_graphStatus = Loading; - m_graph = com_new<IFilterGraph2>(CLSID_FilterGraph, iid_IFilterGraph2); - if (stream) m_pendingTasks = SetStreamSource; else m_pendingTasks = SetUrlSource; + m_pendingTasks |= CreateGraph; + ::SetEvent(m_taskHandle); } @@ -340,6 +337,17 @@ void DirectShowPlayerService::load(const QMediaContent &media, QIODevice *stream updateStatus(); } +void DirectShowPlayerService::doCreateGraph(QMutexLocker *locker) +{ + Q_UNUSED(locker); + + // {36b73882-c2c8-11cf-8b46-00805f6cef60} + static const GUID iid_IFilterGraph2 = { + 0x36b73882, 0xc2c8, 0x11cf, {0x8b, 0x46, 0x00, 0x80, 0x5f, 0x6c, 0xef, 0x60} }; + + m_graph = com_new<IFilterGraph2>(CLSID_FilterGraphNoThread, iid_IFilterGraph2); +} + void DirectShowPlayerService::doSetUrlSource(QMutexLocker *locker) { IBaseFilter *source = 0; @@ -1686,6 +1694,8 @@ void DirectShowPlayerService::run() { QMutexLocker locker(&m_mutex); + CoInitialize(NULL); + for (;;) { while (m_pendingTasks == 0) { DWORD result = 0; @@ -1700,12 +1710,17 @@ void DirectShowPlayerService::run() } locker.relock(); - if (result == WAIT_OBJECT_0 + 1) { + if (m_graph && result == WAIT_OBJECT_0 + 1) { graphEvent(&locker); } } - if (m_pendingTasks & ReleaseGraph) { + if (m_pendingTasks & CreateGraph) { + m_pendingTasks ^= CreateGraph; + m_executingTask = CreateGraph; + + doCreateGraph(&locker); + } else if (m_pendingTasks & ReleaseGraph) { m_pendingTasks ^= ReleaseGraph; m_executingTask = ReleaseGraph; @@ -1798,6 +1813,8 @@ void DirectShowPlayerService::run() } m_executingTask = 0; } + + CoUninitialize(); } QT_END_NAMESPACE diff --git a/src/plugins/directshow/player/directshowplayerservice.h b/src/plugins/directshow/player/directshowplayerservice.h index 01d05449e..cc7b4dd3e 100644 --- a/src/plugins/directshow/player/directshowplayerservice.h +++ b/src/plugins/directshow/player/directshowplayerservice.h @@ -124,6 +124,7 @@ private: void run(); + void doCreateGraph(QMutexLocker *locker); void doSetUrlSource(QMutexLocker *locker); void doSetStreamSource(QMutexLocker *locker); void doRender(QMutexLocker *locker); @@ -169,7 +170,8 @@ private: ReleaseVideoProbe = 0x40000, ReleaseFilters = ReleaseGraph | ReleaseAudioOutput | ReleaseVideoOutput | ReleaseAudioProbe - | ReleaseVideoProbe + | ReleaseVideoProbe, + CreateGraph = 0x80000 }; enum Event diff --git a/src/plugins/gstreamer/camerabin/camerabinsession.cpp b/src/plugins/gstreamer/camerabin/camerabinsession.cpp index 4941c6ef6..cfac61c01 100644 --- a/src/plugins/gstreamer/camerabin/camerabinsession.cpp +++ b/src/plugins/gstreamer/camerabin/camerabinsession.cpp @@ -466,6 +466,9 @@ GstElement *CameraBinSession::buildCameraSource() #if CAMERABIN_DEBUG qDebug() << Q_FUNC_INFO; #endif + if (m_inputDevice.isEmpty()) + return nullptr; + if (!m_inputDeviceHasChanged) return m_cameraSrc; @@ -482,7 +485,7 @@ GstElement *CameraBinSession::buildCameraSource() if (!m_cameraSrc) m_cameraSrc = camSrc; - if (m_cameraSrc && !m_inputDevice.isEmpty()) { + if (m_cameraSrc) { #if CAMERABIN_DEBUG qDebug() << "set camera device" << m_inputDevice; #endif @@ -729,18 +732,21 @@ void CameraBinSession::setState(QCamera::State newState) if (newState == m_pendingState) return; - m_pendingState = newState; - emit pendingStateChanged(m_pendingState); + emit pendingStateChanged(newState); #if CAMERABIN_DEBUG qDebug() << Q_FUNC_INFO << newState; #endif setStateHelper(newState); + m_pendingState = newState; } void CameraBinSession::setStateHelper(QCamera::State state) { + if (state == m_pendingState) + return; + switch (state) { case QCamera::UnloadedState: unload(); diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index 98a1bf242..71b9ec6e1 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -40,7 +40,8 @@ win32:!winrt { winrt { - SUBDIRS += winrt + SUBDIRS += winrt \ + audiocapture } unix:!mac:!android { diff --git a/src/plugins/wasapi/qwasapiaudiodeviceinfo.cpp b/src/plugins/wasapi/qwasapiaudiodeviceinfo.cpp index e1a46841d..53345dec8 100644 --- a/src/plugins/wasapi/qwasapiaudiodeviceinfo.cpp +++ b/src/plugins/wasapi/qwasapiaudiodeviceinfo.cpp @@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(lcMmDeviceInfo, "qt.multimedia.deviceinfo") QWasapiAudioDeviceInfo::QWasapiAudioDeviceInfo(QByteArray dev, QAudio::Mode mode) - : m_deviceName(dev) + : m_deviceName(QString::fromLocal8Bit(dev)) { qCDebug(lcMmDeviceInfo) << __FUNCTION__ << dev << mode; m_interface = QWasapiUtils::createOrGetInterface(dev, mode); diff --git a/src/plugins/windowsaudio/qwindowsaudiodeviceinfo.cpp b/src/plugins/windowsaudio/qwindowsaudiodeviceinfo.cpp index 83e9ccfc8..c054c0f76 100644 --- a/src/plugins/windowsaudio/qwindowsaudiodeviceinfo.cpp +++ b/src/plugins/windowsaudio/qwindowsaudiodeviceinfo.cpp @@ -238,21 +238,16 @@ void QWindowsAudioDeviceInfo::updateLists() if (!sizez.isEmpty()) return; - bool hasCaps = false; DWORD fmt = 0; if(mode == QAudio::AudioOutput) { WAVEOUTCAPS woc; - if (waveOutGetDevCaps(devId, &woc, sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR) { - hasCaps = true; + if (waveOutGetDevCaps(devId, &woc, sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR) fmt = woc.dwFormats; - } } else { WAVEINCAPS woc; - if (waveInGetDevCaps(devId, &woc, sizeof(WAVEINCAPS)) == MMSYSERR_NOERROR) { - hasCaps = true; + if (waveInGetDevCaps(devId, &woc, sizeof(WAVEINCAPS)) == MMSYSERR_NOERROR) fmt = woc.dwFormats; - } } sizez.clear(); @@ -260,7 +255,7 @@ void QWindowsAudioDeviceInfo::updateLists() channelz.clear(); typez.clear(); - if (hasCaps) { + if (fmt) { // Check sample size if ((fmt & WAVE_FORMAT_1M08) || (fmt & WAVE_FORMAT_1S08) diff --git a/src/plugins/windowsaudio/qwindowsaudiooutput.cpp b/src/plugins/windowsaudio/qwindowsaudiooutput.cpp index 815b78979..eb4caf128 100644 --- a/src/plugins/windowsaudio/qwindowsaudiooutput.cpp +++ b/src/plugins/windowsaudio/qwindowsaudiooutput.cpp @@ -298,10 +298,7 @@ void QWindowsAudioOutput::close() deviceState = QAudio::StoppedState; errorState = QAudio::NoError; - int delay = (buffer_size-bytesFree())*1000/(settings.sampleRate() - *settings.channelCount()*(settings.sampleSize()/8)); waveOutReset(hWaveOut); - Sleep(delay+10); freeBlocks(waveBlocks); waveOutClose(hWaveOut); diff --git a/src/qtmultimediaquicktools/qdeclarativevideooutput_render.cpp b/src/qtmultimediaquicktools/qdeclarativevideooutput_render.cpp index 7030b3357..c51aec088 100644 --- a/src/qtmultimediaquicktools/qdeclarativevideooutput_render.cpp +++ b/src/qtmultimediaquicktools/qdeclarativevideooutput_render.cpp @@ -382,9 +382,9 @@ QAbstractVideoSurface *QDeclarativeVideoRendererBackend::videoSurface() const QRectF QDeclarativeVideoRendererBackend::adjustedViewport() const { const QRectF viewport = m_surface->surfaceFormat().viewport(); - const QSize pixelAspectRatio = m_surface->surfaceFormat().pixelAspectRatio(); + const QSizeF pixelAspectRatio = m_surface->surfaceFormat().pixelAspectRatio(); - if (pixelAspectRatio.height() != 0) { + if (pixelAspectRatio.isValid()) { const qreal ratio = pixelAspectRatio.width() / pixelAspectRatio.height(); QRectF result = viewport; result.setX(result.x() * ratio); diff --git a/src/qtmultimediaquicktools/qsgvideonode_rgb.cpp b/src/qtmultimediaquicktools/qsgvideonode_rgb.cpp index 0dfa11ab9..d039e1e0b 100644 --- a/src/qtmultimediaquicktools/qsgvideonode_rgb.cpp +++ b/src/qtmultimediaquicktools/qsgvideonode_rgb.cpp @@ -113,11 +113,19 @@ protected: class QSGVideoMaterialShader_RGB_swizzle : public QSGVideoMaterialShader_RGB { public: - QSGVideoMaterialShader_RGB_swizzle() - : QSGVideoMaterialShader_RGB() + QSGVideoMaterialShader_RGB_swizzle(bool hasAlpha) + : m_hasAlpha(hasAlpha) { setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qtmultimediaquicktools/shaders/rgbvideo_swizzle.frag")); } + +protected: + void initialize() override { + QSGVideoMaterialShader_RGB::initialize(); + program()->setUniformValue(program()->uniformLocation("hasAlpha"), GLboolean(m_hasAlpha)); + } + + bool m_hasAlpha; }; @@ -145,7 +153,8 @@ public: } QSGMaterialShader *createShader() const override { - return needsSwizzling() ? new QSGVideoMaterialShader_RGB_swizzle + const bool hasAlpha = m_format.pixelFormat() == QVideoFrame::Format_ARGB32; + return needsSwizzling() ? new QSGVideoMaterialShader_RGB_swizzle(hasAlpha) : new QSGVideoMaterialShader_RGB; } diff --git a/src/qtmultimediaquicktools/qsgvideonode_texture.cpp b/src/qtmultimediaquicktools/qsgvideonode_texture.cpp index a26d59532..f5545afc7 100644 --- a/src/qtmultimediaquicktools/qsgvideonode_texture.cpp +++ b/src/qtmultimediaquicktools/qsgvideonode_texture.cpp @@ -108,11 +108,19 @@ protected: class QSGVideoMaterialShader_Texture_swizzle : public QSGVideoMaterialShader_Texture { public: - QSGVideoMaterialShader_Texture_swizzle() - : QSGVideoMaterialShader_Texture() + QSGVideoMaterialShader_Texture_swizzle(bool hasAlpha) + : m_hasAlpha(hasAlpha) { setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qtmultimediaquicktools/shaders/rgbvideo_swizzle.frag")); } + +protected: + void initialize() override { + QSGVideoMaterialShader_Texture::initialize(); + program()->setUniformValue(program()->uniformLocation("hasAlpha"), GLboolean(m_hasAlpha)); + } + + int m_hasAlpha; }; @@ -138,7 +146,8 @@ public: } QSGMaterialShader *createShader() const override { - return needsSwizzling() ? new QSGVideoMaterialShader_Texture_swizzle + const bool hasAlpha = m_format.pixelFormat() == QVideoFrame::Format_ARGB32; + return needsSwizzling() ? new QSGVideoMaterialShader_Texture_swizzle(hasAlpha) : new QSGVideoMaterialShader_Texture; } diff --git a/src/qtmultimediaquicktools/shaders/rgbvideo_swizzle.frag b/src/qtmultimediaquicktools/shaders/rgbvideo_swizzle.frag index f01dc86a0..df66bde63 100644 --- a/src/qtmultimediaquicktools/shaders/rgbvideo_swizzle.frag +++ b/src/qtmultimediaquicktools/shaders/rgbvideo_swizzle.frag @@ -1,8 +1,10 @@ uniform sampler2D rgbTexture; uniform lowp float opacity; varying highp vec2 qt_TexCoord; +uniform bool hasAlpha; void main() { - gl_FragColor = vec4(texture2D(rgbTexture, qt_TexCoord).bgr, 1.0) * opacity; + vec4 v = texture2D(rgbTexture, qt_TexCoord); + gl_FragColor = vec4(v.bgr, hasAlpha ? v.a : 1.0) * opacity; } diff --git a/tests/auto/integration/qmediaplayerbackend/BLACKLIST b/tests/auto/integration/qmediaplayerbackend/BLACKLIST index 8aa622881..0a88eef9e 100644 --- a/tests/auto/integration/qmediaplayerbackend/BLACKLIST +++ b/tests/auto/integration/qmediaplayerbackend/BLACKLIST @@ -1,8 +1,7 @@ # QTBUG-46368 osx -windows 32bit developer-build -windows 64bit developer-build +windows # Media player plugin not built at the moment on this platform opensuse-13.1 64bit diff --git a/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp b/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp index 9a0a2d9c1..b68bc030a 100644 --- a/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp +++ b/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp @@ -77,6 +77,7 @@ private slots: void surfaceTest_data(); void surfaceTest(); void metadata(); + void playerStateAtEOS(); private: QMediaContent selectVideoFile(const QStringList& mediaCandidates); @@ -1412,6 +1413,28 @@ void tst_QMediaPlayerBackend::metadata() QVERIFY(player.availableMetaData().isEmpty()); } +void tst_QMediaPlayerBackend::playerStateAtEOS() +{ + if (!isWavSupported()) + QSKIP("Sound format is not supported"); + + QMediaPlayer player; + + bool endOfMediaReceived = false; + connect(&player, &QMediaPlayer::mediaStatusChanged, [&](QMediaPlayer::MediaStatus status) { + if (status == QMediaPlayer::EndOfMedia) { + QCOMPARE(player.state(), QMediaPlayer::StoppedState); + endOfMediaReceived = true; + } + }); + + player.setMedia(localWavFile); + player.play(); + + QTRY_COMPARE(player.mediaStatus(), QMediaPlayer::EndOfMedia); + QVERIFY(endOfMediaReceived); +} + TestVideoSurface::TestVideoSurface(bool storeFrames): m_totalFrames(0), m_storeFrames(storeFrames) |