1// Copyright (C) 2024 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 "qaudiobuffer.h"
5#include "qvideoframeinput.h"
6#include "qmediaframeinput_p.h"
7#include "qmediainputencoderinterface_p.h"
8#include "qplatformvideoframeinput_p.h"
9
10QT_BEGIN_NAMESPACE
11
12class QVideoFrameInputPrivate : public QMediaFrameInputPrivate
13{
14public:
15 QVideoFrameInputPrivate(QVideoFrameInput *q) : q(q) { }
16
17 bool sendVideoFrame(const QVideoFrame &frame)
18 {
19 return sendMediaFrame(sender: [&]() { emit m_platfromVideoFrameInput->newVideoFrame(frame); });
20 }
21
22 void initialize(QVideoFrameFormat format = {})
23 {
24 m_platfromVideoFrameInput = std::make_unique<QPlatformVideoFrameInput>(args: std::move(format));
25 addUpdateSignal(sender: m_platfromVideoFrameInput.get(), signal: &QPlatformVideoFrameInput::encoderUpdated);
26 }
27
28 void uninitialize()
29 {
30 m_platfromVideoFrameInput.reset();
31
32 if (captureSession())
33 captureSession()->setVideoFrameInput(nullptr);
34 }
35
36 QPlatformVideoFrameInput *platfromVideoFrameInput() const
37 {
38 return m_platfromVideoFrameInput.get();
39 }
40
41protected:
42 void updateCaptureSessionConnections(QMediaCaptureSession *prevSession,
43 QMediaCaptureSession *newSession) override
44 {
45 if (prevSession)
46 removeUpdateSignal(sender: prevSession, signal: &QMediaCaptureSession::videoOutputChanged);
47
48 if (newSession)
49 addUpdateSignal(sender: newSession, signal: &QMediaCaptureSession::videoOutputChanged);
50 }
51
52 bool checkIfCanSendMediaFrame() const override
53 {
54 if (auto encoderInterface = m_platfromVideoFrameInput->encoderInterface())
55 return encoderInterface->canPushFrame();
56
57 return captureSession()->videoOutput() || captureSession()->videoSink();
58 }
59
60 void emitReadyToSendMediaFrame() override { emit q->readyToSendVideoFrame(); }
61
62private:
63 QVideoFrameInput *q = nullptr;
64 std::unique_ptr<QPlatformVideoFrameInput> m_platfromVideoFrameInput;
65};
66
67/*!
68 \class QVideoFrameInput
69 \inmodule QtMultimedia
70 \ingroup multimedia
71 \ingroup multimedia_video
72 \since 6.8
73
74 \brief The QVideoFrameInput class is used for providing custom video frames
75 to \l QMediaRecorder or a video output through \l QMediaCaptureSession.
76
77 QVideoFrameInput is only supported with the FFmpeg backend.
78
79 Custom video frames can be recorded by connecting a \l QVideoFrameInput and a
80 \l QMediaRecorder to a \l QMediaCaptureSession. For a pull mode implementation,
81 call \l sendVideoFrame() in response to the \l readyToSendVideoFrame() signal. In
82 the snippet below this is done by connecting the signal to a slot in a custom media
83 generator class. The slot function emits another signal with a new video frame, which
84 is connected to \l sendVideoFrame():
85
86 \snippet custommediainputsnippets/custommediainputsnippets.cpp QVideoFrameInput setup
87
88 Here's a minimal implementation of the slot function that provides video frames:
89
90 \snippet custommediainputsnippets/custommediainputsnippets.cpp nextVideoFrame()
91
92 For more details see readyToSendVideoFrame() and sendVideoFrame().
93
94 \sa QMediaRecorder, QMediaCaptureSession and QVideoSink.
95*/
96
97/*!
98 Constructs a new QVideoFrameInput object with \a parent.
99*/
100QVideoFrameInput::QVideoFrameInput(QObject *parent) : QVideoFrameInput({}, parent) { }
101
102/*!
103 Constructs a new QVideoFrameInput object with video frame \a format and \a parent.
104
105 The specified \a format will work as a hint for the initialization of the matching
106 video encoder upon invoking \l QMediaRecorder::record().
107 If the format is not specified or not valid, the video encoder will be initialized
108 upon sending the first frame.
109 Sending of video frames with another pixel format and size after initialization
110 of the matching video encoder might cause a performance penalty during recording.
111
112 We recommend specifying the format if you know in advance what kind of frames you're
113 going to send.
114*/
115QVideoFrameInput::QVideoFrameInput(const QVideoFrameFormat &format, QObject *parent)
116 : QObject(*new QVideoFrameInputPrivate(this), parent)
117{
118 Q_D(QVideoFrameInput);
119 d->initialize(format);
120}
121
122/*!
123 Destroys the object.
124 */
125QVideoFrameInput::~QVideoFrameInput()
126{
127 Q_D(QVideoFrameInput);
128 d->uninitialize();
129}
130
131/*!
132 Sends \l QVideoFrame to \l QMediaRecorder or a video output
133 through \l QMediaCaptureSession.
134
135 Returns \c true if the specified \a frame has been sent successfully
136 to the destination. Returns \c false, if the frame hasn't been sent,
137 which can happen if the instance is not assigned to
138 \l QMediaCaptureSession, the session doesn't have video outputs or
139 a media recorder, the media recorder is not started or its queue is full.
140 The signal \l readyToSendVideoFrame will be sent as soon as
141 the destination is able to handle a new frame.
142
143 Sending of an empty video frame is treated by \l QMediaRecorder
144 as an end of the input stream. QMediaRecorder stops the recording
145 automatically if \l QMediaRecorder::autoStop is \c true and
146 all the inputs have reported the end of the stream.
147*/
148bool QVideoFrameInput::sendVideoFrame(const QVideoFrame &frame)
149{
150 Q_D(QVideoFrameInput);
151 return d->sendVideoFrame(frame);
152}
153
154/*!
155 Returns the video frame format that was specified
156 upon construction of the video frame input.
157*/
158QVideoFrameFormat QVideoFrameInput::format() const
159{
160 Q_D(const QVideoFrameInput);
161 return d->platfromVideoFrameInput()->frameFormat();
162}
163
164/*!
165 Returns the capture session this video frame input is connected to, or
166 a \c nullptr if the video frame input is not connected to a capture session.
167
168 Use QMediaCaptureSession::setVideoFrameInput() to connect
169 the video frame input to a session.
170*/
171QMediaCaptureSession *QVideoFrameInput::captureSession() const
172{
173 Q_D(const QVideoFrameInput);
174 return d->captureSession();
175}
176
177void QVideoFrameInput::setCaptureSession(QMediaCaptureSession *captureSession)
178{
179 Q_D(QVideoFrameInput);
180 d->setCaptureSession(captureSession);
181}
182
183QPlatformVideoFrameInput *QVideoFrameInput::platformVideoFrameInput() const
184{
185 Q_D(const QVideoFrameInput);
186 return d->platfromVideoFrameInput();
187}
188
189/*!
190 \fn void QVideoFrameInput::readyToSendVideoFrame()
191
192 Signals that a new frame can be sent to the video frame input.
193 After receiving the signal, if you have frames to be sent, invoke \l sendVideoFrame
194 once or in a loop until it returns \c false.
195
196 \sa sendVideoFrame()
197*/
198
199QT_END_NAMESPACE
200

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

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