1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39#include <qcameraimagecapture.h>
40#include <qcameraimagecapturecontrol.h>
41#include <qmediaencodersettings.h>
42#include <qcameracapturedestinationcontrol.h>
43#include <qcameracapturebufferformatcontrol.h>
44
45#include <qimageencodercontrol.h>
46#include "qmediaobject_p.h"
47#include <qmediaservice.h>
48#include <qcamera.h>
49#include <qcameracontrol.h>
50#include <QtCore/qdebug.h>
51#include <QtCore/qurl.h>
52#include <QtCore/qstringlist.h>
53#include <QtCore/qmetaobject.h>
54
55QT_BEGIN_NAMESPACE
56
57/*!
58 \class QCameraImageCapture
59 \inmodule QtMultimedia
60 \ingroup multimedia
61 \ingroup multimedia_camera
62
63
64 \brief The QCameraImageCapture class is used for the recording of media content.
65
66 The QCameraImageCapture class is a high level images recording class.
67 It's not intended to be used alone but for accessing the media
68 recording functions of other media objects, like QCamera.
69
70 \snippet multimedia-snippets/camera.cpp Camera
71
72 \snippet multimedia-snippets/camera.cpp Camera keys
73
74 \sa QCamera
75*/
76
77/*!
78 \enum QCameraImageCapture::CaptureDestination
79
80 \value CaptureToFile Capture the image to a file.
81 \value CaptureToBuffer Capture the image to a buffer for further processing.
82*/
83
84static void qRegisterCameraImageCaptureMetaTypes()
85{
86 qRegisterMetaType<QCameraImageCapture::Error>(typeName: "QCameraImageCapture::Error");
87 qRegisterMetaType<QCameraImageCapture::CaptureDestination>(typeName: "QCameraImageCapture::CaptureDestination");
88 qRegisterMetaType<QCameraImageCapture::CaptureDestinations>(typeName: "QCameraImageCapture::CaptureDestinations");
89}
90
91Q_CONSTRUCTOR_FUNCTION(qRegisterCameraImageCaptureMetaTypes)
92
93
94class QCameraImageCapturePrivate
95{
96 Q_DECLARE_NON_CONST_PUBLIC(QCameraImageCapture)
97public:
98 QCameraImageCapturePrivate();
99
100 QMediaObject *mediaObject;
101
102 QCameraImageCaptureControl *control;
103 QImageEncoderControl *encoderControl;
104 QCameraCaptureDestinationControl *captureDestinationControl;
105 QCameraCaptureBufferFormatControl *bufferFormatControl;
106
107 QCameraImageCapture::Error error;
108 QString errorString;
109
110 void _q_error(int id, int error, const QString &errorString);
111 void _q_readyChanged(bool);
112 void _q_serviceDestroyed();
113
114 void unsetError() { error = QCameraImageCapture::NoError; errorString.clear(); }
115
116 QCameraImageCapture *q_ptr;
117};
118
119QCameraImageCapturePrivate::QCameraImageCapturePrivate():
120 mediaObject(nullptr),
121 control(nullptr),
122 encoderControl(nullptr),
123 captureDestinationControl(nullptr),
124 bufferFormatControl(nullptr),
125 error(QCameraImageCapture::NoError)
126{
127}
128
129void QCameraImageCapturePrivate::_q_error(int id, int error, const QString &errorString)
130{
131 Q_Q(QCameraImageCapture);
132
133 this->error = QCameraImageCapture::Error(error);
134 this->errorString = errorString;
135
136 emit q->error(id, error: this->error, errorString);
137}
138
139void QCameraImageCapturePrivate::_q_readyChanged(bool ready)
140{
141 Q_Q(QCameraImageCapture);
142 emit q->readyForCaptureChanged(ready);
143}
144
145void QCameraImageCapturePrivate::_q_serviceDestroyed()
146{
147 mediaObject = nullptr;
148 control = nullptr;
149 encoderControl = nullptr;
150 captureDestinationControl = nullptr;
151 bufferFormatControl = nullptr;
152}
153
154/*!
155 Constructs a media recorder which records the media produced by \a mediaObject.
156
157 The \a parent is passed to QMediaObject.
158*/
159
160QCameraImageCapture::QCameraImageCapture(QMediaObject *mediaObject, QObject *parent):
161 QObject(parent), d_ptr(new QCameraImageCapturePrivate)
162{
163 Q_D(QCameraImageCapture);
164
165 d->q_ptr = this;
166
167 if (mediaObject)
168 mediaObject->bind(this);
169}
170
171/*!
172 Destroys images capture object.
173*/
174
175QCameraImageCapture::~QCameraImageCapture()
176{
177 Q_D(QCameraImageCapture);
178
179 if (d->mediaObject)
180 d->mediaObject->unbind(this);
181
182 delete d_ptr;
183}
184
185/*!
186 \reimp
187*/
188QMediaObject *QCameraImageCapture::mediaObject() const
189{
190 return d_func()->mediaObject;
191}
192
193/*!
194 \reimp
195*/
196bool QCameraImageCapture::setMediaObject(QMediaObject *mediaObject)
197{
198 Q_D(QCameraImageCapture);
199
200 if (d->mediaObject) {
201 if (d->control) {
202 disconnect(sender: d->control, SIGNAL(imageExposed(int)),
203 receiver: this, SIGNAL(imageExposed(int)));
204 disconnect(sender: d->control, SIGNAL(imageCaptured(int,QImage)),
205 receiver: this, SIGNAL(imageCaptured(int,QImage)));
206 disconnect(sender: d->control, SIGNAL(imageAvailable(int,QVideoFrame)),
207 receiver: this, SIGNAL(imageAvailable(int,QVideoFrame)));
208 disconnect(sender: d->control, SIGNAL(imageMetadataAvailable(int,QString,QVariant)),
209 receiver: this, SIGNAL(imageMetadataAvailable(int,QString,QVariant)));
210 disconnect(sender: d->control, SIGNAL(imageSaved(int,QString)),
211 receiver: this, SIGNAL(imageSaved(int,QString)));
212 disconnect(sender: d->control, SIGNAL(readyForCaptureChanged(bool)),
213 receiver: this, SLOT(_q_readyChanged(bool)));
214 disconnect(sender: d->control, SIGNAL(error(int,int,QString)),
215 receiver: this, SLOT(_q_error(int,int,QString)));
216
217 if (d->captureDestinationControl) {
218 disconnect(sender: d->captureDestinationControl, SIGNAL(captureDestinationChanged(QCameraImageCapture::CaptureDestinations)),
219 receiver: this, SIGNAL(captureDestinationChanged(QCameraImageCapture::CaptureDestinations)));
220 }
221
222 if (d->bufferFormatControl) {
223 disconnect(sender: d->bufferFormatControl, SIGNAL(bufferFormatChanged(QVideoFrame::PixelFormat)),
224 receiver: this, SIGNAL(bufferFormatChanged(QVideoFrame::PixelFormat)));
225 }
226
227 QMediaService *service = d->mediaObject->service();
228 service->releaseControl(control: d->control);
229 if (d->encoderControl)
230 service->releaseControl(control: d->encoderControl);
231 if (d->captureDestinationControl)
232 service->releaseControl(control: d->captureDestinationControl);
233 if (d->bufferFormatControl)
234 service->releaseControl(control: d->bufferFormatControl);
235
236 disconnect(sender: service, SIGNAL(destroyed()), receiver: this, SLOT(_q_serviceDestroyed()));
237 }
238 }
239
240 d->mediaObject = mediaObject;
241
242 if (d->mediaObject) {
243 QMediaService *service = mediaObject->service();
244 if (service) {
245 d->control = qobject_cast<QCameraImageCaptureControl*>(object: service->requestControl(QCameraImageCaptureControl_iid));
246
247 if (d->control) {
248 d->encoderControl = qobject_cast<QImageEncoderControl *>(object: service->requestControl(QImageEncoderControl_iid));
249 d->captureDestinationControl = qobject_cast<QCameraCaptureDestinationControl *>(
250 object: service->requestControl(QCameraCaptureDestinationControl_iid));
251 d->bufferFormatControl = qobject_cast<QCameraCaptureBufferFormatControl *>(
252 object: service->requestControl(QCameraCaptureBufferFormatControl_iid));
253
254 connect(sender: d->control, SIGNAL(imageExposed(int)),
255 receiver: this, SIGNAL(imageExposed(int)));
256 connect(sender: d->control, SIGNAL(imageCaptured(int,QImage)),
257 receiver: this, SIGNAL(imageCaptured(int,QImage)));
258 connect(sender: d->control, SIGNAL(imageMetadataAvailable(int,QString,QVariant)),
259 receiver: this, SIGNAL(imageMetadataAvailable(int,QString,QVariant)));
260 connect(sender: d->control, SIGNAL(imageAvailable(int,QVideoFrame)),
261 receiver: this, SIGNAL(imageAvailable(int,QVideoFrame)));
262 connect(sender: d->control, SIGNAL(imageSaved(int,QString)),
263 receiver: this, SIGNAL(imageSaved(int,QString)));
264 connect(sender: d->control, SIGNAL(readyForCaptureChanged(bool)),
265 receiver: this, SLOT(_q_readyChanged(bool)));
266 connect(sender: d->control, SIGNAL(error(int,int,QString)),
267 receiver: this, SLOT(_q_error(int,int,QString)));
268
269 if (d->captureDestinationControl) {
270 connect(sender: d->captureDestinationControl, SIGNAL(captureDestinationChanged(QCameraImageCapture::CaptureDestinations)),
271 receiver: this, SIGNAL(captureDestinationChanged(QCameraImageCapture::CaptureDestinations)));
272 }
273
274 if (d->bufferFormatControl) {
275 connect(sender: d->bufferFormatControl, SIGNAL(bufferFormatChanged(QVideoFrame::PixelFormat)),
276 receiver: this, SIGNAL(bufferFormatChanged(QVideoFrame::PixelFormat)));
277 }
278
279 connect(sender: service, SIGNAL(destroyed()), receiver: this, SLOT(_q_serviceDestroyed()));
280
281 return true;
282 }
283 }
284 }
285
286 // without QCameraImageCaptureControl discard the media object
287 d->mediaObject = nullptr;
288 d->control = nullptr;
289 d->encoderControl = nullptr;
290 d->captureDestinationControl = nullptr;
291 d->bufferFormatControl = nullptr;
292
293 return false;
294}
295
296/*!
297 Returns true if the images capture service ready to use.
298*/
299bool QCameraImageCapture::isAvailable() const
300{
301 if (d_func()->control != nullptr)
302 return true;
303 else
304 return false;
305}
306
307/*!
308 Returns the availability of this functionality.
309*/
310QMultimedia::AvailabilityStatus QCameraImageCapture::availability() const
311{
312 if (d_func()->control != nullptr)
313 return QMultimedia::Available;
314 else
315 return QMultimedia::ServiceMissing;
316}
317
318/*!
319 Returns the current error state.
320
321 \sa errorString()
322*/
323
324QCameraImageCapture::Error QCameraImageCapture::error() const
325{
326 return d_func()->error;
327}
328
329/*!
330 Returns a string describing the current error state.
331
332 \sa error()
333*/
334
335QString QCameraImageCapture::errorString() const
336{
337 return d_func()->errorString;
338}
339
340
341/*!
342 Returns a list of supported image codecs.
343*/
344QStringList QCameraImageCapture::supportedImageCodecs() const
345{
346 return d_func()->encoderControl ?
347 d_func()->encoderControl->supportedImageCodecs() : QStringList();
348}
349
350/*!
351 Returns a description of an image \a codec.
352*/
353QString QCameraImageCapture::imageCodecDescription(const QString &codec) const
354{
355 return d_func()->encoderControl ?
356 d_func()->encoderControl->imageCodecDescription(codec) : QString();
357}
358
359/*!
360 Returns a list of resolutions images can be encoded at.
361
362 If non null image \a settings parameter is passed,
363 the returned list is reduced to resolution supported with partial settings like image codec or quality applied.
364
365 If the encoder supports arbitrary resolutions within the supported range,
366 *\a continuous is set to true, otherwise *\a continuous is set to false.
367
368 \sa QImageEncoderSettings::resolution()
369*/
370QList<QSize> QCameraImageCapture::supportedResolutions(const QImageEncoderSettings &settings, bool *continuous) const
371{
372 if (continuous)
373 *continuous = false;
374
375 return d_func()->encoderControl ?
376 d_func()->encoderControl->supportedResolutions(settings, continuous) : QList<QSize>();
377}
378
379/*!
380 Returns the image encoder settings being used.
381
382 \sa setEncodingSettings()
383*/
384
385QImageEncoderSettings QCameraImageCapture::encodingSettings() const
386{
387 return d_func()->encoderControl ?
388 d_func()->encoderControl->imageSettings() : QImageEncoderSettings();
389}
390
391/*!
392 Sets the image encoding \a settings.
393
394 If some parameters are not specified, or null settings are passed,
395 the encoder choose the default encoding parameters.
396
397 \sa encodingSettings()
398*/
399
400void QCameraImageCapture::setEncodingSettings(const QImageEncoderSettings &settings)
401{
402 Q_D(QCameraImageCapture);
403
404 if (d->encoderControl) {
405 QCamera *camera = qobject_cast<QCamera*>(object: d->mediaObject);
406 if (camera && camera->captureMode() == QCamera::CaptureStillImage) {
407 QMetaObject::invokeMethod(obj: camera,
408 member: "_q_preparePropertyChange",
409 type: Qt::DirectConnection,
410 Q_ARG(int, QCameraControl::ImageEncodingSettings));
411 }
412
413 d->encoderControl->setImageSettings(settings);
414 }
415}
416
417/*!
418 Returns the list of supported buffer image capture formats.
419
420 \sa bufferFormat(), setBufferFormat()
421*/
422QList<QVideoFrame::PixelFormat> QCameraImageCapture::supportedBufferFormats() const
423{
424 if (d_func()->bufferFormatControl)
425 return d_func()->bufferFormatControl->supportedBufferFormats();
426 else
427 return QList<QVideoFrame::PixelFormat>();
428}
429
430/*!
431 Returns the buffer image capture format being used.
432
433 \sa supportedBufferFormats(), setBufferFormat()
434*/
435QVideoFrame::PixelFormat QCameraImageCapture::bufferFormat() const
436{
437 if (d_func()->bufferFormatControl)
438 return d_func()->bufferFormatControl->bufferFormat();
439 else
440 return QVideoFrame::Format_Invalid;
441}
442
443/*!
444 Sets the buffer image capture \a format to be used.
445
446 \sa bufferFormat(), supportedBufferFormats(), captureDestination()
447*/
448void QCameraImageCapture::setBufferFormat(const QVideoFrame::PixelFormat format)
449{
450 if (d_func()->bufferFormatControl)
451 d_func()->bufferFormatControl->setBufferFormat(format);
452}
453
454/*!
455 Returns true if the image capture \a destination is supported; otherwise returns false.
456
457 \sa captureDestination(), setCaptureDestination()
458*/
459bool QCameraImageCapture::isCaptureDestinationSupported(QCameraImageCapture::CaptureDestinations destination) const
460{
461 if (d_func()->captureDestinationControl)
462 return d_func()->captureDestinationControl->isCaptureDestinationSupported(destination);
463 else
464 return destination == CaptureToFile;
465}
466
467/*!
468 Returns the image capture destination being used.
469
470 \sa isCaptureDestinationSupported(), setCaptureDestination()
471*/
472QCameraImageCapture::CaptureDestinations QCameraImageCapture::captureDestination() const
473{
474 if (d_func()->captureDestinationControl)
475 return d_func()->captureDestinationControl->captureDestination();
476 else
477 return CaptureToFile;
478}
479
480/*!
481 Sets the capture \a destination to be used.
482
483 \sa isCaptureDestinationSupported(), captureDestination()
484*/
485void QCameraImageCapture::setCaptureDestination(QCameraImageCapture::CaptureDestinations destination)
486{
487 Q_D(QCameraImageCapture);
488
489 if (d->captureDestinationControl)
490 d->captureDestinationControl->setCaptureDestination(destination);
491}
492
493/*!
494 \property QCameraImageCapture::readyForCapture
495 \brief whether the service is ready to capture a an image immediately.
496
497 Calling capture() while \e readyForCapture is \c false is not permitted and
498 results in an error.
499*/
500
501bool QCameraImageCapture::isReadyForCapture() const
502{
503 if (d_func()->control)
504 return d_func()->control->isReadyForCapture();
505 else
506 return false;
507}
508
509/*!
510 \fn QCameraImageCapture::readyForCaptureChanged(bool ready)
511
512 Signals that a camera's \a ready for capture state has changed.
513*/
514
515
516/*!
517 Capture the image and save it to \a file.
518 This operation is asynchronous in majority of cases,
519 followed by signals QCameraImageCapture::imageExposed(),
520 QCameraImageCapture::imageCaptured(), QCameraImageCapture::imageSaved()
521 or QCameraImageCapture::error().
522
523 If an empty \a file is passed, the camera backend choses
524 the default location and naming scheme for photos on the system,
525 if only file name without full path is specified, the image will be saved to
526 the default directory, with a full path reported with imageCaptured() and imageSaved() signals.
527
528 QCamera saves all the capture parameters like exposure settings or
529 image processing parameters, so changes to camera parameters after
530 capture() is called do not affect previous capture requests.
531
532 QCameraImageCapture::capture returns the capture Id parameter, used with
533 imageExposed(), imageCaptured() and imageSaved() signals.
534
535 \sa isReadyForCapture()
536*/
537int QCameraImageCapture::capture(const QString &file)
538{
539 Q_D(QCameraImageCapture);
540
541 d->unsetError();
542
543 if (d->control) {
544 return d->control->capture(fileName: file);
545 } else {
546 d->error = NotSupportedFeatureError;
547 d->errorString = tr(s: "Device does not support images capture.");
548
549 emit error(id: -1, error: d->error, errorString: d->errorString);
550 }
551
552 return -1;
553}
554
555/*!
556 Cancel incomplete capture requests.
557 Already captured and queused for proicessing images may be discarded.
558*/
559void QCameraImageCapture::cancelCapture()
560{
561 Q_D(QCameraImageCapture);
562
563 d->unsetError();
564
565 if (d->control) {
566 d->control->cancelCapture();
567 } else {
568 d->error = NotSupportedFeatureError;
569 d->errorString = tr(s: "Device does not support images capture.");
570
571 emit error(id: -1, error: d->error, errorString: d->errorString);
572 }
573}
574
575
576/*!
577 \enum QCameraImageCapture::Error
578
579 \value NoError No Errors.
580 \value NotReadyError The service is not ready for capture yet.
581 \value ResourceError Device is not ready or not available.
582 \value OutOfSpaceError No space left on device.
583 \value NotSupportedFeatureError Device does not support stillimages capture.
584 \value FormatError Current format is not supported.
585*/
586
587/*!
588 \enum QCameraImageCapture::DriveMode
589
590 \value SingleImageCapture Drive mode is capturing a single picture.
591*/
592
593/*!
594 \fn QCameraImageCapture::error(int id, QCameraImageCapture::Error error, const QString &errorString)
595
596 Signals that the capture request \a id has failed with an \a error
597 and \a errorString description.
598*/
599
600/*!
601 \fn QCameraImageCapture::bufferFormatChanged(QVideoFrame::PixelFormat format)
602
603 Signal emitted when the buffer \a format for the buffer image capture has changed.
604*/
605
606/*!
607 \fn QCameraImageCapture::captureDestinationChanged(CaptureDestinations destination)
608
609 Signal emitted when the capture \a destination has changed.
610*/
611
612/*!
613 \fn QCameraImageCapture::imageExposed(int id)
614
615 Signal emitted when the frame with request \a id was exposed.
616*/
617
618/*!
619 \fn QCameraImageCapture::imageCaptured(int id, const QImage &preview);
620
621 Signal emitted when QAbstractVideoSurface is used as a viewfinder and
622 the frame with request \a id was captured, but not processed and saved yet.
623 Frame \a preview can be displayed to user.
624*/
625
626/*!
627 \fn QCameraImageCapture::imageMetadataAvailable(int id, const QString &key, const QVariant &value)
628
629 Signals that a metadata for an image with request \a id is available. Also
630 includes the \a key and \a value of the metadata.
631
632 This signal is emitted between imageExposed and imageSaved signals.
633*/
634
635/*!
636 \fn QCameraImageCapture::imageAvailable(int id, const QVideoFrame &frame)
637
638 Signal emitted when QCameraImageCapture::CaptureToBuffer is set and
639 the \a frame with request \a id is available.
640*/
641
642/*!
643 \fn QCameraImageCapture::imageSaved(int id, const QString &fileName)
644
645 Signal emitted when QCameraImageCapture::CaptureToFile is set and
646 the frame with request \a id was saved to \a fileName.
647*/
648
649QT_END_NAMESPACE
650
651#include "moc_qcameraimagecapture.cpp"
652

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