File indexing completed on 2024-05-12 16:27:14

0001 /*
0002    SPDX-FileCopyrightText: 2020-2024 Laurent Montel <montel@kde.org>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "createvideomessagewidget.h"
0008 #include <KMessageWidget>
0009 #include <QAudioInput>
0010 #include <QCamera>
0011 #include <QCameraDevice>
0012 #include <QComboBox>
0013 #include <QHBoxLayout>
0014 #include <QLabel>
0015 #include <QMediaDevices>
0016 #include <QToolButton>
0017 #include <QVBoxLayout>
0018 #include <QVideoWidget>
0019 
0020 #include <KConfigGroup>
0021 #include <KLocalizedString>
0022 #include <KSharedConfig>
0023 #include <QDir>
0024 #include <QMediaFormat>
0025 
0026 namespace
0027 {
0028 const char myVideoGroupName[] = "Message Video";
0029 }
0030 CreateVideoMessageWidget::CreateVideoMessageWidget(QWidget *parent)
0031     : QWidget(parent)
0032     , mVideoWidget(new QVideoWidget(this))
0033     , mCamera(new QCamera(this))
0034     , mListCamera(new QComboBox(this))
0035     , mRecordButton(new QToolButton(this))
0036     , mPauseButton(new QToolButton(this))
0037     , mStopButton(new QToolButton(this))
0038     , mDurationLabel(new QLabel(this))
0039     , mMessageWidget(new KMessageWidget(this))
0040 {
0041     auto mainLayout = new QVBoxLayout(this);
0042     mainLayout->setObjectName(QStringLiteral("mainLayout"));
0043     mainLayout->setContentsMargins({});
0044 
0045     mMessageWidget->setObjectName(QStringLiteral("mMessageWidget"));
0046     mainLayout->addWidget(mMessageWidget);
0047     mMessageWidget->setVisible(false);
0048     mMessageWidget->setCloseButtonVisible(false);
0049     mMessageWidget->setMessageType(KMessageWidget::Information);
0050     mMessageWidget->setWordWrap(true);
0051 
0052     mListCamera->setObjectName(QStringLiteral("mListCamera"));
0053     mainLayout->addWidget(mListCamera);
0054 
0055     mVideoWidget->setObjectName(QStringLiteral("mVideoWidget"));
0056     mainLayout->addWidget(mVideoWidget, 1);
0057 
0058     auto hboxLayout = new QHBoxLayout;
0059     hboxLayout->setObjectName(QStringLiteral("hboxLayout"));
0060     hboxLayout->setContentsMargins({});
0061 
0062     mStopButton->setObjectName(QStringLiteral("mStopButton"));
0063     mStopButton->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-stop")));
0064     hboxLayout->addWidget(mStopButton);
0065     connect(mStopButton, &QToolButton::clicked, this, &CreateVideoMessageWidget::stop);
0066 
0067     mPauseButton->setObjectName(QStringLiteral("mPauseButton"));
0068     mPauseButton->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-pause")));
0069     hboxLayout->addWidget(mPauseButton);
0070     connect(mPauseButton, &QToolButton::clicked, this, &CreateVideoMessageWidget::pause);
0071 
0072     mRecordButton->setObjectName(QStringLiteral("mRecordButton"));
0073     mRecordButton->setIcon(QIcon::fromTheme(QStringLiteral("media-record")));
0074     hboxLayout->addWidget(mRecordButton);
0075     mRecordButton->setEnabled(false);
0076     connect(mRecordButton, &QToolButton::clicked, this, &CreateVideoMessageWidget::record);
0077 
0078     mDurationLabel->setObjectName(QStringLiteral("mDurationLabel"));
0079     hboxLayout->addWidget(mDurationLabel);
0080     mainLayout->addLayout(hboxLayout);
0081 
0082     updateCameras();
0083     setCamera(QMediaDevices::defaultVideoInput());
0084     if (QMediaDevices::defaultVideoInput().isNull()) {
0085         mRecordButton->setEnabled(false);
0086         mPauseButton->setEnabled(false);
0087     }
0088     connect(mListCamera, &QComboBox::activated, this, [this]() {
0089         setCamera(mListCamera->itemData(mListCamera->currentIndex()).value<QCameraDevice>());
0090     });
0091 }
0092 
0093 CreateVideoMessageWidget::~CreateVideoMessageWidget()
0094 {
0095     delete mTemporaryFile;
0096 }
0097 
0098 void CreateVideoMessageWidget::loadSettings()
0099 {
0100     KConfigGroup group(KSharedConfig::openConfig(), QLatin1String(myVideoGroupName));
0101     const QByteArray deviceIdentifier = group.readEntry("VideoDevice", QByteArray());
0102     if (!deviceIdentifier.isEmpty()) {
0103         for (int i = 0; i < mListCamera->count(); ++i) {
0104             const QCameraDevice videoDevice = mListCamera->itemData(i).value<QCameraDevice>();
0105             if (videoDevice.id() == deviceIdentifier) {
0106                 mListCamera->setCurrentIndex(i);
0107                 break;
0108             }
0109         }
0110     }
0111 }
0112 
0113 void CreateVideoMessageWidget::saveSettings()
0114 {
0115     KConfigGroup group(KSharedConfig::openConfig(), QLatin1String(myVideoGroupName));
0116     const auto device = mListCamera->itemData(mListCamera->currentIndex()).value<QCameraDevice>();
0117     if (!device.isNull()) {
0118         const QByteArray deviceIdentifier = device.id();
0119         group.writeEntry("VideoDevice", deviceIdentifier);
0120     }
0121 }
0122 
0123 QUrl CreateVideoMessageWidget::temporaryFilePath() const
0124 {
0125     // qDebug() << " XCCCCCCCCCCCCCCCCCCC" << mMediaRecorder->outputLocation() << " dd " << mMediaRecorder->actualLocation();
0126     return mMediaRecorder->actualLocation();
0127 }
0128 
0129 void CreateVideoMessageWidget::updateCameras()
0130 {
0131     const QList<QCameraDevice> availableCameras = QMediaDevices::videoInputs();
0132     for (const QCameraDevice &cameraDevice : availableCameras) {
0133         mListCamera->addItem(cameraDevice.description(), QVariant::fromValue(cameraDevice));
0134     }
0135 }
0136 
0137 void CreateVideoMessageWidget::setCamera(const QCameraDevice &cameraDevice)
0138 {
0139     mCamera.reset(new QCamera(cameraDevice));
0140     mCaptureSession.setCamera(mCamera.data());
0141 
0142     mAudioInput.reset(new QAudioInput);
0143     mCaptureSession.setAudioInput(mAudioInput.get());
0144 
0145     connect(mCamera.data(), &QCamera::activeChanged, this, &CreateVideoMessageWidget::updateCameraActive);
0146     connect(mCamera.data(), &QCamera::errorOccurred, this, &CreateVideoMessageWidget::displayCameraError);
0147 
0148     if (!mMediaRecorder) {
0149         mMediaRecorder.reset(new QMediaRecorder);
0150         mTemporaryFile = new QTemporaryFile(QDir::tempPath() + QLatin1String("/ruqola_XXXXXX")); // TODO fix extension
0151         mTemporaryFile->setAutoRemove(false);
0152         mTemporaryFile->open();
0153         //        QMediaFormat format;
0154         //        format.setFileFormat(QMediaFormat::FileFormat::AVI);
0155         //        mMediaRecorder->setMediaFormat(format);
0156         // Define url temporary file.
0157         mMediaRecorder->setOutputLocation(QUrl::fromLocalFile(mTemporaryFile->fileName()));
0158         // qDebug() << " store " << mTemporaryFile->fileName();
0159         mCaptureSession.setRecorder(mMediaRecorder.data());
0160         connect(mMediaRecorder.data(), &QMediaRecorder::recorderStateChanged, this,
0161                 &CreateVideoMessageWidget::updateRecorderState);
0162         connect(mMediaRecorder.data(), &QMediaRecorder::durationChanged, this,
0163                 &CreateVideoMessageWidget::updateRecordTime);
0164         connect(mMediaRecorder.data(), &QMediaRecorder::errorChanged, this,
0165                 &CreateVideoMessageWidget::displayRecorderError);
0166     }
0167     mCaptureSession.setVideoOutput(mVideoWidget);
0168     updateCameraActive(mCamera->isActive());
0169     updateRecorderState(mMediaRecorder->recorderState());
0170 
0171     mCamera->start();
0172 }
0173 
0174 void CreateVideoMessageWidget::displayCameraError()
0175 {
0176     if (mCamera->error() != QCamera::NoError) {
0177         mMessageWidget->setText(mCamera->errorString());
0178         mMessageWidget->animatedShow();
0179     }
0180 }
0181 
0182 void CreateVideoMessageWidget::updateRecorderState(QMediaRecorder::RecorderState state)
0183 {
0184     switch (state) {
0185     case QMediaRecorder::StoppedState:
0186         mRecordButton->setEnabled(true);
0187         mPauseButton->setEnabled(true);
0188         mStopButton->setEnabled(false);
0189         break;
0190     case QMediaRecorder::PausedState:
0191         mRecordButton->setEnabled(true);
0192         mPauseButton->setEnabled(false);
0193         mStopButton->setEnabled(true);
0194         break;
0195     case QMediaRecorder::RecordingState:
0196         mRecordButton->setEnabled(false);
0197         mPauseButton->setEnabled(true);
0198         mStopButton->setEnabled(true);
0199         break;
0200     }
0201 }
0202 
0203 void CreateVideoMessageWidget::updateCameraActive(bool active)
0204 {
0205     if (active) {
0206         mRecordButton->setEnabled(false);
0207         mStopButton->setEnabled(true);
0208     } else {
0209         mRecordButton->setEnabled(true);
0210         mStopButton->setEnabled(false);
0211     }
0212 }
0213 
0214 void CreateVideoMessageWidget::displayRecorderError()
0215 {
0216     if (mMediaRecorder->error() != QMediaRecorder::NoError) {
0217         mMessageWidget->setText(mMediaRecorder->errorString());
0218         mMessageWidget->animatedShow();
0219     }
0220 }
0221 
0222 void CreateVideoMessageWidget::record()
0223 {
0224     mMediaRecorder->record();
0225     updateRecordTime();
0226 }
0227 
0228 void CreateVideoMessageWidget::pause()
0229 {
0230     mMediaRecorder->pause();
0231 }
0232 
0233 void CreateVideoMessageWidget::stop()
0234 {
0235     mMediaRecorder->stop();
0236     Q_EMIT recordDone();
0237 }
0238 
0239 void CreateVideoMessageWidget::updateRecordTime()
0240 {
0241     const QString str = i18n("Recorded %1 sec", mMediaRecorder->duration() / 1000);
0242     mDurationLabel->setText(str);
0243 }
0244 
0245 #include "moc_createvideomessagewidget.cpp"