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:GPL-EXCEPT$
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 General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29//TESTED_COMPONENT=src/multimedia
30
31#include <QtTest/QtTest>
32#include <QtGui/QImageReader>
33#include <QDebug>
34
35#include <qabstractvideosurface.h>
36#include <qcameracontrol.h>
37#include <qcameralockscontrol.h>
38#include <qcameraexposurecontrol.h>
39#include <qcameraflashcontrol.h>
40#include <qcamerafocuscontrol.h>
41#include <qcameraimagecapturecontrol.h>
42#include <qimageencodercontrol.h>
43#include <qcameraimageprocessingcontrol.h>
44#include <qcameracapturebufferformatcontrol.h>
45#include <qcameracapturedestinationcontrol.h>
46#include <qmediaservice.h>
47#include <qcamera.h>
48#include <qcamerainfo.h>
49#include <qcameraimagecapture.h>
50#include <qvideorenderercontrol.h>
51#include <private/qmediaserviceprovider_p.h>
52
53QT_USE_NAMESPACE
54
55/*
56 This is the backend conformance test.
57
58 Since it relies on platform media framework and sound hardware
59 it may be less stable.
60*/
61
62class tst_QCameraBackend: public QObject
63{
64 Q_OBJECT
65
66public slots:
67 void initTestCase();
68 void cleanupTestCase();
69
70private slots:
71#if QT_DEPRECATED_SINCE(5, 3)
72 void testAvailableDevices();
73 void testDeviceDescription();
74#endif
75 void testCameraInfo();
76 void testCtorWithDevice();
77 void testCtorWithCameraInfo();
78 void testCtorWithPosition();
79
80 void testCameraStates();
81 void testCameraStartError();
82 void testCaptureMode();
83 void testCameraCapture();
84 void testCaptureToBuffer();
85 void testCameraCaptureMetadata();
86 void testExposureCompensation();
87 void testExposureMode();
88
89 void testVideoRecording_data();
90 void testVideoRecording();
91private:
92};
93
94void tst_QCameraBackend::initTestCase()
95{
96 QCamera camera;
97 if (!camera.isAvailable())
98 QSKIP("Camera is not available");
99}
100
101void tst_QCameraBackend::cleanupTestCase()
102{
103}
104
105#if QT_DEPRECATED_SINCE(5, 3)
106void tst_QCameraBackend::testAvailableDevices()
107{
108 int deviceCount = QMediaServiceProvider::defaultServiceProvider()->devices(serviceType: QByteArray(Q_MEDIASERVICE_CAMERA)).count();
109 QCOMPARE(QCamera::availableDevices().count(), deviceCount);
110}
111
112void tst_QCameraBackend::testDeviceDescription()
113{
114 int deviceCount = QMediaServiceProvider::defaultServiceProvider()->devices(serviceType: QByteArray(Q_MEDIASERVICE_CAMERA)).count();
115
116 if (deviceCount == 0)
117 QVERIFY(QCamera::deviceDescription(QByteArray("random")).isNull());
118 else {
119 const auto devices = QCamera::availableDevices();
120 for (const QByteArray &device : devices)
121 QVERIFY(QCamera::deviceDescription(device).length() > 0);
122 }
123}
124#endif
125
126void tst_QCameraBackend::testCameraInfo()
127{
128 int deviceCount = QMediaServiceProvider::defaultServiceProvider()->devices(serviceType: QByteArray(Q_MEDIASERVICE_CAMERA)).count();
129 const QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
130 QCOMPARE(cameras.count(), deviceCount);
131 if (cameras.isEmpty()) {
132 QVERIFY(QCameraInfo::defaultCamera().isNull());
133 QSKIP("Camera selection is not supported");
134 }
135
136 for (const QCameraInfo &info : cameras) {
137 QVERIFY(!info.deviceName().isEmpty());
138 QVERIFY(!info.description().isEmpty());
139 QVERIFY(info.orientation() % 90 == 0);
140 }
141}
142
143void tst_QCameraBackend::testCtorWithDevice()
144{
145 const auto availableCameras = QCameraInfo::availableCameras();
146 if (availableCameras.isEmpty())
147 QSKIP("Camera selection not supported");
148
149 QCamera *camera = new QCamera(availableCameras.first().deviceName().toLatin1());
150 QCOMPARE(camera->error(), QCamera::NoError);
151 delete camera;
152
153 //loading non existing camera should fail
154 camera = new QCamera(QUuid::createUuid().toByteArray());
155 QCOMPARE(camera->error(), QCamera::ServiceMissingError);
156
157 delete camera;
158}
159
160void tst_QCameraBackend::testCtorWithCameraInfo()
161{
162 if (QCameraInfo::availableCameras().isEmpty())
163 QSKIP("Camera selection not supported");
164
165 {
166 QCameraInfo info = QCameraInfo::defaultCamera();
167 QCamera camera(info);
168 QCOMPARE(camera.error(), QCamera::NoError);
169 QCOMPARE(QCameraInfo(camera), info);
170 }
171 {
172 QCameraInfo info = QCameraInfo::availableCameras().first();
173 QCamera camera(info);
174 QCOMPARE(camera.error(), QCamera::NoError);
175 QCOMPARE(QCameraInfo(camera), info);
176 }
177 {
178 // loading an invalid CameraInfo should fail
179 QCamera *camera = new QCamera(QCameraInfo());
180 QCOMPARE(camera->error(), QCamera::ServiceMissingError);
181 QVERIFY(QCameraInfo(*camera).isNull());
182 delete camera;
183 }
184 {
185 // loading non existing camera should fail
186 QCamera camera(QCameraInfo(QUuid::createUuid().toByteArray()));
187 QCOMPARE(camera.error(), QCamera::ServiceMissingError);
188 QVERIFY(QCameraInfo(camera).isNull());
189 }
190}
191
192void tst_QCameraBackend::testCtorWithPosition()
193{
194 {
195 QCamera camera(QCamera::UnspecifiedPosition);
196 QCOMPARE(camera.error(), QCamera::NoError);
197 }
198 {
199 QCamera camera(QCamera::FrontFace);
200 // even if no camera is available at this position, it should not fail
201 // and load the default camera
202 QCOMPARE(camera.error(), QCamera::NoError);
203 }
204 {
205 QCamera camera(QCamera::BackFace);
206 // even if no camera is available at this position, it should not fail
207 // and load the default camera
208 QCOMPARE(camera.error(), QCamera::NoError);
209 }
210}
211
212void tst_QCameraBackend::testCameraStates()
213{
214 QCamera camera;
215 QCameraImageCapture imageCapture(&camera);
216
217 QSignalSpy errorSignal(&camera, SIGNAL(errorOccurred(QCamera::Error)));
218 QSignalSpy stateChangedSignal(&camera, SIGNAL(stateChanged(QCamera::State)));
219 QSignalSpy statusChangedSignal(&camera, SIGNAL(statusChanged(QCamera::Status)));
220
221 QCOMPARE(camera.state(), QCamera::UnloadedState);
222 QCOMPARE(camera.status(), QCamera::UnloadedStatus);
223
224 camera.load();
225 QCOMPARE(camera.state(), QCamera::LoadedState);
226 QCOMPARE(stateChangedSignal.count(), 1);
227 QCOMPARE(stateChangedSignal.last().first().value<QCamera::State>(), QCamera::LoadedState);
228 QVERIFY(stateChangedSignal.count() > 0);
229
230 QTRY_COMPARE(camera.status(), QCamera::LoadedStatus);
231 QCOMPARE(statusChangedSignal.last().first().value<QCamera::Status>(), QCamera::LoadedStatus);
232
233 camera.unload();
234 QCOMPARE(camera.state(), QCamera::UnloadedState);
235 QCOMPARE(stateChangedSignal.last().first().value<QCamera::State>(), QCamera::UnloadedState);
236 QTRY_COMPARE(camera.status(), QCamera::UnloadedStatus);
237 QCOMPARE(statusChangedSignal.last().first().value<QCamera::Status>(), QCamera::UnloadedStatus);
238
239 camera.start();
240 QCOMPARE(camera.state(), QCamera::ActiveState);
241 QCOMPARE(stateChangedSignal.last().first().value<QCamera::State>(), QCamera::ActiveState);
242 QTRY_COMPARE(camera.status(), QCamera::ActiveStatus);
243 QCOMPARE(statusChangedSignal.last().first().value<QCamera::Status>(), QCamera::ActiveStatus);
244
245 camera.stop();
246 QCOMPARE(camera.state(), QCamera::LoadedState);
247 QCOMPARE(stateChangedSignal.last().first().value<QCamera::State>(), QCamera::LoadedState);
248 QTRY_COMPARE(camera.status(), QCamera::LoadedStatus);
249 QCOMPARE(statusChangedSignal.last().first().value<QCamera::Status>(), QCamera::LoadedStatus);
250
251 camera.unload();
252 QCOMPARE(camera.state(), QCamera::UnloadedState);
253 QCOMPARE(stateChangedSignal.last().first().value<QCamera::State>(), QCamera::UnloadedState);
254 QTRY_COMPARE(camera.status(), QCamera::UnloadedStatus);
255 QCOMPARE(statusChangedSignal.last().first().value<QCamera::Status>(), QCamera::UnloadedStatus);
256
257 QCOMPARE(camera.errorString(), QString());
258 QCOMPARE(errorSignal.count(), 0);
259}
260
261void tst_QCameraBackend::testCameraStartError()
262{
263 QCamera camera1(QCameraInfo::defaultCamera());
264 QCamera camera2(QCameraInfo::defaultCamera());
265 QSignalSpy errorSpy1(&camera1, &QCamera::errorOccurred);
266 QSignalSpy errorSpy2(&camera2, &QCamera::errorOccurred);
267
268 camera1.start();
269 camera2.start();
270
271 QCOMPARE(camera1.state(), QCamera::ActiveState);
272 QTRY_COMPARE(camera1.status(), QCamera::ActiveStatus);
273 QCOMPARE(camera1.error(), QCamera::NoError);
274 QCOMPARE(camera2.state(), QCamera::UnloadedState);
275 QCOMPARE(camera2.status(), QCamera::UnloadedStatus);
276 QCOMPARE(camera2.error(), QCamera::CameraError);
277
278 QCOMPARE(errorSpy1.count(), 0);
279 QCOMPARE(errorSpy2.count(), 1);
280}
281
282void tst_QCameraBackend::testCaptureMode()
283{
284 QCamera camera;
285
286 QSignalSpy errorSignal(&camera, SIGNAL(errorOccurred(QCamera::Error)));
287 QSignalSpy stateChangedSignal(&camera, SIGNAL(stateChanged(QCamera::State)));
288 QSignalSpy captureModeSignal(&camera, SIGNAL(captureModeChanged(QCamera::CaptureModes)));
289
290 QCOMPARE(camera.captureMode(), QCamera::CaptureStillImage);
291
292 if (!camera.isCaptureModeSupported(mode: QCamera::CaptureVideo)) {
293 camera.setCaptureMode(QCamera::CaptureVideo);
294 QCOMPARE(camera.captureMode(), QCamera::CaptureStillImage);
295 QSKIP("Video capture not supported");
296 }
297
298 camera.setCaptureMode(QCamera::CaptureVideo);
299 QCOMPARE(camera.captureMode(), QCamera::CaptureVideo);
300 QTRY_COMPARE(captureModeSignal.size(), 1);
301 QCOMPARE(captureModeSignal.last().first().value<QCamera::CaptureModes>(), QCamera::CaptureVideo);
302 captureModeSignal.clear();
303
304 camera.load();
305 QTRY_COMPARE(camera.status(), QCamera::LoadedStatus);
306 //capture mode should still be video
307 QCOMPARE(camera.captureMode(), QCamera::CaptureVideo);
308
309 //it should be possible to switch capture mode in Loaded state
310 camera.setCaptureMode(QCamera::CaptureStillImage);
311 QTRY_COMPARE(captureModeSignal.size(), 1);
312 QCOMPARE(captureModeSignal.last().first().value<QCamera::CaptureModes>(), QCamera::CaptureStillImage);
313 captureModeSignal.clear();
314
315 camera.setCaptureMode(QCamera::CaptureVideo);
316 QTRY_COMPARE(captureModeSignal.size(), 1);
317 QCOMPARE(captureModeSignal.last().first().value<QCamera::CaptureModes>(), QCamera::CaptureVideo);
318 captureModeSignal.clear();
319
320 camera.start();
321 QTRY_COMPARE(camera.status(), QCamera::ActiveStatus);
322 //capture mode should still be video
323 QCOMPARE(camera.captureMode(), QCamera::CaptureVideo);
324
325 stateChangedSignal.clear();
326 //it should be possible to switch capture mode in Active state
327 camera.setCaptureMode(QCamera::CaptureStillImage);
328 //camera may leave Active status, but should return to Active
329 QTest::qWait(ms: 10); //camera may leave Active status async
330 QTRY_COMPARE(camera.status(), QCamera::ActiveStatus);
331 QCOMPARE(camera.captureMode(), QCamera::CaptureStillImage);
332 QVERIFY2(stateChangedSignal.isEmpty(), "camera should not change the state during capture mode changes");
333
334 QCOMPARE(captureModeSignal.size(), 1);
335 QCOMPARE(captureModeSignal.last().first().value<QCamera::CaptureModes>(), QCamera::CaptureStillImage);
336 captureModeSignal.clear();
337
338 camera.setCaptureMode(QCamera::CaptureVideo);
339 //camera may leave Active status, but should return to Active
340 QTest::qWait(ms: 10); //camera may leave Active status async
341 QTRY_COMPARE(camera.status(), QCamera::ActiveStatus);
342 QCOMPARE(camera.captureMode(), QCamera::CaptureVideo);
343
344 QVERIFY2(stateChangedSignal.isEmpty(), "camera should not change the state during capture mode changes");
345
346 QCOMPARE(captureModeSignal.size(), 1);
347 QCOMPARE(captureModeSignal.last().first().value<QCamera::CaptureModes>(), QCamera::CaptureVideo);
348 captureModeSignal.clear();
349
350 camera.stop();
351 QCOMPARE(camera.captureMode(), QCamera::CaptureVideo);
352 camera.unload();
353 QCOMPARE(camera.captureMode(), QCamera::CaptureVideo);
354
355 QVERIFY2(errorSignal.isEmpty(), QString("Camera error: %1").arg(camera.errorString()).toLocal8Bit());
356}
357
358void tst_QCameraBackend::testCameraCapture()
359{
360 QCamera camera;
361 QCameraImageCapture imageCapture(&camera);
362 //prevents camera to flash during the test
363 camera.exposure()->setFlashMode(QCameraExposure::FlashOff);
364
365 QVERIFY(!imageCapture.isReadyForCapture());
366
367 QSignalSpy capturedSignal(&imageCapture, SIGNAL(imageCaptured(int,QImage)));
368 QSignalSpy savedSignal(&imageCapture, SIGNAL(imageSaved(int,QString)));
369 QSignalSpy errorSignal(&imageCapture, SIGNAL(error(int,QCameraImageCapture::Error,QString)));
370
371 imageCapture.capture();
372 QTRY_COMPARE(errorSignal.size(), 1);
373 QCOMPARE(imageCapture.error(), QCameraImageCapture::NotReadyError);
374 QCOMPARE(capturedSignal.size(), 0);
375 errorSignal.clear();
376
377 camera.start();
378
379 QTRY_VERIFY(imageCapture.isReadyForCapture());
380 QCOMPARE(camera.status(), QCamera::ActiveStatus);
381 QCOMPARE(errorSignal.size(), 0);
382
383 int id = imageCapture.capture();
384
385 QTRY_VERIFY(!savedSignal.isEmpty());
386
387 QTRY_COMPARE(capturedSignal.size(), 1);
388 QCOMPARE(capturedSignal.last().first().toInt(), id);
389 QCOMPARE(errorSignal.size(), 0);
390 QCOMPARE(imageCapture.error(), QCameraImageCapture::NoError);
391
392 QCOMPARE(savedSignal.last().first().toInt(), id);
393 QString location = savedSignal.last().last().toString();
394 QVERIFY(!location.isEmpty());
395 QVERIFY(QFileInfo(location).exists());
396 QImageReader reader(location);
397 reader.setScaledSize(QSize(320,240));
398 QVERIFY(!reader.read().isNull());
399
400 QFile(location).remove();
401}
402
403
404void tst_QCameraBackend::testCaptureToBuffer()
405{
406 QCamera camera;
407 QCameraImageCapture imageCapture(&camera);
408 camera.exposure()->setFlashMode(QCameraExposure::FlashOff);
409
410 camera.load();
411
412 if (!imageCapture.isCaptureDestinationSupported(destination: QCameraImageCapture::CaptureToBuffer))
413 QSKIP("Buffer capture not supported");
414
415 QTRY_COMPARE(camera.status(), QCamera::LoadedStatus);
416
417 QVERIFY(imageCapture.isCaptureDestinationSupported(QCameraImageCapture::CaptureToFile));
418 QVERIFY(imageCapture.isCaptureDestinationSupported(QCameraImageCapture::CaptureToBuffer));
419 QVERIFY(imageCapture.isCaptureDestinationSupported(
420 QCameraImageCapture::CaptureToBuffer | QCameraImageCapture::CaptureToFile));
421
422 QSignalSpy destinationChangedSignal(&imageCapture, SIGNAL(captureDestinationChanged(QCameraImageCapture::CaptureDestinations)));
423
424 QCOMPARE(imageCapture.captureDestination(), QCameraImageCapture::CaptureToFile);
425 imageCapture.setCaptureDestination(QCameraImageCapture::CaptureToBuffer);
426 QCOMPARE(imageCapture.captureDestination(), QCameraImageCapture::CaptureToBuffer);
427 QCOMPARE(destinationChangedSignal.size(), 1);
428 QCOMPARE(destinationChangedSignal.first().first().value<QCameraImageCapture::CaptureDestinations>(),
429 QCameraImageCapture::CaptureToBuffer);
430
431 QSignalSpy capturedSignal(&imageCapture, SIGNAL(imageCaptured(int,QImage)));
432 QSignalSpy imageAvailableSignal(&imageCapture, SIGNAL(imageAvailable(int,QVideoFrame)));
433 QSignalSpy savedSignal(&imageCapture, SIGNAL(imageSaved(int,QString)));
434 QSignalSpy errorSignal(&imageCapture, SIGNAL(error(int,QCameraImageCapture::Error,QString)));
435
436 camera.start();
437 QTRY_VERIFY(imageCapture.isReadyForCapture());
438
439 int id = imageCapture.capture();
440 QTRY_VERIFY(!imageAvailableSignal.isEmpty());
441
442 QVERIFY(errorSignal.isEmpty());
443 QTRY_VERIFY(!capturedSignal.isEmpty());
444 QVERIFY(!imageAvailableSignal.isEmpty());
445
446 QTest::qWait(ms: 2000);
447 QVERIFY(savedSignal.isEmpty());
448
449 QCOMPARE(capturedSignal.first().first().toInt(), id);
450 QCOMPARE(imageAvailableSignal.first().first().toInt(), id);
451
452 QVideoFrame frame = imageAvailableSignal.first().last().value<QVideoFrame>();
453 QVERIFY(!frame.image().isNull());
454
455 frame = QVideoFrame();
456 capturedSignal.clear();
457 imageAvailableSignal.clear();
458 savedSignal.clear();
459
460 if (imageCapture.supportedBufferFormats().contains(t: QVideoFrame::Format_UYVY)) {
461 imageCapture.setBufferFormat(QVideoFrame::Format_UYVY);
462 QCOMPARE(imageCapture.bufferFormat(), QVideoFrame::Format_UYVY);
463
464 id = imageCapture.capture();
465 QTRY_VERIFY(!imageAvailableSignal.isEmpty());
466
467 QVERIFY(errorSignal.isEmpty());
468 QVERIFY(!capturedSignal.isEmpty());
469 QVERIFY(!imageAvailableSignal.isEmpty());
470 QVERIFY(savedSignal.isEmpty());
471
472 QTest::qWait(ms: 2000);
473 QVERIFY(savedSignal.isEmpty());
474
475 frame = imageAvailableSignal.first().last().value<QVideoFrame>();
476 QVERIFY(frame.isValid());
477
478 qDebug() << frame.pixelFormat();
479 QCOMPARE(frame.pixelFormat(), QVideoFrame::Format_UYVY);
480 QVERIFY(!frame.size().isEmpty());
481 frame = QVideoFrame();
482
483 capturedSignal.clear();
484 imageAvailableSignal.clear();
485 savedSignal.clear();
486
487 imageCapture.setBufferFormat(QVideoFrame::Format_Jpeg);
488 QCOMPARE(imageCapture.bufferFormat(), QVideoFrame::Format_Jpeg);
489 }
490
491 QTRY_VERIFY(imageCapture.isReadyForCapture());
492
493 //Try to capture to both buffer and file
494 if (imageCapture.isCaptureDestinationSupported(destination: QCameraImageCapture::CaptureToBuffer | QCameraImageCapture::CaptureToFile)) {
495 imageCapture.setCaptureDestination(QCameraImageCapture::CaptureToBuffer | QCameraImageCapture::CaptureToFile);
496
497 int oldId = id;
498 id = imageCapture.capture();
499 QVERIFY(id != oldId);
500 QTRY_VERIFY(!savedSignal.isEmpty());
501
502 QVERIFY(errorSignal.isEmpty());
503 QVERIFY(!capturedSignal.isEmpty());
504 QVERIFY(!imageAvailableSignal.isEmpty());
505 QVERIFY(!savedSignal.isEmpty());
506
507 QCOMPARE(capturedSignal.first().first().toInt(), id);
508 QCOMPARE(imageAvailableSignal.first().first().toInt(), id);
509
510 frame = imageAvailableSignal.first().last().value<QVideoFrame>();
511 QVERIFY(!frame.image().isNull());
512
513 QString fileName = savedSignal.first().last().toString();
514 QVERIFY(QFileInfo(fileName).exists());
515 }
516}
517
518void tst_QCameraBackend::testCameraCaptureMetadata()
519{
520 QSKIP("Capture metadata is supported only on harmattan");
521
522 QCamera camera;
523 QCameraImageCapture imageCapture(&camera);
524 camera.exposure()->setFlashMode(QCameraExposure::FlashOff);
525
526 QSignalSpy metadataSignal(&imageCapture, SIGNAL(imageMetadataAvailable(int,QString,QVariant)));
527 QSignalSpy savedSignal(&imageCapture, SIGNAL(imageSaved(int,QString)));
528
529 camera.start();
530
531 QTRY_VERIFY(imageCapture.isReadyForCapture());
532
533 int id = imageCapture.capture(location: QString::fromLatin1(str: "/dev/null"));
534 QTRY_VERIFY(!savedSignal.isEmpty());
535 QVERIFY(!metadataSignal.isEmpty());
536 QCOMPARE(metadataSignal.first().first().toInt(), id);
537}
538
539void tst_QCameraBackend::testExposureCompensation()
540{
541 QSKIP("Capture exposure parameters are supported only on mobile platforms");
542
543 QCamera camera;
544 QCameraExposure *exposure = camera.exposure();
545
546 QSignalSpy exposureCompensationSignal(exposure, SIGNAL(exposureCompensationChanged(qreal)));
547
548 //it should be possible to set exposure parameters in Unloaded state
549 QCOMPARE(exposure->exposureCompensation()+1.0, 1.0);
550 exposure->setExposureCompensation(1.0);
551 QCOMPARE(exposure->exposureCompensation(), 1.0);
552 QTRY_COMPARE(exposureCompensationSignal.count(), 1);
553 QCOMPARE(exposureCompensationSignal.last().first().toReal(), 1.0);
554
555 //exposureCompensationChanged should not be emitted when value is not changed
556 exposure->setExposureCompensation(1.0);
557 QTest::qWait(ms: 50);
558 QCOMPARE(exposureCompensationSignal.count(), 1);
559
560 //exposure compensation should be preserved during load/start
561 camera.load();
562 QTRY_COMPARE(camera.status(), QCamera::LoadedStatus);
563
564 QCOMPARE(exposure->exposureCompensation(), 1.0);
565
566 exposureCompensationSignal.clear();
567 exposure->setExposureCompensation(-1.0);
568 QCOMPARE(exposure->exposureCompensation(), -1.0);
569 QTRY_COMPARE(exposureCompensationSignal.count(), 1);
570 QCOMPARE(exposureCompensationSignal.last().first().toReal(), -1.0);
571
572 camera.start();
573 QTRY_COMPARE(camera.status(), QCamera::ActiveStatus);
574
575 QCOMPARE(exposure->exposureCompensation(), -1.0);
576
577 exposureCompensationSignal.clear();
578 exposure->setExposureCompensation(1.0);
579 QCOMPARE(exposure->exposureCompensation(), 1.0);
580 QTRY_COMPARE(exposureCompensationSignal.count(), 1);
581 QCOMPARE(exposureCompensationSignal.last().first().toReal(), 1.0);
582}
583
584void tst_QCameraBackend::testExposureMode()
585{
586 QSKIP("Capture exposure parameters are supported only on mobile platforms");
587
588 QCamera camera;
589 QCameraExposure *exposure = camera.exposure();
590
591 QCOMPARE(exposure->exposureMode(), QCameraExposure::ExposureAuto);
592
593 // Night
594 exposure->setExposureMode(QCameraExposure::ExposureNight);
595 QCOMPARE(exposure->exposureMode(), QCameraExposure::ExposureNight);
596 camera.start();
597 QTRY_COMPARE(camera.status(), QCamera::ActiveStatus);
598 QCOMPARE(exposure->exposureMode(), QCameraExposure::ExposureNight);
599
600 camera.unload();
601 QTRY_COMPARE(camera.status(), QCamera::UnloadedStatus);
602
603 // Auto
604 exposure->setExposureMode(QCameraExposure::ExposureAuto);
605 QCOMPARE(exposure->exposureMode(), QCameraExposure::ExposureAuto);
606 camera.start();
607 QTRY_COMPARE(camera.status(), QCamera::ActiveStatus);
608 QCOMPARE(exposure->exposureMode(), QCameraExposure::ExposureAuto);
609}
610
611void tst_QCameraBackend::testVideoRecording_data()
612{
613 QTest::addColumn<QByteArray>(name: "device");
614
615 const auto devices = QCameraInfo::availableCameras();
616
617 for (const auto &device : devices) {
618 QTest::newRow(dataTag: device.description().toUtf8())
619 << device.deviceName().toLatin1();
620 }
621
622 if (devices.isEmpty())
623 QTest::newRow(dataTag: "Default device") << QByteArray();
624}
625
626void tst_QCameraBackend::testVideoRecording()
627{
628 QFETCH(QByteArray, device);
629
630 QScopedPointer<QCamera> camera(device.isEmpty() ? new QCamera : new QCamera(device));
631
632 QMediaRecorder recorder(camera.data());
633
634 QSignalSpy errorSignal(camera.data(), SIGNAL(errorOccurred(QCamera::Error)));
635 QSignalSpy recorderErrorSignal(&recorder, SIGNAL(error(QMediaRecorder::Error)));
636 QSignalSpy recorderStatusSignal(&recorder, SIGNAL(statusChanged(QMediaRecorder::Status)));
637
638 if (!camera->isCaptureModeSupported(mode: QCamera::CaptureVideo)) {
639 QSKIP("Video capture not supported");
640 }
641
642 camera->setCaptureMode(QCamera::CaptureVideo);
643
644 QVideoEncoderSettings videoSettings;
645 videoSettings.setResolution(width: 320, height: 240);
646 recorder.setVideoSettings(videoSettings);
647
648 QCOMPARE(recorder.status(), QMediaRecorder::UnloadedStatus);
649
650 camera->start();
651 QVERIFY(recorder.status() == QMediaRecorder::LoadingStatus ||
652 recorder.status() == QMediaRecorder::LoadedStatus);
653 QCOMPARE(recorderStatusSignal.last().first().value<QMediaRecorder::Status>(), recorder.status());
654 QTRY_COMPARE(camera->status(), QCamera::ActiveStatus);
655 QTRY_COMPARE(recorder.status(), QMediaRecorder::LoadedStatus);
656 QCOMPARE(recorderStatusSignal.last().first().value<QMediaRecorder::Status>(), recorder.status());
657
658 //record 5 seconds clip
659 recorder.record();
660 QTRY_COMPARE(recorder.status(), QMediaRecorder::RecordingStatus);
661 QCOMPARE(recorderStatusSignal.last().first().value<QMediaRecorder::Status>(), recorder.status());
662 QTest::qWait(ms: 5000);
663 recorderStatusSignal.clear();
664 recorder.stop();
665 bool foundFinalizingStatus = false;
666 for (auto &list : recorderStatusSignal) {
667 if (list.contains(t: QVariant(QMediaRecorder::FinalizingStatus))) {
668 foundFinalizingStatus = true;
669 break;
670 }
671 }
672 QVERIFY(foundFinalizingStatus);
673 QTRY_COMPARE(recorder.status(), QMediaRecorder::LoadedStatus);
674 QCOMPARE(recorderStatusSignal.last().first().value<QMediaRecorder::Status>(), recorder.status());
675
676 QVERIFY(errorSignal.isEmpty());
677 QVERIFY(recorderErrorSignal.isEmpty());
678
679 QString fileName = recorder.actualLocation().toLocalFile();
680 QVERIFY(!fileName.isEmpty());
681
682 QVERIFY(QFileInfo(fileName).size() > 0);
683 QFile(fileName).remove();
684
685 camera->setCaptureMode(QCamera::CaptureStillImage);
686 QTRY_COMPARE(recorder.status(), QMediaRecorder::UnloadedStatus);
687 QCOMPARE(recorderStatusSignal.last().first().value<QMediaRecorder::Status>(), recorder.status());
688}
689
690QTEST_MAIN(tst_QCameraBackend)
691
692#include "tst_qcamerabackend.moc"
693

source code of qtmultimedia/tests/auto/integration/qcamerabackend/tst_qcamerabackend.cpp