Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qmediacapturesession.cpp
Go to the documentation of this file.
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
6#include "qaudiodevice.h"
7#include "qcamera.h"
10#include "qvideosink.h"
11#include "qscreencapture.h"
12#include "qwindowcapture.h"
14
17#include "qaudioinput.h"
19#include "qaudiooutput.h"
20#if QT_CONFIG(gstreamer_qt_api)
21# include "qgstreamervideosource.h"
22#endif
23
25
27{
28 Q_Q(QMediaCaptureSession);
29
30 if (sink == videoSink)
31 return;
32 if (videoSink)
33 videoSink->setSource(nullptr);
34 videoSink = sink;
35 if (sink)
36 sink->setSource(q);
37 if (captureSession)
38 captureSession->setVideoPreview(sink);
39 emit q->videoOutputChanged();
40}
41
42/*!
43 \class QMediaCaptureSession
44
45 \brief The QMediaCaptureSession class allows capturing of audio and video content.
46 \inmodule QtMultimedia
47 \ingroup multimedia
48 \ingroup multimedia_video
49 \ingroup multimedia_audio
50
51 The QMediaCaptureSession is the central class that manages capturing of media on the local
52 device.
53
54 You can connect a video input to QMediaCaptureSession using setCamera(),
55 setScreenCapture(), setWindowCapture() or setVideoFrameInput().
56 A preview of the captured media can be seen by setting a QVideoWidget or QGraphicsVideoItem
57 using setVideoOutput().
58
59 You can connect a microphone to QMediaCaptureSession using setAudioInput(), or set your
60 custom audio input using setAudioBufferInput().
61 The captured sound can be heard by routing the audio to an output device using setAudioOutput().
62
63 You can capture still images from a camera by setting a QImageCapture object on the capture
64 session, and record audio/video using a QMediaRecorder.
65
66 \sa QCamera, QAudioDevice, QMediaRecorder, QImageCapture, QScreenCapture, QWindowCapture,
67 QVideoFrameInput, QMediaRecorder, QGraphicsVideoItem
68*/
69
70/*!
71 \qmltype CaptureSession
72 \since 6.2
73 \nativetype QMediaCaptureSession
74 \brief Allows capturing of audio and video content.
75
76 \inqmlmodule QtMultimedia
77 \ingroup multimedia_qml
78 \ingroup multimedia_audio_qml
79 \ingroup multimedia_video_qml
80
81 This is the central type that manages capturing of media on the local device.
82
83 Connect a camera and a microphone to a CaptureSession by assigning Camera
84 and AudioInput objects to the relevant properties.
85
86 Capture a screen by connecting a ScreenCapture object to
87 the screenCapture property.
88
89 Capture a window by connecting a WindowCapture object to
90 the windowCapture property.
91
92 Enable a preview of the captured media by assigning a VideoOutput element to
93 the videoOutput property.
94
95 Route audio to an output device by assigning an AudioOutput object
96 to the audioOutput property.
97
98 Capture still images from a camera by assigning an ImageCapture to the
99 imageCapture property.
100
101 Record audio/video by assigning a MediaRecorder to the recorder property.
102
103\qml
104 CaptureSession {
105 id: captureSession
106 camera: Camera {
107 id: camera
108 }
109 imageCapture: ImageCapture {
110 id: imageCapture
111 }
112
113 recorder: MediaRecorder {
114 id: recorder
115 }
116 videoOutput: preview
117
118 Component.onCompleted: {
119 camera.start()
120 }
121 }
122\endqml
123
124 \sa Camera, MediaDevices, MediaRecorder, ImageCapture, ScreenCapture, WindowCapture, AudioInput, VideoOutput
125 \note To ensure the camera starts capturing video frames on all platforms, explicitly call camera.start(),
126 typically in the Component.onCompleted handler.
127*/
128
129template <>
130struct QMediaCaptureSession::ObjectTraits<QCamera>
131{
132 static constexpr bool IsCamera = true;
133 static constexpr auto Member = &QMediaCaptureSessionPrivate::camera;
134 static constexpr auto Setter = &QMediaCaptureSession::setCamera;
135 static constexpr auto PlatformSetter = &QPlatformMediaCaptureSession::setCamera;
136 static constexpr auto PlatformObjectProvider = &QCamera::platformCamera;
137 static constexpr auto ChangeNotifier = &QMediaCaptureSession::cameraChanged;
138};
139
140#if QT_CONFIG(gstreamer_qt_api)
141template <>
142struct QMediaCaptureSession::ObjectTraits<QGStreamerVideoSource>
143{
144 static constexpr bool IsCamera = true;
145 static constexpr auto Member = &QMediaCaptureSessionPrivate::nativeVideoSource;
146 static constexpr auto Setter = &QMediaCaptureSession::setNativeVideoSource;
147 static constexpr auto PlatformSetter = &QPlatformMediaCaptureSession::setCamera;
148 static constexpr auto PlatformObjectProvider = &QGStreamerVideoSource::platformVideoSource;
149 static constexpr auto ChangeNotifier = &QMediaCaptureSession::nativeVideoSourceChanged;
150};
151#endif
152
153template <>
154struct QMediaCaptureSession::ObjectTraits<QScreenCapture>
155{
156 static constexpr bool IsCamera = false;
157 static constexpr auto Member = &QMediaCaptureSessionPrivate::screenCapture;
158 static constexpr auto Setter = &QMediaCaptureSession::setScreenCapture;
159 static constexpr auto PlatformSetter = &QPlatformMediaCaptureSession::setScreenCapture;
160 static constexpr auto PlatformObjectProvider = &QScreenCapture::platformScreenCapture;
161 static constexpr auto ChangeNotifier = &QMediaCaptureSession::screenCaptureChanged;
162};
163
164template <>
165struct QMediaCaptureSession::ObjectTraits<QWindowCapture>
166{
167 static constexpr bool IsCamera = false;
168 static constexpr auto Member = &QMediaCaptureSessionPrivate::windowCapture;
169 static constexpr auto Setter = &QMediaCaptureSession::setWindowCapture;
170 static constexpr auto PlatformSetter = &QPlatformMediaCaptureSession::setWindowCapture;
171 static constexpr auto PlatformObjectProvider = &QWindowCapture::platformWindowCapture;
172 static constexpr auto ChangeNotifier = &QMediaCaptureSession::windowCaptureChanged;
173};
174
175template <>
176struct QMediaCaptureSession::ObjectTraits<QVideoFrameInput>
177{
178 static constexpr bool IsCamera = false;
179 static constexpr auto Member = &QMediaCaptureSessionPrivate::videoFrameInput;
180 static constexpr auto Setter = &QMediaCaptureSession::setVideoFrameInput;
181 static constexpr auto PlatformSetter = &QPlatformMediaCaptureSession::setVideoFrameInput;
182 static constexpr auto PlatformObjectProvider = &QVideoFrameInput::platformVideoFrameInput;
183 static constexpr auto ChangeNotifier = &QMediaCaptureSession::videoFrameInputChanged;
184};
185
186template <>
187struct QMediaCaptureSession::ObjectTraits<QAudioBufferInput>
188{
189 static constexpr bool IsCamera = false;
190 static constexpr auto Member = &QMediaCaptureSessionPrivate::audioBufferInput;
191 static constexpr auto Setter = &QMediaCaptureSession::setAudioBufferInput;
192 static constexpr auto PlatformSetter = &QPlatformMediaCaptureSession::setAudioBufferInput;
193 static constexpr auto PlatformObjectProvider = &QAudioBufferInput::platformAudioBufferInput;
194 static constexpr auto ChangeNotifier = &QMediaCaptureSession::audioBufferInputChanged;
195};
196
197template <>
198struct QMediaCaptureSession::ObjectTraits<QImageCapture>
199{
200 static constexpr bool IsCamera = false;
201 static constexpr auto Member = &QMediaCaptureSessionPrivate::imageCapture;
202 static constexpr auto Setter = &QMediaCaptureSession::setImageCapture;
203 static constexpr auto PlatformSetter = &QPlatformMediaCaptureSession::setImageCapture;
204 static constexpr auto PlatformObjectProvider = &QImageCapture::platformImageCapture;
205 static constexpr auto ChangeNotifier = &QMediaCaptureSession::imageCaptureChanged;
206};
207
208template <>
209struct QMediaCaptureSession::ObjectTraits<QMediaRecorder>
210{
211 static constexpr bool IsCamera = false;
212 static constexpr auto Member = &QMediaCaptureSessionPrivate::recorder;
213 static constexpr auto Setter = &QMediaCaptureSession::setRecorder;
214 static constexpr auto PlatformSetter = &QPlatformMediaCaptureSession::setMediaRecorder;
215 static constexpr auto PlatformObjectProvider = &QMediaRecorder::platformRecoder;
216 static constexpr auto ChangeNotifier = &QMediaCaptureSession::recorderChanged;
217};
218
219template <typename Object>
220void QMediaCaptureSession::setObject(Object *object) {
221 Q_D(QMediaCaptureSession);
222
223 using Traits = QMediaCaptureSession::ObjectTraits<Object>;
224
225 Object *oldObject = qobject_cast<Object *>(d->*Traits::Member);
226 if (oldObject == object)
227 return;
228
229 if constexpr (Traits::IsCamera) {
230 if (!QPlatformMediaIntegration::instance()->isCameraSwitchingDuringRecordingSupported()
231 && recorder() && recorder()->recorderState() == QMediaRecorder::RecordingState) {
232 qWarning("This media backend does not support camera switching during recording");
233 return;
234 }
235 }
236
237 d->*Traits::Member = object;
238
239 if (d->captureSession)
240 std::invoke(Traits::PlatformSetter, d->captureSession, nullptr);
241
242 if (oldObject) {
243 if (oldObject->captureSession() && oldObject->captureSession() != this)
244 std::invoke(Traits::Setter, oldObject->captureSession(), nullptr);
245 oldObject->setCaptureSession(nullptr);
246 }
247
248 if (object) {
249 if (auto *otherSession = object->captureSession())
250 std::invoke(Traits::Setter, otherSession, nullptr);
251 if (d->captureSession)
252 std::invoke(Traits::PlatformSetter, d->captureSession,
253 std::invoke(Traits::PlatformObjectProvider, object));
254 object->setCaptureSession(this);
255 }
256
257 emit (this->*Traits::ChangeNotifier)();
258}
259
260/*!
261 Creates a session for media capture from the \a parent object.
262 */
263QMediaCaptureSession::QMediaCaptureSession(QObject *parent)
264 : QObject{ *new QMediaCaptureSessionPrivate, parent }
265{
266 Q_D(QMediaCaptureSession);
267
268 auto maybeCaptureSession = QPlatformMediaIntegration::instance()->createCaptureSession();
269 if (maybeCaptureSession) {
270 d->captureSession.reset(maybeCaptureSession.value());
271 d->captureSession->setCaptureSession(this);
272 } else {
273 qWarning() << "Failed to initialize QMediaCaptureSession" << maybeCaptureSession.error();
274 }
275}
276
277/*!
278 Destroys the session.
279 */
280QMediaCaptureSession::~QMediaCaptureSession()
281{
282 Q_D(QMediaCaptureSession);
283
284 setCamera(nullptr);
285 setNativeVideoSource(nullptr);
286 setRecorder(nullptr);
287 setImageCapture(nullptr);
288 setScreenCapture(nullptr);
289 setWindowCapture(nullptr);
290 setVideoFrameInput(nullptr);
291 setAudioBufferInput(nullptr);
292 setAudioInput(nullptr);
293 setAudioOutput(nullptr);
294 d->setVideoSink(nullptr);
295 d->captureSession.reset();
296}
297/*!
298 \qmlproperty AudioInput QtMultimedia::CaptureSession::audioInput
299
300 This property holds the audio input that is being used to capture audio.
301*/
302
303/*!
304 \property QMediaCaptureSession::audioInput
305
306 Returns the device that is being used to capture audio.
307*/
308QAudioInput *QMediaCaptureSession::audioInput() const
309{
310 Q_D(const QMediaCaptureSession);
311 return d->audioInput;
312}
313
314/*!
315 Sets the audio input device to \a input. If setting it to an empty
316 QAudioDevice the capture session will use the default input as
317 defined by the operating system.
318*/
319void QMediaCaptureSession::setAudioInput(QAudioInput *input)
320{
321 Q_D(QMediaCaptureSession);
322
323 QAudioInput *oldInput = d->audioInput;
324 if (oldInput == input)
325 return;
326
327 // To avoid double emit of audioInputChanged
328 // from recursive setAudioInput(nullptr) call.
329 d->audioInput = nullptr;
330
331 // TODO: check if it's possible to reuse setObject(input)
332 if (d->captureSession)
333 d->captureSession->setAudioInput(nullptr);
334 if (oldInput)
335 oldInput->setDisconnectFunction({});
336 if (input) {
337 input->setDisconnectFunction([this](){ setAudioInput(nullptr); });
338 if (d->captureSession)
339 d->captureSession->setAudioInput(input->handle());
340 }
341 d->audioInput = input;
342 emit audioInputChanged();
343}
344
345/*!
346 \property QMediaCaptureSession::audioBufferInput
347 \since 6.8
348
349 \brief The object used to send custom audio buffers to \l QMediaRecorder.
350*/
351QAudioBufferInput *QMediaCaptureSession::audioBufferInput() const
352{
353 Q_D(const QMediaCaptureSession);
354
355 return d->audioBufferInput;
356}
357
358void QMediaCaptureSession::setAudioBufferInput(QAudioBufferInput *input)
359{
360 setObject(input);
361}
362
363/*!
364 \qmlproperty Camera QtMultimedia::CaptureSession::camera
365
366 \brief The camera used to capture video.
367
368 Record video or take images by adding a camera to the capture session using
369 this property.
370*/
371
372/*!
373 \property QMediaCaptureSession::camera
374
375 \brief The camera used to capture video.
376
377 Record video or take images by adding a camera to the capture session
378 using this property.
379*/
380QCamera *QMediaCaptureSession::camera() const
381{
382 Q_D(const QMediaCaptureSession);
383 return d->camera;
384}
385
386void QMediaCaptureSession::setCamera(QCamera *camera)
387{
388#if QT_CONFIG(gstreamer_qt_api)
389 Q_D(QMediaCaptureSession);
390 if (d->nativeVideoSource && camera) {
391 // TODO: perhaps, we should relax the limitation
392 qWarning("Setting camera, when gstreamer video source is connected, is not supported");
393 return;
394 }
395#endif
396
397 setObject(camera);
398}
399
400QObject *QMediaCaptureSession::nativeVideoSource() const
401{
402 Q_D(const QMediaCaptureSession);
403 return d->nativeVideoSource;
404}
405
406void QMediaCaptureSession::setNativeVideoSource(QObject *videoSource)
407{
408#if QT_CONFIG(gstreamer_qt_api)
409 Q_D(QMediaCaptureSession);
410
411 auto *gstreamerVideoSource = qobject_cast<QGStreamerVideoSource *>(videoSource);
412
413 if (videoSource && !gstreamerVideoSource) {
414 qCritical() << "Unsupported video source type; QGStreamerVideoSource is expected.";
415 return;
416 }
417
418 if (d->camera && gstreamerVideoSource) {
419 // TODO: perhaps, we should relax the limitation
420 qWarning("Setting GStreamer video source, when camera is connected, is not supported");
421 return;
422 }
423
424 setObject(gstreamerVideoSource);
425#else
426 if (videoSource)
427 qCritical() << "Only gstreamer video source is supported";
428
429#endif
430}
431
432/*!
433 \qmlproperty ScreenCapture QtMultimedia::CaptureSession::screenCapture
434 \since 6.5
435
436 \brief The object used to capture a screen.
437
438 Record a screen by adding a screen capture objet
439 to the capture session using this property.
440*/
441
442/*!
443 \property QMediaCaptureSession::screenCapture
444 \since 6.5
445
446 \brief The object used to capture a screen.
447
448 Record a screen by adding a screen capture object
449 to the capture session using this property.
450*/
451QScreenCapture *QMediaCaptureSession::screenCapture()
452{
453 Q_D(QMediaCaptureSession);
454 return d->screenCapture;
455}
456
457void QMediaCaptureSession::setScreenCapture(QScreenCapture *screenCapture)
458{
459 setObject(screenCapture);
460}
461
462/*!
463 \qmlproperty WindowCapture QtMultimedia::CaptureSession::windowCapture
464 \since 6.6
465
466 \brief The object used to capture a window.
467
468 Record a window by adding a window capture object
469 to the capture session using this property.
470*/
471
472/*!
473 \property QMediaCaptureSession::windowCapture
474 \since 6.6
475
476 \brief The object used to capture a window.
477
478 Record a window by adding a window capture objet
479 to the capture session using this property.
480*/
481QWindowCapture *QMediaCaptureSession::windowCapture()
482{
483 Q_D(QMediaCaptureSession);
484 return d->windowCapture;
485}
486
487void QMediaCaptureSession::setWindowCapture(QWindowCapture *windowCapture)
488{
489 setObject(windowCapture);
490}
491
492/*!
493 \property QMediaCaptureSession::videoFrameInput
494 \since 6.8
495
496 \brief The object used to send custom video frames to
497 \l QMediaRecorder or a video output.
498*/
499QVideoFrameInput *QMediaCaptureSession::videoFrameInput() const
500{
501 Q_D(const QMediaCaptureSession);
502 return d->videoFrameInput;
503}
504
505void QMediaCaptureSession::setVideoFrameInput(QVideoFrameInput *input)
506{
507 setObject(input);
508}
509
510/*!
511 \qmlproperty ImageCapture QtMultimedia::CaptureSession::imageCapture
512
513 \brief The object used to capture still images.
514
515 Add an ImageCapture interface to the capture session to enable
516 capturing of still images from the camera.
517*/
518/*!
519 \property QMediaCaptureSession::imageCapture
520
521 \brief the object used to capture still images.
522
523 Add a QImageCapture object to the capture session to enable
524 capturing of still images from the camera.
525*/
526QImageCapture *QMediaCaptureSession::imageCapture()
527{
528 Q_D(QMediaCaptureSession);
529 return d->imageCapture;
530}
531
532void QMediaCaptureSession::setImageCapture(QImageCapture *imageCapture)
533{
534 setObject(imageCapture);
535}
536/*!
537 \qmlproperty MediaRecorder QtMultimedia::CaptureSession::recorder
538
539 \brief The recorder object used to capture audio/video.
540
541 Add a MediaRcorder object to the capture session to enable
542 recording of audio and/or video from the capture session.
543*/
544/*!
545 \property QMediaCaptureSession::recorder
546
547 \brief The recorder object used to capture audio/video.
548
549 Add a QMediaRecorder object to the capture session to enable
550 recording of audio and/or video from the capture session.
551*/
552
553QMediaRecorder *QMediaCaptureSession::recorder()
554{
555 Q_D(QMediaCaptureSession);
556 return d->recorder;
557}
558
559void QMediaCaptureSession::setRecorder(QMediaRecorder *recorder)
560{
561 setObject(recorder);
562}
563/*!
564 \qmlproperty VideoOutput QtMultimedia::CaptureSession::videoOutput
565
566 \brief The VideoOutput that is the video preview for the capture session.
567
568 A VideoOutput based preview is expected to have an invokable videoSink()
569 method that returns a QVideoSink.
570
571 The previously set preview is detached.
572
573*/
574/*!
575 \property QMediaCaptureSession::videoOutput
576
577 Returns the video output for the session.
578*/
579QObject *QMediaCaptureSession::videoOutput() const
580{
581 Q_D(const QMediaCaptureSession);
582 return d->videoOutput;
583}
584/*!
585 Sets a QObject, (\a output), to a video preview for the capture session.
586
587 A QObject based preview is expected to have an invokable videoSink()
588 method that returns a QVideoSink.
589
590 The previously set preview is detached.
591*/
592void QMediaCaptureSession::setVideoOutput(QObject *output)
593{
594 Q_D(QMediaCaptureSession);
595 if (d->videoOutput == output)
596 return;
597 QVideoSink *sink = qobject_cast<QVideoSink *>(output);
598 if (!sink && output) {
599 auto *mo = output->metaObject();
600 mo->invokeMethod(output, "videoSink", Q_RETURN_ARG(QVideoSink *, sink));
601 }
602 d->videoOutput = output;
603 d->setVideoSink(sink);
604}
605
606/*!
607 Sets a QVideoSink, (\a sink), to a video preview for the capture session.
608
609 A QObject based preview is expected to have an invokable videoSink()
610 method that returns a QVideoSink.
611
612 The previously set preview is detached.
613*/
614void QMediaCaptureSession::setVideoSink(QVideoSink *sink)
615{
616 Q_D(QMediaCaptureSession);
617 d->videoOutput = nullptr;
618 d->setVideoSink(sink);
619}
620
621/*!
622 Returns the QVideoSink for the session.
623*/
624QVideoSink *QMediaCaptureSession::videoSink() const
625{
626 Q_D(const QMediaCaptureSession);
627 return d->videoSink;
628}
629/*!
630 Sets the audio output device to \a{output}.
631
632 Setting an audio output device enables audio routing from an audio input device.
633*/
634void QMediaCaptureSession::setAudioOutput(QAudioOutput *output)
635{
636 Q_D(QMediaCaptureSession);
637
638 QAudioOutput *oldOutput = d->audioOutput;
639 if (oldOutput == output)
640 return;
641
642 // We don't want to end up with signal emitted
643 // twice (from recursive call setAudioInput(nullptr)
644 // from oldOutput->setDisconnectFunction():
645 d->audioOutput = nullptr;
646
647 if (d->captureSession)
648 d->captureSession->setAudioOutput(nullptr);
649 if (oldOutput)
650 oldOutput->setDisconnectFunction({});
651 if (output) {
652 output->setDisconnectFunction([this](){ setAudioOutput(nullptr); });
653 if (d->captureSession)
654 d->captureSession->setAudioOutput(output->handle());
655 }
656 d->audioOutput = output;
657 emit audioOutputChanged();
658}
659/*!
660 \qmlproperty AudioOutput QtMultimedia::CaptureSession::audioOutput
661 \brief The audio output device for the capture session.
662
663 Add an AudioOutput device to the capture session to enable
664 audio routing from an AudioInput device.
665*/
666/*!
667 \property QMediaCaptureSession::audioOutput
668
669 Returns the audio output for the session.
670*/
671QAudioOutput *QMediaCaptureSession::audioOutput() const
672{
673 Q_D(const QMediaCaptureSession);
674 return d->audioOutput;
675}
676
677/*!
678 \internal
679*/
680QPlatformMediaCaptureSession *QMediaCaptureSession::platformSession() const
681{
682 Q_D(const QMediaCaptureSession);
683 return d->captureSession.get();
684}
685/*!
686 \qmlsignal QtMultimedia::CaptureSession::audioInputChanged()
687 This signal is emitted when an audio input has changed.
688 \sa CaptureSession::audioInput
689*/
690
691/*!
692 \qmlsignal QtMultimedia::CaptureSession::cameraChanged()
693 This signal is emitted when the selected camera has changed.
694 \sa CaptureSession::camera
695*/
696
697/*!
698 \qmlsignal QtMultimedia::CaptureSession::imageCaptureChanged()
699 This signal is emitted when the selected interface has changed.
700 \sa CaptureSession::camera
701*/
702
703/*!
704 \qmlsignal QtMultimedia::CaptureSession::recorderChanged()
705 This signal is emitted when the selected recorder has changed.
706 \sa CaptureSession::recorder
707*/
708
709/*!
710 \qmlsignal QtMultimedia::CaptureSession::videoOutputChanged()
711 This signal is emitted when the selected video output has changed.
712 \sa CaptureSession::videoOutput
713*/
714
715/*!
716 \qmlsignal QtMultimedia::CaptureSession::audioOutputChanged()
717 This signal is emitted when the selected audio output has changed.
718 \sa CaptureSession::audioOutput
719*/
720QT_END_NAMESPACE
721
722#include "moc_qmediacapturesession.cpp"
void setVideoSink(QVideoSink *sink)
Combined button and popup list for selecting options.