Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qimagecapture.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3#include <qimagecapture.h>
4#include <private/qplatformimagecapture_p.h>
5#include <qmediametadata.h>
6#include <private/qplatformmediacapture_p.h>
7#include <private/qplatformmediaintegration_p.h>
8#include <private/qplatformmediaformatinfo_p.h>
9#include <qmediacapturesession.h>
10
11#include "private/qobject_p.h"
12#include <qcamera.h>
13#include <private/qplatformcamera_p.h>
14#include <QtCore/qdebug.h>
15#include <QtCore/qurl.h>
16#include <QtCore/qstringlist.h>
17#include <QtCore/qmetaobject.h>
18
19QT_BEGIN_NAMESPACE
20
21/*!
22 \class QImageCapture
23 \inmodule QtMultimedia
24 \ingroup multimedia
25 \ingroup multimedia_camera
26
27
28 \brief The QImageCapture class is used for the recording of media content.
29
30 The QImageCapture class is a high level images recording class.
31 It's not intended to be used alone but for accessing the media
32 recording functions of other media objects, like QCamera.
33
34 \snippet multimedia-snippets/camerasnippets.cpp Camera
35
36 \snippet multimedia-snippets/camerasnippets.cpp Camera keys
37
38 \sa QCamera
39*/
40
41class QImageCapturePrivate
42{
43 Q_DECLARE_PUBLIC(QImageCapture)
44public:
45 QCamera *camera = nullptr;
46
47 QMediaCaptureSession *captureSession = nullptr;
48 QPlatformImageCapture *control = nullptr;
49
50 QImageCapture::Error error = QImageCapture::NoError;
51 QString errorString;
52 QMediaMetaData metaData;
53
54 void _q_error(int id, int error, const QString &errorString);
55
56 void unsetError() { error = QImageCapture::NoError; errorString.clear(); }
57
58 QImageCapture *q_ptr;
59};
60
61void QImageCapturePrivate::_q_error(int id, int error, const QString &errorString)
62{
63 Q_Q(QImageCapture);
64
65 this->error = QImageCapture::Error(error);
66 this->errorString = errorString;
67
68 Q_EMIT q->errorChanged();
69 Q_EMIT q->errorOccurred(id, this->error, errorString);
70}
71
72/*!
73 Constructs a image capture object, from a \a parent, that can capture
74 individual still images produced by a camera.
75
76 You must connect both an image capture object and a QCamera to a capture
77 session to capture images.
78*/
79
80QImageCapture::QImageCapture(QObject *parent)
81 : QObject(parent), d_ptr(new QImageCapturePrivate)
82{
83 Q_D(QImageCapture);
84 d->q_ptr = this;
85
86 auto maybeControl = QPlatformMediaIntegration::instance()->createImageCapture(this);
87 if (!maybeControl) {
88 qWarning() << "Failed to initialize QImageCapture" << maybeControl.error();
89 d->errorString = maybeControl.error();
90 d->error = NotReadyError;
91 return;
92 }
93
94 d->control = maybeControl.value();
95 connect(d->control, &QPlatformImageCapture::imageExposed, this, &QImageCapture::imageExposed);
96 connect(d->control, &QPlatformImageCapture::imageCaptured, this, &QImageCapture::imageCaptured);
97 connect(d->control, &QPlatformImageCapture::imageMetadataAvailable, this,
98 &QImageCapture::imageMetadataAvailable);
99 connect(d->control, &QPlatformImageCapture::imageAvailable, this,
100 &QImageCapture::imageAvailable);
101 connect(d->control, &QPlatformImageCapture::imageSaved, this, &QImageCapture::imageSaved);
102 connect(d->control, &QPlatformImageCapture::readyForCaptureChanged, this,
103 &QImageCapture::readyForCaptureChanged);
104 connect(d->control, SIGNAL(error(int,int,QString)),
105 this, SLOT(_q_error(int,int,QString)));
106}
107
108/*!
109 \fn void QImageCapture::imageMetadataAvailable(int id, const QMediaMetaData &metaData)
110
111 Signals that an image identified by \a id has \a metaData.
112*/
113
114/*!
115 \internal
116*/
117void QImageCapture::setCaptureSession(QMediaCaptureSession *session)
118{
119 Q_D(QImageCapture);
120 d->captureSession = session;
121}
122
123/*!
124 Destroys images capture object.
125*/
126
127QImageCapture::~QImageCapture()
128{
129 if (d_ptr->captureSession)
130 d_ptr->captureSession->setImageCapture(nullptr);
131 delete d_ptr;
132}
133
134/*!
135 Returns true if the images capture service ready to use.
136*/
137bool QImageCapture::isAvailable() const
138{
139 return d_func()->control && d_func()->captureSession && d_func()->captureSession->camera();
140}
141
142/*!
143 Returns the capture session this camera is connected to, or
144 a nullptr if the camera is not connected to a capture session.
145
146 Use QMediaCaptureSession::setImageCapture() to connect the image capture to
147 a session.
148*/
149QMediaCaptureSession *QImageCapture::captureSession() const
150{
151 return d_ptr->captureSession;
152}
153
154/*!
155 \qmlproperty enumeration QtMultimedia::ImageCapture::error
156
157 This property holds the last error type that occurred. It can be one of the following.
158
159 \value ImageCapture.NoError No esrrors.
160 \value ImageCapture.NotReadyError The service is not ready for capture yet.
161 \value ImageCapture.ResourceError Device is not ready or not available.
162 \value ImageCapture.OutOfSpaceError No space left on device.
163 \value ImageCapture.NotSupportedFeatureError Device does not support stillimages capture.
164 \value ImageCapture.FormatError Current format is not supported.
165
166 \sa errorString
167*/
168
169/*!
170 \property QImageCapture::error
171
172 Returns the current error state.
173
174 \sa errorString()
175*/
176
177QImageCapture::Error QImageCapture::error() const
178{
179 return d_func()->error;
180}
181
182/*!
183 \qmlproperty string QtMultimedia::ImageCapture::errorString
184
185 This property holds the last error message that occurred.
186
187 \sa error
188*/
189
190/*!
191 \property QImageCapture::errorString
192
193 Returns a string describing the current error state.
194
195 \sa error()
196*/
197
198QString QImageCapture::errorString() const
199{
200 return d_func()->errorString;
201}
202
203/*!
204 \qmlproperty mediaMetaData QtMultimedia::ImageCapture::metaData
205
206 This property holds the metadata that wil be embedded into the image.
207*/
208
209/*!
210 \property QImageCapture::metaData
211 \brief The meta data that will get embedded into the image.
212
213 \note Additional fields such as a time stamp or location may get added by
214 the camera back end.
215*/
216QMediaMetaData QImageCapture::metaData() const
217{
218 Q_D(const QImageCapture);
219 return d->metaData;
220}
221
222/*!
223 Replaces any existing meta data, to be embedded into the captured image,
224 with a set of \a metaData.
225*/
226void QImageCapture::setMetaData(const QMediaMetaData &metaData)
227{
228 Q_D(QImageCapture);
229 d->metaData = metaData;
230 if (d->control)
231 d->control->setMetaData(d->metaData);
232 Q_EMIT metaDataChanged();
233}
234
235/*!
236 Adds additional \a metaData to any existing meta data, that is embedded
237 into the captured image.
238*/
239void QImageCapture::addMetaData(const QMediaMetaData &metaData)
240{
241 Q_D(QImageCapture);
242 auto data = d->metaData;
243 for (auto &&[key, value] : metaData.asKeyValueRange())
244 data.insert(key, value);
245 setMetaData(data);
246}
247
248/*!
249 \property QImageCapture::readyForCapture
250
251 Holds \c true if the camera is ready to capture an image immediately.
252 Calling capture() while \c readyForCapture is \c false is not
253 permitted and results in an error.
254*/
255bool QImageCapture::isReadyForCapture() const
256{
257 Q_D(const QImageCapture);
258 if (!d->control || !d->captureSession || !d->control->isReadyForCapture())
259 return false;
260 auto *camera = d->captureSession->camera();
261 if (!camera || !camera->isActive())
262 return false;
263 return true;
264}
265
266/*!
267 \fn QImageCapture::readyForCaptureChanged(bool ready)
268
269 Signals that a camera's \a ready for capture state has changed.
270*/
271
272
273/*!
274 Capture the image and save it to \a file.
275 This operation is asynchronous in majority of cases,
276 followed by signals QImageCapture::imageExposed(),
277 QImageCapture::imageCaptured(), QImageCapture::imageSaved()
278 or QImageCapture::error().
279
280 If an empty \a file is passed, the camera back end chooses
281 the default location and naming scheme for photos on the system,
282 if only file name without full path is specified, the image will be saved to
283 the default directory, with a full path reported with imageCaptured() and imageSaved() signals.
284
285 QCamera saves all the capture parameters like exposure settings or
286 image processing parameters, so changes to camera parameters after
287 capture() is called do not affect previous capture requests.
288
289 QImageCapture::capture returns the capture Id parameter, used with
290 imageExposed(), imageCaptured() and imageSaved() signals.
291
292 \sa isReadyForCapture()
293*/
294int QImageCapture::captureToFile(const QString &file)
295{
296 Q_D(QImageCapture);
297 if (!d->control) {
298 d->_q_error(-1, d->error, d->errorString);
299 return -1;
300 }
301
302 d->unsetError();
303
304 if (!isReadyForCapture()) {
305 d->_q_error(-1, NotReadyError, tr("Could not capture in stopped state"));
306 return -1;
307 }
308
309 return d->control->capture(file);
310}
311
312/*!
313 Capture the image and make it available as a QImage.
314 This operation is asynchronous in majority of cases,
315 followed by signals QImageCapture::imageExposed(),
316 QImageCapture::imageCaptured()
317 or QImageCapture::error().
318
319 QImageCapture::capture returns the capture Id parameter, used with
320 imageExposed(), imageCaptured() and imageSaved() signals.
321
322 \sa isReadyForCapture()
323*/
324int QImageCapture::capture()
325{
326 Q_D(QImageCapture);
327 if (!d->control) {
328 d->_q_error(-1, d->error, d->errorString);
329 return -1;
330 } else {
331 d->unsetError();
332 return d->control->captureToBuffer();
333 }
334}
335
336/*!
337 \enum QImageCapture::Error
338
339 \value NoError No Errors.
340 \value NotReadyError The service is not ready for capture yet.
341 \value ResourceError Device is not ready or not available.
342 \value OutOfSpaceError No space left on device.
343 \value NotSupportedFeatureError Device does not support stillimages capture.
344 \value FormatError Current format is not supported.
345*/
346
347/*!
348 \fn QImageCapture::errorOccurred(int id, QImageCapture::Error error, const QString &errorString);
349
350 Signals that the capture request \a id has failed with an \a error
351 and \a errorString description.
352*/
353
354/*!
355 \fn QImageCapture::imageExposed(int id)
356
357 Signal emitted when the frame with request \a id was exposed.
358*/
359
360/*!
361 \fn QImageCapture::imageCaptured(int id, const QImage &preview);
362
363 Signal emitted when the frame with request \a id was captured, but not
364 processed and saved yet. Frame \a preview can be displayed to user.
365*/
366
367/*!
368 \fn QImageCapture::imageAvailable(int id, const QVideoFrame &frame)
369
370 Signal emitted when the \a frame with request \a id is available.
371*/
372
373/*!
374 \fn QImageCapture::imageSaved(int id, const QString &fileName)
375
376 Signal emitted when QImageCapture::CaptureToFile is set and
377 the frame with request \a id was saved to \a fileName.
378*/
379
380/*!
381 \enum QImageCapture::FileFormat
382
383 Choose one of the following image formats:
384
385 \value UnspecifiedFormat No format specified
386 \value JPEG \c .jpg or \c .jpeg format
387 \value PNG \c .png format
388 \value WebP \c .webp format
389 \value Tiff \c .tiff format
390 \omitvalue LastFileFormat
391*/
392
393/*!
394 \qmlproperty enumeration QtMultimedia::ImageCapture::fileFormat
395
396 This property holds the file format for which the image will be
397 written. It can be one of the following.
398
399 \value UnspecifiedFormat No format specified
400 \value JPEG \c .jpg or \c .jpeg format
401 \value PNG \c .png format
402 \value WebP \c .webp format
403 \value Tiff \c .tiff format
404*/
405
406/*!
407 \property QImageCapture::fileFormat
408 \brief The image format.
409*/
410
411QImageCapture::FileFormat QImageCapture::fileFormat() const
412{
413 Q_D(const QImageCapture);
414 return d->control ? d->control->imageSettings().format() : UnspecifiedFormat;
415}
416
417/*!
418 Sets the image \a format.
419
420 Assigning an unsupported \l FileFormat has no effect.
421
422 \sa supportedFormats
423*/
424void QImageCapture::setFileFormat(QImageCapture::FileFormat format)
425{
426 Q_D(QImageCapture);
427 if (!d->control)
428 return;
429 auto fmt = d->control->imageSettings();
430 const FileFormat oldFormat = fmt.format();
431 if (oldFormat == format)
432 return;
433 fmt.setFormat(format);
434 d->control->setImageSettings(fmt);
435 // Only fire the signal if the format was applied.
436 if (oldFormat != fileFormat())
437 Q_EMIT fileFormatChanged();
438}
439
440/*!
441 \qmlproperty list<FileFormat> QtMultimedia::ImageCapture::supportedFormats
442 \since 6.10
443
444 Contains a list of supported file formats.
445
446 \sa fileFormat
447*/
448
449/*!
450 \property QImageCapture::supportedFormats
451 \brief a list of supported file formats.
452*/
453
454/*!
455 Returns a list of supported file formats.
456
457 \sa {QImageCapture::}{FileFormat}
458*/
459QList<QImageCapture::FileFormat> QImageCapture::supportedFormats()
460{
461 return QPlatformMediaIntegration::instance()->formatInfo()->imageFormats;
462}
463
464/*!
465 Returns the name of the given format, \a f.
466*/
467QString QImageCapture::fileFormatName(QImageCapture::FileFormat f)
468{
469 const char *name = nullptr;
470 switch (f) {
471 case UnspecifiedFormat:
472 name = "Unspecified image format";
473 break;
474 case JPEG:
475 name = "JPEG";
476 break;
477 case PNG:
478 name = "PNG";
479 break;
480 case WebP:
481 name = "WebP";
482 break;
483 case Tiff:
484 name = "Tiff";
485 break;
486 }
487 return QString::fromUtf8(name);
488}
489
490/*!
491 Returns the description of the given file format, \a f.
492*/
493QString QImageCapture::fileFormatDescription(QImageCapture::FileFormat f)
494{
495 const char *name = nullptr;
496 switch (f) {
497 case UnspecifiedFormat:
498 name = "Unspecified image format";
499 break;
500 case JPEG:
501 name = "JPEG";
502 break;
503 case PNG:
504 name = "PNG";
505 break;
506 case WebP:
507 name = "WebP";
508 break;
509 case Tiff:
510 name = "Tiff";
511 break;
512 }
513 return QString::fromUtf8(name);
514}
515
516/*!
517 \qmlproperty size QtMultimedia::ImageCapture::resolution
518 \since 6.13
519
520 The resolution of captured images.
521
522 An empty size (the default) lets the backend choose. When the image source is a camera,
523 a size from \l {QtMultimedia::cameraDevice::photoResolutions}{photoResolutions} makes the
524 camera capture stills at that size.
525
526 \sa QtMultimedia::cameraDevice::photoResolutions
527*/
528
529/*!
530 \property QImageCapture::resolution
531 \brief The resolution of captured images
532
533 Set this property to request a specific capture resolution.
534
535 When the image source is a camera, use a size from
536 \l {QCameraDevice::photoResolutions}{photoResolutions} to capture at a resolution the camera
537 supports natively. This might be limited based on the current
538 \l {QCamera::cameraFormat}{camera format}.
539
540 If the source cannot provide the requested resolution, the backend may use the closest
541 supported resolution, and scale the captured image to the requested size.
542
543 \sa QCameraDevice::photoResolutions, QCameraFormat
544*/
545QSize QImageCapture::resolution() const
546{
547 Q_D(const QImageCapture);
548 return d->control ? d->control->imageSettings().resolution() : QSize{};
549}
550
551/*!
552 \fn void QImageCapture::resolutionChanged()
553
554 Signals when the image resolution changes.
555*/
556
557/*!
558 Sets the requested \a resolution of captured images.
559
560 An empty QSize indicates the backend should make an optimal choice based on
561 what is available from the image source.
562*/
563void QImageCapture::setResolution(const QSize &resolution)
564{
565 Q_D(QImageCapture);
566 if (!d->control)
567 return;
568 auto fmt = d->control->imageSettings();
569 if (fmt.resolution() == resolution)
570 return;
571 fmt.setResolution(resolution);
572 d->control->setImageSettings(fmt);
573 Q_EMIT resolutionChanged();
574}
575
576/*!
577 Sets the \a width and \a height of the requested resolution of captured images.
578
579 \overload
580*/
581void QImageCapture::setResolution(int width, int height)
582{
583 setResolution(QSize(width, height));
584}
585
586/*!
587 Resets the requested resolution of captured images to the default.
588
589 \sa setResolution()
590*/
591void QImageCapture::resetResolution()
592{
593 setResolution(QSize{});
594}
595
596/*!
597 \enum QImageCapture::Quality
598
599 Enumerates quality encoding levels.
600
601 \value VeryLowQuality
602 \value LowQuality
603 \value NormalQuality
604 \value HighQuality
605 \value VeryHighQuality
606*/
607
608/*!
609 \qmlproperty enumeration QtMultimedia::ImageCapture::quality
610
611 This property holds the quality hint when storing the captured
612 image. It can be one of the following values.
613
614 \value VeryLowQuality Very low
615 \value LowQuality Low
616 \value NormalQuality Normal
617 \value HighQuality High
618 \value VeryHighQuality Very high
619*/
620
621/*!
622 \property QImageCapture::quality
623 \brief The image encoding quality.
624*/
625QImageCapture::Quality QImageCapture::quality() const
626{
627 Q_D(const QImageCapture);
628 return d->control ? d->control->imageSettings().quality() : NormalQuality;
629}
630
631/*!
632 Sets the image encoding \a quality.
633*/
634void QImageCapture::setQuality(Quality quality)
635{
636 Q_D(QImageCapture);
637 if (!d->control)
638 return;
639 auto fmt = d->control->imageSettings();
640 if (fmt.quality() == quality)
641 return;
642 fmt.setQuality(quality);
643 d->control->setImageSettings(fmt);
644 Q_EMIT qualityChanged();
645}
646
647/*!
648 \internal
649*/
650QPlatformImageCapture *QImageCapture::platformImageCapture()
651{
652 Q_D(QImageCapture);
653 return d->control;
654}
655
656QT_END_NAMESPACE
657
658#include "moc_qimagecapture.cpp"