diff options
13 files changed, 194 insertions, 100 deletions
diff --git a/src/multimedia/playback/qmediaplayer.cpp b/src/multimedia/playback/qmediaplayer.cpp index afea8e147..edccd30ef 100644 --- a/src/multimedia/playback/qmediaplayer.cpp +++ b/src/multimedia/playback/qmediaplayer.cpp @@ -859,17 +859,19 @@ void QMediaPlayer::play() } //if playlist control is available, the service should advance itself - if (d->rootMedia.playlist() && d->rootMedia.playlist()->currentIndex() == -1 && !d->rootMedia.playlist()->isEmpty()) { - + if (d->rootMedia.playlist() && !d->rootMedia.playlist()->isEmpty()) { // switch to playing state if (d->state != QMediaPlayer::PlayingState) d->_q_stateChanged(QMediaPlayer::PlayingState); - if (d->playlist != d->rootMedia.playlist()) - d->setPlaylist(d->rootMedia.playlist()); - Q_ASSERT(d->playlist == d->rootMedia.playlist()); - emit currentMediaChanged(d->rootMedia); - d->playlist->setCurrentIndex(0); + if (d->rootMedia.playlist()->currentIndex() == -1) { + if (d->playlist != d->rootMedia.playlist()) + d->setPlaylist(d->rootMedia.playlist()); + Q_ASSERT(d->playlist == d->rootMedia.playlist()); + + emit currentMediaChanged(d->rootMedia); + d->playlist->setCurrentIndex(0); + } } // Reset error conditions diff --git a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtCameraListener.java b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtCameraListener.java index 57700cd75..49cb0a947 100644 --- a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtCameraListener.java +++ b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtCameraListener.java @@ -57,6 +57,7 @@ public class QtCameraListener implements Camera.ShutterCallback, private int m_cameraId = -1; private boolean m_notifyNewFrames = false; + private boolean m_notifyWhenFrameAvailable = false; private byte[][] m_previewBuffers = null; private byte[] m_lastPreviewBuffer = null; private Camera.Size m_previewSize = null; @@ -73,6 +74,11 @@ public class QtCameraListener implements Camera.ShutterCallback, m_notifyNewFrames = notify; } + public void notifyWhenFrameAvailable(boolean notify) + { + m_notifyWhenFrameAvailable = notify; + } + public byte[] lastPreviewBuffer() { return m_lastPreviewBuffer; @@ -104,11 +110,16 @@ public class QtCameraListener implements Camera.ShutterCallback, return m_previewBytesPerLine; } + public void clearPreviewCallback(Camera camera) + { + camera.setPreviewCallbackWithBuffer(null); + } + public void setupPreviewCallback(Camera camera) { // Clear previous callback (also clears added buffers) + clearPreviewCallback(camera); m_lastPreviewBuffer = null; - camera.setPreviewCallbackWithBuffer(null); final Camera.Parameters params = camera.getParameters(); m_previewSize = params.getPreviewSize(); @@ -164,11 +175,17 @@ public class QtCameraListener implements Camera.ShutterCallback, m_lastPreviewBuffer = data; - if (data != null && m_notifyNewFrames) { - notifyNewPreviewFrame(m_cameraId, data, - m_previewSize.width, m_previewSize.height, - m_previewFormat, - m_previewBytesPerLine); + if (data != null) { + if (m_notifyWhenFrameAvailable) { + m_notifyWhenFrameAvailable = false; + notifyFrameAvailable(m_cameraId); + } + if (m_notifyNewFrames) { + notifyNewPreviewFrame(m_cameraId, data, + m_previewSize.width, m_previewSize.height, + m_previewFormat, + m_previewBytesPerLine); + } } } @@ -195,4 +212,5 @@ public class QtCameraListener implements Camera.ShutterCallback, private static native void notifyPictureCaptured(int id, byte[] data); private static native void notifyNewPreviewFrame(int id, byte[] data, int width, int height, int pixelFormat, int bytesPerLine); + private static native void notifyFrameAvailable(int id); } diff --git a/src/plugins/android/src/common/qandroidvideooutput.cpp b/src/plugins/android/src/common/qandroidvideooutput.cpp index a5cd3580b..1d0df27f2 100644 --- a/src/plugins/android/src/common/qandroidvideooutput.cpp +++ b/src/plugins/android/src/common/qandroidvideooutput.cpp @@ -66,6 +66,22 @@ static const GLfloat g_texture_data[] = { 0.f, 1.f }; +void OpenGLResourcesDeleter::deleteTextureHelper(quint32 id) +{ + if (id != 0) + glDeleteTextures(1, &id); +} + +void OpenGLResourcesDeleter::deleteFboHelper(void *fbo) +{ + delete reinterpret_cast<QOpenGLFramebufferObject *>(fbo); +} + +void OpenGLResourcesDeleter::deleteShaderProgramHelper(void *prog) +{ + delete reinterpret_cast<QOpenGLShaderProgram *>(prog); +} + class AndroidTextureVideoBuffer : public QAbstractVideoBuffer { @@ -130,40 +146,6 @@ private: QImage m_image; }; - -class OpenGLResourcesDeleter : public QObject -{ -public: - OpenGLResourcesDeleter() - : m_textureID(0) - , m_fbo(0) - , m_program(0) - { } - - ~OpenGLResourcesDeleter() - { - glDeleteTextures(1, &m_textureID); - delete m_fbo; - delete m_program; - } - - void setTexture(quint32 id) { - if (m_textureID) - glDeleteTextures(1, &m_textureID); - - m_textureID = id; - } - - void setFbo(QOpenGLFramebufferObject *fbo) { m_fbo = fbo; } - void setShaderProgram(QOpenGLShaderProgram *prog) { m_program = prog; } - -private: - quint32 m_textureID; - QOpenGLFramebufferObject *m_fbo; - QOpenGLShaderProgram *m_program; -}; - - QAndroidTextureVideoOutput::QAndroidTextureVideoOutput(QObject *parent) : QAndroidVideoOutput(parent) , m_surface(0) @@ -171,7 +153,6 @@ QAndroidTextureVideoOutput::QAndroidTextureVideoOutput(QObject *parent) , m_externalTex(0) , m_fbo(0) , m_program(0) - , m_glDeleter(0) , m_surfaceTextureCanAttachToContext(QtAndroidPrivate::androidSdkVersion() >= 16) { @@ -181,8 +162,12 @@ QAndroidTextureVideoOutput::~QAndroidTextureVideoOutput() { clearSurfaceTexture(); - if (m_glDeleter) + if (!m_glDeleter.isNull()) { // Make sure all of these are deleted on the render thread. + m_glDeleter->deleteFbo(m_fbo); + m_glDeleter->deleteShaderProgram(m_program); + m_glDeleter->deleteTexture(m_externalTex); m_glDeleter->deleteLater(); + } } QAbstractVideoSurface *QAndroidTextureVideoOutput::surface() const @@ -229,8 +214,7 @@ bool QAndroidTextureVideoOutput::initSurfaceTexture() // for the GL render thread to call us back to do it. if (QOpenGLContext::currentContext()) { glGenTextures(1, &m_externalTex); - m_glDeleter = new OpenGLResourcesDeleter; - m_glDeleter->setTexture(m_externalTex); + m_glDeleter.reset(new OpenGLResourcesDeleter); } else if (!m_externalTex) { return false; } @@ -245,10 +229,9 @@ bool QAndroidTextureVideoOutput::initSurfaceTexture() } else { delete m_surfaceTexture; m_surfaceTexture = 0; - if (m_glDeleter) - m_glDeleter->deleteLater(); + if (!m_glDeleter.isNull()) + m_glDeleter->deleteTexture(m_externalTex); m_externalTex = 0; - m_glDeleter = 0; } return m_surfaceTexture != 0; @@ -263,8 +246,14 @@ void QAndroidTextureVideoOutput::clearSurfaceTexture() } // Also reset the attached OpenGL texture - if (m_surfaceTextureCanAttachToContext) + // Note: The Android SurfaceTexture class does not release the texture on deletion, + // only if detachFromGLContext() called (API level >= 16), so we'll do it manually, + // on the render thread. + if (m_surfaceTextureCanAttachToContext) { + if (!m_glDeleter.isNull()) + m_glDeleter->deleteTexture(m_externalTex); m_externalTex = 0; + } } AndroidSurfaceTexture *QAndroidTextureVideoOutput::surfaceTexture() @@ -394,19 +383,17 @@ void QAndroidTextureVideoOutput::createGLResources() Q_ASSERT(QOpenGLContext::currentContext() != NULL); if (!m_glDeleter) - m_glDeleter = new OpenGLResourcesDeleter; + m_glDeleter.reset(new OpenGLResourcesDeleter); if (m_surfaceTextureCanAttachToContext && !m_externalTex) { m_surfaceTexture->detachFromGLContext(); glGenTextures(1, &m_externalTex); m_surfaceTexture->attachToGLContext(m_externalTex); - m_glDeleter->setTexture(m_externalTex); } if (!m_fbo || m_fbo->size() != m_nativeSize) { delete m_fbo; m_fbo = new QOpenGLFramebufferObject(m_nativeSize); - m_glDeleter->setFbo(m_fbo); } if (!m_program) { @@ -437,8 +424,6 @@ void QAndroidTextureVideoOutput::createGLResources() m_program->bindAttributeLocation("vertexCoordsArray", 0); m_program->bindAttributeLocation("textureCoordArray", 1); m_program->link(); - - m_glDeleter->setShaderProgram(m_program); } } @@ -448,8 +433,7 @@ void QAndroidTextureVideoOutput::customEvent(QEvent *e) // This is running in the render thread (OpenGL enabled) if (!m_surfaceTextureCanAttachToContext && !m_externalTex) { glGenTextures(1, &m_externalTex); - m_glDeleter = new OpenGLResourcesDeleter; // will cleanup GL resources in the correct thread - m_glDeleter->setTexture(m_externalTex); + m_glDeleter.reset(new OpenGLResourcesDeleter); // We'll use this to cleanup GL resources in the correct thread emit readyChanged(true); } } diff --git a/src/plugins/android/src/common/qandroidvideooutput.h b/src/plugins/android/src/common/qandroidvideooutput.h index 67bac7052..a12db75a2 100644 --- a/src/plugins/android/src/common/qandroidvideooutput.h +++ b/src/plugins/android/src/common/qandroidvideooutput.h @@ -50,7 +50,6 @@ class AndroidSurfaceTexture; class AndroidSurfaceHolder; class QOpenGLFramebufferObject; class QOpenGLShaderProgram; -class OpenGLResourcesDeleter; class QAbstractVideoSurface; class QAndroidVideoOutput : public QObject @@ -75,6 +74,19 @@ protected: QAndroidVideoOutput(QObject *parent) : QObject(parent) { } }; +class OpenGLResourcesDeleter : public QObject +{ + Q_OBJECT +public: + void deleteTexture(quint32 id) { QMetaObject::invokeMethod(this, "deleteTextureHelper", Qt::AutoConnection, Q_ARG(quint32, id)); } + void deleteFbo(QOpenGLFramebufferObject *fbo) { QMetaObject::invokeMethod(this, "deleteFboHelper", Qt::AutoConnection, Q_ARG(void *, fbo)); } + void deleteShaderProgram(QOpenGLShaderProgram *prog) { QMetaObject::invokeMethod(this, "deleteShaderProgramHelper", Qt::AutoConnection, Q_ARG(void *, prog)); } + +private: + Q_INVOKABLE void deleteTextureHelper(quint32 id); + Q_INVOKABLE void deleteFboHelper(void *fbo); + Q_INVOKABLE void deleteShaderProgramHelper(void *prog); +}; class QAndroidTextureVideoOutput : public QAndroidVideoOutput { @@ -114,7 +126,7 @@ private: quint32 m_externalTex; QOpenGLFramebufferObject *m_fbo; QOpenGLShaderProgram *m_program; - OpenGLResourcesDeleter *m_glDeleter; + QScopedPointer<OpenGLResourcesDeleter, QScopedPointerDeleteLater> m_glDeleter; bool m_surfaceTextureCanAttachToContext; diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp index 0b082b02b..8663f8c5f 100644 --- a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp +++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp @@ -684,6 +684,9 @@ void QAndroidCameraSession::onCameraTakePictureFailed() { emit imageCaptureError(m_currentImageCaptureId, QCameraImageCapture::ResourceError, tr("Failed to capture image")); + + // Preview needs to be restarted and the preview call back must be setup again + m_camera->startPreview(); } void QAndroidCameraSession::onCameraPictureExposed() @@ -697,6 +700,9 @@ void QAndroidCameraSession::onCameraPictureExposed() void QAndroidCameraSession::onLastPreviewFrameFetched(const QVideoFrame &frame) { + if (m_captureCanceled) + return; + QtConcurrent::run(this, &QAndroidCameraSession::processPreviewImage, m_currentImageCaptureId, frame, diff --git a/src/plugins/android/src/wrappers/jni/androidcamera.cpp b/src/plugins/android/src/wrappers/jni/androidcamera.cpp index 3295e4d33..76d3ffb44 100644 --- a/src/plugins/android/src/wrappers/jni/androidcamera.cpp +++ b/src/plugins/android/src/wrappers/jni/androidcamera.cpp @@ -152,6 +152,16 @@ static void notifyNewPreviewFrame(JNIEnv *env, jobject, int id, jbyteArray data, Q_EMIT (*it)->newPreviewFrame(frame); } +static void notifyFrameAvailable(JNIEnv *, jobject, int id) +{ + QReadLocker locker(rwLock); + const auto it = cameras->constFind(id); + if (Q_UNLIKELY(it == cameras->cend())) + return; + + (*it)->fetchLastPreviewFrame(); +} + class AndroidCameraPrivate : public QObject { Q_OBJECT @@ -1540,6 +1550,9 @@ void AndroidCameraPrivate::stopPreview() { QJNIEnvironmentPrivate env; + // cancel any pending new frame notification + m_cameraListener.callMethod<void>("notifyWhenFrameAvailable", "(Z)V", false); + m_camera.callMethod<void>("stopPreview"); exceptionCheckAndClear(env); @@ -1550,6 +1563,11 @@ void AndroidCameraPrivate::takePicture() { QJNIEnvironmentPrivate env; + // We must clear the preview callback before calling takePicture(), otherwise the call will + // block and the camera server will be frozen until the next device restart... + // That problem only happens on some devices and on the emulator + m_cameraListener.callMethod<void>("clearPreviewCallback", "(Landroid/hardware/Camera;)V", m_camera.object()); + m_camera.callMethod<void>("takePicture", "(Landroid/hardware/Camera$ShutterCallback;" "Landroid/hardware/Camera$PictureCallback;" "Landroid/hardware/Camera$PictureCallback;)V", @@ -1576,8 +1594,11 @@ void AndroidCameraPrivate::fetchLastPreviewFrame() QJNIEnvironmentPrivate env; QJNIObjectPrivate data = m_cameraListener.callObjectMethod("lastPreviewBuffer", "()[B"); - if (!data.isValid()) + if (!data.isValid()) { + // If there's no buffer received yet, retry when the next one arrives + m_cameraListener.callMethod<void>("notifyWhenFrameAvailable", "(Z)V", true); return; + } const int arrayLength = env->GetArrayLength(static_cast<jbyteArray>(data.object())); if (arrayLength == 0) @@ -1643,7 +1664,8 @@ bool AndroidCamera::initJNI(JNIEnv *env) {"notifyAutoFocusComplete", "(IZ)V", (void *)notifyAutoFocusComplete}, {"notifyPictureExposed", "(I)V", (void *)notifyPictureExposed}, {"notifyPictureCaptured", "(I[B)V", (void *)notifyPictureCaptured}, - {"notifyNewPreviewFrame", "(I[BIIII)V", (void *)notifyNewPreviewFrame} + {"notifyNewPreviewFrame", "(I[BIIII)V", (void *)notifyNewPreviewFrame}, + {"notifyFrameAvailable", "(I)V", (void *)notifyFrameAvailable} }; if (clazz && env->RegisterNatives(clazz, diff --git a/src/plugins/android/src/wrappers/jni/androidsurfacetexture.cpp b/src/plugins/android/src/wrappers/jni/androidsurfacetexture.cpp index df09d0819..764315acd 100644 --- a/src/plugins/android/src/wrappers/jni/androidsurfacetexture.cpp +++ b/src/plugins/android/src/wrappers/jni/androidsurfacetexture.cpp @@ -62,7 +62,7 @@ static void notifyFrameAvailable(JNIEnv* , jobject, jlong id) Q_EMIT obj->frameAvailable(); } -AndroidSurfaceTexture::AndroidSurfaceTexture(unsigned int texName) +AndroidSurfaceTexture::AndroidSurfaceTexture(quint32 texName) : QObject() { Q_STATIC_ASSERT(sizeof (jlong) >= sizeof (void *)); @@ -163,7 +163,7 @@ jobject AndroidSurfaceTexture::surfaceHolder() return m_surfaceHolder.object(); } -void AndroidSurfaceTexture::attachToGLContext(int texName) +void AndroidSurfaceTexture::attachToGLContext(quint32 texName) { if (QtAndroidPrivate::androidSdkVersion() < 16 || !m_surfaceTexture.isValid()) return; diff --git a/src/plugins/android/src/wrappers/jni/androidsurfacetexture.h b/src/plugins/android/src/wrappers/jni/androidsurfacetexture.h index 0a271287a..911711774 100644 --- a/src/plugins/android/src/wrappers/jni/androidsurfacetexture.h +++ b/src/plugins/android/src/wrappers/jni/androidsurfacetexture.h @@ -51,7 +51,7 @@ class AndroidSurfaceTexture : public QObject { Q_OBJECT public: - explicit AndroidSurfaceTexture(unsigned int texName); + explicit AndroidSurfaceTexture(quint32 texName); ~AndroidSurfaceTexture(); jobject surfaceTexture(); @@ -63,7 +63,7 @@ public: void release(); // API level 14 void updateTexImage(); - void attachToGLContext(int texName); // API level 16 + void attachToGLContext(quint32 texName); // API level 16 void detachFromGLContext(); // API level 16 static bool initJNI(JNIEnv *env); diff --git a/src/plugins/audiocapture/audiocapturesession.cpp b/src/plugins/audiocapture/audiocapturesession.cpp index 19347dca9..e4a9688e8 100644 --- a/src/plugins/audiocapture/audiocapturesession.cpp +++ b/src/plugins/audiocapture/audiocapturesession.cpp @@ -349,11 +349,12 @@ void AudioCaptureSession::stop() file.stopProbes(); file.close(); if (m_wavFile) { - qint32 fileSize = file.size()-8; + qint32 fileSize = file.size(); file.open(QIODevice::ReadWrite | QIODevice::Unbuffered); file.read((char*)&header,sizeof(CombinedHeader)); - header.riff.descriptor.size = fileSize; // filesize-8 - header.data.descriptor.size = fileSize-44; // samples*channels*sampleSize/8 + header.riff.descriptor.size = fileSize - 8; // The RIFF chunk size is the file size minus + // the first two RIFF fields (8 bytes) + header.data.descriptor.size = fileSize - 44; // dataSize = fileSize - headerSize (44 bytes) file.seek(0); file.write((char*)&header,sizeof(CombinedHeader)); file.close(); diff --git a/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm b/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm index 99f06edf3..87bb08e5c 100644 --- a/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm +++ b/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm @@ -464,15 +464,19 @@ void AVFMediaPlayerSession::setMedia(const QMediaContent &content, QIODevice *st m_requestedPosition = -1; Q_EMIT positionChanged(position()); - QMediaPlayer::MediaStatus oldMediaStatus = m_mediaStatus; + const QMediaPlayer::MediaStatus oldMediaStatus = m_mediaStatus; + const QMediaPlayer::State oldState = m_state; if (content.isNull() || content.canonicalUrl().isEmpty()) { m_mediaStatus = QMediaPlayer::NoMedia; - if (m_state != QMediaPlayer::StoppedState) - Q_EMIT stateChanged(m_state = QMediaPlayer::StoppedState); + m_state = QMediaPlayer::StoppedState; if (m_mediaStatus != oldMediaStatus) Q_EMIT mediaStatusChanged(m_mediaStatus); + + if (m_state != oldState) + Q_EMIT stateChanged(m_state); + return; } else { @@ -783,14 +787,15 @@ void AVFMediaPlayerSession::processEOS() #endif Q_EMIT positionChanged(position()); m_mediaStatus = QMediaPlayer::EndOfMedia; + m_state = QMediaPlayer::StoppedState; // At this point, frames should not be rendered anymore. // Clear the output layer to make sure of that. if (m_videoOutput) m_videoOutput->setLayer(0); - Q_EMIT stateChanged(m_state = QMediaPlayer::StoppedState); Q_EMIT mediaStatusChanged(m_mediaStatus); + Q_EMIT stateChanged(m_state); } void AVFMediaPlayerSession::processLoadStateChange() @@ -870,7 +875,11 @@ void AVFMediaPlayerSession::processMediaLoadError() m_requestedPosition = -1; Q_EMIT positionChanged(position()); } + + m_mediaStatus = QMediaPlayer::InvalidMedia; + m_state = QMediaPlayer::StoppedState; + Q_EMIT error(QMediaPlayer::FormatError, tr("Failed to load media")); - Q_EMIT mediaStatusChanged(m_mediaStatus = QMediaPlayer::InvalidMedia); - Q_EMIT stateChanged(m_state = QMediaPlayer::StoppedState); + Q_EMIT mediaStatusChanged(m_mediaStatus); + Q_EMIT stateChanged(m_state); } diff --git a/src/plugins/directshow/camera/dscamerasession.cpp b/src/plugins/directshow/camera/dscamerasession.cpp index 9e1be9606..64532d04b 100644 --- a/src/plugins/directshow/camera/dscamerasession.cpp +++ b/src/plugins/directshow/camera/dscamerasession.cpp @@ -668,7 +668,7 @@ void DSCameraSession::onFrameAvailable(const char *frameData, long len) QMutexLocker locker(&m_captureMutex); if (m_currentImageId != -1 && !m_capturedFrame.isValid()) { m_capturedFrame = m_currentFrame; - emit imageExposed(m_currentImageId); + QMetaObject::invokeMethod(this, "imageExposed", Qt::QueuedConnection, Q_ARG(int, m_currentImageId)); } QMetaObject::invokeMethod(this, "presentFrame", Qt::QueuedConnection); @@ -685,6 +685,9 @@ void DSCameraSession::presentFrame() m_presentMutex.unlock(); + QImage captureImage; + int captureId; + m_captureMutex.lock(); if (m_capturedFrame.isValid()) { @@ -692,27 +695,31 @@ void DSCameraSession::presentFrame() m_capturedFrame.map(QAbstractVideoBuffer::ReadOnly); - QImage image = QImage(m_capturedFrame.bits(), - m_previewSize.width(), m_previewSize.height(), - QImage::Format_RGB32); + captureImage = QImage(m_capturedFrame.bits(), + m_previewSize.width(), m_previewSize.height(), + QImage::Format_RGB32); - image = image.mirrored(m_needsHorizontalMirroring); // also causes a deep copy of the data + captureImage = captureImage.mirrored(m_needsHorizontalMirroring); // also causes a deep copy of the data m_capturedFrame.unmap(); - emit imageCaptured(m_currentImageId, image); + captureId = m_currentImageId; QtConcurrent::run(this, &DSCameraSession::saveCapturedImage, - m_currentImageId, image, m_imageCaptureFileName); + m_currentImageId, captureImage, m_imageCaptureFileName); m_imageCaptureFileName.clear(); m_currentImageId = -1; - updateReadyForCapture(); m_capturedFrame = QVideoFrame(); } m_captureMutex.unlock(); + + if (!captureImage.isNull()) + emit imageCaptured(captureId, captureImage); + + updateReadyForCapture(); } void DSCameraSession::saveCapturedImage(int id, const QImage &image, const QString &path) diff --git a/src/plugins/winrt/qwinrtmediaplayercontrol.cpp b/src/plugins/winrt/qwinrtmediaplayercontrol.cpp index 68cf60db2..5720488f2 100644 --- a/src/plugins/winrt/qwinrtmediaplayercontrol.cpp +++ b/src/plugins/winrt/qwinrtmediaplayercontrol.cpp @@ -266,18 +266,19 @@ public: break; } - if (d->state != newState) { - d->state = newState; - emit q->stateChanged(d->state); - } - if (d->videoRenderer) d->videoRenderer->setActive(d->state == QMediaPlayer::PlayingState); - if (d->mediaStatus != newStatus) { - d->mediaStatus = newStatus; + const QMediaPlayer::MediaStatus oldMediaStatus = d->mediaStatus; + const QMediaPlayer::State oldState = d->state; + d->mediaStatus = newStatus; + d->state = newState; + + if (d->mediaStatus != oldMediaStatus) emit q->mediaStatusChanged(d->mediaStatus); - } + + if (d->state != oldState) + emit q->stateChanged(d->state); return S_OK; } @@ -859,17 +860,22 @@ void QWinRTMediaPlayerControl::stop() { Q_D(QWinRTMediaPlayerControl); - if (d->state != QMediaPlayer::StoppedState) { - d->state = QMediaPlayer::StoppedState; - emit stateChanged(d->state); - } + const QMediaPlayer::MediaStatus oldMediaStatus = d->mediaStatus; + const QMediaPlayer::State oldState = d->state; + + d->state = QMediaPlayer::StoppedState; if (d->mediaStatus == QMediaPlayer::BufferedMedia || d->mediaStatus == QMediaPlayer::BufferingMedia) { d->mediaStatus = QMediaPlayer::LoadedMedia; - emit mediaStatusChanged(d->mediaStatus); } + if (d->mediaStatus != oldMediaStatus) + emit mediaStatusChanged(d->mediaStatus); + + if (d->state != oldState) + emit stateChanged(d->state); + if (d->media.isNull() && d->stream.isNull()) return; diff --git a/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp b/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp index dfa1bf254..1f1df9aac 100644 --- a/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp +++ b/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp @@ -331,6 +331,33 @@ void tst_QMediaPlayerBackend::playPauseStop() QSignalSpy stateSpy(&player, SIGNAL(stateChanged(QMediaPlayer::State))); QSignalSpy statusSpy(&player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus))); QSignalSpy positionSpy(&player, SIGNAL(positionChanged(qint64))); + QSignalSpy errorSpy(&player, SIGNAL(error(QMediaPlayer::Error))); + + // Check play() without a media + player.play(); + + QCOMPARE(player.state(), QMediaPlayer::StoppedState); + QCOMPARE(player.mediaStatus(), QMediaPlayer::NoMedia); + QCOMPARE(player.error(), QMediaPlayer::NoError); + QCOMPARE(player.position(), 0); + QCOMPARE(stateSpy.count(), 0); + QCOMPARE(statusSpy.count(), 0); + QCOMPARE(positionSpy.count(), 0); + QCOMPARE(errorSpy.count(), 0); + + // Check pause() without a media + player.pause(); + + QCOMPARE(player.state(), QMediaPlayer::StoppedState); + QCOMPARE(player.mediaStatus(), QMediaPlayer::NoMedia); + QCOMPARE(player.error(), QMediaPlayer::NoError); + QCOMPARE(player.position(), 0); + QCOMPARE(stateSpy.count(), 0); + QCOMPARE(statusSpy.count(), 0); + QCOMPARE(positionSpy.count(), 0); + QCOMPARE(errorSpy.count(), 0); + + // The rest is with a valid media player.setMedia(localWavFile); |