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();
83 QString fileNameCopy = fileName;
84 [m_stillImageOutput captureStillImageAsynchronouslyFromConnection:m_videoConnection
85 completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error) {
87 QStringList messageParts;
88 messageParts << QString::fromUtf8([[error localizedDescription] UTF8String]);
89 messageParts << QString::fromUtf8([[error localizedFailureReason] UTF8String]);
90 messageParts << QString::fromUtf8([[error localizedRecoverySuggestion] UTF8String]);
92 QString errorMessage = messageParts.join(QChar(u' '));
93 qCDebug(qLcCamera) <<
"Image capture failed:" << errorMessage;
95 QMetaObject::invokeMethod(
this,
"error", Qt::QueuedConnection,
96 Q_ARG(
int, request.captureId),
97 Q_ARG(
int, QImageCapture::ResourceError),
98 Q_ARG(QString, errorMessage));
111 if (!m_session->videoOutput() || request.previewReady->tryAcquire(1, 1000)) {
112 qCDebug(qLcCamera) <<
"Image capture completed";
114 NSData *nsJpgData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
115 QByteArray jpgData = QByteArray::fromRawData((
const char *)[nsJpgData bytes], [nsJpgData length]);
117 if (captureToBuffer) {
118 QBuffer data(&jpgData);
119 QImageReader reader(&data,
"JPEG");
120 QSize size = reader.size();
121 auto buffer = std::make_unique<QMemoryVideoBuffer>(
122 QByteArray(jpgData.constData(), jpgData.size()), -1);
123 QVideoFrame frame = QVideoFramePrivate::createFrame(
124 std::move(buffer), QVideoFrameFormat(size, QVideoFrameFormat::Format_Jpeg));
125 QMetaObject::invokeMethod(
this,
"imageAvailable", Qt::QueuedConnection,
126 Q_ARG(
int, request.captureId),
127 Q_ARG(QVideoFrame, frame));
129 QFile f(fileNameCopy);
130 if (f.open(QFile::WriteOnly)) {
131 if (f.write(jpgData) != -1) {
132 QMetaObject::invokeMethod(
this,
"imageSaved", Qt::QueuedConnection,
133 Q_ARG(
int, request.captureId),
134 Q_ARG(QString, fileNameCopy));
136 QMetaObject::invokeMethod(
this,
"error", Qt::QueuedConnection,
137 Q_ARG(
int, request.captureId),
138 Q_ARG(
int, QImageCapture::OutOfSpaceError),
139 Q_ARG(QString, f.errorString()));
142 QString errorMessage = tr(
"Could not open destination file:\n%1").arg(fileNameCopy);
143 QMetaObject::invokeMethod(
this,
"error", Qt::QueuedConnection,
144 Q_ARG(
int, request.captureId),
145 Q_ARG(
int, QImageCapture::ResourceError),
146 Q_ARG(QString, errorMessage));
150 const QLatin1String errorMessage(
"Image capture failed: timed out waiting"
151 " for a preview frame.");
152 qCDebug(qLcCamera) << errorMessage;
153 QMetaObject::invokeMethod(
this,
"error", Qt::QueuedConnection,
154 Q_ARG(
int, request.captureId),
155 Q_ARG(
int, QImageCapture::ResourceError),
156 Q_ARG(QString, errorMessage));
160 return request.captureId;
243 QImageEncoderSettings settings;
245 if (!videoCaptureDeviceIsValid())
248 AVCaptureDevice *captureDevice = m_service
->session()->videoCaptureDevice();
249 if (!captureDevice.activeFormat) {
250 qCDebug(qLcCamera) << Q_FUNC_INFO <<
"no active format";
254 QSize res(qt_device_format_resolution(captureDevice.activeFormat));
256 if (!m_service->avfImageCaptureControl() || !m_service->avfImageCaptureControl()->stillImageOutput()) {
257 qCDebug(qLcCamera) << Q_FUNC_INFO <<
"no still image output";
261 AVCaptureStillImageOutput *stillImageOutput = m_service->avfImageCaptureControl()->stillImageOutput();
262 if (stillImageOutput.highResolutionStillImageOutputEnabled)
263 res = qt_device_format_high_resolution(captureDevice.activeFormat);
265 if (res.isNull() || !res.isValid()) {
266 qCDebug(qLcCamera) << Q_FUNC_INFO <<
"failed to exctract the image resolution";
270 settings.setResolution(res);
271 settings.setFormat(QImageCapture::JPEG);
287 if (!videoCaptureDeviceIsValid())
294 if (!m_service->imageCapture()
296 qCDebug(qLcCamera) << Q_FUNC_INFO <<
"no still image output";
300 if (m_settings.format() != QImageCapture::UnspecifiedFormat && m_settings.format() != QImageCapture::JPEG) {
301 qCDebug(qLcCamera) << Q_FUNC_INFO <<
"unsupported format:" << m_settings.format();
305 QSize res(m_settings.resolution());
307 qCDebug(qLcCamera) << Q_FUNC_INFO <<
"invalid resolution:" << res;
311 if (!res.isValid()) {
319 bool activeFormatChanged =
false;
321 AVCaptureDevice *captureDevice = m_service
->session()->videoCaptureDevice();
322 AVCaptureDeviceFormat *match = qt_find_best_resolution_match(captureDevice, res,
326 qCDebug(qLcCamera) << Q_FUNC_INFO <<
"unsupported resolution:" << res;
330 activeFormatChanged = qt_set_active_format(captureDevice, match,
true);
333 AVCaptureStillImageOutput *imageOutput = m_service->avfImageCaptureControl()->stillImageOutput();
334 if (res == qt_device_format_high_resolution(captureDevice.activeFormat))
335 imageOutput.highResolutionStillImageOutputEnabled = YES;
337 imageOutput.highResolutionStillImageOutputEnabled = NO;
340 return activeFormatChanged;
346 if (m_service == captureSession)
349 m_service = captureSession;
351 m_session->disconnect(
this);
353 m_cameraControl->disconnect(
this);
355 m_cameraControl =
nullptr;
356 m_videoConnection = nil;
361 connect(m_service, &AVFCameraService::cameraChanged,
this, &
AVFImageCapture::onCameraChanged);
362 connect(m_session, SIGNAL(readyToConfigureConnections()), SLOT(updateCaptureConnection()));
363 connect(m_session, &AVFCameraSession::newViewfinderFrame,
364 this, &AVFImageCapture::onNewViewfinderFrame);
367 updateCaptureConnection();