60 QMetaObject::invokeMethod(
this,
"error", Qt::QueuedConnection,
61 Q_ARG(
int, m_lastCaptureId),
62 Q_ARG(
int, QImageCapture::ResourceError),
63 Q_ARG(QString, QPlatformImageCapture::msgImageCaptureNotSet()));
67 QMetaObject::invokeMethod(
this,
"error", Qt::QueuedConnection,
68 Q_ARG(
int, m_lastCaptureId),
69 Q_ARG(
int, QImageCapture::NotReadyError),
70 Q_ARG(QString, QPlatformImageCapture::msgCameraNotReady()));
75 bool captureToBuffer = fileName.isEmpty();
77 CaptureRequest request = { m_lastCaptureId, QSharedPointer<QSemaphore>::create()};
78 m_requestsMutex.lock();
79 m_captureRequests.enqueue(request);
80 m_requestsMutex.unlock();
82 [m_stillImageOutput captureStillImageAsynchronouslyFromConnection:m_videoConnection
83 completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error) {
86 QStringList messageParts;
87 messageParts << QString::fromUtf8([[error localizedDescription] UTF8String]);
88 messageParts << QString::fromUtf8([[error localizedFailureReason] UTF8String]);
89 messageParts << QString::fromUtf8([[error localizedRecoverySuggestion] UTF8String]);
91 QString errorMessage = messageParts.join(QChar(u' '));
92 qCDebug(qLcCamera) <<
"Image capture failed:" << errorMessage;
94 QMetaObject::invokeMethod(
this,
"error", Qt::QueuedConnection,
95 Q_ARG(
int, request.captureId),
96 Q_ARG(
int, QImageCapture::ResourceError),
97 Q_ARG(QString, errorMessage));
110 if (!m_session->videoOutput() || request.previewReady->tryAcquire(1, 1000)) {
111 qCDebug(qLcCamera) <<
"Image capture completed";
113 NSData *nsJpgData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
114 QByteArray jpgData = QByteArray::fromRawData((
const char *)[nsJpgData bytes], [nsJpgData length]);
116 if (captureToBuffer) {
117 QBuffer data(&jpgData);
118 QImageReader reader(&data,
"JPEG");
119 QSize size = reader.size();
120 auto buffer = std::make_unique<QMemoryVideoBuffer>(
121 QByteArray(jpgData.constData(), jpgData.size()), -1);
122 QVideoFrame frame = QVideoFramePrivate::createFrame(
123 std::move(buffer), QVideoFrameFormat(size, QVideoFrameFormat::Format_Jpeg));
124 QMetaObject::invokeMethod(
this,
"imageAvailable", Qt::QueuedConnection,
125 Q_ARG(
int, request.captureId),
126 Q_ARG(QVideoFrame, frame));
129 if (f.open(QFile::WriteOnly)) {
130 if (f.write(jpgData) != -1) {
131 QMetaObject::invokeMethod(
this,
"imageSaved", Qt::QueuedConnection,
132 Q_ARG(
int, request.captureId),
133 Q_ARG(QString, fileName));
135 QMetaObject::invokeMethod(
this,
"error", Qt::QueuedConnection,
136 Q_ARG(
int, request.captureId),
137 Q_ARG(
int, QImageCapture::OutOfSpaceError),
138 Q_ARG(QString, f.errorString()));
141 QString errorMessage = tr(
"Could not open destination file:\n%1").arg(fileName);
142 QMetaObject::invokeMethod(
this,
"error", Qt::QueuedConnection,
143 Q_ARG(
int, request.captureId),
144 Q_ARG(
int, QImageCapture::ResourceError),
145 Q_ARG(QString, errorMessage));
149 const QLatin1String errorMessage(
"Image capture failed: timed out waiting"
150 " for a preview frame.");
151 qCDebug(qLcCamera) << errorMessage;
152 QMetaObject::invokeMethod(
this,
"error", Qt::QueuedConnection,
153 Q_ARG(
int, request.captureId),
154 Q_ARG(
int, QImageCapture::ResourceError),
155 Q_ARG(QString, errorMessage));
159 return request.captureId;
242 QImageEncoderSettings settings;
244 if (!videoCaptureDeviceIsValid())
247 AVCaptureDevice *captureDevice = m_service
->session()->videoCaptureDevice();
248 if (!captureDevice.activeFormat) {
249 qCDebug(qLcCamera) << Q_FUNC_INFO <<
"no active format";
253 QSize res(qt_device_format_resolution(captureDevice.activeFormat));
255 if (!m_service->avfImageCaptureControl() || !m_service->avfImageCaptureControl()->stillImageOutput()) {
256 qCDebug(qLcCamera) << Q_FUNC_INFO <<
"no still image output";
260 AVCaptureStillImageOutput *stillImageOutput = m_service->avfImageCaptureControl()->stillImageOutput();
261 if (stillImageOutput.highResolutionStillImageOutputEnabled)
262 res = qt_device_format_high_resolution(captureDevice.activeFormat);
264 if (res.isNull() || !res.isValid()) {
265 qCDebug(qLcCamera) << Q_FUNC_INFO <<
"failed to exctract the image resolution";
269 settings.setResolution(res);
270 settings.setFormat(QImageCapture::JPEG);
286 if (!videoCaptureDeviceIsValid())
293 if (!m_service->imageCapture()
295 qCDebug(qLcCamera) << Q_FUNC_INFO <<
"no still image output";
299 if (m_settings.format() != QImageCapture::UnspecifiedFormat && m_settings.format() != QImageCapture::JPEG) {
300 qCDebug(qLcCamera) << Q_FUNC_INFO <<
"unsupported format:" << m_settings.format();
304 QSize res(m_settings.resolution());
306 qCDebug(qLcCamera) << Q_FUNC_INFO <<
"invalid resolution:" << res;
310 if (!res.isValid()) {
318 bool activeFormatChanged =
false;
320 AVCaptureDevice *captureDevice = m_service
->session()->videoCaptureDevice();
321 AVCaptureDeviceFormat *match = qt_find_best_resolution_match(captureDevice, res,
325 qCDebug(qLcCamera) << Q_FUNC_INFO <<
"unsupported resolution:" << res;
329 activeFormatChanged = qt_set_active_format(captureDevice, match,
true);
332 AVCaptureStillImageOutput *imageOutput = m_service->avfImageCaptureControl()->stillImageOutput();
333 if (res == qt_device_format_high_resolution(captureDevice.activeFormat))
334 imageOutput.highResolutionStillImageOutputEnabled = YES;
336 imageOutput.highResolutionStillImageOutputEnabled = NO;
339 return activeFormatChanged;
345 if (m_service == captureSession)
348 m_service = captureSession;
350 m_session->disconnect(
this);
352 m_cameraControl->disconnect(
this);
354 m_cameraControl =
nullptr;
355 m_videoConnection = nil;
360 connect(m_service, &AVFCameraService::cameraChanged,
this, &AVFImageCapture::onCameraChanged);
361 connect(m_session, SIGNAL(readyToConfigureConnections()), SLOT(updateCaptureConnection()));
362 connect(m_session, &AVFCameraSession::newViewfinderFrame,
363 this, &AVFImageCapture::onNewViewfinderFrame);
366 updateCaptureConnection();