diff options
Diffstat (limited to 'src/multimedia/recording/qmediarecorder.cpp')
-rw-r--r-- | src/multimedia/recording/qmediarecorder.cpp | 328 |
1 files changed, 217 insertions, 111 deletions
diff --git a/src/multimedia/recording/qmediarecorder.cpp b/src/multimedia/recording/qmediarecorder.cpp index afa189c89..a7f5a31b8 100644 --- a/src/multimedia/recording/qmediarecorder.cpp +++ b/src/multimedia/recording/qmediarecorder.cpp @@ -1,49 +1,16 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qmediarecorder_p.h" -#include <private/qplatformmediaencoder_p.h> +#include <private/qplatformmediarecorder_p.h> #include <qaudiodevice.h> #include <qcamera.h> +#include <qscreencapture.h> +#include <qwindowcapture.h> #include <qmediacapturesession.h> #include <private/qplatformcamera_p.h> +#include <private/qplatformsurfacecapture_p.h> #include <private/qplatformmediaintegration_p.h> #include <private/qplatformmediacapture_p.h> @@ -62,6 +29,8 @@ QT_BEGIN_NAMESPACE \inmodule QtMultimedia \ingroup multimedia \ingroup multimedia_recording + \ingroup multimedia_video + \ingroup multimedia_audio \brief The QMediaRecorder class is used for encoding and recording a capture session. @@ -80,48 +49,44 @@ QT_BEGIN_NAMESPACE \ingroup multimedia_audio_qml \ingroup multimedia_video_qml + The MediaRecorder element can be used within a CaptureSession to record and encode audio and + video captured from a microphone and camera + \since 6.2 - The code below shows how this qml is instantiated. + The code below shows a simple capture session containing a MediaRecorder using the default + camera and default audio input. + \qml CaptureSession { id: captureSession camera: Camera { id: camera + active: true } - imageCapture: ImageCapture { - id: imageCapture - } - + audioInput: AudioInput {} recorder: MediaRecorder { id: recorder } } \endqml - The code below shows how some properties are used. + The code below shows how the recording can be started and stopped. \qml CameraButton { text: "Record" - visible: captureSession.recorder.status !== MediaRecorder.RecordingStatus - onClicked: captureSession.recorder.record() + visible: recorder.recorderState !== MediaRecorder.RecordingState + onClicked: recorder.record() } CameraButton { id: stopButton text: "Stop" - visible: captureSession.recorder.status === MediaRecorder.RecordingStatus - onClicked: captureSession.recorder.stop() - } - - CameraButton { - text: "View" - onClicked: captureControls.previewSelected() - //don't show View button during recording - visible: captureSession.recorder.actualLocation && !stopButton.visible + visible: recorder.recorderState === MediaRecorder.RecordingState + onClicked: recorder.stop() } \endqml - \sa CaptureSession + \sa CaptureSession, Camera, AudioInput, ImageCapture */ QMediaRecorderPrivate::QMediaRecorderPrivate() { @@ -145,8 +110,22 @@ QMediaRecorder::QMediaRecorder(QObject *parent) d_ptr(new QMediaRecorderPrivate) { Q_D(QMediaRecorder); + + auto &mediaIntegration = *QPlatformMediaIntegration::instance(); + d->q_ptr = this; - d->control = QPlatformMediaIntegration::instance()->createEncoder(this); + auto maybeControl = mediaIntegration.createRecorder(this); + if (maybeControl) { + // The first format info initialization may take some time, + // for users it seems to be more suitable to have a delay on the object construction + // rather than on QMediaRecorder::record + mediaIntegration.formatInfo(); + + d->control = maybeControl.value(); + } else { + d->initErrorMessage = maybeControl.error(); + qWarning() << "Failed to initialize QMediaRecorder" << maybeControl.error(); + } } /*! @@ -155,11 +134,8 @@ QMediaRecorder::QMediaRecorder(QObject *parent) QMediaRecorder::~QMediaRecorder() { - if (d_ptr->captureSession) { - if (d_ptr->captureSession->platformSession()) - d_ptr->captureSession->platformSession()->setMediaEncoder(nullptr); + if (d_ptr->captureSession) d_ptr->captureSession->setRecorder(nullptr); - } delete d_ptr->control; delete d_ptr; } @@ -167,22 +143,18 @@ QMediaRecorder::~QMediaRecorder() /*! \internal */ +QPlatformMediaRecorder *QMediaRecorder::platformRecoder() const +{ + return d_ptr->control; +} + +/*! + \internal +*/ void QMediaRecorder::setCaptureSession(QMediaCaptureSession *session) { Q_D(QMediaRecorder); - if (d->captureSession == session) - return; - d->captureSession = session; - - if (!d->captureSession) - return; - - QPlatformMediaCaptureSession *platformSession = session->platformSession(); - if (!platformSession || !d->control) - return; - - platformSession->setMediaEncoder(d->control); } /*! \qmlproperty QUrl QtMultimedia::MediaRecorder::outputLocation @@ -227,17 +199,11 @@ void QMediaRecorder::setCaptureSession(QMediaCaptureSession *session) */ /*! - \qmlproperty bool QtMultimedia::MediaRecorder::isAvailable - \brief This property holds whether the recorder service is ready to use. - - Returns \c true if media recorder service ready to use. -*/ -/*! Returns \c true if media recorder service ready to use. */ bool QMediaRecorder::isAvailable() const { - return d_func()->control != nullptr && d_func()->captureSession; + return d_func()->control && d_func()->captureSession; } QUrl QMediaRecorder::outputLocation() const @@ -249,7 +215,7 @@ void QMediaRecorder::setOutputLocation(const QUrl &location) { Q_D(QMediaRecorder); if (!d->control) { - emit errorOccurred(QMediaRecorder::ResourceError, tr("Not available")); + emit errorOccurred(QMediaRecorder::ResourceError, d->initErrorMessage); return; } d->control->setOutputLocation(location); @@ -258,6 +224,35 @@ void QMediaRecorder::setOutputLocation(const QUrl &location) emit errorOccurred(QMediaRecorder::LocationNotWritable, tr("Output location not writable")); } +/*! + Set the output IO device for media content. + + The \a device must have been opened in the \l{QIODevice::Write}{Write} or + \l{QIODevice::ReadWrite}{ReadWrite} modes before the recording starts. + + The media recorder doesn't take ownership of the specified \a device. + If the recording has been started, the device must be kept alive and open until + the signal \c recorderStateChanged(StoppedState) is emitted. + + \sa outputDevice() +*/ +void QMediaRecorder::setOutputDevice(QIODevice *device) +{ + Q_D(QMediaRecorder); + d->control->setOutputDevice(device); +} + +/*! + Returns the output IO device for media content. + + \sa setOutputDevice() +*/ +QIODevice *QMediaRecorder::outputDevice() const +{ + Q_D(const QMediaRecorder); + return d->control->outputDevice(); +} + QUrl QMediaRecorder::actualLocation() const { Q_D(const QMediaRecorder); @@ -276,6 +271,8 @@ QMediaRecorder::RecorderState QMediaRecorder::recorderState() const } /*! + \property QMediaRecorder::error + Returns the current error state. \sa errorString() @@ -294,6 +291,8 @@ QMediaRecorder::Error QMediaRecorder::error() const \sa error */ /*! + \property QMediaRecorder::errorString + Returns a string describing the current error state. \sa error() @@ -303,7 +302,7 @@ QString QMediaRecorder::errorString() const { Q_D(const QMediaRecorder); - return d->control ? d->control->errorString() : tr("QMediaRecorder not supported on this platform"); + return d->control ? d->control->errorString() : d->initErrorMessage; } /*! \qmlproperty qint64 QtMultimedia::MediaRecorder::duration @@ -322,6 +321,11 @@ qint64 QMediaRecorder::duration() const return d_func()->control ? d_func()->control->duration() : 0; } /*! + \fn void QMediaRecorder::encoderSettingsChanged() + + Signals when the encoder settings change. +*/ +/*! \qmlmethod QtMultimedia::MediaRecorder::record() \brief Starts recording. @@ -359,17 +363,18 @@ void QMediaRecorder::record() { Q_D(QMediaRecorder); - if (!d->control || ! d->captureSession) + if (!d->control || !d->captureSession) return; if (d->control->state() == QMediaRecorder::PausedState) { d->control->resume(); } else { auto oldMediaFormat = d->encoderSettings.mediaFormat(); - auto camera = d->captureSession->camera(); - auto flags = camera && camera->isActive() ? QMediaFormat::RequiresVideo - : QMediaFormat::NoFlags; - d->encoderSettings.resolveFormat(flags); + + auto platformSession = d->captureSession->platformSession(); + const bool hasVideo = platformSession && !platformSession->activeVideoSources().empty(); + + d->encoderSettings.resolveFormat(hasVideo ? QMediaFormat::RequiresVideo : QMediaFormat::NoFlags); d->control->clearActualLocation(); d->control->clearError(); @@ -409,17 +414,18 @@ void QMediaRecorder::pause() } /*! \qmlmethod QtMultimedia::MediaRecorder::stop() - \brief Stops recording. + \brief Stops the recording. - The recorder state is changed to \c{QMediaRecorder.StoppedState}. + The recorder will stop the recording. Processing pending video and audio data might + however still take some time. The recording is finished, once the state of the media + recorder changes to QMediaRecorder::StoppedState. */ /*! - Stops recording. - - The recorder state is changed to QMediaRecorder::StoppedState. + The recorder will stop the recording. Processing pending video and audio data might + however still take some time. The recording is finished, once the state of the media + recorder changes to QMediaRecorder::StoppedState. */ - void QMediaRecorder::stop() { Q_D(QMediaRecorder); @@ -434,22 +440,14 @@ void QMediaRecorder::stop() during record(), pause() or stop() calls. RecorderSstate may also change asynchronously when recording fails. - \value recorderState.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 recorderState.RecordingState The recording is requested. - \value recorderState.PausedState The recorder is pause. + \value MediaRecorder.StoppedState The recorder is not active. + \value MediaRecorder.RecordingState The recording is requested. + \value MediaRecorder.PausedState The recorder is pause. */ /*! \enum QMediaRecorder::RecorderState \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. */ @@ -529,7 +527,7 @@ void QMediaRecorder::stop() */ /*! - \qmlproperty MetaData QtMultimedia::MediaRecorder::metaData + \qmlproperty mediaMetaData QtMultimedia::MediaRecorder::metaData \brief This property holds meta data associated with the recording. @@ -538,9 +536,13 @@ void QMediaRecorder::stop() \note Ensure that meta-data is assigned correctly by assigning it before starting the recording. + + \sa mediaMetaData */ /*! + \property QMediaRecorder::metaData + Returns the metaData associated with the recording. */ QMediaMetaData QMediaRecorder::metaData() const @@ -564,6 +566,9 @@ void QMediaRecorder::setMetaData(const QMediaMetaData &metaData) d->control->setMetaData(metaData); } +/*! + Adds \a metaData to the recorded media. +*/ void QMediaRecorder::addMetaData(const QMediaMetaData &metaData) { auto data = this->metaData(); @@ -589,6 +594,9 @@ void QMediaRecorder::addMetaData(const QMediaMetaData &metaData) once. */ +/*! + Returns the media capture session. +*/ QMediaCaptureSession *QMediaRecorder::captureSession() const { Q_D(const QMediaRecorder); @@ -599,11 +607,11 @@ QMediaCaptureSession *QMediaRecorder::captureSession() const Enumerates quality encoding levels. - \value MediaaRecorder.VeryLowQuality - \value MediaaRecorder.LowQuality - \value MediaaRecorder.NormalQuality - \value MediaaRecorder.HighQuality - \value MediaaRecorder.VeryHighQuality + \value MediaRecorder.VeryLowQuality + \value MediaRecorder.LowQuality + \value MediaRecorder.NormalQuality + \value MediaRecorder.HighQuality + \value MediaRecorder.VeryHighQuality */ /*! \enum QMediaRecorder::Quality @@ -637,7 +645,11 @@ QMediaCaptureSession *QMediaRecorder::captureSession() const \brief This property holds the current MediaFormat of the recorder. */ +/*! + \property QMediaRecorder::mediaFormat + Returns the recording media format. +*/ QMediaFormat QMediaRecorder::mediaFormat() const { Q_D(const QMediaRecorder); @@ -654,6 +666,14 @@ void QMediaRecorder::setMediaFormat(const QMediaFormat &format) } /*! + + \qmlproperty enumeration QtMultimedia::MediaRecorder::encodingMode + \since 6.6 + \brief This property holds the encoding mode. + \sa QMediaRecorder::EncodingMode +*/ + +/*! Returns the encoding mode. \sa EncodingMode @@ -665,6 +685,11 @@ QMediaRecorder::EncodingMode QMediaRecorder::encodingMode() const } /*! + \fn void QMediaRecorder::encodingModeChanged() + + Signals when the encoding mode changes. +*/ +/*! Sets the encoding \a mode setting. If ConstantQualityEncoding is set, the quality @@ -682,12 +707,22 @@ void QMediaRecorder::setEncodingMode(EncodingMode mode) emit encodingModeChanged(); } +/*! + \property QMediaRecorder::quality + + Returns the recording quality. +*/ QMediaRecorder::Quality QMediaRecorder::quality() const { Q_D(const QMediaRecorder); return d->encoderSettings.quality(); } +/*! + \fn void QMediaRecorder::qualityChanged() + + Signals when the recording quality changes. +*/ void QMediaRecorder::setQuality(Quality quality) { Q_D(QMediaRecorder); @@ -697,6 +732,15 @@ void QMediaRecorder::setQuality(Quality quality) emit qualityChanged(); } +/*! + \qmlproperty Size QtMultimedia::MediaRecorder::videoResolution + \since 6.6 + \brief This property holds the resolution of the encoded video. + + Set an empty Size to make the recorder choose an optimal resolution based + on what is available from the video source and the limitations of the codec. +*/ + /*! Returns the resolution of the encoded video. @@ -708,6 +752,11 @@ QSize QMediaRecorder::videoResolution() const } /*! + \fn void QMediaRecorder::videoResolutionChanged() + + Signals when the video recording resolution changes. +*/ +/*! Sets the resolution of the encoded video to \a{size}. Pass an empty QSize to make the recorder choose an optimal resolution based @@ -730,6 +779,15 @@ void QMediaRecorder::setVideoResolution(const QSize &size) */ /*! + \qmlproperty real QtMultimedia::MediaRecorder::videoFrameRate + \since 6.6 + \brief This property holds the video frame rate. + + A value of 0 indicates the recorder should make an optimal choice based on what is available + from the video source and the limitations of the codec. +*/ + +/*! Returns the video frame rate. */ qreal QMediaRecorder::videoFrameRate() const @@ -739,6 +797,11 @@ qreal QMediaRecorder::videoFrameRate() const } /*! + \fn void QMediaRecorder::videoFrameRateChanged() + + Signals when the recording video frame rate changes. +*/ +/*! Sets the video \a frameRate. A value of 0 indicates the recorder should make an optimal choice based on what is available @@ -754,6 +817,12 @@ void QMediaRecorder::setVideoFrameRate(qreal frameRate) } /*! + \qmlproperty int QtMultimedia::MediaRecorder::videoBitRate + \since 6.6 + \brief This property holds the bit rate of the compressed video stream in bits per second. +*/ + +/*! Returns the bit rate of the compressed video stream in bits per second. */ int QMediaRecorder::videoBitRate() const @@ -763,6 +832,11 @@ int QMediaRecorder::videoBitRate() const } /*! + \fn void QMediaRecorder::videoBitRateChanged() + + Signals when the recording video bit rate changes. +*/ +/*! Sets the video \a bitRate in bits per second. */ void QMediaRecorder::setVideoBitRate(int bitRate) @@ -775,6 +849,12 @@ void QMediaRecorder::setVideoBitRate(int bitRate) } /*! + \qmlproperty int QtMultimedia::MediaRecorder::audioBitRate + \since 6.6 + \brief This property holds the bit rate of the compressed audio stream in bits per second. +*/ + +/*! Returns the bit rate of the compressed audio stream in bits per second. */ int QMediaRecorder::audioBitRate() const @@ -784,6 +864,11 @@ int QMediaRecorder::audioBitRate() const } /*! + \fn void QMediaRecorder::audioBitRateChanged() + + Signals when the recording audio bit rate changes. +*/ +/*! Sets the audio \a bitRate in bits per second. */ void QMediaRecorder::setAudioBitRate(int bitRate) @@ -796,6 +881,12 @@ void QMediaRecorder::setAudioBitRate(int bitRate) } /*! + \qmlproperty int QtMultimedia::MediaRecorder::audioChannelCount + \since 6.6 + \brief This property holds the number of audio channels. +*/ + +/*! Returns the number of audio channels. */ int QMediaRecorder::audioChannelCount() const @@ -805,6 +896,11 @@ int QMediaRecorder::audioChannelCount() const } /*! + \fn void QMediaRecorder::audioChannelCountChanged() + + Signals when the recording audio channel count changes. +*/ +/*! Sets the number of audio \a channels. A value of -1 indicates the recorder should make an optimal choice based on @@ -820,6 +916,12 @@ void QMediaRecorder::setAudioChannelCount(int channels) } /*! + \qmlproperty int QtMultimedia::MediaRecorder::audioSampleRate + \since 6.6 + \brief This property holds the audio sample rate in Hz. +*/ + +/*! Returns the audio sample rate in Hz. */ int QMediaRecorder::audioSampleRate() const @@ -827,7 +929,11 @@ int QMediaRecorder::audioSampleRate() const Q_D(const QMediaRecorder); return d->encoderSettings.audioSampleRate(); } +/*! + \fn void QMediaRecorder::audioSampleRateChanged() + Signals when the recording audio sample rate changes. +*/ /*! Sets the audio \a sampleRate in Hz. |