1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qmediacapturesession.h"
5#include "qaudiodevice.h"
6#include "qcamera.h"
7#include "qmediarecorder.h"
8#include "qimagecapture.h"
9#include "qvideosink.h"
10#include "qscreencapture.h"
11#include "qwindowcapture.h"
12
13#include <qpointer.h>
14
15#include "qplatformmediaintegration_p.h"
16#include "qplatformmediacapture_p.h"
17#include "qaudioinput.h"
18#include "qaudiooutput.h"
19
20QT_BEGIN_NAMESPACE
21
22class QMediaCaptureSessionPrivate
23{
24public:
25 QMediaCaptureSession *q = nullptr;
26 QPlatformMediaCaptureSession *captureSession = nullptr;
27 QAudioInput *audioInput = nullptr;
28 QAudioOutput *audioOutput = nullptr;
29 QPointer<QCamera> camera;
30 QPointer<QScreenCapture> screenCapture;
31 QPointer<QWindowCapture> windowCapture;
32 QPointer<QImageCapture> imageCapture;
33 QPointer<QMediaRecorder> recorder;
34 QPointer<QVideoSink> videoSink;
35 QPointer<QObject> videoOutput;
36
37 void setVideoSink(QVideoSink *sink)
38 {
39 if (sink == videoSink)
40 return;
41 if (videoSink)
42 videoSink->setSource(nullptr);
43 videoSink = sink;
44 if (sink)
45 sink->setSource(q);
46 if (captureSession)
47 captureSession->setVideoPreview(sink);
48 emit q->videoOutputChanged();
49 }
50};
51
52/*!
53 \class QMediaCaptureSession
54
55 \brief The QMediaCaptureSession class allows capturing of audio and video content.
56 \inmodule QtMultimedia
57 \ingroup multimedia
58 \ingroup multimedia_video
59 \ingroup multimedia_audio
60
61 The QMediaCaptureSession is the central class that manages capturing of media on the local device.
62
63 You can connect a video input to QMediaCaptureSession using setCamera(), setScreenCapture() or setWindowCapture().
64 A preview of the captured media can be seen by setting a QVideoWidget or QGraphicsVideoItem using setVideoOutput().
65
66 You can connect a microphone to QMediaCaptureSession using setAudioInput().
67 The captured sound can be heard by routing the audio to an output device using setAudioOutput().
68
69 You can capture still images from a camera by setting a QImageCapture object on the capture session,
70 and record audio/video using a QMediaRecorder.
71
72 \sa QCamera, QAudioDevice, QMediaRecorder, QImageCapture, QScreenCapture, QWindowCapture, QMediaRecorder, QGraphicsVideoItem
73*/
74
75/*!
76 \qmltype CaptureSession
77 \since 6.2
78 \instantiates QMediaCaptureSession
79 \brief Allows capturing of audio and video content.
80
81 \inqmlmodule QtMultimedia
82 \ingroup multimedia_qml
83 \ingroup multimedia_audio_qml
84 \ingroup multimedia_video_qml
85
86 This is the central type that manages capturing of media on the local device.
87
88 Connect a camera and a microphone to a CaptureSession by assigning Camera
89 and AudioInput objects to the relevant properties.
90
91 Capture a screen by connecting a ScreenCapture object to
92 the screenCapture property.
93
94 Capture a window by connecting a WindowCapture object to
95 the windowCapture property.
96
97 Enable a preview of the captured media by assigning a VideoOutput element to
98 the videoOutput property.
99
100 Route audio to an output device by assigning an AudioOutput object
101 to the audioOutput property.
102
103 Capture still images from a camera by assigning an ImageCapture to the
104 imageCapture property.
105
106 Record audio/video by assigning a MediaRecorder to the recorder property.
107
108\qml
109 CaptureSession {
110 id: captureSession
111 camera: Camera {
112 id: camera
113 }
114 imageCapture: ImageCapture {
115 id: imageCapture
116 }
117
118 recorder: MediaRecorder {
119 id: recorder
120 }
121 videoOutput: preview
122 }
123\endqml
124
125 \sa Camera, MediaDevices, MediaRecorder, ImageCapture, ScreenCapture, WindowCapture, AudioInput, VideoOutput
126*/
127
128/*!
129 Creates a session for media capture from the \a parent object.
130 */
131QMediaCaptureSession::QMediaCaptureSession(QObject *parent)
132 : QObject(parent),
133 d_ptr(new QMediaCaptureSessionPrivate)
134{
135 d_ptr->q = this;
136 auto maybeCaptureSession = QPlatformMediaIntegration::instance()->createCaptureSession();
137 if (maybeCaptureSession) {
138 d_ptr->captureSession = maybeCaptureSession.value();
139 d_ptr->captureSession->setCaptureSession(this);
140 } else {
141 qWarning() << "Failed to initialize QMediaCaptureSession" << maybeCaptureSession.error();
142 }
143}
144
145/*!
146 Destroys the session.
147 */
148QMediaCaptureSession::~QMediaCaptureSession()
149{
150 setCamera(nullptr);
151 setRecorder(nullptr);
152 setImageCapture(nullptr);
153 setScreenCapture(nullptr);
154 setWindowCapture(nullptr);
155 setAudioInput(nullptr);
156 setAudioOutput(nullptr);
157 d_ptr->setVideoSink(nullptr);
158 delete d_ptr->captureSession;
159 delete d_ptr;
160}
161/*!
162 \qmlproperty AudioInput QtMultimedia::CaptureSession::audioInput
163
164 This property holds the audio input that is being used to capture audio.
165*/
166
167/*!
168 \property QMediaCaptureSession::audioInput
169
170 Returns the device that is being used to capture audio.
171*/
172QAudioInput *QMediaCaptureSession::audioInput() const
173{
174 return d_ptr->audioInput;
175}
176
177/*!
178 Sets the audio input device to \a input. If setting it to an empty
179 QAudioDevice the capture session will use the default input as
180 defined by the operating system.
181*/
182void QMediaCaptureSession::setAudioInput(QAudioInput *input)
183{
184 QAudioInput *oldInput = d_ptr->audioInput;
185 if (oldInput == input)
186 return;
187 d_ptr->audioInput = input;
188 if (d_ptr->captureSession)
189 d_ptr->captureSession->setAudioInput(nullptr);
190 if (oldInput)
191 oldInput->setDisconnectFunction({});
192 if (input) {
193 input->setDisconnectFunction([this](){ setAudioInput(nullptr); });
194 if (d_ptr->captureSession)
195 d_ptr->captureSession->setAudioInput(input->handle());
196 }
197 emit audioInputChanged();
198}
199
200/*!
201 \qmlproperty Camera QtMultimedia::CaptureSession::camera
202
203 \brief The camera used to capture video.
204
205 Record video or take images by adding a camera to the capture session using
206 this property.
207*/
208
209/*!
210 \property QMediaCaptureSession::camera
211
212 \brief The camera used to capture video.
213
214 Record video or take images by adding a camera to the capture session
215 using this property.
216*/
217QCamera *QMediaCaptureSession::camera() const
218{
219 return d_ptr->camera;
220}
221
222void QMediaCaptureSession::setCamera(QCamera *camera)
223{
224 // TODO: come up with an unification of the captures setup
225 QCamera *oldCamera = d_ptr->camera;
226 if (oldCamera == camera)
227 return;
228 d_ptr->camera = camera;
229 if (d_ptr->captureSession)
230 d_ptr->captureSession->setCamera(nullptr);
231 if (oldCamera) {
232 if (oldCamera->captureSession() && oldCamera->captureSession() != this)
233 oldCamera->captureSession()->setCamera(nullptr);
234 oldCamera->setCaptureSession(nullptr);
235 }
236 if (camera) {
237 if (camera->captureSession())
238 camera->captureSession()->setCamera(nullptr);
239 if (d_ptr->captureSession)
240 d_ptr->captureSession->setCamera(camera->platformCamera());
241 camera->setCaptureSession(this);
242 }
243 emit cameraChanged();
244}
245
246/*!
247 \qmlproperty ScreenCapture QtMultimedia::CaptureSession::screenCapture
248 \since 6.5
249
250 \brief The object used to capture a screen.
251
252 Record a screen by adding a screen capture objet
253 to the capture session using this property.
254*/
255
256/*!
257 \property QMediaCaptureSession::screenCapture
258 \since 6.5
259
260 \brief The object used to capture a screen.
261
262 Record a screen by adding a screen capture object
263 to the capture session using this property.
264*/
265QScreenCapture *QMediaCaptureSession::screenCapture()
266{
267 return d_ptr ? d_ptr->screenCapture : nullptr;
268}
269
270void QMediaCaptureSession::setScreenCapture(QScreenCapture *screenCapture)
271{
272 // TODO: come up with an unification of the captures setup
273 QScreenCapture *oldScreenCapture = d_ptr->screenCapture;
274 if (oldScreenCapture == screenCapture)
275 return;
276 d_ptr->screenCapture = screenCapture;
277 if (d_ptr->captureSession)
278 d_ptr->captureSession->setScreenCapture(nullptr);
279 if (oldScreenCapture) {
280 if (oldScreenCapture->captureSession() && oldScreenCapture->captureSession() != this)
281 oldScreenCapture->captureSession()->setScreenCapture(nullptr);
282 oldScreenCapture->setCaptureSession(nullptr);
283 }
284 if (screenCapture) {
285 if (screenCapture->captureSession())
286 screenCapture->captureSession()->setScreenCapture(nullptr);
287 if (d_ptr->captureSession)
288 d_ptr->captureSession->setScreenCapture(screenCapture->platformScreenCapture());
289 screenCapture->setCaptureSession(this);
290 }
291 emit screenCaptureChanged();
292}
293
294/*!
295 \qmlproperty WindowCapture QtMultimedia::CaptureSession::windowCapture
296 \since 6.6
297
298 \brief The object used to capture a window.
299
300 Record a window by adding a window capture object
301 to the capture session using this property.
302*/
303
304/*!
305 \property QMediaCaptureSession::windowCapture
306 \since 6.6
307
308 \brief The object used to capture a window.
309
310 Record a window by adding a window capture objet
311 to the capture session using this property.
312*/
313QWindowCapture *QMediaCaptureSession::windowCapture() {
314 return d_ptr ? d_ptr->windowCapture : nullptr;
315}
316
317void QMediaCaptureSession::setWindowCapture(QWindowCapture *windowCapture)
318{
319 // TODO: come up with an unification of the captures setup
320 QWindowCapture *oldCapture = d_ptr->windowCapture;
321 if (oldCapture == windowCapture)
322 return;
323 d_ptr->windowCapture = windowCapture;
324 if (d_ptr->captureSession)
325 d_ptr->captureSession->setWindowCapture(nullptr);
326 if (oldCapture) {
327 if (oldCapture->captureSession() && oldCapture->captureSession() != this)
328 oldCapture->captureSession()->setWindowCapture(nullptr);
329 oldCapture->setCaptureSession(nullptr);
330 }
331 if (windowCapture) {
332 if (windowCapture->captureSession())
333 windowCapture->captureSession()->setWindowCapture(nullptr);
334 if (d_ptr->captureSession)
335 d_ptr->captureSession->setWindowCapture(windowCapture->platformWindowCapture());
336 windowCapture->setCaptureSession(this);
337 }
338 emit windowCaptureChanged();
339}
340
341/*!
342 \qmlproperty ImageCapture QtMultimedia::CaptureSession::imageCapture
343
344 \brief The object used to capture still images.
345
346 Add an ImageCapture interface to the capture session to enable
347 capturing of still images from the camera.
348*/
349/*!
350 \property QMediaCaptureSession::imageCapture
351
352 \brief the object used to capture still images.
353
354 Add a QImageCapture object to the capture session to enable
355 capturing of still images from the camera.
356*/
357QImageCapture *QMediaCaptureSession::imageCapture()
358{
359 return d_ptr->imageCapture;
360}
361
362void QMediaCaptureSession::setImageCapture(QImageCapture *imageCapture)
363{
364 // TODO: come up with an unification of the captures setup
365 QImageCapture *oldImageCapture = d_ptr->imageCapture;
366 if (oldImageCapture == imageCapture)
367 return;
368 d_ptr->imageCapture = imageCapture;
369 if (d_ptr->captureSession)
370 d_ptr->captureSession->setImageCapture(nullptr);
371 if (oldImageCapture) {
372 if (oldImageCapture->captureSession() && oldImageCapture->captureSession() != this)
373 oldImageCapture->captureSession()->setImageCapture(nullptr);
374 oldImageCapture->setCaptureSession(nullptr);
375 }
376 if (imageCapture) {
377 if (imageCapture->captureSession())
378 imageCapture->captureSession()->setImageCapture(nullptr);
379 if (d_ptr->captureSession)
380 d_ptr->captureSession->setImageCapture(imageCapture->platformImageCapture());
381 imageCapture->setCaptureSession(this);
382 }
383 emit imageCaptureChanged();
384}
385/*!
386 \qmlproperty MediaRecorder QtMultimedia::CaptureSession::recorder
387
388 \brief The recorder object used to capture audio/video.
389
390 Add a MediaRcorder object to the capture session to enable
391 recording of audio and/or video from the capture session.
392*/
393/*!
394 \property QMediaCaptureSession::recorder
395
396 \brief The recorder object used to capture audio/video.
397
398 Add a QMediaRecorder object to the capture session to enable
399 recording of audio and/or video from the capture session.
400*/
401
402QMediaRecorder *QMediaCaptureSession::recorder()
403{
404 return d_ptr->recorder;
405}
406
407void QMediaCaptureSession::setRecorder(QMediaRecorder *recorder)
408{
409 QMediaRecorder *oldRecorder = d_ptr->recorder;
410 if (oldRecorder == recorder)
411 return;
412 d_ptr->recorder = recorder;
413 if (d_ptr->captureSession)
414 d_ptr->captureSession->setMediaRecorder(nullptr);
415 if (oldRecorder) {
416 if (oldRecorder->captureSession() && oldRecorder->captureSession() != this)
417 oldRecorder->captureSession()->setRecorder(nullptr);
418 oldRecorder->setCaptureSession(nullptr);
419 }
420 if (recorder) {
421 if (recorder->captureSession())
422 recorder->captureSession()->setRecorder(nullptr);
423 if (d_ptr->captureSession)
424 d_ptr->captureSession->setMediaRecorder(recorder->platformRecoder());
425 recorder->setCaptureSession(this);
426 }
427 emit recorderChanged();
428}
429/*!
430 \qmlproperty VideoOutput QtMultimedia::CaptureSession::videoOutput
431
432 \brief The VideoOutput that is the video preview for the capture session.
433
434 A VideoOutput based preview is expected to have an invokable videoSink()
435 method that returns a QVideoSink.
436
437 The previously set preview is detached.
438
439*/
440/*!
441 \property QMediaCaptureSession::videoOutput
442
443 Returns the video output for the session.
444*/
445QObject *QMediaCaptureSession::videoOutput() const
446{
447 Q_D(const QMediaCaptureSession);
448 return d->videoOutput;
449}
450/*!
451 Sets a QObject, (\a output), to a video preview for the capture session.
452
453 A QObject based preview is expected to have an invokable videoSink()
454 method that returns a QVideoSink.
455
456 The previously set preview is detached.
457*/
458void QMediaCaptureSession::setVideoOutput(QObject *output)
459{
460 Q_D(QMediaCaptureSession);
461 if (d->videoOutput == output)
462 return;
463 QVideoSink *sink = qobject_cast<QVideoSink *>(object: output);
464 if (!sink && output) {
465 auto *mo = output->metaObject();
466 mo->invokeMethod(obj: output, member: "videoSink", Q_RETURN_ARG(QVideoSink *, sink));
467 }
468 d->videoOutput = output;
469 d->setVideoSink(sink);
470}
471
472/*!
473 Sets a QVideoSink, (\a sink), to a video preview for the capture session.
474
475 A QObject based preview is expected to have an invokable videoSink()
476 method that returns a QVideoSink.
477
478 The previously set preview is detached.
479*/
480void QMediaCaptureSession::setVideoSink(QVideoSink *sink)
481{
482 Q_D(QMediaCaptureSession);
483 d->videoOutput = nullptr;
484 d->setVideoSink(sink);
485}
486
487/*!
488 Returns the QVideoSink for the session.
489*/
490QVideoSink *QMediaCaptureSession::videoSink() const
491{
492 Q_D(const QMediaCaptureSession);
493 return d->videoSink;
494}
495/*!
496 Sets the audio output device to \a{output}.
497
498 Setting an audio output device enables audio routing from an audio input device.
499*/
500void QMediaCaptureSession::setAudioOutput(QAudioOutput *output)
501{
502 QAudioOutput *oldOutput = d_ptr->audioOutput;
503 if (oldOutput == output)
504 return;
505 d_ptr->audioOutput = output;
506 if (d_ptr->captureSession)
507 d_ptr->captureSession->setAudioOutput(nullptr);
508 if (oldOutput)
509 oldOutput->setDisconnectFunction({});
510 if (output) {
511 output->setDisconnectFunction([this](){ setAudioOutput(nullptr); });
512 if (d_ptr->captureSession)
513 d_ptr->captureSession->setAudioOutput(output->handle());
514 }
515 emit audioOutputChanged();
516}
517/*!
518 \qmlproperty AudioOutput QtMultimedia::CaptureSession::audioOutput
519 \brief The audio output device for the capture session.
520
521 Add an AudioOutput device to the capture session to enable
522 audio routing from an AudioInput device.
523*/
524/*!
525 \property QMediaCaptureSession::audioOutput
526
527 Returns the audio output for the session.
528*/
529QAudioOutput *QMediaCaptureSession::audioOutput() const
530{
531 Q_D(const QMediaCaptureSession);
532 return d->audioOutput;
533}
534
535/*!
536 \internal
537*/
538QPlatformMediaCaptureSession *QMediaCaptureSession::platformSession() const
539{
540 return d_ptr->captureSession;
541}
542/*!
543 \qmlsignal QtMultimedia::CaptureSession::audioInputChanged()
544 This signal is emitted when an audio input has changed.
545 \sa CaptureSession::audioInput
546*/
547
548/*!
549 \qmlsignal QtMultimedia::CaptureSession::cameraChanged()
550 This signal is emitted when the selected camera has changed.
551 \sa CaptureSession::camera
552*/
553
554/*!
555 \qmlsignal QtMultimedia::CaptureSession::imageCaptureChanged()
556 This signal is emitted when the selected interface has changed.
557 \sa CaptureSession::camera
558*/
559
560/*!
561 \qmlsignal QtMultimedia::CaptureSession::recorderChanged()
562 This signal is emitted when the selected recorder has changed.
563 \sa CaptureSession::recorder
564*/
565
566/*!
567 \qmlsignal QtMultimedia::CaptureSession::videoOutputChanged()
568 This signal is emitted when the selected video output has changed.
569 \sa CaptureSession::videoOutput
570*/
571
572/*!
573 \qmlsignal QtMultimedia::CaptureSession::audioOutputChanged()
574 This signal is emitted when the selected audio output has changed.
575 \sa CaptureSession::audioOutput
576*/
577QT_END_NAMESPACE
578
579#include "moc_qmediacapturesession.cpp"
580

source code of qtmultimedia/src/multimedia/recording/qmediacapturesession.cpp