summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/multimedia/playback/qmediaplayer.cpp16
-rw-r--r--src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtCameraListener.java30
-rw-r--r--src/plugins/android/src/common/qandroidvideooutput.cpp82
-rw-r--r--src/plugins/android/src/common/qandroidvideooutput.h16
-rw-r--r--src/plugins/android/src/mediacapture/qandroidcamerasession.cpp6
-rw-r--r--src/plugins/android/src/wrappers/jni/androidcamera.cpp26
-rw-r--r--src/plugins/android/src/wrappers/jni/androidsurfacetexture.cpp4
-rw-r--r--src/plugins/android/src/wrappers/jni/androidsurfacetexture.h4
-rw-r--r--src/plugins/audiocapture/audiocapturesession.cpp7
-rw-r--r--src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm21
-rw-r--r--src/plugins/directshow/camera/dscamerasession.cpp23
-rw-r--r--src/plugins/winrt/qwinrtmediaplayercontrol.cpp32
-rw-r--r--tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp27
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);