Revision control

++ // 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/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>
++
++ #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 QMediaRecorder
++ \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.
++
++ Use the QMediaRecorder class to encode and record media generated in
++ \l QMediaCaptureSession. You can generate:
++ \list
++ \li Audio. Use \l QAudioInput or \l QAudioBufferInput.
++ \li Video. Use \l QCamera, \l QScreenCapture, \l QWindowCapture, \l QVideoFrameInput,
++ or \l QGStreamerVideoSource (on embedded Linux with the \c gstreamer media backend).
++ \endlist
++
++ To record media, connect a generator to a corresponding media capture session.
++
++ Performance of video encoding and recording is limited by the hardware,
++ the operating system, the installed graphic drivers, and the input video format.
++ If \c QCamera, \c QScreenCapture, or \c QWindowCapture produces video frames
++ faster than \c QMediaRecorder can encode and record them, the recorder
++ may drop some frames. This is likely to occur if the input frame resolution
++ is high, 4K for example, and hardware-accelerated encoding is unavailable.
++ If you generate input video via \c QVideoFrameInput, the method
++ \c QVideoFrameInput::sendVideoFrame will do nothing and return \c false
++ whenever this limitation is reached and the internal frame queue is full.
++ Rely on the signal \c QVideoFrameInput::readyToSendVideoFrame to know
++ when the recorder is ready to receive new frames again.
++ If you cannot change the rate of video frame generation and dropping frames
++ is undesirable, we recommend implementing your own frame queue on top of
++ \c QVideoFrameInput, considering the memory limitations of the hardware.
++
++ \snippet multimedia-snippets/media.cpp Media recorder
++ */
++ /*!
++ \qmltype MediaRecorder
++ \nativetype QMediaRecorder
++ \brief For encoding and recording media generated in a CaptureSession.
++
++ \inqmlmodule QtMultimedia
++ \ingroup multimedia_qml
++ \ingroup multimedia_audio_qml
++ \ingroup multimedia_video_qml
++
++ Use the MediaRecorder element within a CaptureSession to encode and record:
++ \list
++ \li Audio captured from an audio interface (like microphone or line input).
++ \li Video captured from camera, screen, or an application window.
++ \endlist
++
++ Performance of video encoding and recording is limited by the hardware,
++ the operating system, the installed graphic drivers, and the input video format.
++ If \c Camera, \c ScreenCapture, or \c WindowCapture produces video frames
++ faster than \c MediaRecorder can encode and record them, the recorder
++ may drop some frames. This is likely to occur if the input frame resolution
++ is high, 4K for example, and hardware-accelerated encoding is unavailable.
++
++ \since 6.2
++ 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
++ }
++ audioInput: AudioInput {}
++ recorder: MediaRecorder {
++ id: recorder
++ }
++ }
++ \endqml
++
++ The code below shows how the recording can be started and stopped.
++ \qml
++ CameraButton {
++ text: "Record"
++ visible: recorder.recorderState !== MediaRecorder.RecordingState
++ onClicked: recorder.record()
++ }
++
++ CameraButton {
++ id: stopButton
++ text: "Stop"
++ visible: recorder.recorderState === MediaRecorder.RecordingState
++ onClicked: recorder.stop()
++ }
++ \endqml
++
++ \sa CaptureSession, Camera, ScreenCapture, WindowCapture, AudioInput, ImageCapture
++ */
++ QMediaRecorderPrivate::QMediaRecorderPrivate()
++ {
++ #if QT_CONFIG(mimetype)
++ // Force an early initialization of the mime database
++ // to avoid a delay when recording for the first time.
++ encoderSettings.mimeType();
++ #endif
++ }
++
++ QString QMediaRecorderPrivate::msgFailedStartRecording()
++ {
++ return QMediaRecorder::tr("Failed to start recording");
++ }
++
++ /*!
++ Constructs a media recorder.
++ The media recorder is a child of \a{parent}.
++ */
++
++ QMediaRecorder::QMediaRecorder(QObject *parent)
++ : QObject(parent),
++ d_ptr(new QMediaRecorderPrivate)
++ {
++ Q_D(QMediaRecorder);
++
++ auto &mediaIntegration = *QPlatformMediaIntegration::instance();
++
++ d->q_ptr = 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();
++ }
++ }
++
++ /*!
++ Destroys a media recorder object.
++ */
++
++ QMediaRecorder::~QMediaRecorder()
++ {
++ if (d_ptr->captureSession)
++ d_ptr->captureSession->setRecorder(nullptr);
++ delete d_ptr->control;
++ delete d_ptr;
++ }
++
++ /*!
++ \internal
++ */
++ QPlatformMediaRecorder *QMediaRecorder::platformRecoder() const
++ {
++ return d_ptr->control;
++ }
++
++ /*!
++ \internal
++ */
++ void QMediaRecorder::setCaptureSession(QMediaCaptureSession *session)
++ {
++ Q_D(QMediaRecorder);
++ d->captureSession = session;
++ }
++ /*!
++ \qmlproperty url QtMultimedia::MediaRecorder::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 operation
++ fails, the \l errorOccurred() signal is emitted.
++
++ The output location can be empty, a directory, or a file. The path to a
++ directory or file can be relative or absolute. The \l record() method
++ generates the actual location according to the specified output location and
++ system-specific settings. Refer to the \l actualLocation property description
++ for details.
++
++ \sa actualLocation, errorOccurred()
++ */
++
++ /*!
++ \property QMediaRecorder::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 operation
++ fails, the \l errorOccurred() signal is emitted.
++
++ The output location is ignored if a writable \l outputDevice
++ has been assigned to the recorder.
++ This behavior may change in the future, so we recommend setting only one output,
++ either \c outputLocation or \c outputDevice.
++
++ The output location can be empty, a directory, or a file. The path to a
++ directory or file can be relative or absolute. The \l record() method
++ generates the actual location according to the specified output location and
++ system-specific settings. Refer to the \l actualLocation property description
++ for details.
++
++ \sa actualLocation, outputDevice()
++ */
++
++ /*!
++ \qmlproperty url QtMultimedia::MediaRecorder::actualLocation
++ \brief The actual location of the last media content.
++
++ The actual location is reset when a new \l outputLocation is assigned.
++ When \l record() is invoked, the recorder generates the actual location
++ basing on the following rules.
++ \list
++ \li If \c outputLocation is empty, a directory, or a file
++ without an extension, the recorder generates the appropriate extension
++ based on the selected media format and system MIME types.
++ \li If \c outputLocation is a directory, the recorder generates a new file
++ name within it.
++ \li If \c outputLocation is empty, the recorder generates a new file name in
++ the system-specific directory for audio or video.
++ \li The recorder generates the actual location before
++ emitting \c recorderStateChanged(RecordingState).
++ \endlist
++ */
++
++ /*!
++ \property QMediaRecorder::actualLocation
++ \brief The actual location of the last media content.
++
++ The actual location is reset when a new \l outputLocation
++ or a non-null \l outputDevice is assigned.
++ When \l record() is invoked and \c outputDevice is \c null or not writable,
++ the recorder generates the actual location basing on the following rules.
++ \list
++ \li If \c outputLocation is empty, a directory, or a file
++ without an extension, the recorder generates the appropriate extension
++ based on the selected media format and system MIME types.
++ \li If \c outputLocation is a directory, the recorder generates a new file
++ name within it.
++ \li If \c outputLocation is empty, the recorder generates a new file name in
++ the system-specific directory for audio or video.
++ \li The recorder generates the actual location before
++ emitting \c recorderStateChanged(RecordingState).
++ \endlist
++ */
++
++ /*!
++ Returns \c true if media recorder service ready to use.
++ */
++ bool QMediaRecorder::isAvailable() const
++ {
++ return d_func()->control && d_func()->captureSession;
++ }
++
++ QUrl QMediaRecorder::outputLocation() const
++ {
++ return d_func()->control ? d_func()->control->outputLocation() : QUrl();
++ }
++
++ void QMediaRecorder::setOutputLocation(const QUrl &location)
++ {
++ Q_D(QMediaRecorder);
++ if (!d->control) {
++ Q_EMIT errorOccurred(QMediaRecorder::ResourceError, d->initErrorMessage);
++ return;
++ }
++ d->control->setOutputLocation(location);
++ d->control->clearActualLocation();
++ if (!location.isEmpty() && !d->control->isLocationWritable(location))
++ Q_EMIT errorOccurred(QMediaRecorder::LocationNotWritable,
++ QStringLiteral("Output location not writable"));
++ }
++
++ /*!
++ Set the output IO device for media content.
++
++ The \a device must have been opened in the \l{QIODevice::WriteOnly}{WriteOnly} 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.
++
++ This method resets \l actualLocation immediately unless
++ the specified \a device is \c null.
++
++ If a writable output device is assigned to the recorder, \l outputLocation
++ is ignored, and \l actualLocation is not generated when recording starts.
++ This behavior may change in the future, so we recommend setting only
++ one output, either \c outputLocation or \c outputDevice.
++
++ \c QMediaRecorder::setOutputDevice is only supported with the FFmpeg backend.
++
++ \sa outputDevice(), outputLocation
++ */
++ void QMediaRecorder::setOutputDevice(QIODevice *device)
++ {
++ Q_D(QMediaRecorder);
++ if (!d->control) {
++ Q_EMIT errorOccurred(QMediaRecorder::ResourceError, d->initErrorMessage);
++ return;
++ }
++
++ d->control->setOutputDevice(device);
++
++ if (device)
++ d->control->clearActualLocation();
++ }
++
++ /*!
++ Returns the output IO device for media content.
++
++ \sa setOutputDevice()
++ */
++ QIODevice *QMediaRecorder::outputDevice() const
++ {
++ Q_D(const QMediaRecorder);
++ return d->control ? d->control->outputDevice() : nullptr;
++ }
++
++ QUrl QMediaRecorder::actualLocation() const
++ {
++ Q_D(const QMediaRecorder);
++ return d->control ? d->control->actualLocation() : QUrl();
++ }
++
++ /*!
++ Returns the current media recorder state.
++
++ \sa QMediaRecorder::RecorderState
++ */
++
++ QMediaRecorder::RecorderState QMediaRecorder::recorderState() const
++ {
++ return d_func()->control ? QMediaRecorder::RecorderState(d_func()->control->state()) : StoppedState;
++ }
++
++ /*!
++ \property QMediaRecorder::error
++
++ Returns the current error state.
++
++ \sa errorString()
++ */
++
++ QMediaRecorder::Error QMediaRecorder::error() const
++ {
++ Q_D(const QMediaRecorder);
++
++ return d->control ? d->control->error() : QMediaRecorder::ResourceError;
++ }
++ /*!
++ \qmlproperty string QtMultimedia::MediaRecorder::errorString
++ \brief This property holds a string describing the current error state.
++
++ \sa error
++ */
++ /*!
++ \property QMediaRecorder::errorString
++
++ Returns a string describing the current error state.
++
++ \sa error()
++ */
++
++ QString QMediaRecorder::errorString() const
++ {
++ Q_D(const QMediaRecorder);
++
++ return d->control ? d->control->errorString() : d->initErrorMessage;
++ }
++ /*!
++ \qmlproperty qint64 QtMultimedia::MediaRecorder::duration
++
++ \brief This property holds the recorded media duration in milliseconds.
++ */
++
++ /*!
++ \property QMediaRecorder::duration
++
++ \brief the recorded media duration in milliseconds.
++ */
++
++ qint64 QMediaRecorder::duration() const
++ {
++ return d_func()->control ? d_func()->control->duration() : 0;
++ }
++
++ #if QT_DEPRECATED_SINCE(6, 9)
++ /*!
++ \fn void QMediaRecorder::encoderSettingsChanged()
++ \deprecated [6.9] Use specific signals instead.
++
++ Signals when the encoder settings change.
++ */
++ #endif
++
++ /*!
++ \qmlmethod void QtMultimedia::MediaRecorder::record()
++ \brief Starts recording.
++
++ While the recorder state is changed immediately to
++ \c MediaRecorder.RecordingState, recording may start asynchronously.
++
++ If recording fails, the error() signal is emitted with recorder state being
++ reset back to \c{QMediaRecorder.StoppedState}.
++
++ This method updates \l actualLocation according to its generation rules.
++
++ \note On mobile devices, recording will happen in the orientation the
++ device had when calling record and is locked for the duration of the recording.
++ To avoid artifacts on the user interface, we recommend to keep the user interface
++ locked to the same orientation as long as the recording is ongoing using
++ the contentOrientation property of the Window and unlock it again once the recording
++ is finished.
++ */
++ /*!
++ Starts recording.
++
++ While the recorder state is changed immediately to
++ c\{QMediaRecorder::RecordingState}, recording may start asynchronously.
++
++ If recording fails error() signal is emitted with recorder state being
++ reset back to \c{QMediaRecorder::StoppedState}.
++
++ This method updates \l actualLocation according to its generation rules.
++
++ \note On mobile devices, recording will happen in the orientation the
++ device had when calling record and is locked for the duration of the recording.
++ To avoid artifacts on the user interface, we recommend to keep the user interface
++ locked to the same orientation as long as the recording is ongoing using
++ the contentOrientation property of QWindow and unlock it again once the recording
++ is finished.
++ */
++
++ void QMediaRecorder::record()
++ {
++ Q_D(QMediaRecorder);
++
++ if (!d->control || !d->captureSession)
++ return;
++
++ if (d->control->state() == QMediaRecorder::PausedState) {
++ d->control->resume();
++ } else {
++ auto oldMediaFormat = d->encoderSettings.mediaFormat();
++
++ 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();
++
++ auto settings = d->encoderSettings;
++ d->control->record(d->encoderSettings);
++
++ #if QT_DEPRECATED_SINCE(6, 9)
++ QT_WARNING_PUSH
++ QT_WARNING_DISABLE_DEPRECATED
++ if (settings != d->encoderSettings)
++ Q_EMIT encoderSettingsChanged();
++ QT_WARNING_POP
++ #endif
++
++ if (oldMediaFormat != d->encoderSettings.mediaFormat())
++ Q_EMIT mediaFormatChanged();
++
++ if (settings.encodingMode() != d->encoderSettings.encodingMode())
++ Q_EMIT encodingModeChanged();
++
++ if (settings.quality() != d->encoderSettings.quality())
++ Q_EMIT qualityChanged();
++
++ if (settings.videoResolution() != d->encoderSettings.videoResolution())
++ Q_EMIT videoResolutionChanged();
++
++ if (!QtPrivate::fuzzyCompare(settings.videoFrameRate(),
++ d->encoderSettings.videoFrameRate()))
++ Q_EMIT videoFrameRateChanged();
++
++ if (settings.videoBitRate() != d->encoderSettings.videoBitRate())
++ Q_EMIT videoBitRateChanged();
++
++ if (settings.audioBitRate() != d->encoderSettings.audioBitRate())
++ Q_EMIT audioBitRateChanged();
++
++ if (settings.audioChannelCount() != d->encoderSettings.audioChannelCount())
++ Q_EMIT audioChannelCountChanged();
++
++ if (settings.audioSampleRate() != d->encoderSettings.audioSampleRate())
++ Q_EMIT audioSampleRateChanged();
++ }
++ }
++ /*!
++ \qmlmethod void QtMultimedia::MediaRecorder::pause()
++ \brief Pauses recording.
++
++ The recorder state is changed to QMediaRecorder.PausedState.
++
++ Depending on the platform, pausing recording may be not supported.
++ In this case the recorder state is unchanged.
++ */
++ /*!
++ Pauses recording.
++
++ The recorder state is changed to QMediaRecorder::PausedState.
++
++ Depending on the platform, pausing recording may be not supported.
++ In this case the recorder state is unchanged.
++ */
++
++ void QMediaRecorder::pause()
++ {
++ Q_D(QMediaRecorder);
++ if (d->control && d->captureSession)
++ d->control->pause();
++ }
++ /*!
++ \qmlmethod void QtMultimedia::MediaRecorder::stop()
++ \brief Stops the recording.
++
++ 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.
++ */
++
++ /*!
++ 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);
++ if (d->control && d->captureSession)
++ d->control->stop();
++ }
++ /*!
++ \qmlproperty enumeration QtMultimedia::MediaRecorder::recorderState
++ \brief This property holds the current media recorder state.
++
++ 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.
++
++ \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.
++ \value RecordingState The recording is requested.
++ \value PausedState The recorder is paused.
++ */
++ /*!
++ \qmlproperty enumeration QtMultimedia::MediaRecorder::error
++ \brief This property holds the current media recorder error state.
++
++ \value MediaRecorder.NoError Not in an error state.
++ \value MediaRecorder.ResourceError Not enough system resources
++ \value MediaRecorder.FormatError the current format is not supported.
++ \value MediaRecorder.OutOfSpaceError No space left on device.
++ \value MediaRecorder.LocationNotWriteable The output location is not writable.
++ */
++ /*!
++ \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.
++ \value LocationNotWritable The output location is not writable.
++ */
++
++ /*!
++ \property QMediaRecorder::recorderState
++ \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.
++ */
++
++ /*!
++ \qmlsignal QtMultimedia::MediaRecorder::recorderStateChanged(RecorderState state)
++ \brief Signals that a media recorder's \a state has changed.
++ */
++
++ /*!
++ \fn QMediaRecorder::recorderStateChanged(QMediaRecorder::RecorderState state)
++
++ Signals that a media recorder's \a state has changed.
++ */
++
++ /*!
++ \qmlsignal QtMultimedia::MediaRecorder::durationChanged(qint64 duration)
++ \brief Signals that the \a duration of the recorded media has changed.
++ */
++
++ /*!
++ \fn QMediaRecorder::durationChanged(qint64 duration)
++
++ Signals that the \a duration of the recorded media has changed.
++ */
++ /*!
++ \qmlsignal QtMultimedia::MediaRecorder::actualLocationChanged(const QUrl &location)
++ \brief Signals that the actual \a location of the recorded media has changed.
++
++ This signal is usually emitted when recording starts.
++ */
++ /*!
++ \fn QMediaRecorder::actualLocationChanged(const QUrl &location)
++
++ Signals that the actual \a location of the recorded media has changed.
++ This signal is usually emitted when recording starts.
++ */
++ /*!
++ \qmlsignal QtMultimedia::MediaRecorder::errorOccurred(Error error, const QString &errorString)
++ \brief Signals that an \a error has occurred.
++
++ The \a errorString contains a description of the error.
++ */
++ /*!
++ \fn QMediaRecorder::errorOccurred(QMediaRecorder::Error error, const QString &errorString)
++
++ Signals that an \a error has occurred, with \a errorString containing
++ a description of the error.
++ */
++
++ /*!
++ \qmlproperty mediaMetaData QtMultimedia::MediaRecorder::metaData
++
++ \brief This property holds meta data associated with the recording.
++
++ When a recording is started, any meta-data assigned will be attached to that
++ recording.
++
++ \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
++ {
++ Q_D(const QMediaRecorder);
++
++ return d->control ? d->control->metaData() : QMediaMetaData{};
++ }
++
++ /*!
++ Sets the meta data to \a metaData.
++
++ \note To ensure that meta-data is set correctly, it should be set before starting the recording.
++ Once the recording is started, any meta-data set will be attached to the next recording.
++ */
++ void QMediaRecorder::setMetaData(const QMediaMetaData &metaData)
++ {
++ Q_D(QMediaRecorder);
++
++ if (d->control && d->captureSession)
++ d->control->setMetaData(metaData);
++ }
++
++ /*!
++ Adds \a metaData to the recorded media.
++ */
++ void QMediaRecorder::addMetaData(const QMediaMetaData &metaData)
++ {
++ auto data = this->metaData();
++ // merge data
++ for (auto &&[key, value] : metaData.asKeyValueRange())
++ data.insert(key, value);
++ setMetaData(data);
++ }
++
++ /*!
++ \property QMediaRecorder::autoStop
++
++ This property controls whether the media recorder stops automatically when
++ all media inputs have reported the end of the stream or have been deactivated.
++
++ The end of the stream is reported by sending an empty media frame,
++ which you can send explicitly via \l QVideoFrameInput or \l QAudioBufferInput.
++
++ Video inputs, specificly, \l QCamera, \l QScreenCapture and \l QWindowCapture,
++ can be deactivated via the function \c setActive.
++
++ Defaults to \c false.
++
++ QMediaRecorder::autoStop is only supported with the FFmpeg backend.
++
++ \sa QCamera, QScreenCapture, QWindowCapture
++ */
++
++ bool QMediaRecorder::autoStop() const
++ {
++ Q_D(const QMediaRecorder);
++
++ return d->autoStop;
++ }
++
++ void QMediaRecorder::setAutoStop(bool autoStop)
++ {
++ Q_D(QMediaRecorder);
++
++ if (d->autoStop == autoStop)
++ return;
++
++ d->autoStop = autoStop;
++
++ if (d->control)
++ d->control->updateAutoStop();
++
++ Q_EMIT autoStopChanged();
++ }
++
++ /*!
++ \qmlsignal QtMultimedia::MediaRecorder::metaDataChanged()
++
++ \brief Signals that a media object's meta-data has changed.
++
++ If multiple meta-data elements are changed metaDataChanged() is emitted
++ once.
++ */
++ /*!
++ \fn QMediaRecorder::metaDataChanged()
++
++ Signals that a media object's meta-data has changed.
++
++ If multiple meta-data elements are changed metaDataChanged() is emitted
++ once.
++ */
++
++ /*!
++ Returns the media capture session.
++ */
++ QMediaCaptureSession *QMediaRecorder::captureSession() const
++ {
++ Q_D(const QMediaRecorder);
++ return d->captureSession;
++ }
++ /*!
++ \qmlproperty enumeration QtMultimedia::MediaRecorder::quality
++
++ Enumerates quality encoding levels.
++
++ \value MediaRecorder.VeryLowQuality
++ \value MediaRecorder.LowQuality
++ \value MediaRecorder.NormalQuality
++ \value MediaRecorder.HighQuality
++ \value MediaRecorder.VeryHighQuality
++ */
++ /*!
++ \enum QMediaRecorder::Quality
++
++ Enumerates quality encoding levels.
++
++ \value VeryLowQuality
++ \value LowQuality
++ \value NormalQuality
++ \value HighQuality
++ \value VeryHighQuality
++ */
++
++ /*!
++ \enum QMediaRecorder::EncodingMode
++
++ Enumerates encoding modes.
++
++ \value ConstantQualityEncoding Encoding will aim to have a constant quality, adjusting bitrate to fit.
++ \value ConstantBitRateEncoding Encoding will use a constant bit rate, adjust quality to fit.
++ \value AverageBitRateEncoding Encoding will try to keep an average bitrate setting, but will use
++ more or less as needed.
++ \value TwoPassEncoding The media will first be processed to determine the characteristics,
++ and then processed a second time allocating more bits to the areas
++ that need it.
++ */
++
++ /*!
++
++ \qmlproperty mediaFormat QtMultimedia::MediaRecorder::mediaFormat
++
++ \brief This property holds the current MediaFormat of the recorder.
++ */
++ /*!
++ \property QMediaRecorder::mediaFormat
++
++ \brief This property holds the current \l QMediaFormat of the recorder.
++
++ The value of this property may change when invoking \l record(). If this happens, the
++ mediaFormatChanged() signal will be emitted. This will always happen if the
++ \l QMediaFormat::audioCodec or \l QMediaFormat::fileFormat properties are set to unspecified.
++ If a video source (\l QCamera, \l QScreenCapture, or \l QVideoFrameInput) is connected to the
++ \l QMediaCaptureSession, \l QMediaFormat::videoCodec must also be specified.
++ The \l QMediaFormat::audioCodec and \l QMediaFormat::videoCodec property values may also change
++ if the media backend does not support the selected file format or codec.
++
++ The \l QMediaFormat::fileFormat property value may also change to an \c audio only format if a
++ video format was requested, but \l QMediaCaptureSession does not have a video source connected.
++ For example, if \l QMediaFormat::fileFormat is set to \l QMediaFormat::MPEG4, it may
++ be changed to \l QMediaFormat::Mpeg4Audio.
++
++ Applications can determine if \c mediaFormat will change before recording starts by calling the
++ \l QMediaFormat::isSupported() function. When recording without any video inputs,
++ \l record() will not be changed the \l QMediaFormat if the following is true:
++ \list
++ \li \l QMediaFormat::fileFormat is specified
++ \li \l QMediaFormat::audioCodec is specified
++ \li \l QMediaFormat::videoCodec is \b{unspecified}
++ \li \l QMediaFormat::isSupported() returns \c true
++ \endlist
++ When recording with video input, \c mediaFormat will not be changed if the following is true:
++ \list
++ \li \l QMediaFormat::fileFormat is specified
++ \li \l QMediaFormat::audioCodec is specified
++ \li \l QMediaFormat::videoCodec is specified
++ \li \l QMediaFormat::isSupported() returns \c true
++ \endlist
++
++ \note The \l QMediaRecorder does not take the file name extension from the \l outputLocation
++ property into account when determining the \l QMediaFormat::fileFormat, and will not adjust the
++ extension of the \l outputLocation \l QUrl to match the selected file format if an extension is
++ specified. Applications should therefore make sure to set the
++ \l {QMediaFormat::fileFormat}{QMediaRecorder::mediaFormat::fileFormat} to match the file
++ extension, or not specify a file extension. If no file extension is specified, the
++ \l actualLocation file extension will be updated to match the file format used for recording.
++
++ \sa QMediaFormat::isSupported(), actualLocation
++ */
++ QMediaFormat QMediaRecorder::mediaFormat() const
++ {
++ Q_D(const QMediaRecorder);
++ return d->encoderSettings.mediaFormat();
++ }
++
++ void QMediaRecorder::setMediaFormat(const QMediaFormat &format)
++ {
++ Q_D(QMediaRecorder);
++ if (d->encoderSettings.mediaFormat() == format)
++ return;
++ d->encoderSettings.setMediaFormat(format);
++ Q_EMIT mediaFormatChanged();
++ }
++
++ /*!
++
++ \qmlproperty enumeration QtMultimedia::MediaRecorder::encodingMode
++ \since 6.6
++ \brief This property holds the encoding mode.
++ \sa QMediaRecorder::EncodingMode
++ */
++
++ /*!
++ \property QMediaRecorder::encodingMode
++ \brief the encoding mode.
++ \sa EncodingMode
++ */
++
++ /*!
++ Returns the encoding mode.
++
++ \sa EncodingMode
++ */
++ QMediaRecorder::EncodingMode QMediaRecorder::encodingMode() const
++ {
++ Q_D(const QMediaRecorder);
++ return d->encoderSettings.encodingMode();
++ }
++
++ /*!
++ \fn void QMediaRecorder::encodingModeChanged()
++
++ Signals when the encoding mode changes.
++ */
++ /*!
++ Sets the encoding \a mode setting.
++
++ If ConstantQualityEncoding is set, the quality
++ encoding parameter is used and bit rates are ignored,
++ otherwise the bitrates are used.
++
++ \sa encodingMode(), EncodingMode
++ */
++ void QMediaRecorder::setEncodingMode(EncodingMode mode)
++ {
++ Q_D(QMediaRecorder);
++ if (d->encoderSettings.encodingMode() == mode)
++ return;
++ d->encoderSettings.setEncodingMode(mode);
++ Q_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);
++
++ quality = std::clamp(quality, QMediaRecorder::Quality::VeryLowQuality,
++ QMediaRecorder::Quality::VeryHighQuality);
++
++ if (d->encoderSettings.quality() == quality)
++ return;
++
++ d->encoderSettings.setQuality(quality);
++ Q_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.
++ */
++
++ /*!
++ \property QMediaRecorder::videoResolution
++ \since 6.6
++ \brief the resolution of the encoded video.
++
++ An empty QSize indicates the recorder will 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.
++ */
++ QSize QMediaRecorder::videoResolution() const
++ {
++ Q_D(const QMediaRecorder);
++ return d->encoderSettings.videoResolution();
++ }
++
++ /*!
++ \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
++ on what is available from the video source and the limitations of the codec.
++ */
++ void QMediaRecorder::setVideoResolution(const QSize &size)
++ {
++ Q_D(QMediaRecorder);
++ if (d->encoderSettings.videoResolution() == size)
++ return;
++ d->encoderSettings.setVideoResolution(size);
++ Q_EMIT videoResolutionChanged();
++ }
++
++ /*! \fn void QMediaRecorder::setVideoResolution(int width, int height)
++
++ Sets the \a width and \a height of the resolution of the encoded video.
++
++ \overload
++ */
++
++ /*!
++ \qmlproperty real QtMultimedia::MediaRecorder::videoFrameRate
++ \since 6.6
++ \brief This property holds the video frame rate used in encoding.
++
++ If this property is set to a positive frame rate, MediaRecorder attempts to
++ encode at that rate. If the video source's and recoder's frame rates are
++ different, frames from the source may be dropped or duplicated to
++ reach the target rate.
++
++ If left at the default value (-1) or set to another non-positive value,
++ MediaRecorder attempts to make the optimal choice based on the video source
++ and codec limitations.
++ */
++
++ /*!
++ \property QMediaRecorder::videoFrameRate
++ \since 6.6
++ \brief the video frame rate used in encoding.
++
++ If this property is set to a positive frame rate, QMediaRecorder attempts to
++ encode at that rate. If the video source's and recoder's frame rates are
++ different, frames from the source may be dropped or duplicated to
++ reach the target rate.
++
++ If left at the default value (-1) or set to another non-positive value,
++ QMediaRecorder attempts to make the optimal choice based on the video source
++ and codec limitations.
++ */
++
++ /*!
++ Returns the video encoding frame rate.
++ */
++ qreal QMediaRecorder::videoFrameRate() const
++ {
++ Q_D(const QMediaRecorder);
++ return d->encoderSettings.videoFrameRate();
++ }
++
++ /*!
++ \fn void QMediaRecorder::videoFrameRateChanged()
++
++ Signals when the video encoding frame rate changes.
++ */
++ /*!
++ Sets the video encoding \a frameRate.
++ */
++ void QMediaRecorder::setVideoFrameRate(qreal frameRate)
++ {
++ Q_D(QMediaRecorder);
++ if (d->encoderSettings.videoFrameRate() == frameRate)
++ return;
++ d->encoderSettings.setVideoFrameRate(frameRate);
++ Q_EMIT videoFrameRateChanged();
++ }
++
++ /*!
++ \qmlproperty int QtMultimedia::MediaRecorder::videoBitRate
++ \since 6.6
++ \brief This property holds the bit rate of the compressed video stream in bits per second.
++ */
++
++ /*!
++ \property QMediaRecorder::videoBitRate
++ \since 6.6
++ \brief 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
++ {
++ Q_D(const QMediaRecorder);
++ return d->encoderSettings.videoBitRate();
++ }
++
++ /*!
++ \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)
++ {
++ Q_D(QMediaRecorder);
++ if (d->encoderSettings.videoBitRate() == bitRate)
++ return;
++ d->encoderSettings.setVideoBitRate(bitRate);
++ Q_EMIT videoBitRateChanged();
++ }
++
++ /*!
++ \qmlproperty int QtMultimedia::MediaRecorder::audioBitRate
++ \since 6.6
++ \brief This property holds the bit rate of the compressed audio stream in bits per second.
++ */
++
++ /*!
++ \property QMediaRecorder::audioBitRate
++ \brief 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
++ {
++ Q_D(const QMediaRecorder);
++ return d->encoderSettings.audioBitRate();
++ }
++
++ /*!
++ \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)
++ {
++ Q_D(QMediaRecorder);
++ if (d->encoderSettings.audioBitRate() == bitRate)
++ return;
++ d->encoderSettings.setAudioBitRate(bitRate);
++ Q_EMIT audioBitRateChanged();
++ }
++
++ /*!
++ \qmlproperty int QtMultimedia::MediaRecorder::audioChannelCount
++ \since 6.6
++ \brief This property holds the number of audio channels.
++ */
++
++ /*!
++ \property QMediaRecorder::audioChannelCount
++ \brief the number of audio channels.
++ */
++
++ /*!
++ Returns the number of audio channels.
++ */
++ int QMediaRecorder::audioChannelCount() const
++ {
++ Q_D(const QMediaRecorder);
++ return d->encoderSettings.audioChannelCount();
++ }
++
++ /*!
++ \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
++ what is available from the audio source and the limitations of the codec.
++ */
++ void QMediaRecorder::setAudioChannelCount(int channels)
++ {
++ Q_D(QMediaRecorder);
++ if (d->encoderSettings.audioChannelCount() == channels)
++ return;
++ d->encoderSettings.setAudioChannelCount(channels);
++ Q_EMIT audioChannelCountChanged();
++ }
++
++ /*!
++ \qmlproperty int QtMultimedia::MediaRecorder::audioSampleRate
++ \since 6.6
++ \brief This property holds the audio sample rate in Hz.
++ */
++
++ /*!
++ \property QMediaRecorder::audioSampleRate
++ \brief the audio sample rate in Hz.
++ */
++
++ /*!
++ Returns the audio sample rate in Hz.
++ */
++ 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.
++
++ A value of \c -1 indicates the recorder should make an optimal choice based
++ on what is available from the audio source, and the limitations of the codec.
++ */
++ void QMediaRecorder::setAudioSampleRate(int sampleRate)
++ {
++ Q_D(QMediaRecorder);
++ if (d->encoderSettings.audioSampleRate() == sampleRate)
++ return;
++ d->encoderSettings.setAudioSampleRate(sampleRate);
++ Q_EMIT audioSampleRateChanged();
++ }
++
++ QT_END_NAMESPACE
++
++ #include "moc_qmediarecorder.cpp"