Qt 5.11 | Qt Multimedia | Camera Example | camera.cpp Example File

Qt 5.11.3 Reference Documentation

# 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);
          }
      }

      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();
          }
      }