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 = actualFileName.isEmpty();
77 CaptureRequest request = { m_lastCaptureId, QSharedPointer<QSemaphore>::create()};
78 m_requestsMutex.lock();
79 m_captureRequests.enqueue(request);
80 m_requestsMutex.unlock();
82 QString fileName(actualFileName);
84 [m_stillImageOutput captureStillImageAsynchronouslyFromConnection:m_videoConnection
85 completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error) {
88 QStringList messageParts;
89 messageParts << QString::fromUtf8([[error localizedDescription] UTF8String]);
90 messageParts << QString::fromUtf8([[error localizedFailureReason] UTF8String]);
91 messageParts << QString::fromUtf8([[error localizedRecoverySuggestion] UTF8String]);
93 QString errorMessage = messageParts.join(QChar(u' '));
94 qCDebug(qLcCamera) <<
"Image capture failed:" << errorMessage;
96 QMetaObject::invokeMethod(
this,
"error", Qt::QueuedConnection,
97 Q_ARG(
int, request.captureId),
98 Q_ARG(
int, QImageCapture::ResourceError),
99 Q_ARG(QString, errorMessage));
112 if (!m_session->videoOutput() || request.previewReady->tryAcquire(1, 1000)) {
113 qCDebug(qLcCamera) <<
"Image capture completed";
115 NSData *nsJpgData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
116 QByteArray jpgData = QByteArray::fromRawData((
const char *)[nsJpgData bytes], [nsJpgData length]);
118 if (captureToBuffer) {
119 QBuffer data(&jpgData);
120 QImageReader reader(&data,
"JPEG");
121 QSize size = reader.size();
122 auto buffer = std::make_unique<QMemoryVideoBuffer>(
123 QByteArray(jpgData.constData(), jpgData.size()), -1);
124 QVideoFrame frame = QVideoFramePrivate::createFrame(
125 std::move(buffer), QVideoFrameFormat(size, QVideoFrameFormat::Format_Jpeg));
126 QMetaObject::invokeMethod(
this,
"imageAvailable", Qt::QueuedConnection,
127 Q_ARG(
int, request.captureId),
128 Q_ARG(QVideoFrame, frame));
131 if (f.open(QFile::WriteOnly)) {
132 if (f.write(jpgData) != -1) {
133 QMetaObject::invokeMethod(
this,
"imageSaved", Qt::QueuedConnection,
134 Q_ARG(
int, request.captureId),
135 Q_ARG(QString, fileName));
137 QMetaObject::invokeMethod(
this,
"error", Qt::QueuedConnection,
138 Q_ARG(
int, request.captureId),
139 Q_ARG(
int, QImageCapture::OutOfSpaceError),
140 Q_ARG(QString, f.errorString()));
143 QString errorMessage = tr(
"Could not open destination file:\n%1").arg(fileName);
144 QMetaObject::invokeMethod(
this,
"error", Qt::QueuedConnection,
145 Q_ARG(
int, request.captureId),
146 Q_ARG(
int, QImageCapture::ResourceError),
147 Q_ARG(QString, errorMessage));
151 const QLatin1String errorMessage(
"Image capture failed: timed out waiting"
152 " for a preview frame.");
153 qCDebug(qLcCamera) << errorMessage;
154 QMetaObject::invokeMethod(
this,
"error", Qt::QueuedConnection,
155 Q_ARG(
int, request.captureId),
156 Q_ARG(
int, QImageCapture::ResourceError),
157 Q_ARG(QString, errorMessage));
161 return request.captureId;
244 QImageEncoderSettings settings;
246 if (!videoCaptureDeviceIsValid())
249 AVCaptureDevice *captureDevice = m_service->session()->videoCaptureDevice();
250 if (!captureDevice.activeFormat) {
251 qCDebug(qLcCamera) << Q_FUNC_INFO <<
"no active format";
255 QSize res(qt_device_format_resolution(captureDevice.activeFormat));
257 if (!m_service->avfImageCaptureControl() || !m_service->avfImageCaptureControl()->stillImageOutput()) {
258 qCDebug(qLcCamera) << Q_FUNC_INFO <<
"no still image output";
262 AVCaptureStillImageOutput *stillImageOutput = m_service->avfImageCaptureControl()->stillImageOutput();
263 if (stillImageOutput.highResolutionStillImageOutputEnabled)
264 res = qt_device_format_high_resolution(captureDevice.activeFormat);
266 if (res.isNull() || !res.isValid()) {
267 qCDebug(qLcCamera) << Q_FUNC_INFO <<
"failed to exctract the image resolution";
271 settings.setResolution(res);
272 settings.setFormat(QImageCapture::JPEG);
288 if (!videoCaptureDeviceIsValid())
295 if (!m_service->imageCapture()
297 qCDebug(qLcCamera) << Q_FUNC_INFO <<
"no still image output";
301 if (m_settings.format() != QImageCapture::UnspecifiedFormat && m_settings.format() != QImageCapture::JPEG) {
302 qCDebug(qLcCamera) << Q_FUNC_INFO <<
"unsupported format:" << m_settings.format();
306 QSize res(m_settings.resolution());
308 qCDebug(qLcCamera) << Q_FUNC_INFO <<
"invalid resolution:" << res;
312 if (!res.isValid()) {
320 bool activeFormatChanged =
false;
322 AVCaptureDevice *captureDevice = m_service->session()->videoCaptureDevice();
323 AVCaptureDeviceFormat *match = qt_find_best_resolution_match(captureDevice, res,
324 m_service->session()->defaultCodec());
327 qCDebug(qLcCamera) << Q_FUNC_INFO <<
"unsupported resolution:" << res;
331 activeFormatChanged = qt_set_active_format(captureDevice, match,
true);
334 AVCaptureStillImageOutput *imageOutput = m_service->avfImageCaptureControl()->stillImageOutput();
335 if (res == qt_device_format_high_resolution(captureDevice.activeFormat))
336 imageOutput.highResolutionStillImageOutputEnabled = YES;
338 imageOutput.highResolutionStillImageOutputEnabled = NO;
341 return activeFormatChanged;
347 if (m_service == captureSession)
350 m_service = captureSession;
352 m_session->disconnect(
this);
354 m_cameraControl->disconnect(
this);
356 m_cameraControl =
nullptr;
357 m_videoConnection = nil;
362 connect(m_service, &AVFCameraService::cameraChanged,
this, &AVFImageCapture::onCameraChanged);
363 connect(m_session, SIGNAL(readyToConfigureConnections()), SLOT(updateCaptureConnection()));
364 connect(m_session, &AVFCameraSession::newViewfinderFrame,
365 this, &AVFImageCapture::onNewViewfinderFrame);
368 updateCaptureConnection();