61 QMetaObject::invokeMethod(
this,
"error", Qt::QueuedConnection,
62 Q_ARG(
int, m_lastCaptureId),
63 Q_ARG(
int, QImageCapture::ResourceError),
64 Q_ARG(QString, QPlatformImageCapture::msgImageCaptureNotSet()));
68 QMetaObject::invokeMethod(
this,
"error", Qt::QueuedConnection,
69 Q_ARG(
int, m_lastCaptureId),
70 Q_ARG(
int, QImageCapture::NotReadyError),
71 Q_ARG(QString, QPlatformImageCapture::msgCameraNotReady()));
76 bool captureToBuffer = fileName.isEmpty();
78 CaptureRequest request = { m_lastCaptureId, QSharedPointer<QSemaphore>::create()};
79 m_requestsMutex.lock();
80 m_captureRequests.enqueue(request);
81 m_requestsMutex.unlock();
84 captureStillImageAsynchronouslyFromConnection:m_videoConnection
85 completionHandler:[=,
this](CMSampleBufferRef
89 QStringList messageParts;
90 messageParts << QString::fromUtf8([[error localizedDescription] UTF8String]);
91 messageParts << QString::fromUtf8([[error localizedFailureReason] UTF8String]);
92 messageParts << QString::fromUtf8([[error localizedRecoverySuggestion] UTF8String]);
94 QString errorMessage = messageParts.join(QChar(u' '));
95 qCDebug(qLcCamera) <<
"Image capture failed:" << errorMessage;
97 QMetaObject::invokeMethod(
this,
"error", Qt::QueuedConnection,
98 Q_ARG(
int, request.captureId),
99 Q_ARG(
int, QImageCapture::ResourceError),
100 Q_ARG(QString, errorMessage));
113 if (!m_session->videoOutput() || request.previewReady->tryAcquire(1, 1000)) {
114 qCDebug(qLcCamera) <<
"Image capture completed";
116 NSData *nsJpgData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
117 QByteArray jpgData = QByteArray::fromRawData((
const char *)[nsJpgData bytes], [nsJpgData length]);
119 if (captureToBuffer) {
120 QBuffer data(&jpgData);
121 QImageReader reader(&data,
"JPEG");
122 QSize size = reader.size();
123 auto buffer = std::make_unique<QMemoryVideoBuffer>(
124 QByteArray(jpgData.constData(), jpgData.size()), -1);
125 QVideoFrame frame = QVideoFramePrivate::createFrame(
126 std::move(buffer), QVideoFrameFormat(size, QVideoFrameFormat::Format_Jpeg));
127 QMetaObject::invokeMethod(
this,
"imageAvailable", Qt::QueuedConnection,
128 Q_ARG(
int, request.captureId),
129 Q_ARG(QVideoFrame, frame));
132 if (f.open(QFile::WriteOnly)) {
133 if (f.write(jpgData) != -1) {
134 QMetaObject::invokeMethod(
this,
"imageSaved", Qt::QueuedConnection,
135 Q_ARG(
int, request.captureId),
136 Q_ARG(QString, fileName));
138 QMetaObject::invokeMethod(
this,
"error", Qt::QueuedConnection,
139 Q_ARG(
int, request.captureId),
140 Q_ARG(
int, QImageCapture::OutOfSpaceError),
141 Q_ARG(QString, f.errorString()));
144 QString errorMessage = tr(
"Could not open destination file:\n%1").arg(fileName);
145 QMetaObject::invokeMethod(
this,
"error", Qt::QueuedConnection,
146 Q_ARG(
int, request.captureId),
147 Q_ARG(
int, QImageCapture::ResourceError),
148 Q_ARG(QString, errorMessage));
152 const QLatin1String errorMessage(
"Image capture failed: timed out waiting"
153 " for a preview frame.");
154 qCDebug(qLcCamera) << errorMessage;
155 QMetaObject::invokeMethod(
this,
"error", Qt::QueuedConnection,
156 Q_ARG(
int, request.captureId),
157 Q_ARG(
int, QImageCapture::ResourceError),
158 Q_ARG(QString, errorMessage));
162 return request.captureId;
245 QImageEncoderSettings settings;
247 if (!videoCaptureDeviceIsValid())
250 AVCaptureDevice *captureDevice = m_service
->session()->videoCaptureDevice();
251 if (!captureDevice.activeFormat) {
252 qCDebug(qLcCamera) << Q_FUNC_INFO <<
"no active format";
256 QSize res(qt_device_format_resolution(captureDevice.activeFormat));
258 if (!m_service->avfImageCaptureControl() || !m_service->avfImageCaptureControl()->stillImageOutput()) {
259 qCDebug(qLcCamera) << Q_FUNC_INFO <<
"no still image output";
263 AVCaptureStillImageOutput *stillImageOutput = m_service->avfImageCaptureControl()->stillImageOutput();
264 if (stillImageOutput.highResolutionStillImageOutputEnabled)
265 res = qt_device_format_high_resolution(captureDevice.activeFormat);
267 if (res.isNull() || !res.isValid()) {
268 qCDebug(qLcCamera) << Q_FUNC_INFO <<
"failed to exctract the image resolution";
272 settings.setResolution(res);
273 settings.setFormat(QImageCapture::JPEG);
289 if (!videoCaptureDeviceIsValid())
296 if (!m_service->imageCapture()
298 qCDebug(qLcCamera) << Q_FUNC_INFO <<
"no still image output";
302 if (m_settings.format() != QImageCapture::UnspecifiedFormat && m_settings.format() != QImageCapture::JPEG) {
303 qCDebug(qLcCamera) << Q_FUNC_INFO <<
"unsupported format:" << m_settings.format();
307 QSize res(m_settings.resolution());
309 qCDebug(qLcCamera) << Q_FUNC_INFO <<
"invalid resolution:" << res;
313 if (!res.isValid()) {
321 bool activeFormatChanged =
false;
323 AVCaptureDevice *captureDevice = m_service
->session()->videoCaptureDevice();
324 AVCaptureDeviceFormat *match = qt_find_best_resolution_match(captureDevice, res,
328 qCDebug(qLcCamera) << Q_FUNC_INFO <<
"unsupported resolution:" << res;
332 activeFormatChanged = qt_set_active_format(captureDevice, match,
true);
335 AVCaptureStillImageOutput *imageOutput = m_service->avfImageCaptureControl()->stillImageOutput();
336 if (res == qt_device_format_high_resolution(captureDevice.activeFormat))
337 imageOutput.highResolutionStillImageOutputEnabled = YES;
339 imageOutput.highResolutionStillImageOutputEnabled = NO;
342 return activeFormatChanged;
348 if (m_service == captureSession)
351 m_service = captureSession;
353 m_session->disconnect(
this);
355 m_cameraControl->disconnect(
this);
357 m_cameraControl =
nullptr;
358 m_videoConnection = nil;
363 connect(m_service, &AVFCameraService::cameraChanged,
this, &
AVFImageCapture::onCameraChanged);
364 connect(m_session, SIGNAL(readyToConfigureConnections()), SLOT(updateCaptureConnection()));
365 connect(m_session, &AVFCameraSession::newViewfinderFrame,
366 this, &AVFImageCapture::onNewViewfinderFrame);
369 updateCaptureConnection();