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/camera.cpp Camera
35
36 \snippet multimedia-snippets/camera.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 emit q->errorChanged();
69 emit q->errorOccurred(id, error: 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(sender: d->control, signal: &QPlatformImageCapture::imageExposed, context: this, slot: &QImageCapture::imageExposed);
96 connect(sender: d->control, signal: &QPlatformImageCapture::imageCaptured, context: this, slot: &QImageCapture::imageCaptured);
97 connect(sender: d->control, signal: &QPlatformImageCapture::imageMetadataAvailable, context: this,
98 slot: &QImageCapture::imageMetadataAvailable);
99 connect(sender: d->control, signal: &QPlatformImageCapture::imageAvailable, context: this,
100 slot: &QImageCapture::imageAvailable);
101 connect(sender: d->control, signal: &QPlatformImageCapture::imageSaved, context: this, slot: &QImageCapture::imageSaved);
102 connect(sender: d->control, signal: &QPlatformImageCapture::readyForCaptureChanged, context: this,
103 slot: &QImageCapture::readyForCaptureChanged);
104 connect(sender: d->control, SIGNAL(error(int,int,QString)),
105 receiver: 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 \property QImageCapture::error
156
157 Returns the current error state.
158
159 \sa errorString()
160*/
161
162QImageCapture::Error QImageCapture::error() const
163{
164 return d_func()->error;
165}
166
167/*!
168 \property QImageCapture::errorString
169
170 Returns a string describing the current error state.
171
172 \sa error()
173*/
174
175QString QImageCapture::errorString() const
176{
177 return d_func()->errorString;
178}
179
180/*!
181 \property QImageCapture::metaData
182 \brief The meta data that will get embedded into the image.
183
184 \note Additional fields such as a time stamp or location may get added by
185 the camera back end.
186*/
187QMediaMetaData QImageCapture::metaData() const
188{
189 Q_D(const QImageCapture);
190 return d->metaData;
191}
192
193/*!
194 Replaces any existing meta data, to be embedded into the captured image,
195 with a set of \a metaData.
196*/
197void QImageCapture::setMetaData(const QMediaMetaData &metaData)
198{
199 Q_D(QImageCapture);
200 d->metaData = metaData;
201 if (d->control)
202 d->control->setMetaData(d->metaData);
203 emit metaDataChanged();
204}
205
206/*!
207 Adds additional \a metaData to any existing meta data, that is embedded
208 into the captured image.
209*/
210void QImageCapture::addMetaData(const QMediaMetaData &metaData)
211{
212 Q_D(QImageCapture);
213 auto data = d->metaData;
214 for (auto &&[key, value] : metaData.asKeyValueRange())
215 data.insert(k: key, value);
216 setMetaData(data);
217}
218
219/*!
220 \property QImageCapture::readyForCapture
221
222 Holds \c true if the camera is ready to capture an image immediately.
223 Calling capture() while \c readyForCapture is \c false is not
224 permitted and results in an error.
225*/
226bool QImageCapture::isReadyForCapture() const
227{
228 Q_D(const QImageCapture);
229 if (!d->control || !d->captureSession || !d->control->isReadyForCapture())
230 return false;
231 auto *camera = d->captureSession->camera();
232 if (!camera || !camera->isActive())
233 return false;
234 return true;
235}
236
237/*!
238 \fn QImageCapture::readyForCaptureChanged(bool ready)
239
240 Signals that a camera's \a ready for capture state has changed.
241*/
242
243
244/*!
245 Capture the image and save it to \a file.
246 This operation is asynchronous in majority of cases,
247 followed by signals QImageCapture::imageExposed(),
248 QImageCapture::imageCaptured(), QImageCapture::imageSaved()
249 or QImageCapture::error().
250
251 If an empty \a file is passed, the camera back end chooses
252 the default location and naming scheme for photos on the system,
253 if only file name without full path is specified, the image will be saved to
254 the default directory, with a full path reported with imageCaptured() and imageSaved() signals.
255
256 QCamera saves all the capture parameters like exposure settings or
257 image processing parameters, so changes to camera parameters after
258 capture() is called do not affect previous capture requests.
259
260 QImageCapture::capture returns the capture Id parameter, used with
261 imageExposed(), imageCaptured() and imageSaved() signals.
262
263 \sa isReadyForCapture()
264*/
265int QImageCapture::captureToFile(const QString &file)
266{
267 Q_D(QImageCapture);
268 if (!d->control) {
269 d->_q_error(id: -1, error: d->error, errorString: d->errorString);
270 return -1;
271 }
272
273 d->unsetError();
274
275 if (!isReadyForCapture()) {
276 d->_q_error(id: -1, error: NotReadyError, errorString: tr(s: "Could not capture in stopped state"));
277 return -1;
278 }
279
280 return d->control->capture(fileName: file);
281}
282
283/*!
284 Capture the image and make it available as a QImage.
285 This operation is asynchronous in majority of cases,
286 followed by signals QImageCapture::imageExposed(),
287 QImageCapture::imageCaptured()
288 or QImageCapture::error().
289
290 QImageCapture::capture returns the capture Id parameter, used with
291 imageExposed(), imageCaptured() and imageSaved() signals.
292
293 \sa isReadyForCapture()
294*/
295int QImageCapture::capture()
296{
297 Q_D(QImageCapture);
298 if (!d->control) {
299 d->_q_error(id: -1, error: d->error, errorString: d->errorString);
300 return -1;
301 } else {
302 d->unsetError();
303 return d->control->captureToBuffer();
304 }
305}
306
307/*!
308 \enum QImageCapture::Error
309
310 \value NoError No Errors.
311 \value NotReadyError The service is not ready for capture yet.
312 \value ResourceError Device is not ready or not available.
313 \value OutOfSpaceError No space left on device.
314 \value NotSupportedFeatureError Device does not support stillimages capture.
315 \value FormatError Current format is not supported.
316*/
317
318/*!
319 \fn QImageCapture::errorOccurred(int id, QImageCapture::Error error, const QString &errorString);
320
321 Signals that the capture request \a id has failed with an \a error
322 and \a errorString description.
323*/
324
325/*!
326 \fn QImageCapture::imageExposed(int id)
327
328 Signal emitted when the frame with request \a id was exposed.
329*/
330
331/*!
332 \fn QImageCapture::imageCaptured(int id, const QImage &preview);
333
334 Signal emitted when the frame with request \a id was captured, but not
335 processed and saved yet. Frame \a preview can be displayed to user.
336*/
337
338/*!
339 \fn QImageCapture::imageAvailable(int id, const QVideoFrame &frame)
340
341 Signal emitted when the \a frame with request \a id is available.
342*/
343
344/*!
345 \fn QImageCapture::imageSaved(int id, const QString &fileName)
346
347 Signal emitted when QImageCapture::CaptureToFile is set and
348 the frame with request \a id was saved to \a fileName.
349*/
350
351/*!
352 \enum QImageCapture::FileFormat
353
354 Choose one of the following image formats:
355
356 \value UnspecifiedFormat No format specified
357 \value JPEG \c .jpg or \c .jpeg format
358 \value PNG \c .png format
359 \value WebP \c .webp format
360 \value Tiff \c .tiff format
361 \omitvalue LastFileFormat
362*/
363
364
365/*!
366 \property QImageCapture::fileFormat
367 \brief The image format.
368*/
369
370QImageCapture::FileFormat QImageCapture::fileFormat() const
371{
372 Q_D(const QImageCapture);
373 return d->control ? d->control->imageSettings().format() : UnspecifiedFormat;
374}
375
376/*!
377 Sets the image \a format.
378
379 Assigning an unsupported \l FileFormat has no effect.
380
381 \sa supportedFormats
382*/
383void QImageCapture::setFileFormat(QImageCapture::FileFormat format)
384{
385 Q_D(QImageCapture);
386 if (!d->control)
387 return;
388 auto fmt = d->control->imageSettings();
389 const FileFormat oldFormat = fmt.format();
390 if (oldFormat == format)
391 return;
392 fmt.setFormat(format);
393 d->control->setImageSettings(fmt);
394 // Only fire the signal if the format was applied.
395 if (oldFormat != fileFormat())
396 emit fileFormatChanged();
397}
398
399/*!
400 Returns a list of supported file formats.
401
402 \sa {QImageCapture::}{FileFormat}
403*/
404QList<QImageCapture::FileFormat> QImageCapture::supportedFormats()
405{
406 return QPlatformMediaIntegration::instance()->formatInfo()->imageFormats;
407}
408
409/*!
410 Returns the name of the given format, \a f.
411*/
412QString QImageCapture::fileFormatName(QImageCapture::FileFormat f)
413{
414 const char *name = nullptr;
415 switch (f) {
416 case UnspecifiedFormat:
417 name = "Unspecified image format";
418 break;
419 case JPEG:
420 name = "JPEG";
421 break;
422 case PNG:
423 name = "PNG";
424 break;
425 case WebP:
426 name = "WebP";
427 break;
428 case Tiff:
429 name = "Tiff";
430 break;
431 }
432 return QString::fromUtf8(utf8: name);
433}
434
435/*!
436 Returns the description of the given file format, \a f.
437*/
438QString QImageCapture::fileFormatDescription(QImageCapture::FileFormat f)
439{
440 const char *name = nullptr;
441 switch (f) {
442 case UnspecifiedFormat:
443 name = "Unspecified image format";
444 break;
445 case JPEG:
446 name = "JPEG";
447 break;
448 case PNG:
449 name = "PNG";
450 break;
451 case WebP:
452 name = "WebP";
453 break;
454 case Tiff:
455 name = "Tiff";
456 break;
457 }
458 return QString::fromUtf8(utf8: name);
459}
460
461/*!
462 Returns the resolution of the encoded image.
463*/
464
465QSize QImageCapture::resolution() const
466{
467 Q_D(const QImageCapture);
468 return d->control ? d->control->imageSettings().resolution() : QSize{};
469}
470
471/*!
472 \fn void QImageCapture::resolutionChanged()
473
474 Signals when the image resolution changes.
475*/
476
477/*!
478 Sets the \a resolution of the encoded image.
479
480 An empty QSize indicates the encoder should make an optimal choice based on
481 what is available from the image source and the limitations of the codec.
482*/
483void QImageCapture::setResolution(const QSize &resolution)
484{
485 Q_D(QImageCapture);
486 if (!d->control)
487 return;
488 auto fmt = d->control->imageSettings();
489 if (fmt.resolution() == resolution)
490 return;
491 fmt.setResolution(resolution);
492 d->control->setImageSettings(fmt);
493 emit resolutionChanged();
494}
495
496/*!
497 Sets the \a width and \a height of the resolution of the encoded image.
498
499 \overload
500*/
501void QImageCapture::setResolution(int width, int height)
502{
503 setResolution(QSize(width, height));
504}
505
506/*!
507 \enum QImageCapture::Quality
508
509 Enumerates quality encoding levels.
510
511 \value VeryLowQuality
512 \value LowQuality
513 \value NormalQuality
514 \value HighQuality
515 \value VeryHighQuality
516*/
517
518/*!
519 \property QImageCapture::quality
520 \brief The image encoding quality.
521*/
522QImageCapture::Quality QImageCapture::quality() const
523{
524 Q_D(const QImageCapture);
525 return d->control ? d->control->imageSettings().quality() : NormalQuality;
526}
527
528/*!
529 Sets the image encoding \a quality.
530*/
531void QImageCapture::setQuality(Quality quality)
532{
533 Q_D(QImageCapture);
534 if (!d->control)
535 return;
536 auto fmt = d->control->imageSettings();
537 if (fmt.quality() == quality)
538 return;
539 fmt.setQuality(quality);
540 d->control->setImageSettings(fmt);
541 emit qualityChanged();
542}
543
544/*!
545 \internal
546*/
547QPlatformImageCapture *QImageCapture::platformImageCapture()
548{
549 Q_D(QImageCapture);
550 return d->control;
551}
552
553QT_END_NAMESPACE
554
555#include "moc_qimagecapture.cpp"
556

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtmultimedia/src/multimedia/camera/qimagecapture.cpp