From 528588f9f106f25bbf95f632e79106774319079a Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Mon, 11 Jul 2016 16:07:21 +0200 Subject: DirectShow: fix possible deadlock when capturing camera image Don't emit signals while mutexes are locked. Task-number: QTBUG-41573 Change-Id: I287b031a579cbec1cd178501df4426ceff9e9142 Reviewed-by: Christian Stromme Reviewed-by: Ruslan Vorobei --- src/plugins/directshow/camera/dscamerasession.cpp | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/directshow/camera/dscamerasession.cpp b/src/plugins/directshow/camera/dscamerasession.cpp index 3421f2cd1..1cb91cd4a 100644 --- a/src/plugins/directshow/camera/dscamerasession.cpp +++ b/src/plugins/directshow/camera/dscamerasession.cpp @@ -662,7 +662,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); @@ -679,6 +679,9 @@ void DSCameraSession::presentFrame() m_presentMutex.unlock(); + QImage captureImage; + int captureId; + m_captureMutex.lock(); if (m_capturedFrame.isValid()) { @@ -686,27 +689,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) -- cgit v1.2.3 From 4f93cd5a7673b5683b12d55c65852e12d556a372 Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Tue, 19 Jul 2016 14:35:02 +0200 Subject: Android: fix imageCaptured() signal When capturing two pictures in a row, the second capture would not trigger the imageCaptured() signal. The reason is that capturing a picture restarts the preview when done, which in turns clears the cached last preview frame. The second fetchLastPreviewFrame() would therefore not do anything. In this situation, we now retry fetching the frame as soon as a new one arrives (rather than bailing out). Task-number: QTBUG-48975 Change-Id: Id5476f37641c04b0edd92bddd40711d5125887f0 Reviewed-by: Christian Stromme --- .../qt5/android/multimedia/QtCameraListener.java | 23 +++++++++++++++++----- .../android/src/wrappers/jni/androidcamera.cpp | 21 ++++++++++++++++++-- 2 files changed, 37 insertions(+), 7 deletions(-) (limited to 'src/plugins') 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 8724eeba4..008458e89 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 @@ -51,6 +51,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; @@ -67,6 +68,11 @@ public class QtCameraListener implements Camera.ShutterCallback, m_notifyNewFrames = notify; } + public void notifyWhenFrameAvailable(boolean notify) + { + m_notifyWhenFrameAvailable = notify; + } + public byte[] lastPreviewBuffer() { return m_lastPreviewBuffer; @@ -158,11 +164,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); + } } } @@ -189,4 +201,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/wrappers/jni/androidcamera.cpp b/src/plugins/android/src/wrappers/jni/androidcamera.cpp index 009ab70b9..0ce8eff39 100644 --- a/src/plugins/android/src/wrappers/jni/androidcamera.cpp +++ b/src/plugins/android/src/wrappers/jni/androidcamera.cpp @@ -145,6 +145,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 @@ -1413,6 +1423,9 @@ void AndroidCameraPrivate::stopPreview() { QJNIEnvironmentPrivate env; + // cancel any pending new frame notification + m_cameraListener.callMethod("notifyWhenFrameAvailable", "(Z)V", false); + m_camera.callMethod("stopPreview"); exceptionCheckAndClear(env); @@ -1449,8 +1462,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("notifyWhenFrameAvailable", "(Z)V", true); return; + } const int arrayLength = env->GetArrayLength(static_cast(data.object())); if (arrayLength == 0) @@ -1516,7 +1532,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, -- cgit v1.2.3 From b76958f23e971e25a38ed2b9525dcca1cb3d954d Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Fri, 15 Jul 2016 11:47:41 +0200 Subject: AudioCapture: fix data chunk size in WAV header The size in the data chunk was missing 8 bytes. Task-number: QTBUG-54710 Change-Id: I0530ea9d2420dd90d196993e1678003697c0ebaa Reviewed-by: Christian Stromme --- src/plugins/audiocapture/audiocapturesession.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/audiocapture/audiocapturesession.cpp b/src/plugins/audiocapture/audiocapturesession.cpp index 1b183db26..448e8538b 100644 --- a/src/plugins/audiocapture/audiocapturesession.cpp +++ b/src/plugins/audiocapture/audiocapturesession.cpp @@ -342,11 +342,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(); -- cgit v1.2.3 From d78e0716dd97ea0c874928bcde0531fda297703a Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Wed, 13 Jul 2016 11:20:54 +0200 Subject: Android: don't process capture previews when capture is canceled Change-Id: Ia068b0fcc30412755639412ec03e49c740b66bed Reviewed-by: Christian Stromme --- src/plugins/android/src/mediacapture/qandroidcamerasession.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp index df9f0367b..1689a55b4 100644 --- a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp +++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp @@ -576,6 +576,9 @@ void QAndroidCameraSession::onCameraPictureExposed() void QAndroidCameraSession::onLastPreviewFrameFetched(const QVideoFrame &frame) { + if (m_captureCanceled) + return; + QtConcurrent::run(this, &QAndroidCameraSession::processPreviewImage, m_currentImageCaptureId, frame, -- cgit v1.2.3 From 624ac719d6d3dd596fc697ce587cc6bb9e33845f Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Wed, 13 Jul 2016 11:18:36 +0200 Subject: Android: restart preview when image capture fails The preview must be restarted after taking a picture but were doing that only when the capture succeeded. We now also do it when it fails. Change-Id: I8bfff06a811d9333220050e5e81561438f5a3786 Reviewed-by: Christian Stromme --- src/plugins/android/src/mediacapture/qandroidcamerasession.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/plugins') diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp index 1689a55b4..635a51152 100644 --- a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp +++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp @@ -563,6 +563,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() -- cgit v1.2.3 From 95e1012c9dc49e0afbed52d17ff32a4a59a723f7 Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Wed, 13 Jul 2016 11:15:45 +0200 Subject: Android: fix freeze when taking pictures on some devices On some devices and on the emulator, the preview callback must be cleared before taking a picture to avoid a camera server freeze. Task-number: QTBUG-54709 Change-Id: I9e4ad417fa08cddea7edfd232f5b5df40ada59ee Reviewed-by: Christian Stromme --- .../src/org/qtproject/qt5/android/multimedia/QtCameraListener.java | 7 ++++++- src/plugins/android/src/wrappers/jni/androidcamera.cpp | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'src/plugins') 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 008458e89..8a2697afe 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 @@ -104,11 +104,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(); diff --git a/src/plugins/android/src/wrappers/jni/androidcamera.cpp b/src/plugins/android/src/wrappers/jni/androidcamera.cpp index 0ce8eff39..b0e02b7c2 100644 --- a/src/plugins/android/src/wrappers/jni/androidcamera.cpp +++ b/src/plugins/android/src/wrappers/jni/androidcamera.cpp @@ -1436,6 +1436,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("clearPreviewCallback", "(Landroid/hardware/Camera;)V", m_camera.object()); + m_camera.callMethod("takePicture", "(Landroid/hardware/Camera$ShutterCallback;" "Landroid/hardware/Camera$PictureCallback;" "Landroid/hardware/Camera$PictureCallback;)V", -- cgit v1.2.3 From 124987e4bc4b39cae7074eb75e2bb3e3436aded0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Str=C3=B8mme?= Date: Tue, 5 Jul 2016 13:46:01 +0200 Subject: Android: Fix texture leak in QAndroidTextureVideoOutput Simplify the ownership of the OpenGL resources and make it simpler to release individual resources as needed. Previously we would reset the texture handle without releasing it back to the system, making us leak texture each time the video output was reset. Also, be consistent with the type used for the texture handle. Task-number: QTBUG-54340 Change-Id: Ic3b3c7322677a909e51aa5983fa99ccf8b290302 Reviewed-by: Yoann Lopes --- .../android/src/common/qandroidvideooutput.cpp | 82 +++++++++------------- .../android/src/common/qandroidvideooutput.h | 16 ++++- .../src/wrappers/jni/androidsurfacetexture.cpp | 4 +- .../src/wrappers/jni/androidsurfacetexture.h | 4 +- 4 files changed, 51 insertions(+), 55 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/android/src/common/qandroidvideooutput.cpp b/src/plugins/android/src/common/qandroidvideooutput.cpp index f462a28d5..2010ec9e0 100644 --- a/src/plugins/android/src/common/qandroidvideooutput.cpp +++ b/src/plugins/android/src/common/qandroidvideooutput.cpp @@ -60,6 +60,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(fbo); +} + +void OpenGLResourcesDeleter::deleteShaderProgramHelper(void *prog) +{ + delete reinterpret_cast(prog); +} + class AndroidTextureVideoBuffer : public QAbstractVideoBuffer { @@ -124,40 +140,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) @@ -165,7 +147,6 @@ QAndroidTextureVideoOutput::QAndroidTextureVideoOutput(QObject *parent) , m_externalTex(0) , m_fbo(0) , m_program(0) - , m_glDeleter(0) , m_surfaceTextureCanAttachToContext(QtAndroidPrivate::androidSdkVersion() >= 16) { @@ -175,8 +156,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 @@ -223,8 +208,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; } @@ -239,10 +223,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; @@ -257,8 +240,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() @@ -388,19 +377,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) { @@ -431,8 +418,6 @@ void QAndroidTextureVideoOutput::createGLResources() m_program->bindAttributeLocation("vertexCoordsArray", 0); m_program->bindAttributeLocation("textureCoordArray", 1); m_program->link(); - - m_glDeleter->setShaderProgram(m_program); } } @@ -442,8 +427,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 0068a5809..09bd5d87e 100644 --- a/src/plugins/android/src/common/qandroidvideooutput.h +++ b/src/plugins/android/src/common/qandroidvideooutput.h @@ -44,7 +44,6 @@ class AndroidSurfaceTexture; class AndroidSurfaceHolder; class QOpenGLFramebufferObject; class QOpenGLShaderProgram; -class OpenGLResourcesDeleter; class QAbstractVideoSurface; class QAndroidVideoOutput : public QObject @@ -69,6 +68,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 { @@ -108,7 +120,7 @@ private: quint32 m_externalTex; QOpenGLFramebufferObject *m_fbo; QOpenGLShaderProgram *m_program; - OpenGLResourcesDeleter *m_glDeleter; + QScopedPointer m_glDeleter; bool m_surfaceTextureCanAttachToContext; diff --git a/src/plugins/android/src/wrappers/jni/androidsurfacetexture.cpp b/src/plugins/android/src/wrappers/jni/androidsurfacetexture.cpp index bc7187e9c..cd6d41d84 100644 --- a/src/plugins/android/src/wrappers/jni/androidsurfacetexture.cpp +++ b/src/plugins/android/src/wrappers/jni/androidsurfacetexture.cpp @@ -56,7 +56,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 *)); @@ -157,7 +157,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 3c41bf51d..1b82ad20e 100644 --- a/src/plugins/android/src/wrappers/jni/androidsurfacetexture.h +++ b/src/plugins/android/src/wrappers/jni/androidsurfacetexture.h @@ -45,7 +45,7 @@ class AndroidSurfaceTexture : public QObject { Q_OBJECT public: - explicit AndroidSurfaceTexture(unsigned int texName); + explicit AndroidSurfaceTexture(quint32 texName); ~AndroidSurfaceTexture(); jobject surfaceTexture(); @@ -57,7 +57,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); -- cgit v1.2.3 From b69862eb2ac587d75580d80b293042e9fdb3bb1c Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Thu, 28 Jul 2016 12:06:45 +0200 Subject: AVFoundation: fix mediaStatus and state changes When both state and mediaStatus are updated at the same time, make sure both variables are updated before emitting the corresponding signals. Also, always emit mediaStatusChanged() signals before stateChanged() to make sure mediaStatus changes are not cancelled by some action resulting from a state change. Task-number: QTBUG-49578 Change-Id: I0caea8261120595227834dbac7fed286d125bcab Reviewed-by: Christian Stromme --- .../mediaplayer/avfmediaplayersession.mm | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm b/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm index 53cdebd82..d3ec2ff9c 100644 --- a/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm +++ b/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm @@ -458,15 +458,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 { @@ -777,14 +781,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() @@ -864,7 +869,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); } -- cgit v1.2.3 From c30eeb5b7486caa31cdb0f9279de2f78fed89c54 Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Thu, 28 Jul 2016 11:53:40 +0200 Subject: WinRT: emit mediaStatus changes before state changes This makes sure all mediaStatus changes are emitted, even when some action is done on the media player as a result of a state change. Also, when both mediaStatus and state are changed at the same time, make sure both variables are updated before sending the corresponding signals. Task-number: QTBUG-49578 Change-Id: I8eed6692503bba1540070f6435b7ea1f5e25c023 Reviewed-by: Andrew Knight Reviewed-by: Oliver Wolff Reviewed-by: Christian Stromme Reviewed-by: Maurice Kalinowski --- src/plugins/winrt/qwinrtmediaplayercontrol.cpp | 32 +++++++++++++++----------- 1 file changed, 19 insertions(+), 13 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/winrt/qwinrtmediaplayercontrol.cpp b/src/plugins/winrt/qwinrtmediaplayercontrol.cpp index d00788e64..05dcc29f4 100644 --- a/src/plugins/winrt/qwinrtmediaplayercontrol.cpp +++ b/src/plugins/winrt/qwinrtmediaplayercontrol.cpp @@ -263,18 +263,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; } @@ -855,17 +856,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; -- cgit v1.2.3