From 528588f9f106f25bbf95f632e79106774319079a Mon Sep 17 00:00:00 2001
From: Yoann Lopes <yoann.lopes@theqtcompany.com>
Date: Mon, 11 Jul 2016 16:07:21 +0200
Subject: [PATCH] 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 <christian.stromme@qt.io>
Reviewed-by: Ruslan Vorobei <zvorobei@gmail.com>
---
 .../directshow/camera/dscamerasession.cpp     | 23 ++++++++++++-------
 1 file changed, 15 insertions(+), 8 deletions(-)

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)
-- 
GitLab