diff options
Diffstat (limited to 'src/multimedia/recording/qmediacapturesession.cpp')
-rw-r--r-- | src/multimedia/recording/qmediacapturesession.cpp | 436 |
1 files changed, 328 insertions, 108 deletions
diff --git a/src/multimedia/recording/qmediacapturesession.cpp b/src/multimedia/recording/qmediacapturesession.cpp index 9860ea65b..9df09acef 100644 --- a/src/multimedia/recording/qmediacapturesession.cpp +++ b/src/multimedia/recording/qmediacapturesession.cpp @@ -1,85 +1,40 @@ -/**************************************************************************** -** -** 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) 2022 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 "qmediacapturesession.h" +#include "qmediacapturesession_p.h" #include "qaudiodevice.h" #include "qcamera.h" #include "qmediarecorder.h" #include "qimagecapture.h" #include "qvideosink.h" - -#include <qpointer.h> +#include "qscreencapture.h" +#include "qwindowcapture.h" +#include "qvideoframeinput.h" #include "qplatformmediaintegration_p.h" #include "qplatformmediacapture_p.h" #include "qaudioinput.h" +#include "qaudiobufferinput.h" #include "qaudiooutput.h" QT_BEGIN_NAMESPACE -class QMediaCaptureSessionPrivate +void QMediaCaptureSessionPrivate::setVideoSink(QVideoSink *sink) { -public: - QMediaCaptureSession *q = nullptr; - QPlatformMediaCaptureSession *captureSession; - QAudioInput *audioInput = nullptr; - QAudioOutput *audioOutput = nullptr; - QCamera *camera = nullptr; - QImageCapture *imageCapture = nullptr; - QMediaRecorder *recorder = nullptr; - QVideoSink *videoSink = nullptr; - QPointer<QObject> videoOutput; - - void setVideoSink(QVideoSink *sink) - { - if (sink == videoSink) - return; - if (videoSink) - videoSink->setSource(nullptr); - videoSink = sink; - if (sink) - sink->setSource(q); - captureSession->setVideoPreview(sink); - emit q->videoOutputChanged(); - } + Q_Q(QMediaCaptureSession); -}; + if (sink == videoSink) + return; + if (videoSink) + videoSink->setSource(nullptr); + videoSink = sink; + if (sink) + sink->setSource(q); + if (captureSession) + captureSession->setVideoPreview(sink); + emit q->videoOutputChanged(); +} /*! \class QMediaCaptureSession @@ -90,16 +45,23 @@ public: \ingroup multimedia_video \ingroup multimedia_audio - The QMediaCaptureSession is the central class that manages capturing of media on the local device. + The QMediaCaptureSession is the central class that manages capturing of media on the local + device. - You can connect a camera and a microphone to QMediaCaptureSession using setCamera() and setAudioInput(). - A preview of the captured media can be seen by setting a QVideoSink of QVideoWidget using setVideoOutput() - and heard by routing the audio to an output device using setAudioOutput(). + You can connect a video input to QMediaCaptureSession using setCamera(), + setScreenCapture(), setWindowCapture() or setVideoFrameInput(). + A preview of the captured media can be seen by setting a QVideoWidget or QGraphicsVideoItem + using setVideoOutput(). - You can capture still images from a camera by setting a QImageCapture object on the capture session, - and record audio/video using a QMediaRecorder. + You can connect a microphone to QMediaCaptureSession using setAudioInput(), or set your + custom audio input using setAudioBufferInput(). + The captured sound can be heard by routing the audio to an output device using setAudioOutput(). - \sa QCamera, QAudioDevice, QMediaRecorder, QImageCapture, QMediaRecorder + You can capture still images from a camera by setting a QImageCapture object on the capture + session, and record audio/video using a QMediaRecorder. + + \sa QCamera, QAudioDevice, QMediaRecorder, QImageCapture, QScreenCapture, QWindowCapture, + QVideoFrameInput, QMediaRecorder, QGraphicsVideoItem */ /*! @@ -118,6 +80,12 @@ public: Connect a camera and a microphone to a CaptureSession by assigning Camera and AudioInput objects to the relevant properties. + Capture a screen by connecting a ScreenCapture object to + the screenCapture property. + + Capture a window by connecting a WindowCapture object to + the windowCapture property. + Enable a preview of the captured media by assigning a VideoOutput element to the videoOutput property. @@ -146,20 +114,26 @@ public: } \endqml - \sa Camera, MediaDevices, MediaRecorder, ImageCapture, AudioInput, VideoOutput + \sa Camera, MediaDevices, MediaRecorder, ImageCapture, ScreenCapture, WindowCapture, AudioInput, VideoOutput */ /*! Creates a session for media capture from the \a parent object. */ QMediaCaptureSession::QMediaCaptureSession(QObject *parent) - : QObject(parent), - d_ptr(new QMediaCaptureSessionPrivate) + : QObject{ *new QMediaCaptureSessionPrivate, parent } { - d_ptr->q = this; - d_ptr->captureSession = QPlatformMediaIntegration::instance()->createCaptureSession(); - d_ptr->captureSession->setCaptureSession(this); - Q_ASSERT(d_ptr->captureSession); + QT6_ONLY(Q_UNUSED(unused)) + + Q_D(QMediaCaptureSession); + + auto maybeCaptureSession = QPlatformMediaIntegration::instance()->createCaptureSession(); + if (maybeCaptureSession) { + d->captureSession.reset(maybeCaptureSession.value()); + d->captureSession->setCaptureSession(this); + } else { + qWarning() << "Failed to initialize QMediaCaptureSession" << maybeCaptureSession.error(); + } } /*! @@ -167,14 +141,19 @@ QMediaCaptureSession::QMediaCaptureSession(QObject *parent) */ QMediaCaptureSession::~QMediaCaptureSession() { + Q_D(QMediaCaptureSession); + setCamera(nullptr); setRecorder(nullptr); setImageCapture(nullptr); + setScreenCapture(nullptr); + setWindowCapture(nullptr); + setVideoFrameInput(nullptr); + setAudioBufferInput(nullptr); setAudioInput(nullptr); setAudioOutput(nullptr); - d_ptr->setVideoSink(nullptr); - delete d_ptr->captureSession; - delete d_ptr; + d->setVideoSink(nullptr); + d->captureSession.reset(); } /*! \qmlproperty AudioInput QtMultimedia::CaptureSession::audioInput @@ -183,11 +162,14 @@ QMediaCaptureSession::~QMediaCaptureSession() */ /*! + \property QMediaCaptureSession::audioInput + Returns the device that is being used to capture audio. */ QAudioInput *QMediaCaptureSession::audioInput() const { - return d_ptr->audioInput; + Q_D(const QMediaCaptureSession); + return d->audioInput; } /*! @@ -197,21 +179,69 @@ QAudioInput *QMediaCaptureSession::audioInput() const */ void QMediaCaptureSession::setAudioInput(QAudioInput *input) { - QAudioInput *oldInput = d_ptr->audioInput; + Q_D(QMediaCaptureSession); + + QAudioInput *oldInput = d->audioInput; if (oldInput == input) return; - d_ptr->audioInput = input; - d_ptr->captureSession->setAudioInput(nullptr); + + // To avoid double emit of audioInputChanged + // from recursive setAudioInput(nullptr) call. + d->audioInput = nullptr; + + if (d->captureSession) + d->captureSession->setAudioInput(nullptr); if (oldInput) oldInput->setDisconnectFunction({}); if (input) { input->setDisconnectFunction([this](){ setAudioInput(nullptr); }); - d_ptr->captureSession->setAudioInput(input->handle()); + if (d->captureSession) + d->captureSession->setAudioInput(input->handle()); } + d->audioInput = input; emit audioInputChanged(); } /*! + \property QMediaCaptureSession::audioBufferInput + \since 6.8 + + \brief The object used to send custom audio buffers to \l QMediaRecorder. +*/ +QAudioBufferInput *QMediaCaptureSession::audioBufferInput() const +{ + Q_D(const QMediaCaptureSession); + + return d->audioBufferInput; +} + +void QMediaCaptureSession::setAudioBufferInput(QAudioBufferInput *input) +{ + Q_D(QMediaCaptureSession); + + // TODO: come up with an unification of the captures setup + QAudioBufferInput *oldInput = d->audioBufferInput; + if (oldInput == input) + return; + d->audioBufferInput = input; + if (d->captureSession) + d->captureSession->setAudioBufferInput(nullptr); + if (oldInput) { + if (oldInput->captureSession() && oldInput->captureSession() != this) + oldInput->captureSession()->setAudioBufferInput(nullptr); + oldInput->setCaptureSession(nullptr); + } + if (input) { + if (input->captureSession()) + input->captureSession()->setAudioBufferInput(nullptr); + if (d->captureSession) + d->captureSession->setAudioBufferInput(input->platformAudioBufferInput()); + input->setCaptureSession(this); + } + emit audioBufferInputChanged(); +} + +/*! \qmlproperty Camera QtMultimedia::CaptureSession::camera \brief The camera used to capture video. @@ -226,20 +256,26 @@ void QMediaCaptureSession::setAudioInput(QAudioInput *input) \brief The camera used to capture video. Record video or take images by adding a camera to the capture session - using this property, + using this property. */ QCamera *QMediaCaptureSession::camera() const { - return d_ptr->camera; + Q_D(const QMediaCaptureSession); + + return d->camera; } void QMediaCaptureSession::setCamera(QCamera *camera) { - QCamera *oldCamera = d_ptr->camera; + Q_D(QMediaCaptureSession); + + // TODO: come up with an unification of the captures setup + QCamera *oldCamera = d->camera; if (oldCamera == camera) return; - d_ptr->camera = camera; - d_ptr->captureSession->setCamera(nullptr); + d->camera = camera; + if (d->captureSession) + d->captureSession->setCamera(nullptr); if (oldCamera) { if (oldCamera->captureSession() && oldCamera->captureSession() != this) oldCamera->captureSession()->setCamera(nullptr); @@ -248,11 +284,154 @@ void QMediaCaptureSession::setCamera(QCamera *camera) if (camera) { if (camera->captureSession()) camera->captureSession()->setCamera(nullptr); - d_ptr->captureSession->setCamera(camera->platformCamera()); + if (d->captureSession) + d->captureSession->setCamera(camera->platformCamera()); camera->setCaptureSession(this); } emit cameraChanged(); } + +/*! + \qmlproperty ScreenCapture QtMultimedia::CaptureSession::screenCapture + \since 6.5 + + \brief The object used to capture a screen. + + Record a screen by adding a screen capture objet + to the capture session using this property. +*/ + +/*! + \property QMediaCaptureSession::screenCapture + \since 6.5 + + \brief The object used to capture a screen. + + Record a screen by adding a screen capture object + to the capture session using this property. +*/ +QScreenCapture *QMediaCaptureSession::screenCapture() +{ + Q_D(QMediaCaptureSession); + + return d->screenCapture; +} + +void QMediaCaptureSession::setScreenCapture(QScreenCapture *screenCapture) +{ + Q_D(QMediaCaptureSession); + + // TODO: come up with an unification of the captures setup + QScreenCapture *oldScreenCapture = d->screenCapture; + if (oldScreenCapture == screenCapture) + return; + d->screenCapture = screenCapture; + if (d->captureSession) + d->captureSession->setScreenCapture(nullptr); + if (oldScreenCapture) { + if (oldScreenCapture->captureSession() && oldScreenCapture->captureSession() != this) + oldScreenCapture->captureSession()->setScreenCapture(nullptr); + oldScreenCapture->setCaptureSession(nullptr); + } + if (screenCapture) { + if (screenCapture->captureSession()) + screenCapture->captureSession()->setScreenCapture(nullptr); + if (d->captureSession) + d->captureSession->setScreenCapture(screenCapture->platformScreenCapture()); + screenCapture->setCaptureSession(this); + } + emit screenCaptureChanged(); +} + +/*! + \qmlproperty WindowCapture QtMultimedia::CaptureSession::windowCapture + \since 6.6 + + \brief The object used to capture a window. + + Record a window by adding a window capture object + to the capture session using this property. +*/ + +/*! + \property QMediaCaptureSession::windowCapture + \since 6.6 + + \brief The object used to capture a window. + + Record a window by adding a window capture objet + to the capture session using this property. +*/ +QWindowCapture *QMediaCaptureSession::windowCapture() +{ + Q_D(QMediaCaptureSession); + return d->windowCapture; +} + +void QMediaCaptureSession::setWindowCapture(QWindowCapture *windowCapture) +{ + Q_D(QMediaCaptureSession); + + // TODO: come up with an unification of the captures setup + QWindowCapture *oldCapture = d->windowCapture; + if (oldCapture == windowCapture) + return; + d->windowCapture = windowCapture; + if (d->captureSession) + d->captureSession->setWindowCapture(nullptr); + if (oldCapture) { + if (oldCapture->captureSession() && oldCapture->captureSession() != this) + oldCapture->captureSession()->setWindowCapture(nullptr); + oldCapture->setCaptureSession(nullptr); + } + if (windowCapture) { + if (windowCapture->captureSession()) + windowCapture->captureSession()->setWindowCapture(nullptr); + if (d->captureSession) + d->captureSession->setWindowCapture(windowCapture->platformWindowCapture()); + windowCapture->setCaptureSession(this); + } + emit windowCaptureChanged(); +} + +/*! + \property QMediaCaptureSession::videoFrameInput + \since 6.8 + + \brief The object used to send custom video frames to + \l QMediaRecorder or a video output. +*/ +QVideoFrameInput *QMediaCaptureSession::videoFrameInput() const +{ + Q_D(const QMediaCaptureSession); + return d->videoFrameInput; +} + +void QMediaCaptureSession::setVideoFrameInput(QVideoFrameInput *input) +{ + Q_D(QMediaCaptureSession); + // TODO: come up with an unification of the captures setup + QVideoFrameInput *oldInput = d->videoFrameInput; + if (oldInput == input) + return; + d->videoFrameInput = input; + if (d->captureSession) + d->captureSession->setVideoFrameInput(nullptr); + if (oldInput) { + if (oldInput->captureSession() && oldInput->captureSession() != this) + oldInput->captureSession()->setVideoFrameInput(nullptr); + oldInput->setCaptureSession(nullptr); + } + if (input) { + if (input->captureSession()) + input->captureSession()->setVideoFrameInput(nullptr); + if (d->captureSession) + d->captureSession->setVideoFrameInput(input->platformVideoFrameInput()); + input->setCaptureSession(this); + } + emit videoFrameInputChanged(); +} + /*! \qmlproperty ImageCapture QtMultimedia::CaptureSession::imageCapture @@ -271,16 +450,22 @@ void QMediaCaptureSession::setCamera(QCamera *camera) */ QImageCapture *QMediaCaptureSession::imageCapture() { - return d_ptr->imageCapture; + Q_D(QMediaCaptureSession); + + return d->imageCapture; } void QMediaCaptureSession::setImageCapture(QImageCapture *imageCapture) { - QImageCapture *oldImageCapture = d_ptr->imageCapture; + Q_D(QMediaCaptureSession); + + // TODO: come up with an unification of the captures setup + QImageCapture *oldImageCapture = d->imageCapture; if (oldImageCapture == imageCapture) return; - d_ptr->imageCapture = imageCapture; - d_ptr->captureSession->setImageCapture(nullptr); + d->imageCapture = imageCapture; + if (d->captureSession) + d->captureSession->setImageCapture(nullptr); if (oldImageCapture) { if (oldImageCapture->captureSession() && oldImageCapture->captureSession() != this) oldImageCapture->captureSession()->setImageCapture(nullptr); @@ -289,7 +474,8 @@ void QMediaCaptureSession::setImageCapture(QImageCapture *imageCapture) if (imageCapture) { if (imageCapture->captureSession()) imageCapture->captureSession()->setImageCapture(nullptr); - d_ptr->captureSession->setImageCapture(imageCapture->platformImageCapture()); + if (d->captureSession) + d->captureSession->setImageCapture(imageCapture->platformImageCapture()); imageCapture->setCaptureSession(this); } emit imageCaptureChanged(); @@ -313,16 +499,19 @@ void QMediaCaptureSession::setImageCapture(QImageCapture *imageCapture) QMediaRecorder *QMediaCaptureSession::recorder() { - return d_ptr->recorder; + Q_D(QMediaCaptureSession); + return d->recorder; } void QMediaCaptureSession::setRecorder(QMediaRecorder *recorder) { - QMediaRecorder *oldRecorder = d_ptr->recorder; + Q_D(QMediaCaptureSession); + QMediaRecorder *oldRecorder = d->recorder; if (oldRecorder == recorder) return; - d_ptr->recorder = recorder; - d_ptr->captureSession->setMediaRecorder(nullptr); + d->recorder = recorder; + if (d->captureSession) + d->captureSession->setMediaRecorder(nullptr); if (oldRecorder) { if (oldRecorder->captureSession() && oldRecorder->captureSession() != this) oldRecorder->captureSession()->setRecorder(nullptr); @@ -331,7 +520,8 @@ void QMediaCaptureSession::setRecorder(QMediaRecorder *recorder) if (recorder) { if (recorder->captureSession()) recorder->captureSession()->setRecorder(nullptr); - d_ptr->captureSession->setMediaRecorder(recorder->platformRecoder()); + if (d->captureSession) + d->captureSession->setMediaRecorder(recorder->platformRecoder()); recorder->setCaptureSession(this); } emit recorderChanged(); @@ -347,6 +537,11 @@ void QMediaCaptureSession::setRecorder(QMediaRecorder *recorder) The previously set preview is detached. */ +/*! + \property QMediaCaptureSession::videoOutput + + Returns the video output for the session. +*/ QObject *QMediaCaptureSession::videoOutput() const { Q_D(const QMediaCaptureSession); @@ -388,6 +583,10 @@ void QMediaCaptureSession::setVideoSink(QVideoSink *sink) d->videoOutput = nullptr; d->setVideoSink(sink); } + +/*! + Returns the QVideoSink for the session. +*/ QVideoSink *QMediaCaptureSession::videoSink() const { Q_D(const QMediaCaptureSession); @@ -395,25 +594,45 @@ QVideoSink *QMediaCaptureSession::videoSink() const } /*! Sets the audio output device to \a{output}. + + Setting an audio output device enables audio routing from an audio input device. */ void QMediaCaptureSession::setAudioOutput(QAudioOutput *output) { - QAudioOutput *oldOutput = d_ptr->audioOutput; + Q_D(QMediaCaptureSession); + + QAudioOutput *oldOutput = d->audioOutput; if (oldOutput == output) return; - d_ptr->audioOutput = output; - d_ptr->captureSession->setAudioOutput(nullptr); + + // We don't want to end up with signal emitted + // twice (from recursive call setAudioInput(nullptr) + // from oldOutput->setDisconnectFunction(): + d->audioOutput = nullptr; + + if (d->captureSession) + d->captureSession->setAudioOutput(nullptr); if (oldOutput) oldOutput->setDisconnectFunction({}); if (output) { output->setDisconnectFunction([this](){ setAudioOutput(nullptr); }); - d_ptr->captureSession->setAudioOutput(output->handle()); + if (d->captureSession) + d->captureSession->setAudioOutput(output->handle()); } + d->audioOutput = output; emit audioOutputChanged(); } /*! \qmlproperty AudioOutput QtMultimedia::CaptureSession::audioOutput \brief The audio output device for the capture session. + + Add an AudioOutput device to the capture session to enable + audio routing from an AudioInput device. +*/ +/*! + \property QMediaCaptureSession::audioOutput + + Returns the audio output for the session. */ QAudioOutput *QMediaCaptureSession::audioOutput() const { @@ -426,7 +645,8 @@ QAudioOutput *QMediaCaptureSession::audioOutput() const */ QPlatformMediaCaptureSession *QMediaCaptureSession::platformSession() const { - return d_ptr->captureSession; + Q_D(const QMediaCaptureSession); + return d->captureSession.get(); } /*! \qmlsignal QtMultimedia::CaptureSession::audioInputChanged() |