diff options
author | Lars Knoll <lars.knoll@qt.io> | 2021-03-05 12:15:59 +0100 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2021-03-17 09:27:36 +0000 |
commit | 625ae91bddb9f920494ac80ccc1ebe9f54a1ec2a (patch) | |
tree | 61db52ff51d7e0c7486ad48747ed59a3348da2cd /src | |
parent | c93b4b54c44ca28e34fe7e12cc2fb279f3e84b54 (diff) |
Add a QMediaEncoder class
This class is currently a simply a rename of QMediaRecorder, but
they will start to diverge in the next commits.
QMediaRecorder is now an all-in-one class, that contains
a QMediaCaptureSession and handles standard recording cases.
QMediaEncoder will in the next couple of commits loose APIs
that should be in other places in the capture pipeline.
Change-Id: Ied1098092920610dac08e966078d44a22110bcf7
Reviewed-by: Doris Verria <doris.verria@qt.io>
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/imports/multimedia/qdeclarativecamerarecorder.cpp | 104 | ||||
-rw-r--r-- | src/imports/multimedia/qdeclarativecamerarecorder_p.h | 32 | ||||
-rw-r--r-- | src/multimedia/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/multimedia/recording/qmediacapturesession.cpp | 24 | ||||
-rw-r--r-- | src/multimedia/recording/qmediacapturesession.h | 10 | ||||
-rw-r--r-- | src/multimedia/recording/qmediaencoder.cpp | 629 | ||||
-rw-r--r-- | src/multimedia/recording/qmediaencoder.h | 189 | ||||
-rw-r--r-- | src/multimedia/recording/qmediaencoder_p.h | 101 | ||||
-rw-r--r-- | src/multimedia/recording/qmediarecorder.cpp | 321 | ||||
-rw-r--r-- | src/multimedia/recording/qmediarecorder.h | 67 | ||||
-rw-r--r-- | src/multimedia/recording/qmediarecorder_p.h | 28 |
11 files changed, 1105 insertions, 401 deletions
diff --git a/src/imports/multimedia/qdeclarativecamerarecorder.cpp b/src/imports/multimedia/qdeclarativecamerarecorder.cpp index d5e49b6cf..8044230a1 100644 --- a/src/imports/multimedia/qdeclarativecamerarecorder.cpp +++ b/src/imports/multimedia/qdeclarativecamerarecorder.cpp @@ -78,17 +78,17 @@ QT_BEGIN_NAMESPACE QDeclarativeCameraRecorder::QDeclarativeCameraRecorder(QMediaCaptureSession *session, QObject *parent) : QObject(parent) { - m_recorder = new QMediaRecorder(this); - session->setRecorder(m_recorder); - connect(m_recorder, SIGNAL(stateChanged(QMediaRecorder::State)), - SLOT(updateRecorderState(QMediaRecorder::State))); - connect(m_recorder, SIGNAL(statusChanged(QMediaRecorder::Status)), + m_encoder = new QMediaEncoder(this); + session->setEncoder(m_encoder); + connect(m_encoder, SIGNAL(stateChanged(QMediaEncoder::State)), + SLOT(updateRecorderState(QMediaEncoder::State))); + connect(m_encoder, SIGNAL(statusChanged(QMediaEncoder::Status)), SIGNAL(recorderStatusChanged())); - connect(m_recorder, SIGNAL(error(QMediaRecorder::Error)), - SLOT(updateRecorderError(QMediaRecorder::Error))); - connect(m_recorder, SIGNAL(mutedChanged(bool)), SIGNAL(mutedChanged(bool))); - connect(m_recorder, SIGNAL(durationChanged(qint64)), SIGNAL(durationChanged(qint64))); - connect(m_recorder, SIGNAL(actualLocationChanged(QUrl)), + connect(m_encoder, SIGNAL(error(QMediaEncoder::Error)), + SLOT(updateRecorderError(QMediaEncoder::Error))); + connect(m_encoder, SIGNAL(mutedChanged(bool)), SIGNAL(mutedChanged(bool))); + connect(m_encoder, SIGNAL(durationChanged(qint64)), SIGNAL(durationChanged(qint64))); + connect(m_encoder, SIGNAL(actualLocationChanged(QUrl)), SLOT(updateActualLocation(QUrl))); } @@ -144,40 +144,40 @@ QMediaFormat::FileFormat QDeclarativeCameraRecorder::mediaContainer() const void QDeclarativeCameraRecorder::setCaptureResolution(const QSize &resolution) { - m_encoderSettings = m_recorder->encoderSettings(); + m_encoderSettings = m_encoder->encoderSettings(); if (resolution != captureResolution()) { m_encoderSettings.setVideoResolution(resolution); - m_recorder->setEncoderSettings(m_encoderSettings); + m_encoder->setEncoderSettings(m_encoderSettings); emit captureResolutionChanged(resolution); } } void QDeclarativeCameraRecorder::setAudioCodec(QMediaFormat::AudioCodec codec) { - m_encoderSettings = m_recorder->encoderSettings(); + m_encoderSettings = m_encoder->encoderSettings(); if (codec != audioCodec()) { m_encoderSettings.setAudioCodec(codec); - m_recorder->setEncoderSettings(m_encoderSettings); + m_encoder->setEncoderSettings(m_encoderSettings); emit audioCodecChanged(); } } void QDeclarativeCameraRecorder::setVideoCodec(QMediaFormat::VideoCodec codec) { - m_encoderSettings = m_recorder->encoderSettings(); + m_encoderSettings = m_encoder->encoderSettings(); if (codec != videoCodec()) { m_encoderSettings.setVideoCodec(codec); - m_recorder->setEncoderSettings(m_encoderSettings); + m_encoder->setEncoderSettings(m_encoderSettings); emit videoCodecChanged(); } } void QDeclarativeCameraRecorder::setMediaContainer(QMediaFormat::FileFormat container) { - m_encoderSettings = m_recorder->encoderSettings(); + m_encoderSettings = m_encoder->encoderSettings(); if (container != m_encoderSettings.format()) { m_encoderSettings.setFormat(container); - m_recorder->setEncoderSettings(m_encoderSettings); + m_encoder->setEncoderSettings(m_encoderSettings); emit mediaContainerChanged(); } } @@ -284,70 +284,70 @@ QDeclarativeCameraRecorder::EncodingMode QDeclarativeCameraRecorder::audioEncodi void QDeclarativeCameraRecorder::setFrameRate(qreal frameRate) { - m_encoderSettings = m_recorder->encoderSettings(); + m_encoderSettings = m_encoder->encoderSettings(); if (!qFuzzyCompare(m_encoderSettings.videoFrameRate(),frameRate)) { m_encoderSettings.setVideoFrameRate(frameRate); - m_recorder->setEncoderSettings(m_encoderSettings); + m_encoder->setEncoderSettings(m_encoderSettings); emit frameRateChanged(frameRate); } } void QDeclarativeCameraRecorder::setVideoBitRate(int rate) { - m_encoderSettings = m_recorder->encoderSettings(); + m_encoderSettings = m_encoder->encoderSettings(); if (m_encoderSettings.videoBitRate() != rate) { m_encoderSettings.setVideoBitRate(rate); - m_recorder->setEncoderSettings(m_encoderSettings); + m_encoder->setEncoderSettings(m_encoderSettings); emit videoBitRateChanged(rate); } } void QDeclarativeCameraRecorder::setAudioBitRate(int rate) { - m_encoderSettings = m_recorder->encoderSettings(); + m_encoderSettings = m_encoder->encoderSettings(); if (m_encoderSettings.audioBitRate() != rate) { m_encoderSettings.setAudioBitRate(rate); - m_recorder->setEncoderSettings(m_encoderSettings); + m_encoder->setEncoderSettings(m_encoderSettings); emit audioBitRateChanged(rate); } } void QDeclarativeCameraRecorder::setAudioChannels(int channels) { - m_encoderSettings = m_recorder->encoderSettings(); + m_encoderSettings = m_encoder->encoderSettings(); if (m_encoderSettings.audioChannelCount() != channels) { m_encoderSettings.setAudioChannelCount(channels); - m_recorder->setEncoderSettings(m_encoderSettings); + m_encoder->setEncoderSettings(m_encoderSettings); emit audioChannelsChanged(channels); } } void QDeclarativeCameraRecorder::setAudioSampleRate(int rate) { - m_encoderSettings = m_recorder->encoderSettings(); + m_encoderSettings = m_encoder->encoderSettings(); if (m_encoderSettings.audioSampleRate() != rate) { m_encoderSettings.setAudioSampleRate(rate); - m_recorder->setEncoderSettings(m_encoderSettings); + m_encoder->setEncoderSettings(m_encoderSettings); emit audioSampleRateChanged(rate); } } void QDeclarativeCameraRecorder::setAudioEncodingMode(QDeclarativeCameraRecorder::EncodingMode encodingMode) { - m_encoderSettings = m_recorder->encoderSettings(); + m_encoderSettings = m_encoder->encoderSettings(); if (m_encoderSettings.encodingMode() != QMediaEncoderSettings::EncodingMode(encodingMode)) { m_encoderSettings.setEncodingMode(QMediaEncoderSettings::EncodingMode(encodingMode)); - m_recorder->setEncoderSettings(m_encoderSettings); + m_encoder->setEncoderSettings(m_encoderSettings); emit audioEncodingModeChanged(encodingMode); } } void QDeclarativeCameraRecorder::setVideoEncodingMode(QDeclarativeCameraRecorder::EncodingMode encodingMode) { - m_encoderSettings = m_recorder->encoderSettings(); + m_encoderSettings = m_encoder->encoderSettings(); if (m_encoderSettings.encodingMode() != QMediaEncoderSettings::EncodingMode(encodingMode)) { m_encoderSettings.setEncodingMode(QMediaEncoderSettings::EncodingMode(encodingMode)); - m_recorder->setEncoderSettings(m_encoderSettings); + m_encoder->setEncoderSettings(m_encoderSettings); emit videoEncodingModeChanged(encodingMode); } } @@ -375,7 +375,7 @@ void QDeclarativeCameraRecorder::setVideoEncodingMode(QDeclarativeCameraRecorder */ QDeclarativeCameraRecorder::Error QDeclarativeCameraRecorder::errorCode() const { - return QDeclarativeCameraRecorder::Error(m_recorder->error()); + return QDeclarativeCameraRecorder::Error(m_encoder->error()); } /*! @@ -385,7 +385,7 @@ QDeclarativeCameraRecorder::Error QDeclarativeCameraRecorder::errorCode() const */ QString QDeclarativeCameraRecorder::errorString() const { - return m_recorder->errorString(); + return m_encoder->errorString(); } /*! @@ -407,10 +407,10 @@ QString QDeclarativeCameraRecorder::errorString() const QDeclarativeCameraRecorder::RecorderState QDeclarativeCameraRecorder::recorderState() const { //paused state is not supported for camera - QMediaRecorder::State state = m_recorder->state(); + QMediaEncoder::State state = m_encoder->state(); - if (state == QMediaRecorder::PausedState) - state = QMediaRecorder::StoppedState; + if (state == QMediaEncoder::PausedState) + state = QMediaEncoder::StoppedState; return RecorderState(state); } @@ -444,7 +444,7 @@ QDeclarativeCameraRecorder::RecorderState QDeclarativeCameraRecorder::recorderSt QDeclarativeCameraRecorder::RecorderStatus QDeclarativeCameraRecorder::recorderStatus() const { - return RecorderStatus(m_recorder->status()); + return RecorderStatus(m_encoder->status()); } /*! @@ -469,15 +469,15 @@ void QDeclarativeCameraRecorder::stop() void QDeclarativeCameraRecorder::setRecorderState(QDeclarativeCameraRecorder::RecorderState state) { - if (!m_recorder) + if (!m_encoder) return; switch (state) { case QDeclarativeCameraRecorder::RecordingState: - m_recorder->record(); + m_encoder->record(); break; case QDeclarativeCameraRecorder::StoppedState: - m_recorder->stop(); + m_encoder->stop(); break; } } @@ -496,7 +496,7 @@ void QDeclarativeCameraRecorder::setRecorderState(QDeclarativeCameraRecorder::Re QString QDeclarativeCameraRecorder::outputLocation() const { - return m_recorder->outputLocation().toString(); + return m_encoder->outputLocation().toString(); } /*! \property QDeclarativeCameraRecorder::actualLocation @@ -514,13 +514,13 @@ QString QDeclarativeCameraRecorder::outputLocation() const QString QDeclarativeCameraRecorder::actualLocation() const { - return m_recorder->actualLocation().toString(); + return m_encoder->actualLocation().toString(); } void QDeclarativeCameraRecorder::setOutputLocation(const QString &location) { if (outputLocation() != location) { - m_recorder->setOutputLocation(location); + m_encoder->setOutputLocation(location); emit outputLocationChanged(outputLocation()); } } @@ -536,7 +536,7 @@ void QDeclarativeCameraRecorder::setOutputLocation(const QString &location) */ qint64 QDeclarativeCameraRecorder::duration() const { - return m_recorder->duration(); + return m_encoder->duration(); } /*! \property QDeclarativeCameraRecorder::muted @@ -551,12 +551,12 @@ qint64 QDeclarativeCameraRecorder::duration() const */ bool QDeclarativeCameraRecorder::isMuted() const { - return m_recorder->isMuted(); + return m_encoder->isMuted(); } void QDeclarativeCameraRecorder::setMuted(bool muted) { - m_recorder->setMuted(muted); + m_encoder->setMuted(muted); } /*! @@ -574,17 +574,17 @@ QDeclarativeMediaMetaData *QDeclarativeCameraRecorder::metaData() return m_metaData; } -void QDeclarativeCameraRecorder::updateRecorderState(QMediaRecorder::State state) +void QDeclarativeCameraRecorder::updateRecorderState(QMediaEncoder::State state) { - if (state == QMediaRecorder::PausedState) - state = QMediaRecorder::StoppedState; + if (state == QMediaEncoder::PausedState) + state = QMediaEncoder::StoppedState; emit recorderStateChanged(RecorderState(state)); } -void QDeclarativeCameraRecorder::updateRecorderError(QMediaRecorder::Error errorCode) +void QDeclarativeCameraRecorder::updateRecorderError(QMediaEncoder::Error errorCode) { - qWarning() << "QMediaRecorder error:" << errorString(); + qWarning() << "QMediaEncoder error:" << errorString(); emit error(Error(errorCode), errorString()); } diff --git a/src/imports/multimedia/qdeclarativecamerarecorder_p.h b/src/imports/multimedia/qdeclarativecamerarecorder_p.h index 48a35703a..4ea3f9a2f 100644 --- a/src/imports/multimedia/qdeclarativecamerarecorder_p.h +++ b/src/imports/multimedia/qdeclarativecamerarecorder_p.h @@ -52,7 +52,7 @@ // #include <qcamera.h> -#include <qmediarecorder.h> +#include <qmediaencoder.h> #include <qmediaencodersettings.h> #include <qmediaformat.h> @@ -96,18 +96,18 @@ class QDeclarativeCameraRecorder : public QObject public: enum RecorderState { - StoppedState = QMediaRecorder::StoppedState, - RecordingState = QMediaRecorder::RecordingState + StoppedState = QMediaEncoder::StoppedState, + RecordingState = QMediaEncoder::RecordingState }; enum RecorderStatus { - UnavailableStatus = QMediaRecorder::UnavailableStatus, - StoppedStatus = QMediaRecorder::StoppedStatus, - StartingStatus = QMediaRecorder::StartingStatus, - RecordingStatus = QMediaRecorder::RecordingStatus, - PausedStatus = QMediaRecorder::PausedStatus, - FinalizingStatus = QMediaRecorder::FinalizingStatus + UnavailableStatus = QMediaEncoder::UnavailableStatus, + StoppedStatus = QMediaEncoder::StoppedStatus, + StartingStatus = QMediaEncoder::StartingStatus, + RecordingStatus = QMediaEncoder::RecordingStatus, + PausedStatus = QMediaEncoder::PausedStatus, + FinalizingStatus = QMediaEncoder::FinalizingStatus }; enum EncodingMode @@ -118,10 +118,10 @@ public: }; enum Error { - NoError = QMediaRecorder::NoError, - ResourceError = QMediaRecorder::ResourceError, - FormatError = QMediaRecorder::FormatError, - OutOfSpaceError = QMediaRecorder::OutOfSpaceError + NoError = QMediaEncoder::NoError, + ResourceError = QMediaEncoder::ResourceError, + FormatError = QMediaEncoder::FormatError, + OutOfSpaceError = QMediaEncoder::OutOfSpaceError }; ~QDeclarativeCameraRecorder(); @@ -203,15 +203,15 @@ Q_SIGNALS: void videoEncodingModeChanged(EncodingMode encodingMode); private slots: - void updateRecorderState(QMediaRecorder::State); - void updateRecorderError(QMediaRecorder::Error); + void updateRecorderState(QMediaEncoder::State); + void updateRecorderError(QMediaEncoder::Error); void updateActualLocation(const QUrl&); private: friend class QDeclarativeCamera; QDeclarativeCameraRecorder(QMediaCaptureSession *session, QObject *parent = 0); - QMediaRecorder *m_recorder = nullptr; + QMediaEncoder *m_encoder = nullptr; QDeclarativeMediaMetaData *m_metaData = nullptr; QMediaEncoderSettings m_encoderSettings; diff --git a/src/multimedia/CMakeLists.txt b/src/multimedia/CMakeLists.txt index efe6fdf85..ffaa94b7b 100644 --- a/src/multimedia/CMakeLists.txt +++ b/src/multimedia/CMakeLists.txt @@ -56,6 +56,7 @@ qt_internal_add_module(Multimedia qmultimediautils.cpp qmultimediautils_p.h qtmultimediaglobal.h qtmultimediaglobal_p.h recording/qmediacapturesession.cpp recording/qmediacapturesession.h + recording/qmediaencoder.cpp recording/qmediaencoder.h recording/qmediaencoder_p.h recording/qmediaencodersettings.cpp recording/qmediaencodersettings.h recording/qmediarecorder.cpp recording/qmediarecorder.h recording/qmediarecorder_p.h video/qabstractvideobuffer.cpp video/qabstractvideobuffer_p.h diff --git a/src/multimedia/recording/qmediacapturesession.cpp b/src/multimedia/recording/qmediacapturesession.cpp index 251f09b51..5cde856a4 100644 --- a/src/multimedia/recording/qmediacapturesession.cpp +++ b/src/multimedia/recording/qmediacapturesession.cpp @@ -40,7 +40,7 @@ #include "qmediacapturesession.h" #include "qaudiodeviceinfo.h" #include "qcamera.h" -#include "qmediarecorder.h" +#include "qmediaencoder.h" #include "qcameraimagecapture.h" #include "qplatformmediaintegration_p.h" @@ -55,7 +55,7 @@ public: QAudioDeviceInfo audioInput; QCamera *camera = nullptr; QCameraImageCapture *imageCapture = nullptr; - QMediaRecorder *recorder = nullptr; + QMediaEncoder *encoder = nullptr; }; @@ -135,22 +135,22 @@ void QMediaCaptureSession::setImageCapture(QCameraImageCapture *imageCapture) emit imageCaptureChanged(); } -QMediaRecorder *QMediaCaptureSession::recorder() +QMediaEncoder *QMediaCaptureSession::encoder() { - return d_ptr->recorder; + return d_ptr->encoder; } -void QMediaCaptureSession::setRecorder(QMediaRecorder *recorder) +void QMediaCaptureSession::setEncoder(QMediaEncoder *recorder) { - if (d_ptr->recorder == recorder) + if (d_ptr->encoder == recorder) return; - if (d_ptr->recorder) - d_ptr->recorder->setCaptureSession(nullptr); + if (d_ptr->encoder) + d_ptr->encoder->setCaptureSession(nullptr); - d_ptr->recorder = recorder; - if (d_ptr->recorder) - d_ptr->recorder->setCaptureSession(this); - emit recorderChanged(); + d_ptr->encoder = recorder; + if (d_ptr->encoder) + d_ptr->encoder->setCaptureSession(this); + emit encoderChanged(); } /*! diff --git a/src/multimedia/recording/qmediacapturesession.h b/src/multimedia/recording/qmediacapturesession.h index db2976385..e6fae4780 100644 --- a/src/multimedia/recording/qmediacapturesession.h +++ b/src/multimedia/recording/qmediacapturesession.h @@ -49,7 +49,7 @@ class QCamera; class QAudioDeviceInfo; class QCameraInfo; class QCameraImageCapture; // ### rename to QMediaImageCapture -class QMediaRecorder; +class QMediaEncoder; class QPlatformMediaCaptureSession; class QAbstractVideoSurface; @@ -60,7 +60,7 @@ class Q_MULTIMEDIA_EXPORT QMediaCaptureSession : public QObject Q_PROPERTY(QAudioDeviceInfo audioInput READ audioInput WRITE setAudioInput NOTIFY audioInputChanged) Q_PROPERTY(QCamera *camera READ camera WRITE setCamera NOTIFY cameraChanged) Q_PROPERTY(QCameraImageCapture *imageCapture READ imageCapture WRITE setImageCapture NOTIFY imageCaptureChanged) - Q_PROPERTY(QMediaRecorder *recorder READ recorder WRITE setRecorder NOTIFY recorderChanged) + Q_PROPERTY(QMediaEncoder *encoder READ encoder WRITE setEncoder NOTIFY encoderChanged) public: explicit QMediaCaptureSession(QObject *parent = nullptr); ~QMediaCaptureSession(); @@ -76,8 +76,8 @@ public: QCameraImageCapture *imageCapture(); void setImageCapture(QCameraImageCapture *imageCapture); - QMediaRecorder *recorder(); - void setRecorder(QMediaRecorder *recorder); + QMediaEncoder *encoder(); + void setEncoder(QMediaEncoder *recorder); void setVideoPreview(QObject *preview); void setVideoPreview(QAbstractVideoSurface *preview); @@ -88,7 +88,7 @@ Q_SIGNALS: void audioInputChanged(); void cameraChanged(); void imageCaptureChanged(); - void recorderChanged(); + void encoderChanged(); private: QMediaCaptureSessionPrivate *d_ptr; diff --git a/src/multimedia/recording/qmediaencoder.cpp b/src/multimedia/recording/qmediaencoder.cpp new file mode 100644 index 000000000..9d53c5163 --- /dev/null +++ b/src/multimedia/recording/qmediaencoder.cpp @@ -0,0 +1,629 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmediaencoder_p.h" + +#include <private/qplatformmediarecorder_p.h> +#include <qaudiodeviceinfo.h> +#include <qcamera.h> +#include <qmediacapturesession.h> +#include <private/qplatformcamera_p.h> +#include <private/qplatformmediaintegration_p.h> +#include <private/qplatformmediacapture_p.h> + +#include <QtCore/qdebug.h> +#include <QtCore/qurl.h> +#include <QtCore/qstringlist.h> +#include <QtCore/qmetaobject.h> +#include <QtCore/qtimer.h> + +#include <qaudioformat.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QMediaEncoder + \inmodule QtMultimedia + \ingroup multimedia + \ingroup multimedia_recording + + \brief The QMediaEncoder class is used for the recording of media content. + + The QMediaEncoder class is a high level media recording class. It's not + intended to be used alone but for accessing the media recording functions + of other media objects, like QCamera. + + \snippet multimedia-snippets/media.cpp Media encoder +*/ + + +#define ENUM_NAME(c,e,v) (c::staticMetaObject.enumerator(c::staticMetaObject.indexOfEnumerator(e)).valueToKey((v))) + +void QMediaEncoderPrivate::_q_stateChanged(QMediaEncoder::State ps) +{ + Q_Q(QMediaEncoder); + +// qDebug() << "Encoder state changed:" << ENUM_NAME(QMediaEncoder,"State",ps); + if (state != ps) { + emit q->stateChanged(ps); + } + + state = ps; +} + + +void QMediaEncoderPrivate::_q_error(int error, const QString &errorString) +{ + Q_Q(QMediaEncoder); + + this->error = QMediaEncoder::Error(error); + this->errorString = errorString; + + emit q->error(this->error); +} + +void QMediaEncoderPrivate::_q_updateActualLocation(const QUrl &location) +{ + if (actualLocation != location) { + actualLocation = location; + emit q_func()->actualLocationChanged(actualLocation); + } +} + +void QMediaEncoderPrivate::applySettingsLater() +{ + if (control && !settingsChanged) { + settingsChanged = true; + QMetaObject::invokeMethod(q_func(), "_q_applySettings", Qt::QueuedConnection); + } +} + +void QMediaEncoderPrivate::_q_applySettings() +{ + if (control && settingsChanged) { + settingsChanged = false; + control->applySettings(); + } +} + +/*! + Constructs a media encoder which records the media produced by a microphone and camera. +*/ + +QMediaEncoder::QMediaEncoder(QObject *parent) + : QMediaEncoderBase(parent), + d_ptr(new QMediaEncoderPrivate) +{ + Q_D(QMediaEncoder); + d->q_ptr = this; +} + +/*! + Destroys a media encoder object. +*/ + +QMediaEncoder::~QMediaEncoder() +{ + if (d_ptr->captureSession) + d_ptr->captureSession->setEncoder(nullptr); + delete d_ptr; +} + +/*! + \internal +*/ +void QMediaEncoder::setCaptureSession(QMediaCaptureSession *session) +{ + Q_D(QMediaEncoder); + if (d->captureSession == session) + return; + + if (d->control) + d->control->disconnect(this); + + d->captureSession = session; + + if (!d->captureSession) { + d->control = nullptr; + return; + } + + d->control = d->captureSession->platformSession()->mediaRecorderControl(); + Q_ASSERT(d->control); + + connect(d->control, SIGNAL(stateChanged(QMediaEncoder::State)), + this, SLOT(_q_stateChanged(QMediaEncoder::State))); + + connect(d->control, SIGNAL(statusChanged(QMediaEncoder::Status)), + this, SIGNAL(statusChanged(QMediaEncoder::Status))); + + connect(d->control, SIGNAL(mutedChanged(bool)), + this, SIGNAL(mutedChanged(bool))); + + connect(d->control, SIGNAL(volumeChanged(qreal)), + this, SIGNAL(volumeChanged(qreal))); + + connect(d->control, SIGNAL(durationChanged(qint64)), + this, SIGNAL(durationChanged(qint64))); + + connect(d->control, SIGNAL(actualLocationChanged(QUrl)), + this, SLOT(_q_updateActualLocation(QUrl))); + + connect(d->control, SIGNAL(error(int,QString)), + this, SLOT(_q_error(int,QString))); + + connect(d->control, SIGNAL(metaDataChanged()), + this, SIGNAL(metaDataChanged())); + + d->applySettingsLater(); + +} + +/*! + \property QMediaEncoder::outputLocation + \brief the destination location of media content. + + Setting the location can fail, for example when the service supports only + local file system locations but a network URL was passed. If the service + does not support media recording this setting the output location will + always fail. + + The \a location can be relative or empty; + in this case the encoder uses the system specific place and file naming scheme. + After recording has stated, QMediaEncoder::outputLocation() returns the actual output location. +*/ + +/*! + \property QMediaEncoder::actualLocation + \brief the actual location of the last media content. + + The actual location is usually available after recording starts, + and reset when new location is set or new recording starts. +*/ + +/*! + Returns true if media encoder service ready to use. + + \sa availabilityChanged() +*/ +bool QMediaEncoder::isAvailable() const +{ + return d_func()->control != nullptr; +} + +QUrl QMediaEncoder::outputLocation() const +{ + return d_func()->control ? d_func()->control->outputLocation() : QUrl(); +} + +bool QMediaEncoder::setOutputLocation(const QUrl &location) +{ + Q_D(QMediaEncoder); + d->actualLocation.clear(); + return d->control ? d->control->setOutputLocation(location) : false; +} + +QUrl QMediaEncoder::actualLocation() const +{ + return d_func()->actualLocation; +} + +/*! + Returns the current media encoder state. + + \sa QMediaEncoder::State +*/ + +QMediaEncoder::State QMediaEncoder::state() const +{ + return d_func()->control ? QMediaEncoder::State(d_func()->control->state()) : StoppedState; +} + +/*! + Returns the current media encoder status. + + \sa QMediaEncoder::Status +*/ + +QMediaEncoder::Status QMediaEncoder::status() const +{ + return d_func()->control ? QMediaEncoder::Status(d_func()->control->status()) : UnavailableStatus; +} + +/*! + Returns the current error state. + + \sa errorString() +*/ + +QMediaEncoder::Error QMediaEncoder::error() const +{ + return d_func()->error; +} + +/*! + Returns a string describing the current error state. + + \sa error() +*/ + +QString QMediaEncoder::errorString() const +{ + return d_func()->errorString; +} + +/*! + \property QMediaEncoder::duration + + \brief the recorded media duration in milliseconds. +*/ + +qint64 QMediaEncoder::duration() const +{ + return d_func()->control ? d_func()->control->duration() : 0; +} + +/*! + \property QMediaEncoder::muted + + \brief whether a recording audio stream is muted. +*/ + +bool QMediaEncoder::isMuted() const +{ + return d_func()->control ? d_func()->control->isMuted() : false; +} + +void QMediaEncoder::setMuted(bool muted) +{ + Q_D(QMediaEncoder); + + if (d->control) + d->control->setMuted(muted); +} + +/*! + \property QMediaEncoder::volume + + \brief the current recording audio volume. + + The volume is scaled linearly from \c 0.0 (silence) to \c 1.0 (full volume). Values outside this + range will be clamped. + + The default volume is \c 1.0. + + UI volume controls should usually be scaled nonlinearly. For example, using a logarithmic scale + will produce linear changes in perceived loudness, which is what a user would normally expect + from a volume control. See QAudio::convertVolume() for more details. +*/ + +qreal QMediaEncoder::volume() const +{ + return d_func()->control ? d_func()->control->volume() : 1.0; +} + +/*! + Sets the encoder settings to \a settings. + + \sa QMediaEncoderSettings +*/ +void QMediaEncoder::setEncoderSettings(const QMediaEncoderSettings &settings) +{ + Q_D(QMediaEncoder); + + d->encoderSettings = settings; + d->control->setEncoderSettings(settings); + d->applySettingsLater(); +} + +/*! + Returns the current encoder settings. + + \sa QMediaEncoderSettings +*/ +QMediaEncoderSettings QMediaEncoder::encoderSettings() const +{ + return d_func()->encoderSettings; +} + + +void QMediaEncoder::setVolume(qreal volume) +{ + Q_D(QMediaEncoder); + + if (d->control) { + volume = qMax(qreal(0.0), volume); + d->control->setVolume(volume); + } +} + +/*! + Start recording. + + While the encoder state is changed immediately to QMediaEncoder::RecordingState, + recording may start asynchronously, with statusChanged(QMediaEncoder::RecordingStatus) + signal emitted when recording starts. + + If recording fails error() signal is emitted + with encoder state being reset back to QMediaEncoder::StoppedState. +*/ + +void QMediaEncoder::record() +{ + Q_D(QMediaEncoder); + + d->actualLocation.clear(); + + if (d->settingsChanged) + d->_q_applySettings(); + + // reset error + d->error = NoError; + d->errorString = QString(); + + if (d->control) + d->control->setState(QMediaRecorder::RecordingState); +} + +/*! + Pause recording. + + The encoder state is changed to QMediaEncoder::PausedState. + + Depending on platform recording pause may be not supported, + in this case the encoder state stays unchanged. +*/ + +void QMediaEncoder::pause() +{ + Q_D(QMediaEncoder); + if (d->control) + d->control->setState(QMediaRecorder::PausedState); +} + +/*! + Stop recording. + + The encoder state is changed to QMediaEncoder::StoppedState. +*/ + +void QMediaEncoder::stop() +{ + Q_D(QMediaEncoder); + if (d->control) + d->control->setState(QMediaRecorder::StoppedState); +} + +/*! + \enum QMediaEncoderBase::State + + \value StoppedState The recorder is not active. + If this is the state after recording then the actual created recording has + finished being written to the final location and is ready on all platforms + except on Android. On Android, due to platform limitations, there is no way + to be certain that the recording has finished writing to the final location. + \value RecordingState The recording is requested. + \value PausedState The recorder is paused. +*/ + +/*! + \enum QMediaEncoderBase::Status + + \value UnavailableStatus + The recorder is not available or not supported by connected media object. + \value UnloadedStatus + The recorder is avilable but not loaded. + \value LoadingStatus + The recorder is initializing. + \value LoadedStatus + The recorder is initialized and ready to record media. + \value StartingStatus + Recording is requested but not active yet. + \value RecordingStatus + Recording is active. + \value PausedStatus + Recording is paused. + \value FinalizingStatus + Recording is stopped with media being finalized. +*/ + +/*! + \enum QMediaEncoderBase::Error + + \value NoError No Errors. + \value ResourceError Device is not ready or not available. + \value FormatError Current format is not supported. + \value OutOfSpaceError No space left on device. +*/ + +/*! + \property QMediaEncoder::state + \brief The current state of the media recorder. + + The state property represents the user request and is changed synchronously + during record(), pause() or stop() calls. + Recorder state may also change asynchronously when recording fails. +*/ + +/*! + \property QMediaEncoder::status + \brief The current status of the media recorder. + + The status is changed asynchronously and represents the actual status + of media recorder. +*/ + +/*! + \fn QMediaEncoder::stateChanged(State state) + + Signals that a media recorder's \a state has changed. +*/ + +/*! + \fn QMediaEncoder::durationChanged(qint64 duration) + + Signals that the \a duration of the recorded media has changed. +*/ + +/*! + \fn QMediaEncoder::actualLocationChanged(const QUrl &location) + + Signals that the actual \a location of the recorded media has changed. + This signal is usually emitted when recording starts. +*/ + +/*! + \fn QMediaEncoder::error(QMediaEncoder::Error error) + + Signals that an \a error has occurred. +*/ + +/*! + \fn QMediaEncoder::availabilityChanged(bool available) + + Signals that the media recorder is now available (if \a available is true), or not. +*/ + +/*! + \fn QMediaEncoder::mutedChanged(bool muted) + + Signals that the \a muted state has changed. If true the recording is being muted. +*/ + +/*! + Returns the metaData associated with the recording. +*/ +QMediaMetaData QMediaEncoder::metaData() const +{ + Q_D(const QMediaEncoder); + + return d->control ? d->control->metaData() : QMediaMetaData{}; +} + +/*! + Sets the meta data tp \a metaData. + + \note To ensure that meta data is set corretly, it should be set before starting the recording. + Once the recording is stopped, any meta data set will be attached to the next recording. +*/ +void QMediaEncoder::setMetaData(const QMediaMetaData &metaData) +{ + Q_D(QMediaEncoder); + + if (d->control) + d->control->setMetaData(metaData); +} + +void QMediaEncoder::addMetaData(const QMediaMetaData &metaData) +{ + auto data = this->metaData(); + // merge data + for (const auto &k : metaData.keys()) + data.insert(k, metaData.value(k)); + setMetaData(data); +} + +/*! + \fn QMediaEncoder::metaDataChanged() + + Signals that a media object's meta-data has changed. + + If multiple meta-data elements are changed, + metaDataChanged(const QString &key, const QVariant &value) signal is emitted + for each of them with metaDataChanged() changed emitted once. +*/ + +/*! + \property QMediaEncoder::audioInput + \brief the active audio input name. + +*/ + +/*! + Returns the active audio input. +*/ + +QAudioDeviceInfo QMediaEncoder::audioInput() const +{ + Q_D(const QMediaEncoder); + + return d->control->audioInput(); +} + +/*! + Returns information about the active video input. +*/ +QCameraInfo QMediaEncoder::videoInput() const +{ + Q_D(const QMediaEncoder); + + auto *camera = d->captureSession->camera(); + return camera ? camera->cameraInfo() : QCameraInfo(); +} + +QMediaCaptureSession *QMediaEncoder::captureSession() const +{ + Q_D(const QMediaEncoder); + return d->captureSession; +} + +/*! + Set the active audio input to \a device. +*/ + +bool QMediaEncoder::setAudioInput(const QAudioDeviceInfo &device) +{ + Q_D(QMediaEncoder); + + if (d->control && d->control->setAudioInput(device)) { + audioInputChanged(); + return true; + } + return false; +} + +/*! + \fn QMediaEncoder::audioInputChanged(const QString& name) + + Signal emitted when active audio input changes to \a name. +*/ + +QT_END_NAMESPACE + +#include "moc_qmediaencoder.cpp" diff --git a/src/multimedia/recording/qmediaencoder.h b/src/multimedia/recording/qmediaencoder.h new file mode 100644 index 000000000..6135fc1e5 --- /dev/null +++ b/src/multimedia/recording/qmediaencoder.h @@ -0,0 +1,189 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAENCODER_H +#define QMEDIAENCODER_H + +#include <QtCore/qobject.h> +#include <QtMultimedia/qtmultimediaglobal.h> +#include <QtMultimedia/qmediaencodersettings.h> +#include <QtMultimedia/qmediaenumdebug.h> +#include <QtMultimedia/qmediametadata.h> + +#include <QtCore/qpair.h> + +QT_BEGIN_NAMESPACE + +class QUrl; +class QSize; +class QAudioFormat; +class QCamera; +class QCameraInfo; +class QMediaRecorderService; +class QAudioEncoderSettings; +class QVideoEncoderSettings; +class QAudioDeviceInfo; +class QMediaCaptureSession; + +class Q_MULTIMEDIA_EXPORT QMediaEncoderBase : public QObject +{ + Q_OBJECT + Q_ENUMS(State) + Q_ENUMS(Status) + Q_ENUMS(Error) + +public: + QMediaEncoderBase(QObject *parent) : QObject(parent) {} + enum State + { + StoppedState, + RecordingState, + PausedState + }; + + enum Status { + UnavailableStatus, + StoppedStatus, + StartingStatus, + RecordingStatus, + PausedStatus, + FinalizingStatus + }; + + enum Error + { + NoError, + ResourceError, + FormatError, + OutOfSpaceError + }; + +}; + +class QMediaEncoderPrivate; +class Q_MULTIMEDIA_EXPORT QMediaEncoder : public QMediaEncoderBase +{ + Q_OBJECT + Q_ENUMS(State) + Q_ENUMS(Status) + Q_ENUMS(Error) + Q_PROPERTY(QMediaEncoder::State state READ state NOTIFY stateChanged) + Q_PROPERTY(QMediaEncoder::Status status READ status NOTIFY statusChanged) + Q_PROPERTY(qint64 duration READ duration NOTIFY durationChanged) + Q_PROPERTY(QUrl outputLocation READ outputLocation WRITE setOutputLocation) + Q_PROPERTY(QUrl actualLocation READ actualLocation NOTIFY actualLocationChanged) + Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged) + Q_PROPERTY(qreal volume READ volume WRITE setVolume NOTIFY volumeChanged) + Q_PROPERTY(QMediaMetaData metaData READ metaData WRITE setMetaData NOTIFY metaDataChanged) + Q_PROPERTY(QAudioDeviceInfo audioInput READ audioInput WRITE setAudioInput NOTIFY audioInputChanged) + +public: + QMediaEncoder(QObject *parent = nullptr); + ~QMediaEncoder(); + + bool isAvailable() const; + + QUrl outputLocation() const; + bool setOutputLocation(const QUrl &location); + + QUrl actualLocation() const; + + State state() const; + Status status() const; + + Error error() const; + QString errorString() const; + + qint64 duration() const; + + bool isMuted() const; + qreal volume() const; + + void setEncoderSettings(const QMediaEncoderSettings &); + QMediaEncoderSettings encoderSettings() const; + + QMediaMetaData metaData() const; + void setMetaData(const QMediaMetaData &metaData); + void addMetaData(const QMediaMetaData &metaData); + + QAudioDeviceInfo audioInput() const; + QCameraInfo videoInput() const; + + QMediaCaptureSession *captureSession() const; + +public Q_SLOTS: + void record(); + void pause(); + void stop(); + void setMuted(bool muted); + void setVolume(qreal volume); + bool setAudioInput(const QAudioDeviceInfo &device); + +Q_SIGNALS: + void stateChanged(QMediaEncoder::State state); + void statusChanged(QMediaEncoder::Status status); + void durationChanged(qint64 duration); + void mutedChanged(bool muted); + void volumeChanged(qreal volume); + void actualLocationChanged(const QUrl &location); + void audioInputChanged(); + + void error(QMediaEncoder::Error error); + + void metaDataChanged(); + +private: + QMediaEncoderPrivate *d_ptr; + friend class QMediaCaptureSession; + void setCaptureSession(QMediaCaptureSession *session); + Q_DISABLE_COPY(QMediaEncoder) + Q_DECLARE_PRIVATE(QMediaEncoder) + Q_PRIVATE_SLOT(d_func(), void _q_stateChanged(QMediaEncoder::State)) + Q_PRIVATE_SLOT(d_func(), void _q_error(int, const QString &)) + Q_PRIVATE_SLOT(d_func(), void _q_updateActualLocation(const QUrl &)) + Q_PRIVATE_SLOT(d_func(), void _q_applySettings()) +}; + +QT_END_NAMESPACE + +Q_MEDIA_ENUM_DEBUG(QMediaEncoderBase, State) +Q_MEDIA_ENUM_DEBUG(QMediaEncoderBase, Status) +Q_MEDIA_ENUM_DEBUG(QMediaEncoderBase, Error) + +#endif // QMEDIAENCODER_H diff --git a/src/multimedia/recording/qmediaencoder_p.h b/src/multimedia/recording/qmediaencoder_p.h new file mode 100644 index 000000000..a2f220dc8 --- /dev/null +++ b/src/multimedia/recording/qmediaencoder_p.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMEDIAENCODER_P_H +#define QMEDIAENCODER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qmediaencoder.h" +#include "qcamera.h" +#include <QtCore/qurl.h> +#include <QtCore/qpointer.h> + +QT_BEGIN_NAMESPACE + +class QPlatformMediaRecorder; +class QMediaContainerControl; +class QAudioEncoderSettingsControl; +class QVideoEncoderSettingsControl; +class QTimer; + +class QMediaEncoderPrivate +{ + Q_DECLARE_PUBLIC(QMediaEncoder) + +public: + QMediaEncoderPrivate() = default; + + void applySettingsLater(); + + QMediaCaptureSession *captureSession = nullptr; + + QPlatformMediaRecorder *control = nullptr; + + bool settingsChanged = false; + + QMediaEncoder::State state = QMediaEncoder::StoppedState; + QMediaEncoder::Error error = QMediaEncoder::NoError; + QString errorString; + QUrl actualLocation; + QMediaEncoderSettings encoderSettings; + + void _q_stateChanged(QMediaEncoder::State state); + void _q_error(int error, const QString &errorString); + void _q_updateActualLocation(const QUrl &); + void _q_applySettings(); + + QMediaEncoder *q_ptr = nullptr; +}; + +#undef Q_DECLARE_NON_CONST_PUBLIC + +QT_END_NAMESPACE + +#endif + diff --git a/src/multimedia/recording/qmediarecorder.cpp b/src/multimedia/recording/qmediarecorder.cpp index 7cd5b2a32..462b8c9c8 100644 --- a/src/multimedia/recording/qmediarecorder.cpp +++ b/src/multimedia/recording/qmediarecorder.cpp @@ -38,26 +38,31 @@ ****************************************************************************/ #include "qmediarecorder.h" -#include "qmediarecorder_p.h" -#include <private/qplatformmediarecorder_p.h> #include <qaudiodeviceinfo.h> #include <qcamera.h> #include <qmediacapturesession.h> -#include <private/qplatformcamera_p.h> -#include <private/qplatformmediaintegration_p.h> -#include <private/qplatformmediacapture_p.h> +#include <qmediaencoder.h> +#include <qcamera.h> #include <QtCore/qdebug.h> #include <QtCore/qurl.h> #include <QtCore/qstringlist.h> -#include <QtCore/qmetaobject.h> -#include <QtCore/qtimer.h> - -#include <qaudioformat.h> QT_BEGIN_NAMESPACE +class QMediaRecorderPrivate +{ + Q_DECLARE_PUBLIC(QMediaRecorder) +public: + QMediaRecorder::CaptureMode mode = QMediaRecorder::AudioOnly; + QMediaCaptureSession *captureSession = nullptr; + QCamera *camera = nullptr; + QMediaEncoder *encoder = nullptr; + + QMediaRecorder *q_ptr = nullptr; +}; + /*! \class QMediaRecorder \inmodule QtMultimedia @@ -73,66 +78,26 @@ QT_BEGIN_NAMESPACE \snippet multimedia-snippets/media.cpp Media recorder */ - -#define ENUM_NAME(c,e,v) (c::staticMetaObject.enumerator(c::staticMetaObject.indexOfEnumerator(e)).valueToKey((v))) - -void QMediaRecorderPrivate::_q_stateChanged(QMediaRecorder::State ps) -{ - Q_Q(QMediaRecorder); - -// qDebug() << "Recorder state changed:" << ENUM_NAME(QMediaRecorder,"State",ps); - if (state != ps) { - emit q->stateChanged(ps); - } - - state = ps; -} - - -void QMediaRecorderPrivate::_q_error(int error, const QString &errorString) -{ - Q_Q(QMediaRecorder); - - this->error = QMediaRecorder::Error(error); - this->errorString = errorString; - - emit q->error(this->error); -} - -void QMediaRecorderPrivate::_q_updateActualLocation(const QUrl &location) -{ - if (actualLocation != location) { - actualLocation = location; - emit q_func()->actualLocationChanged(actualLocation); - } -} - -void QMediaRecorderPrivate::applySettingsLater() -{ - if (control && !settingsChanged) { - settingsChanged = true; - QMetaObject::invokeMethod(q_func(), "_q_applySettings", Qt::QueuedConnection); - } -} - -void QMediaRecorderPrivate::_q_applySettings() -{ - if (control && settingsChanged) { - settingsChanged = false; - control->applySettings(); - } -} - /*! Constructs a media recorder which records the media produced by a microphone and camera. */ -QMediaRecorder::QMediaRecorder(QObject *parent) - : QObject(parent), +QMediaRecorder::QMediaRecorder(QObject *parent, CaptureMode mode) + : QMediaEncoderBase(parent), d_ptr(new QMediaRecorderPrivate) { Q_D(QMediaRecorder); d->q_ptr = this; + + d->captureSession = new QMediaCaptureSession(this); + d->encoder = new QMediaEncoder(this); + setCaptureMode(mode); + + connect(d->encoder, &QMediaEncoder::stateChanged, this, &QMediaRecorder::stateChanged); + connect(d->encoder, &QMediaEncoder::statusChanged, this, &QMediaRecorder::statusChanged); + connect(d->encoder, &QMediaEncoder::mutedChanged, this, &QMediaRecorder::mutedChanged); + connect(d->encoder, &QMediaEncoder::volumeChanged, this, &QMediaRecorder::volumeChanged); + connect(d->encoder, &QMediaEncoder::audioInputChanged, this, &QMediaRecorder::audioInputChanged); } /*! @@ -141,62 +106,10 @@ QMediaRecorder::QMediaRecorder(QObject *parent) QMediaRecorder::~QMediaRecorder() { - if (d_ptr->captureSession) - d_ptr->captureSession->setRecorder(nullptr); delete d_ptr; } /*! - \internal -*/ -void QMediaRecorder::setCaptureSession(QMediaCaptureSession *session) -{ - Q_D(QMediaRecorder); - if (d->captureSession == session) - return; - - if (d->control) - d->control->disconnect(this); - - d->captureSession = session; - - if (!d->captureSession) { - d->control = nullptr; - return; - } - - d->control = d->captureSession->platformSession()->mediaRecorderControl(); - Q_ASSERT(d->control); - - connect(d->control, SIGNAL(stateChanged(QMediaRecorder::State)), - this, SLOT(_q_stateChanged(QMediaRecorder::State))); - - connect(d->control, SIGNAL(statusChanged(QMediaRecorder::Status)), - this, SIGNAL(statusChanged(QMediaRecorder::Status))); - - connect(d->control, SIGNAL(mutedChanged(bool)), - this, SIGNAL(mutedChanged(bool))); - - connect(d->control, SIGNAL(volumeChanged(qreal)), - this, SIGNAL(volumeChanged(qreal))); - - connect(d->control, SIGNAL(durationChanged(qint64)), - this, SIGNAL(durationChanged(qint64))); - - connect(d->control, SIGNAL(actualLocationChanged(QUrl)), - this, SLOT(_q_updateActualLocation(QUrl))); - - connect(d->control, SIGNAL(error(int,QString)), - this, SLOT(_q_error(int,QString))); - - connect(d->control, SIGNAL(metaDataChanged()), - this, SIGNAL(metaDataChanged())); - - d->applySettingsLater(); - -} - -/*! \property QMediaRecorder::outputLocation \brief the destination location of media content. @@ -225,24 +138,59 @@ void QMediaRecorder::setCaptureSession(QMediaCaptureSession *session) */ bool QMediaRecorder::isAvailable() const { - return d_func()->control != nullptr; + return d_ptr->encoder->isAvailable(); } -QUrl QMediaRecorder::outputLocation() const +/*! + \property QMediaRecorder::captureMode + \brief The current mode the recorder operates in. + + The capture mode defines whether QMediaRecorder will record audio and + video or audio only. + + The capture mode can only be changed while nothing is being recorded. +*/ + +QMediaRecorder::CaptureMode QMediaRecorder::captureMode() const { - return d_func()->control ? d_func()->control->outputLocation() : QUrl(); + return d_ptr->mode; } -bool QMediaRecorder::setOutputLocation(const QUrl &location) +void QMediaRecorder::setCaptureMode(QMediaRecorder::CaptureMode mode) { - Q_D(QMediaRecorder); - d->actualLocation.clear(); - return d->control ? d->control->setOutputLocation(location) : false; + if (d_ptr->mode == mode) + return; + if (mode == AudioAndVideo) { + Q_ASSERT(!d_ptr->camera); + d_ptr->camera = new QCamera(this); + d_ptr->captureSession->setCamera(d_ptr->camera); + } else { // AudioOnly + Q_ASSERT(d_ptr->camera); + d_ptr->captureSession->setCamera(nullptr); + delete d_ptr->camera; + d_ptr->camera = nullptr; + } +} + +/*! + Returns the camera object associated with this recording session. + If the current \l captureMode is \l AudioOnly, a nullptr will be + returned. + */ +QCamera *QMediaRecorder::camera() const +{ + return d_ptr->camera; } -QUrl QMediaRecorder::actualLocation() const +QUrl QMediaRecorder::outputLocation() const { - return d_func()->actualLocation; + return d_ptr->encoder->outputLocation(); +} + +bool QMediaRecorder::setOutputLocation(const QUrl &location) +{ + Q_D(QMediaRecorder); + return d->encoder->setOutputLocation(location); } /*! @@ -253,7 +201,7 @@ QUrl QMediaRecorder::actualLocation() const QMediaRecorder::State QMediaRecorder::state() const { - return d_func()->control ? QMediaRecorder::State(d_func()->control->state()) : StoppedState; + return d_ptr->encoder->state(); } /*! @@ -264,7 +212,7 @@ QMediaRecorder::State QMediaRecorder::state() const QMediaRecorder::Status QMediaRecorder::status() const { - return d_func()->control ? QMediaRecorder::Status(d_func()->control->status()) : UnavailableStatus; + return d_ptr->encoder->status(); } /*! @@ -275,7 +223,7 @@ QMediaRecorder::Status QMediaRecorder::status() const QMediaRecorder::Error QMediaRecorder::error() const { - return d_func()->error; + return d_ptr->encoder->error(); } /*! @@ -286,7 +234,7 @@ QMediaRecorder::Error QMediaRecorder::error() const QString QMediaRecorder::errorString() const { - return d_func()->errorString; + return d_ptr->encoder->errorString(); } /*! @@ -297,7 +245,7 @@ QString QMediaRecorder::errorString() const qint64 QMediaRecorder::duration() const { - return d_func()->control ? d_func()->control->duration() : 0; + return d_ptr->encoder->duration(); } /*! @@ -308,15 +256,12 @@ qint64 QMediaRecorder::duration() const bool QMediaRecorder::isMuted() const { - return d_func()->control ? d_func()->control->isMuted() : false; + return d_ptr->encoder->isMuted(); } void QMediaRecorder::setMuted(bool muted) { - Q_D(QMediaRecorder); - - if (d->control) - d->control->setMuted(muted); + d_ptr->encoder->setMuted(muted); } /*! @@ -336,7 +281,7 @@ void QMediaRecorder::setMuted(bool muted) qreal QMediaRecorder::volume() const { - return d_func()->control ? d_func()->control->volume() : 1.0; + return d_ptr->encoder->volume(); } /*! @@ -346,11 +291,7 @@ qreal QMediaRecorder::volume() const */ void QMediaRecorder::setEncoderSettings(const QMediaEncoderSettings &settings) { - Q_D(QMediaRecorder); - - d->encoderSettings = settings; - d->control->setEncoderSettings(settings); - d->applySettingsLater(); + d_ptr->encoder->setEncoderSettings(settings); } /*! @@ -360,18 +301,13 @@ void QMediaRecorder::setEncoderSettings(const QMediaEncoderSettings &settings) */ QMediaEncoderSettings QMediaRecorder::encoderSettings() const { - return d_func()->encoderSettings; + return d_ptr->encoder->encoderSettings(); } void QMediaRecorder::setVolume(qreal volume) { - Q_D(QMediaRecorder); - - if (d->control) { - volume = qMax(qreal(0.0), volume); - d->control->setVolume(volume); - } + d_ptr->encoder->setVolume(volume); } /*! @@ -387,19 +323,7 @@ void QMediaRecorder::setVolume(qreal volume) void QMediaRecorder::record() { - Q_D(QMediaRecorder); - - d->actualLocation.clear(); - - if (d->settingsChanged) - d->_q_applySettings(); - - // reset error - d->error = NoError; - d->errorString = QString(); - - if (d->control) - d->control->setState(RecordingState); + d_ptr->encoder->record(); } /*! @@ -413,9 +337,7 @@ void QMediaRecorder::record() void QMediaRecorder::pause() { - Q_D(QMediaRecorder); - if (d->control) - d->control->setState(PausedState); + d_ptr->encoder->pause(); } /*! @@ -426,52 +348,9 @@ void QMediaRecorder::pause() void QMediaRecorder::stop() { - Q_D(QMediaRecorder); - if (d->control) - d->control->setState(StoppedState); + d_ptr->encoder->stop(); } -/*! - \enum QMediaRecorder::State - - \value StoppedState The recorder is not active. - If this is the state after recording then the actual created recording has - finished being written to the final location and is ready on all platforms - except on Android. On Android, due to platform limitations, there is no way - to be certain that the recording has finished writing to the final location. - \value RecordingState The recording is requested. - \value PausedState The recorder is paused. -*/ - -/*! - \enum QMediaRecorder::Status - - \value UnavailableStatus - The recorder is not available or not supported by connected media object. - \value UnloadedStatus - The recorder is avilable but not loaded. - \value LoadingStatus - The recorder is initializing. - \value LoadedStatus - The recorder is initialized and ready to record media. - \value StartingStatus - Recording is requested but not active yet. - \value RecordingStatus - Recording is active. - \value PausedStatus - Recording is paused. - \value FinalizingStatus - Recording is stopped with media being finalized. -*/ - -/*! - \enum QMediaRecorder::Error - - \value NoError No Errors. - \value ResourceError Device is not ready or not available. - \value FormatError Current format is not supported. - \value OutOfSpaceError No space left on device. -*/ /*! \property QMediaRecorder::state @@ -532,9 +411,7 @@ void QMediaRecorder::stop() */ QMediaMetaData QMediaRecorder::metaData() const { - Q_D(const QMediaRecorder); - - return d->control ? d->control->metaData() : QMediaMetaData{}; + return d_ptr->encoder->metaData(); } /*! @@ -545,19 +422,12 @@ QMediaMetaData QMediaRecorder::metaData() const */ void QMediaRecorder::setMetaData(const QMediaMetaData &metaData) { - Q_D(QMediaRecorder); - - if (d->control) - d->control->setMetaData(metaData); + d_ptr->encoder->setMetaData(metaData); } void QMediaRecorder::addMetaData(const QMediaMetaData &metaData) { - auto data = this->metaData(); - // merge data - for (const auto &k : metaData.keys()) - data.insert(k, metaData.value(k)); - setMetaData(data); + d_ptr->encoder->addMetaData(metaData); } /*! @@ -582,9 +452,7 @@ void QMediaRecorder::addMetaData(const QMediaMetaData &metaData) QAudioDeviceInfo QMediaRecorder::audioInput() const { - Q_D(const QMediaRecorder); - - return d->control->audioInput(); + return d_ptr->encoder->audioInput(); } /*! @@ -592,10 +460,7 @@ QAudioDeviceInfo QMediaRecorder::audioInput() const */ QCameraInfo QMediaRecorder::videoInput() const { - Q_D(const QMediaRecorder); - - auto *camera = d->captureSession->camera(); - return camera ? camera->cameraInfo() : QCameraInfo(); + return d_ptr->encoder->videoInput(); } QMediaCaptureSession *QMediaRecorder::captureSession() const @@ -610,13 +475,7 @@ QMediaCaptureSession *QMediaRecorder::captureSession() const bool QMediaRecorder::setAudioInput(const QAudioDeviceInfo &device) { - Q_D(QMediaRecorder); - - if (d->control && d->control->setAudioInput(device)) { - audioInputChanged(); - return true; - } - return false; + return d_ptr->encoder->setAudioInput(device); } /*! diff --git a/src/multimedia/recording/qmediarecorder.h b/src/multimedia/recording/qmediarecorder.h index eb0c02b56..a9efcd945 100644 --- a/src/multimedia/recording/qmediarecorder.h +++ b/src/multimedia/recording/qmediarecorder.h @@ -40,29 +40,12 @@ #ifndef QMEDIARECORDER_H #define QMEDIARECORDER_H -#include <QtCore/qobject.h> -#include <QtMultimedia/qtmultimediaglobal.h> -#include <QtMultimedia/qmediaencodersettings.h> -#include <QtMultimedia/qmediaenumdebug.h> -#include <QtMultimedia/qmediametadata.h> - -#include <QtCore/qpair.h> +#include <QtMultimedia/qmediaencoder.h> QT_BEGIN_NAMESPACE -class QUrl; -class QSize; -class QAudioFormat; -class QCamera; -class QCameraInfo; -class QMediaRecorderService; -class QAudioEncoderSettings; -class QVideoEncoderSettings; -class QAudioDeviceInfo; -class QMediaCaptureSession; - class QMediaRecorderPrivate; -class Q_MULTIMEDIA_EXPORT QMediaRecorder : public QObject +class Q_MULTIMEDIA_EXPORT QMediaRecorder : public QMediaEncoderBase { Q_OBJECT Q_ENUMS(State) @@ -72,52 +55,31 @@ class Q_MULTIMEDIA_EXPORT QMediaRecorder : public QObject Q_PROPERTY(QMediaRecorder::Status status READ status NOTIFY statusChanged) Q_PROPERTY(qint64 duration READ duration NOTIFY durationChanged) Q_PROPERTY(QUrl outputLocation READ outputLocation WRITE setOutputLocation) - Q_PROPERTY(QUrl actualLocation READ actualLocation NOTIFY actualLocationChanged) Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged) Q_PROPERTY(qreal volume READ volume WRITE setVolume NOTIFY volumeChanged) Q_PROPERTY(QMediaMetaData metaData READ metaData WRITE setMetaData NOTIFY metaDataChanged) Q_PROPERTY(QAudioDeviceInfo audioInput READ audioInput WRITE setAudioInput NOTIFY audioInputChanged) + Q_PROPERTY(CaptureMode captureMode READ captureMode WRITE setCaptureMode NOTIFY captureModeChanged) public: - enum State - { - StoppedState, - RecordingState, - PausedState - }; - - enum Status { - UnavailableStatus, - StoppedStatus, - StartingStatus, - RecordingStatus, - PausedStatus, - FinalizingStatus - }; - - enum Error - { - NoError, - ResourceError, - FormatError, - OutOfSpaceError - }; - enum CaptureMode { AudioOnly, AudioAndVideo }; - QMediaRecorder(QObject *parent = nullptr); + QMediaRecorder(QObject *parent = nullptr, CaptureMode mode = AudioOnly); ~QMediaRecorder(); bool isAvailable() const; + CaptureMode captureMode() const; + void setCaptureMode(CaptureMode mode); + + QCamera *camera() const; + QUrl outputLocation() const; bool setOutputLocation(const QUrl &location); - QUrl actualLocation() const; - State state() const; Status status() const; @@ -155,8 +117,8 @@ Q_SIGNALS: void durationChanged(qint64 duration); void mutedChanged(bool muted); void volumeChanged(qreal volume); - void actualLocationChanged(const QUrl &location); void audioInputChanged(); + void captureModeChanged(); void error(QMediaRecorder::Error error); @@ -168,19 +130,10 @@ private: QMediaRecorderPrivate *d_ptr; friend class QMediaCaptureSession; - void setCaptureSession(QMediaCaptureSession *session); Q_DISABLE_COPY(QMediaRecorder) Q_DECLARE_PRIVATE(QMediaRecorder) - Q_PRIVATE_SLOT(d_func(), void _q_stateChanged(QMediaRecorder::State)) - Q_PRIVATE_SLOT(d_func(), void _q_error(int, const QString &)) - Q_PRIVATE_SLOT(d_func(), void _q_updateActualLocation(const QUrl &)) - Q_PRIVATE_SLOT(d_func(), void _q_applySettings()) }; QT_END_NAMESPACE -Q_MEDIA_ENUM_DEBUG(QMediaRecorder, State) -Q_MEDIA_ENUM_DEBUG(QMediaRecorder, Status) -Q_MEDIA_ENUM_DEBUG(QMediaRecorder, Error) - #endif // QMEDIARECORDER_H diff --git a/src/multimedia/recording/qmediarecorder_p.h b/src/multimedia/recording/qmediarecorder_p.h index 2cadc709a..f1859d13a 100644 --- a/src/multimedia/recording/qmediarecorder_p.h +++ b/src/multimedia/recording/qmediarecorder_p.h @@ -64,34 +64,6 @@ class QAudioEncoderSettingsControl; class QVideoEncoderSettingsControl; class QTimer; -class QMediaRecorderPrivate -{ - Q_DECLARE_PUBLIC(QMediaRecorder) - -public: - QMediaRecorderPrivate() = default; - - void applySettingsLater(); - - QMediaCaptureSession *captureSession = nullptr; - - QPlatformMediaRecorder *control = nullptr; - - bool settingsChanged = false; - - QMediaRecorder::State state = QMediaRecorder::StoppedState; - QMediaRecorder::Error error = QMediaRecorder::NoError; - QString errorString; - QUrl actualLocation; - QMediaEncoderSettings encoderSettings; - - void _q_stateChanged(QMediaRecorder::State state); - void _q_error(int error, const QString &errorString); - void _q_updateActualLocation(const QUrl &); - void _q_applySettings(); - - QMediaRecorder *q_ptr = nullptr; -}; #undef Q_DECLARE_NON_CONST_PUBLIC |