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
13Q_STATIC_LOGGING_CATEGORY(qLcMediaVideoOutput, "qt.multimedia.videooutput");
14
16
18{
20 if (factory) // videoconvertscale is only available in gstreamer 1.20
22
23 return QGstBin::createFromPipelineDescription("videoconvert ! videoscale", name,
24 /*ghostUnlinkedPads=*/true);
25}
26
27QMaybe<QGstreamerVideoOutput *> QGstreamerVideoOutput::create(QObject *parent)
28{
30
31 static std::optional<QString> elementCheck = []() -> std::optional<QString> {
32 std::optional<QString> error = qGstErrorMessageIfElementsNotAvailable("fakesink", "queue");
33 if (error)
34 return error;
35
37 if (factory)
38 return std::nullopt;
39
40 return qGstErrorMessageIfElementsNotAvailable("videoconvert", "videoscale");
41 }();
42
43 if (elementCheck)
44 return *elementCheck;
45
46 return new QGstreamerVideoOutput(parent);
47}
48
49QGstreamerVideoOutput::QGstreamerVideoOutput(QObject *parent)
50 : QObject(parent),
51 m_outputBin{
52 QGstBin::create("videoOutput"),
53 },
54 m_videoQueue{
55 QGstElement::createFromFactory("queue", "videoQueue"),
56 },
57 m_videoConvertScale{
58 makeVideoConvertScale("videoConvertScale"),
59 },
60 m_videoSink{
61 QGstElement::createFromFactory("fakesink", "fakeVideoSink"),
62 }
63{
64 m_videoSink.set("sync", true);
65 m_videoSink.set("async", false); // no asynchronous state changes
66
67 m_outputBin.add(m_videoQueue, m_videoConvertScale, m_videoSink);
68 qLinkGstElements(m_videoQueue, m_videoConvertScale, m_videoSink);
69
70 m_subtitleSink = QGstSubtitleSink::createSink(this);
71
72 m_outputBin.addGhostPad(m_videoQueue, "sink");
73}
74
76{
77 QObject::disconnect(m_subtitleConnection);
78 m_outputBin.setStateSync(GST_STATE_NULL);
79}
80
82{
83 auto *gstVideoSink = sink ? static_cast<QGstreamerVideoSink *>(sink->platformVideoSink()) : nullptr;
84 if (gstVideoSink == m_platformVideoSink)
85 return;
86
87 m_platformVideoSink = gstVideoSink;
88 if (m_platformVideoSink) {
89 m_platformVideoSink->setActive(m_isActive);
90 if (m_nativeSize.isValid())
91 m_platformVideoSink->setNativeSize(m_nativeSize);
92 }
93 QGstElement videoSink;
94 if (m_platformVideoSink) {
95 videoSink = m_platformVideoSink->gstSink();
96 } else {
97 videoSink = QGstElement::createFromFactory("fakesink", "fakevideosink");
98 Q_ASSERT(videoSink);
99 videoSink.set("sync", true);
100 videoSink.set("async", false); // no asynchronous state changes
101 }
102
103 QObject::disconnect(m_subtitleConnection);
104 if (sink) {
105 m_subtitleConnection = QObject::connect(this, &QGstreamerVideoOutput::subtitleChanged, sink,
106 [sink](const QString &subtitle) {
107 sink->setSubtitleText(subtitle);
108 });
109 sink->setSubtitleText(m_lastSubtitleString);
110 }
111
112 if (m_videoSink == videoSink)
113 return;
114
115 m_pipeline.modifyPipelineWhileNotRunning([&] {
116 if (!m_videoSink.isNull())
117 m_outputBin.stopAndRemoveElements(m_videoSink);
118
119 m_videoSink = videoSink;
120 m_outputBin.add(m_videoSink);
121
122 qLinkGstElements(m_videoConvertScale, m_videoSink);
123
124 GstEvent *event = gst_event_new_reconfigure();
125 gst_element_send_event(m_videoSink.element(), event);
126 m_videoSink.syncStateWithParent();
127 });
128
129 qCDebug(qLcMediaVideoOutput) << "sinkChanged" << videoSink.name();
130
131 m_pipeline.dumpGraph(m_videoSink.name().constData());
132}
133
135{
136 m_pipeline = pipeline;
137}
138
140{
141 if (m_isActive == isActive)
142 return;
143
144 m_isActive = isActive;
145 if (m_platformVideoSink)
146 m_platformVideoSink->setActive(isActive);
147}
148
149void QGstreamerVideoOutput::updateNativeSize()
150{
151 if (!m_platformVideoSink)
152 return;
153
154 m_platformVideoSink->setNativeSize(qRotatedFrameSize(m_nativeSize, m_rotation));
155}
156
158{
159 // configures the queue to be fast and lightweight for camera preview
160 // also avoids blocking the queue in case we have an encodebin attached to the tee as well
161 m_videoQueue.set("leaky", 2 /*downstream*/);
162 m_videoQueue.set("silent", true);
163 m_videoQueue.set("max-size-buffers", uint(1));
164 m_videoQueue.set("max-size-bytes", uint(0));
165 m_videoQueue.set("max-size-time", quint64(0));
166}
167
169{
170 if (!m_subtitleSink.isNull()) {
171 auto pad = m_subtitleSink.staticPad("sink");
172 auto *event = gst_event_new_flush_start();
173 pad.sendEvent(event);
174 event = gst_event_new_flush_stop(false);
175 pad.sendEvent(event);
176 }
177}
178
180{
181 m_nativeSize = sz;
182 updateNativeSize();
183}
184
186{
187 m_rotation = rot;
188 updateNativeSize();
189}
190
192{
193 // GStreamer thread
194
195 QMetaObject::invokeMethod(this, [this, string = std::move(string)]() mutable {
196 m_lastSubtitleString = string;
197 Q_EMIT subtitleChanged(std::move(string));
198 });
199}
200
202
203#include "moc_qgstreamervideooutput_p.cpp"
bool isActive
std::enable_if_t<(std::is_base_of_v< QGstElement, Ts > &&...), void add)(const Ts &...ts)
Definition qgst_p.h:707
void dumpGraph(const char *fileNamePrefix) const
Definition qgst.cpp:1257
void addGhostPad(const QGstElement &child, const char *name)
Definition qgst.cpp:1242
std::enable_if_t<(std::is_base_of_v< QGstElement, Ts > &&...), void stopAndRemoveElements)(Ts... ts)
Definition qgst_p.h:726
static QGstBin createFromPipelineDescription(const QByteArray &pipelineDescription, const char *name=nullptr, bool ghostUnlinkedPads=false)
Definition qgst.cpp:1199
GstElement * element() const
Definition qgst.cpp:1131
bool setStateSync(GstState state, std::chrono::nanoseconds timeout=std::chrono::seconds(1))
Definition qgst.cpp:1002
bool syncStateWithParent()
Definition qgst.cpp:1024
QGstPad staticPad(const char *name) const
Definition qgst.cpp:953
static QGstElement createFromFactory(const char *factory, const char *name=nullptr)
Definition qgst.cpp:877
static QGstElementFactoryHandle findFactory(const char *)
Definition qgst.cpp:940
QLatin1StringView name() const
Definition qgst.cpp:700
void set(const char *property, const char *str)
Definition qgst.cpp:554
void modifyPipelineWhileNotRunning(Functor &&fn)
static QGstElement createSink(QAbstractSubtitleObserver *observer)
void setPipeline(const QGstPipeline &pipeline)
void subtitleChanged(QString)
void updateSubtitle(QString) override
void setVideoSink(QVideoSink *sink)
void setRotation(QtVideo::Rotation)
static QMaybe< QGstreamerVideoOutput * > create(QObject *parent=nullptr)
constexpr const char * constData() const noexcept
\inmodule QtCore
Definition qobject.h:103
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:346
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Definition qobject.cpp:3236
\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
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
The QVideoSink class represents a generic sink for video data.
Definition qvideosink.h:22
Combined button and popup list for selecting options.
DBusConnection const char DBusError * error
std::enable_if_t<(std::is_base_of_v< QGstElement, Ts > &&...), void qLinkGstElements)(const Ts &...ts)
Definition qgst_p.h:660
std::optional< QString > qGstErrorMessageIfElementsNotAvailable(const Arg &arg, Args... args)
Definition qgst_p.h:833
static QT_BEGIN_NAMESPACE QGstElement makeVideoConvertScale(const char *name)
#define qCDebug(category,...)
#define Q_STATIC_LOGGING_CATEGORY(name,...)
QSize qRotatedFrameSize(QSize size, int rotation)
GLuint name
struct _cl_event * event
GLsizei GLenum GLboolean sink
GLsizei const GLchar *const * string
[0]
Definition qopenglext.h:694
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_EMIT
unsigned long long quint64
Definition qtypes.h:61
unsigned int uint
Definition qtypes.h:34
QItemEditorFactory * factory
view create()
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(nullptr), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument())
\threadsafe This is an overloaded member function, provided for convenience. It differs from the abov...