Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qgstreamervideooutput.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 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 <QtMultimedia/qvideosink.h>
5
6#include <QtCore/qloggingcategory.h>
7#include <QtCore/qthread.h>
8
12
13static Q_LOGGING_CATEGORY(qLcMediaVideoOutput, "qt.multimedia.videooutput")
14
16
18{
19 QGstElement videoConvert;
20 QGstElement videoScale;
21
23 gst_element_factory_find("videoconvertscale"),
24 };
25
26 if (factory) { // videoconvertscale is only available in gstreamer 1.20
27 videoConvert = QGstElement::createFromFactory(factory, "videoConvertScale");
28 } else {
29 videoConvert = QGstElement::createFromFactory("videoconvert", "videoConvert");
30 if (!videoConvert)
31 return errorMessageCannotFindElement("videoconvert");
32
33 videoScale = QGstElement::createFromFactory("videoscale", "videoScale");
34 if (!videoScale)
35 return errorMessageCannotFindElement("videoscale");
36 }
37
38 QGstElement videoSink = QGstElement::createFromFactory("fakesink", "fakeVideoSink");
39 if (!videoSink)
40 return errorMessageCannotFindElement("fakesink");
41 videoSink.set("sync", true);
42
43 return new QGstreamerVideoOutput(videoConvert, videoScale, videoSink, parent);
44}
45
46QGstreamerVideoOutput::QGstreamerVideoOutput(QGstElement convert, QGstElement scale,
47 QGstElement sink, QObject *parent)
48 : QObject(parent),
49 gstVideoOutput(QGstBin::create("videoOutput")),
50 videoConvert(std::move(convert)),
51 videoScale(std::move(scale)),
52 videoSink(std::move(sink))
53{
54 videoQueue = QGstElement::createFromFactory("queue", "videoQueue");
55
56 videoSink.set("sync", true);
57 videoSink.set("async", false); // no asynchronous state changes
58
59 if (videoScale) {
60 gstVideoOutput.add(videoQueue, videoConvert, videoScale, videoSink);
61 qLinkGstElements(videoQueue, videoConvert, videoScale, videoSink);
62 } else {
63 gstVideoOutput.add(videoQueue, videoConvert, videoSink);
64 qLinkGstElements(videoQueue, videoConvert, videoSink);
65 }
66
67 gstVideoOutput.addGhostPad(videoQueue, "sink");
68}
69
71{
72 gstVideoOutput.setStateSync(GST_STATE_NULL);
73}
74
76{
77 auto *gstVideoSink = sink ? static_cast<QGstreamerVideoSink *>(sink->platformVideoSink()) : nullptr;
78 if (gstVideoSink == m_videoSink)
79 return;
80
81 if (m_videoSink)
82 m_videoSink->setPipeline({});
83
84 m_videoSink = gstVideoSink;
85 if (m_videoSink) {
86 m_videoSink->setPipeline(gstPipeline);
87 if (nativeSize.isValid())
88 m_videoSink->setNativeSize(nativeSize);
89 }
90 QGstElement gstSink;
91 if (m_videoSink) {
92 gstSink = m_videoSink->gstSink();
93 } else {
94 gstSink = QGstElement::createFromFactory("fakesink", "fakevideosink");
95 Q_ASSERT(gstSink);
96 gstSink.set("sync", true);
97 gstSink.set("async", false); // no asynchronous state changes
98 }
99
100 if (videoSink == gstSink)
101 return;
102
103 gstPipeline.modifyPipelineWhileNotRunning([&] {
104 if (!videoSink.isNull())
105 gstVideoOutput.stopAndRemoveElements(videoSink);
106
107 videoSink = gstSink;
108 gstVideoOutput.add(videoSink);
109
110 if (videoScale)
111 qLinkGstElements(videoScale, videoSink);
112 else
113 qLinkGstElements(videoConvert, videoSink);
114
115 GstEvent *event = gst_event_new_reconfigure();
116 gst_element_send_event(videoSink.element(), event);
117 videoSink.syncStateWithParent();
118
119 doLinkSubtitleStream();
120 });
121
122 qCDebug(qLcMediaVideoOutput) << "sinkChanged" << gstSink.name();
123
124 GST_DEBUG_BIN_TO_DOT_FILE(gstPipeline.bin(),
125 GstDebugGraphDetails(/*GST_DEBUG_GRAPH_SHOW_ALL |*/ GST_DEBUG_GRAPH_SHOW_MEDIA_TYPE |
126 GST_DEBUG_GRAPH_SHOW_NON_DEFAULT_PARAMS | GST_DEBUG_GRAPH_SHOW_STATES),
127 videoSink.name());
128
129}
130
132{
133 gstPipeline = pipeline;
134 if (m_videoSink)
135 m_videoSink->setPipeline(gstPipeline);
136}
137
139{
140 qCDebug(qLcMediaVideoOutput) << "link subtitle stream" << src.isNull();
141 if (src == subtitleSrc)
142 return;
143
144 gstPipeline.modifyPipelineWhileNotRunning([&] {
145 subtitleSrc = src;
146 doLinkSubtitleStream();
147 });
148}
149
151{
152 if (subtitleSrc.isNull())
153 return;
154 qCDebug(qLcMediaVideoOutput) << "unlink subtitle stream";
155 subtitleSrc = {};
156 if (!subtitleSink.isNull()) {
157 gstPipeline.modifyPipelineWhileNotRunning([&] {
158 gstPipeline.stopAndRemoveElements(subtitleSink);
159 return;
160 });
161 subtitleSink = {};
162 }
163 if (m_videoSink)
164 m_videoSink->setSubtitleText({});
165}
166
167void QGstreamerVideoOutput::doLinkSubtitleStream()
168{
169 if (!subtitleSink.isNull()) {
170 gstPipeline.stopAndRemoveElements(subtitleSink);
171 subtitleSink = {};
172 }
173 if (!m_videoSink || subtitleSrc.isNull())
174 return;
175 if (subtitleSink.isNull()) {
176 subtitleSink = m_videoSink->subtitleSink();
177 gstPipeline.add(subtitleSink);
178 }
179 qLinkGstElements(subtitleSrc, subtitleSink);
180}
181
182void QGstreamerVideoOutput::updateNativeSize()
183{
184 if (!m_videoSink)
185 return;
186
187 m_videoSink->setNativeSize(qRotatedFrameSize(nativeSize, rotation));
188}
189
191{
192 // configures the queue to be fast and lightweight for camera preview
193 // also avoids blocking the queue in case we have an encodebin attached to the tee as well
194 videoQueue.set("leaky", 2 /*downstream*/);
195 videoQueue.set("silent", true);
196 videoQueue.set("max-size-buffers", uint(1));
197 videoQueue.set("max-size-bytes", uint(0));
198 videoQueue.set("max-size-time", quint64(0));
199}
200
202{
203 if (!subtitleSink.isNull()) {
204 auto pad = subtitleSink.staticPad("sink");
205 auto *event = gst_event_new_flush_start();
206 pad.sendEvent(event);
207 event = gst_event_new_flush_stop(false);
208 pad.sendEvent(event);
209 }
210}
211
213{
214 nativeSize = sz;
215 updateNativeSize();
216}
217
219{
220 rotation = rot;
221 updateNativeSize();
222}
223
225
226#include "moc_qgstreamervideooutput_p.cpp"
std::enable_if_t<(std::is_base_of_v< QGstElement, Ts > &&...), void add)(const Ts &...ts)
Definition qgst_p.h:690
GstBin * bin() const
Definition qgst.cpp:1111
std::enable_if_t<(std::is_base_of_v< QGstElement, Ts > &&...), void stopAndRemoveElements)(Ts... ts)
Definition qgst_p.h:709
GstElement * element() const
Definition qgst.cpp:1026
bool setStateSync(GstState state, std::chrono::nanoseconds timeout=std::chrono::seconds(1))
Definition qgst.cpp:947
bool syncStateWithParent()
Definition qgst.cpp:969
QGstPad staticPad(const char *name) const
Definition qgst.cpp:898
static QGstElement createFromFactory(const char *factory, const char *name=nullptr)
Definition qgst.cpp:835
const char * name() const
Definition qgst.cpp:682
void set(const char *property, const char *str)
Definition qgst.cpp:538
void modifyPipelineWhileNotRunning(Functor &&fn)
void setPipeline(const QGstPipeline &pipeline)
void linkSubtitleStream(QGstElement subtitleSrc)
void setVideoSink(QVideoSink *sink)
void setRotation(QtVideo::Rotation)
void setPipeline(QGstPipeline pipeline)
QGstElement subtitleSink() const
\inmodule QtCore
Definition qobject.h:103
void setSubtitleText(const QString &subtitleText)
\inmodule QtCore
Definition qsize.h:25
constexpr bool isValid() const noexcept
Returns true if both the width and height is equal to or greater than 0; otherwise returns false.
Definition qsize.h:127
The QVideoSink class represents a generic sink for video data.
Definition qvideosink.h:22
Combined button and popup list for selecting options.
std::enable_if_t<(std::is_base_of_v< QGstElement, Ts > &&...), void qLinkGstElements)(const Ts &...ts)
Definition qgst_p.h:643
QString errorMessageCannotFindElement(std::string_view element)
Definition qgst_p.h:804
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
QSize qRotatedFrameSize(QSize size, int rotation)
GLenum src
struct _cl_event * event
GLsizei GLenum GLboolean sink
GLenum GLenum GLenum GLenum GLenum scale
static constexpr To convert(const std::array< Mapping, N > &mapping, From Mapping::*from, To Mapping::*to, From value, To defaultValue)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
unsigned long long quint64
Definition qtypes.h:61
unsigned int uint
Definition qtypes.h:34
QItemEditorFactory * factory
view create()