summaryrefslogtreecommitdiffstats
path: root/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/avfoundation/camera/avfimagecapturecontrol.mm')
-rw-r--r--src/plugins/avfoundation/camera/avfimagecapturecontrol.mm84
1 files changed, 50 insertions, 34 deletions
diff --git a/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm b/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm
index c28ccef8e..edaaf8ce3 100644
--- a/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm
+++ b/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm
@@ -33,14 +33,15 @@
#include "avfcameradebug.h"
#include "avfimagecapturecontrol.h"
-#include "avfcamerasession.h"
#include "avfcameraservice.h"
#include "avfcameracontrol.h"
#include <QtCore/qurl.h>
#include <QtCore/qfile.h>
#include <QtCore/qbuffer.h>
+#include <QtConcurrent/qtconcurrentrun.h>
#include <QtGui/qimagereader.h>
+#include <private/qvideoframe_p.h>
QT_USE_NAMESPACE
@@ -65,6 +66,10 @@ AVFImageCaptureControl::AVFImageCaptureControl(AVFCameraService *service, QObjec
connect(m_cameraControl, SIGNAL(statusChanged(QCamera::Status)), SLOT(updateReadyStatus()));
connect(m_session, SIGNAL(readyToConfigureConnections()), SLOT(updateCaptureConnection()));
+
+ connect(m_session, &AVFCameraSession::newViewfinderFrame,
+ this, &AVFImageCaptureControl::onNewViewfinderFrame,
+ Qt::DirectConnection);
}
AVFImageCaptureControl::~AVFImageCaptureControl()
@@ -106,9 +111,18 @@ int AVFImageCaptureControl::capture(const QString &fileName)
qDebugCamera() << "Capture image to" << actualFileName;
- int captureId = m_lastCaptureId;
+ CaptureRequest request = { m_lastCaptureId, new QSemaphore };
+ m_requestsMutex.lock();
+ m_captureRequests.enqueue(request);
+ m_requestsMutex.unlock();
+
[m_stillImageOutput captureStillImageAsynchronouslyFromConnection:m_videoConnection
completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error) {
+
+ // Wait for the preview to be generated before saving the JPEG
+ request.previewReady->acquire();
+ delete request.previewReady;
+
if (error) {
QStringList messageParts;
messageParts << QString::fromUtf8([[error localizedDescription] UTF8String]);
@@ -119,64 +133,66 @@ int AVFImageCaptureControl::capture(const QString &fileName)
qDebugCamera() << "Image capture failed:" << errorMessage;
QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
- Q_ARG(int, captureId),
+ Q_ARG(int, request.captureId),
Q_ARG(int, QCameraImageCapture::ResourceError),
Q_ARG(QString, errorMessage));
} else {
- qDebugCamera() << "Image captured:" << actualFileName;
- //we can't find the exact time the image is exposed,
- //but image capture is very fast on desktop, so emit it here
- QMetaObject::invokeMethod(this, "imageExposed", Qt::QueuedConnection,
- Q_ARG(int, captureId));
+ qDebugCamera() << "Image capture completed:" << actualFileName;
NSData *nsJpgData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
QByteArray jpgData = QByteArray::fromRawData((const char *)[nsJpgData bytes], [nsJpgData length]);
- //Generate snap preview as downscalled image
- {
- QBuffer buffer(&jpgData);
- QImageReader imageReader(&buffer);
- QSize imgSize = imageReader.size();
- int downScaleSteps = 0;
- while (imgSize.width() > 800 && downScaleSteps < 8) {
- imgSize.rwidth() /= 2;
- imgSize.rheight() /= 2;
- downScaleSteps++;
- }
-
- imageReader.setScaledSize(imgSize);
- QImage snapPreview = imageReader.read();
-
- QMetaObject::invokeMethod(this, "imageCaptured", Qt::QueuedConnection,
- Q_ARG(int, captureId),
- Q_ARG(QImage, snapPreview));
- }
-
- qDebugCamera() << "Image captured" << actualFileName;
-
QFile f(actualFileName);
if (f.open(QFile::WriteOnly)) {
if (f.write(jpgData) != -1) {
QMetaObject::invokeMethod(this, "imageSaved", Qt::QueuedConnection,
- Q_ARG(int, captureId),
+ Q_ARG(int, request.captureId),
Q_ARG(QString, actualFileName));
} else {
QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
- Q_ARG(int, captureId),
+ Q_ARG(int, request.captureId),
Q_ARG(int, QCameraImageCapture::OutOfSpaceError),
Q_ARG(QString, f.errorString()));
}
} else {
QString errorMessage = tr("Could not open destination file:\n%1").arg(actualFileName);
QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection,
- Q_ARG(int, captureId),
+ Q_ARG(int, request.captureId),
Q_ARG(int, QCameraImageCapture::ResourceError),
Q_ARG(QString, errorMessage));
}
}
}];
- return captureId;
+ return request.captureId;
+}
+
+void AVFImageCaptureControl::onNewViewfinderFrame(const QVideoFrame &frame)
+{
+ QMutexLocker locker(&m_requestsMutex);
+
+ if (m_captureRequests.isEmpty())
+ return;
+
+ CaptureRequest request = m_captureRequests.dequeue();
+ Q_EMIT imageExposed(request.captureId);
+
+ QtConcurrent::run(this, &AVFImageCaptureControl::makeCapturePreview,
+ request,
+ frame,
+ 0 /* rotation */);
+}
+
+void AVFImageCaptureControl::makeCapturePreview(CaptureRequest request,
+ const QVideoFrame &frame,
+ int rotation)
+{
+ QTransform transform;
+ transform.rotate(rotation);
+
+ Q_EMIT imageCaptured(request.captureId, qt_imageFromVideoFrame(frame).transformed(transform));
+
+ request.previewReady->release();
}
void AVFImageCaptureControl::cancelCapture()