camera.cpp Example File
multimediawidgets/camera/camera.cpp
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "camera.h"
#include "ui_camera.h"
#include "videosettings.h"
#include "imagesettings.h"
#include <QMediaService>
#include <QMediaRecorder>
#include <QCameraViewfinder>
#include <QCameraInfo>
#include <QMediaMetaData>
#include <QMessageBox>
#include <QPalette>
#include <QtWidgets>
Q_DECLARE_METATYPE(QCameraInfo )
Camera:: Camera() : ui(new Ui:: Camera)
{
ui- > setupUi(this );
//Camera devices:
QActionGroup * videoDevicesGroup = new QActionGroup (this );
videoDevicesGroup- > setExclusive(true );
const QList < QCameraInfo > availableCameras = QCameraInfo :: availableCameras();
for (const QCameraInfo & cameraInfo : availableCameras) {
QAction * videoDeviceAction = new QAction (cameraInfo. description(), videoDevicesGroup);
videoDeviceAction- > setCheckable(true );
videoDeviceAction- > setData(QVariant :: fromValue(cameraInfo));
if (cameraInfo = = QCameraInfo :: defaultCamera())
videoDeviceAction- > setChecked(true );
ui- > menuDevices- > addAction(videoDeviceAction);
}
connect(videoDevicesGroup, & QActionGroup :: triggered, this , & Camera:: updateCameraDevice);
connect(ui- > captureWidget, & QTabWidget :: currentChanged, this , & Camera:: updateCaptureMode);
setCamera(QCameraInfo :: defaultCamera());
}
void Camera:: setCamera(const QCameraInfo & cameraInfo)
{
m_camera. reset(new QCamera (cameraInfo));
connect(m_camera. data(), & QCamera :: stateChanged, this , & Camera:: updateCameraState);
connect(m_camera. data(), QOverload < QCamera :: Error> :: of(& QCamera :: error), this , & Camera:: displayCameraError);
m_mediaRecorder. reset(new QMediaRecorder (m_camera. data()));
connect(m_mediaRecorder. data(), & QMediaRecorder :: stateChanged, this , & Camera:: updateRecorderState);
m_imageCapture. reset(new QCameraImageCapture (m_camera. data()));
connect(m_mediaRecorder. data(), & QMediaRecorder :: durationChanged, this , & Camera:: updateRecordTime);
connect(m_mediaRecorder. data(), QOverload < QMediaRecorder :: Error> :: of(& QMediaRecorder :: error),
this , & Camera:: displayRecorderError);
m_mediaRecorder- > setMetaData(QMediaMetaData :: Title, QVariant (QLatin1String("Test Title" )));
connect(ui- > exposureCompensation, & QAbstractSlider :: valueChanged, this , & Camera:: setExposureCompensation);
m_camera- > setViewfinder(ui- > viewfinder);
updateCameraState(m_camera- > state());
updateLockStatus(m_camera- > lockStatus(), QCamera :: UserRequest);
updateRecorderState(m_mediaRecorder- > state());
connect(m_imageCapture. data(), & QCameraImageCapture :: readyForCaptureChanged, this , & Camera:: readyForCapture);
connect(m_imageCapture. data(), & QCameraImageCapture :: imageCaptured, this , & Camera:: processCapturedImage);
connect(m_imageCapture. data(), & QCameraImageCapture :: imageSaved, this , & Camera:: imageSaved);
connect(m_imageCapture. data(), QOverload < int , QCameraImageCapture :: Error, const QString & > :: of(& QCameraImageCapture :: error),
this , & Camera:: displayCaptureError);
connect(m_camera. data(), QOverload < QCamera :: LockStatus, QCamera :: LockChangeReason> :: of(& QCamera :: lockStatusChanged),
this , & Camera:: updateLockStatus);
ui- > captureWidget- > setTabEnabled(0 , (m_camera- > isCaptureModeSupported(QCamera :: CaptureStillImage)));
ui- > captureWidget- > setTabEnabled(1 , (m_camera- > isCaptureModeSupported(QCamera :: CaptureVideo)));
updateCaptureMode();
m_camera- > start();
}
void Camera:: keyPressEvent(QKeyEvent * event)
{
if (event- > isAutoRepeat())
return ;
switch (event- > key()) {
case Qt :: Key_CameraFocus:
displayViewfinder();
m_camera- > searchAndLock();
event- > accept();
break ;
case Qt :: Key_Camera:
if (m_camera- > captureMode() = = QCamera :: CaptureStillImage) {
takeImage();
} else {
if (m_mediaRecorder- > state() = = QMediaRecorder :: RecordingState)
stop();
else
record();
}
event- > accept();
break ;
default :
QMainWindow :: keyPressEvent(event);
}
}
void Camera:: keyReleaseEvent(QKeyEvent * event)
{
if (event- > isAutoRepeat())
return ;
switch (event- > key()) {
case Qt :: Key_CameraFocus:
m_camera- > unlock();
break ;
default :
QMainWindow :: keyReleaseEvent(event);
}
}
void Camera:: updateRecordTime()
{
QString str = QString ("Recorded %1 sec" ). arg(m_mediaRecorder- > duration()/ 1000 );
ui- > statusbar- > showMessage(str);
}
void Camera:: processCapturedImage(int requestId, const QImage & img)
{
Q_UNUSED(requestId);
QImage scaledImage = img. scaled(ui- > viewfinder- > size(),
Qt :: KeepAspectRatio,
Qt :: SmoothTransformation);
ui- > lastImagePreviewLabel- > setPixmap(QPixmap :: fromImage(scaledImage));
// Display captured image for 4 seconds.
displayCapturedImage();
QTimer :: singleShot(4000 , this , & Camera:: displayViewfinder);
}
void Camera:: configureCaptureSettings()
{
switch (m_camera- > captureMode()) {
case QCamera :: CaptureStillImage:
configureImageSettings();
break ;
case QCamera :: CaptureVideo:
configureVideoSettings();
break ;
default :
break ;
}
}
void Camera:: configureVideoSettings()
{
VideoSettings settingsDialog(m_mediaRecorder. data());
settingsDialog. setWindowFlags(settingsDialog. windowFlags() & ~ Qt :: WindowContextHelpButtonHint);
settingsDialog. setAudioSettings(m_audioSettings);
settingsDialog. setVideoSettings(m_videoSettings);
settingsDialog. setFormat(m_videoContainerFormat);
if (settingsDialog. exec()) {
m_audioSettings = settingsDialog. audioSettings();
m_videoSettings = settingsDialog. videoSettings();
m_videoContainerFormat = settingsDialog. format();
m_mediaRecorder- > setEncodingSettings(
m_audioSettings,
m_videoSettings,
m_videoContainerFormat);
m_camera- > unload();
m_camera- > start();
}
}
void Camera:: configureImageSettings()
{
ImageSettings settingsDialog(m_imageCapture. data());
settingsDialog. setWindowFlags(settingsDialog. windowFlags() & ~ Qt :: WindowContextHelpButtonHint);
settingsDialog. setImageSettings(m_imageSettings);
if (settingsDialog. exec()) {
m_imageSettings = settingsDialog. imageSettings();
m_imageCapture- > setEncodingSettings(m_imageSettings);
}
}
void Camera:: record()
{
m_mediaRecorder- > record();
updateRecordTime();
}
void Camera:: pause()
{
m_mediaRecorder- > pause();
}
void Camera:: stop()
{
m_mediaRecorder- > stop();
}
void Camera:: setMuted(bool muted)
{
m_mediaRecorder- > setMuted(muted);
}
void Camera:: toggleLock()
{
switch (m_camera- > lockStatus()) {
case QCamera :: Searching:
case QCamera :: Locked:
m_camera- > unlock();
break ;
case QCamera :: Unlocked:
m_camera- > searchAndLock();
}
}
void Camera:: updateLockStatus(QCamera :: LockStatus status, QCamera :: LockChangeReason reason)
{
QColor indicationColor = Qt :: black;
switch (status) {
case QCamera :: Searching:
indicationColor = Qt :: yellow;
ui- > statusbar- > showMessage(tr("Focusing..." ));
ui- > lockButton- > setText(tr("Focusing..." ));
break ;
case QCamera :: Locked:
indicationColor = Qt :: darkGreen;
ui- > lockButton- > setText(tr("Unlock" ));
ui- > statusbar- > showMessage(tr("Focused" ), 2000 );
break ;
case QCamera :: Unlocked:
indicationColor = reason = = QCamera :: LockFailed ? Qt :: red : Qt :: black;
ui- > lockButton- > setText(tr("Focus" ));
if (reason = = QCamera :: LockFailed)
ui- > statusbar- > showMessage(tr("Focus Failed" ), 2000 );
}
QPalette palette = ui- > lockButton- > palette();
palette. setColor(QPalette :: ButtonText, indicationColor);
ui- > lockButton- > setPalette(palette);
}
void Camera:: takeImage()
{
m_isCapturingImage = true ;
m_imageCapture- > capture();
}
void Camera:: displayCaptureError(int id, const QCameraImageCapture :: Error error, const QString & errorString)
{
Q_UNUSED(id);
Q_UNUSED(error);
QMessageBox :: warning(this , tr("Image Capture Error" ), errorString);
m_isCapturingImage = false ;
}
void Camera:: startCamera()
{
m_camera- > start();
}
void Camera:: stopCamera()
{
m_camera- > stop();
}
void Camera:: updateCaptureMode()
{
int tabIndex = ui- > captureWidget- > currentIndex();
QCamera :: CaptureModes captureMode = tabIndex = = 0 ? QCamera :: CaptureStillImage : QCamera :: CaptureVideo;
if (m_camera- > isCaptureModeSupported(captureMode))
m_camera- > setCaptureMode(captureMode);
}
void Camera:: updateCameraState(QCamera :: State state)
{
switch (state) {
case QCamera :: ActiveState:
ui- > actionStartCamera- > setEnabled(false );
ui- > actionStopCamera- > setEnabled(true );
ui- > captureWidget- > setEnabled(true );
ui- > actionSettings- > setEnabled(true );
break ;
case QCamera :: UnloadedState:
case QCamera :: LoadedState:
ui- > actionStartCamera- > setEnabled(true );
ui- > actionStopCamera- > setEnabled(false );
ui- > captureWidget- > setEnabled(false );
ui- > actionSettings- > setEnabled(false );
}
}
void Camera:: updateRecorderState(QMediaRecorder :: State state)
{
switch (state) {
case QMediaRecorder :: StoppedState:
ui- > recordButton- > setEnabled(true );
ui- > pauseButton- > setEnabled(true );
ui- > stopButton- > setEnabled(false );
break ;
case QMediaRecorder :: PausedState:
ui- > recordButton- > setEnabled(true );
ui- > pauseButton- > setEnabled(false );
ui- > stopButton- > setEnabled(true );
break ;
case QMediaRecorder :: RecordingState:
ui- > recordButton- > setEnabled(false );
ui- > pauseButton- > setEnabled(true );
ui- > stopButton- > setEnabled(true );
break ;
}
}
void Camera:: setExposureCompensation(int index)
{
m_camera- > exposure()- > setExposureCompensation(index* 0.5 );
}
void Camera:: displayRecorderError()
{
QMessageBox :: warning(this , tr("Capture Error" ), m_mediaRecorder- > errorString());
}
void Camera:: displayCameraError()
{
QMessageBox :: warning(this , tr("Camera Error" ), m_camera- > errorString());
}
void Camera:: updateCameraDevice(QAction * action)
{
setCamera(qvariant_cast< QCameraInfo > (action- > data()));
}
void Camera:: displayViewfinder()
{
ui- > stackedWidget- > setCurrentIndex(0 );
}
void Camera:: displayCapturedImage()
{
ui- > stackedWidget- > setCurrentIndex(1 );
}
void Camera:: readyForCapture(bool ready)
{
ui- > takeImageButton- > setEnabled(ready);
}
void Camera:: imageSaved(int id, const QString & fileName)
{
Q_UNUSED(id);
ui- > statusbar- > showMessage(tr("Captured \"%1\"" ). arg(QDir :: toNativeSeparators(fileName)));
m_isCapturingImage = false ;
if (m_applicationExiting)
close();
}
void Camera:: closeEvent(QCloseEvent * event)
{
if (m_isCapturingImage) {
setEnabled(false );
m_applicationExiting = true ;
event- > ignore();
} else {
event- > accept();
}
}