diff options
Diffstat (limited to 'examples/multimedia/camera/camera.cpp')
-rw-r--r-- | examples/multimedia/camera/camera.cpp | 421 |
1 files changed, 421 insertions, 0 deletions
diff --git a/examples/multimedia/camera/camera.cpp b/examples/multimedia/camera/camera.cpp new file mode 100644 index 000000000..c5aa19e2d --- /dev/null +++ b/examples/multimedia/camera/camera.cpp @@ -0,0 +1,421 @@ +// Copyright (C) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include "camera.h" +#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) +# include "ui_camera_mobile.h" +#else +# include "ui_camera.h" +#endif + +#include "imagesettings.h" +#include "metadatadialog.h" +#include "videosettings.h" + +#include <QAudioDevice> +#include <QAudioInput> +#include <QCameraDevice> +#include <QMediaDevices> +#include <QMediaFormat> +#include <QMediaMetaData> +#include <QMediaRecorder> +#include <QVideoWidget> + +#include <QLineEdit> +#include <QMessageBox> + +#include <QAction> +#include <QActionGroup> +#include <QImage> +#include <QKeyEvent> +#include <QPalette> + +#include <QDir> +#include <QTimer> + +#if QT_CONFIG(permissions) + #include <QPermission> +#endif + +Camera::Camera() : ui(new Ui::Camera) +{ + ui->setupUi(this); + // disable all buttons by default + updateCameraActive(false); + readyForCapture(false); + ui->recordButton->setEnabled(false); + ui->pauseButton->setEnabled(false); + ui->stopButton->setEnabled(false); + ui->metaDataButton->setEnabled(false); + + // try to actually initialize camera & mic + init(); +} + +void Camera::init() +{ +#if QT_CONFIG(permissions) + // camera + QCameraPermission cameraPermission; + switch (qApp->checkPermission(cameraPermission)) { + case Qt::PermissionStatus::Undetermined: + qApp->requestPermission(cameraPermission, this, &Camera::init); + return; + case Qt::PermissionStatus::Denied: + qWarning("Camera permission is not granted!"); + return; + case Qt::PermissionStatus::Granted: + break; + } + // microphone + QMicrophonePermission microphonePermission; + switch (qApp->checkPermission(microphonePermission)) { + case Qt::PermissionStatus::Undetermined: + qApp->requestPermission(microphonePermission, this, &Camera::init); + return; + case Qt::PermissionStatus::Denied: + qWarning("Microphone permission is not granted!"); + return; + case Qt::PermissionStatus::Granted: + break; + } +#endif + + m_audioInput.reset(new QAudioInput); + m_captureSession.setAudioInput(m_audioInput.get()); + + // Camera devices: + + videoDevicesGroup = new QActionGroup(this); + videoDevicesGroup->setExclusive(true); + updateCameras(); + connect(&m_devices, &QMediaDevices::videoInputsChanged, this, &Camera::updateCameras); + + connect(videoDevicesGroup, &QActionGroup::triggered, this, &Camera::updateCameraDevice); + connect(ui->captureWidget, &QTabWidget::currentChanged, this, &Camera::updateCaptureMode); + + connect(ui->metaDataButton, &QPushButton::clicked, this, &Camera::showMetaDataDialog); + connect(ui->exposureCompensation, &QAbstractSlider::valueChanged, this, + &Camera::setExposureCompensation); + + setCamera(QMediaDevices::defaultVideoInput()); +} + +void Camera::setCamera(const QCameraDevice &cameraDevice) +{ + m_camera.reset(new QCamera(cameraDevice)); + m_captureSession.setCamera(m_camera.data()); + + connect(m_camera.data(), &QCamera::activeChanged, this, &Camera::updateCameraActive); + connect(m_camera.data(), &QCamera::errorOccurred, this, &Camera::displayCameraError); + + if (!m_mediaRecorder) { + m_mediaRecorder.reset(new QMediaRecorder); + m_captureSession.setRecorder(m_mediaRecorder.data()); + connect(m_mediaRecorder.data(), &QMediaRecorder::recorderStateChanged, this, + &Camera::updateRecorderState); + connect(m_mediaRecorder.data(), &QMediaRecorder::durationChanged, this, + &Camera::updateRecordTime); + connect(m_mediaRecorder.data(), &QMediaRecorder::errorChanged, this, + &Camera::displayRecorderError); + } + + if (!m_imageCapture) { + m_imageCapture.reset(new QImageCapture); + m_captureSession.setImageCapture(m_imageCapture.get()); + connect(m_imageCapture.get(), &QImageCapture::readyForCaptureChanged, this, + &Camera::readyForCapture); + connect(m_imageCapture.get(), &QImageCapture::imageCaptured, this, + &Camera::processCapturedImage); + connect(m_imageCapture.get(), &QImageCapture::imageSaved, this, &Camera::imageSaved); + connect(m_imageCapture.get(), &QImageCapture::errorOccurred, this, + &Camera::displayCaptureError); + } + + m_captureSession.setVideoOutput(ui->viewfinder); + + updateCameraActive(m_camera->isActive()); + updateRecorderState(m_mediaRecorder->recorderState()); + readyForCapture(m_imageCapture->isReadyForCapture()); + + updateCaptureMode(); + + m_camera->start(); +} + +void Camera::keyPressEvent(QKeyEvent *event) +{ + if (event->isAutoRepeat()) + return; + + switch (event->key()) { + case Qt::Key_CameraFocus: + displayViewfinder(); + event->accept(); + break; + case Qt::Key_Camera: + if (m_doImageCapture) { + takeImage(); + } else { + if (m_mediaRecorder->recorderState() == QMediaRecorder::RecordingState) + stop(); + else + record(); + } + event->accept(); + break; + default: + QMainWindow::keyPressEvent(event); + } +} + +void Camera::updateRecordTime() +{ + QString str = tr("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() +{ + if (m_doImageCapture) + configureImageSettings(); + else + configureVideoSettings(); +} + +void Camera::configureVideoSettings() +{ + VideoSettings settingsDialog(m_mediaRecorder.data()); + + if (settingsDialog.exec()) + settingsDialog.applySettings(); +} + +void Camera::configureImageSettings() +{ + ImageSettings settingsDialog(m_imageCapture.get()); + + if (settingsDialog.exec() == QDialog::Accepted) + settingsDialog.applyImageSettings(); +} + +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_captureSession.audioInput()->setMuted(muted); +} + +void Camera::takeImage() +{ + m_isCapturingImage = true; + m_imageCapture->captureToFile(); +} + +void Camera::displayCaptureError(int id, const QImageCapture::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(); + m_doImageCapture = (tabIndex == 0); +} + +void Camera::updateCameraActive(bool active) +{ + if (active) { + ui->actionStartCamera->setEnabled(false); + ui->actionStopCamera->setEnabled(true); + ui->captureWidget->setEnabled(true); + ui->actionSettings->setEnabled(true); + } else { + ui->actionStartCamera->setEnabled(true); + ui->actionStopCamera->setEnabled(false); + ui->captureWidget->setEnabled(false); + ui->actionSettings->setEnabled(false); + } +} + +void Camera::updateRecorderState(QMediaRecorder::RecorderState state) +{ + switch (state) { + case QMediaRecorder::StoppedState: + ui->recordButton->setEnabled(true); + ui->pauseButton->setEnabled(true); + ui->stopButton->setEnabled(false); + ui->metaDataButton->setEnabled(true); + break; + case QMediaRecorder::PausedState: + ui->recordButton->setEnabled(true); + ui->pauseButton->setEnabled(false); + ui->stopButton->setEnabled(true); + ui->metaDataButton->setEnabled(false); + break; + case QMediaRecorder::RecordingState: + ui->recordButton->setEnabled(false); + ui->pauseButton->setEnabled(true); + ui->stopButton->setEnabled(true); + ui->metaDataButton->setEnabled(false); + break; + } +} + +void Camera::setExposureCompensation(int index) +{ + m_camera->setExposureCompensation(index * 0.5); +} + +void Camera::displayRecorderError() +{ + if (m_mediaRecorder->error() != QMediaRecorder::NoError) + QMessageBox::warning(this, tr("Capture Error"), m_mediaRecorder->errorString()); +} + +void Camera::displayCameraError() +{ + if (m_camera->error() != QCamera::NoError) + QMessageBox::warning(this, tr("Camera Error"), m_camera->errorString()); +} + +void Camera::updateCameraDevice(QAction *action) +{ + setCamera(qvariant_cast<QCameraDevice>(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(); + } +} + +void Camera::updateCameras() +{ + ui->menuDevices->clear(); + const QList<QCameraDevice> availableCameras = QMediaDevices::videoInputs(); + for (const QCameraDevice &cameraDevice : availableCameras) { + QAction *videoDeviceAction = new QAction(cameraDevice.description(), videoDevicesGroup); + videoDeviceAction->setCheckable(true); + videoDeviceAction->setData(QVariant::fromValue(cameraDevice)); + if (cameraDevice == QMediaDevices::defaultVideoInput()) + videoDeviceAction->setChecked(true); + + ui->menuDevices->addAction(videoDeviceAction); + } +} + +void Camera::showMetaDataDialog() +{ + if (!m_metaDataDialog) + m_metaDataDialog = new MetaDataDialog(this); + m_metaDataDialog->setAttribute(Qt::WA_DeleteOnClose, false); + if (m_metaDataDialog->exec() == QDialog::Accepted) + saveMetaData(); +} + +void Camera::saveMetaData() +{ + QMediaMetaData data; + for (int i = 0; i < QMediaMetaData::NumMetaData; i++) { + QString val = m_metaDataDialog->m_metaDataFields[i]->text(); + if (!val.isEmpty()) { + const auto key = static_cast<QMediaMetaData::Key>(i); + switch (key) { + case QMediaMetaData::CoverArtImage: { + QImage coverArt(val); + data.insert(key, coverArt); + break; + } + case QMediaMetaData::ThumbnailImage: { + QImage thumbnail(val); + data.insert(key, thumbnail); + break; + } + case QMediaMetaData::Date: { + QDateTime date = QDateTime::fromString(val); + data.insert(key, date); + break; + } + case QMediaMetaData::HasHdrContent: + break; + default: + data.insert(key, val); + } + } + } + m_mediaRecorder->setMetaData(data); +} + +#include "moc_camera.cpp" |