Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qgstpipeline.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 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 <QtCore/qmap.h>
5#include <QtCore/qtimer.h>
6#include <QtCore/qmutex.h>
7#include <QtCore/qlist.h>
8#include <QtCore/qabstracteventdispatcher.h>
9#include <QtCore/qcoreapplication.h>
10#include <QtCore/qproperty.h>
11
12#include "qgstpipeline_p.h"
13#include "qgstreamermessage_p.h"
14
16
18{
20public:
21
22 int m_ref = 0;
23 guint m_tag = 0;
24 GstBus *m_bus = nullptr;
29 bool inStoppedState = true;
30 mutable qint64 m_position = 0;
31 double m_rate = 1.;
33 bool m_pendingFlush = false;
34
36 GstState m_savedState = GST_STATE_NULL;
37
38 QGstPipelinePrivate(GstBus* bus, QObject* parent = 0);
40
41 void ref() { ++ m_ref; }
42 void deref() { if (!--m_ref) delete this; }
43
48
49 static GstBusSyncReply syncGstBusFilter(GstBus* bus, GstMessage* message, QGstPipelinePrivate *d)
50 {
51 Q_UNUSED(bus);
52 QMutexLocker lock(&d->filterMutex);
53
54 for (QGstreamerSyncMessageFilter *filter : std::as_const(d->syncFilters)) {
55 if (filter->processSyncMessage(QGstreamerMessage(message))) {
56 gst_message_unref(message);
57 return GST_BUS_DROP;
58 }
59 }
60
61 return GST_BUS_PASS;
62 }
63
64private Q_SLOTS:
65 void interval()
66 {
67 GstMessage* message;
68 while ((message = gst_bus_poll(m_bus, GST_MESSAGE_ANY, 0)) != nullptr) {
69 processMessage(message);
70 gst_message_unref(message);
71 }
72 }
73 void doProcessMessage(const QGstreamerMessage& msg)
74 {
76 if (filter->processBusMessage(msg))
77 break;
78 }
79 }
80
81private:
82 void processMessage(GstMessage* message)
83 {
85 doProcessMessage(msg);
86 }
87
88 void queueMessage(GstMessage* message)
89 {
91 QMetaObject::invokeMethod(this, "doProcessMessage", Qt::QueuedConnection,
93 }
94
95 static gboolean busCallback(GstBus *bus, GstMessage *message, gpointer data)
96 {
97 Q_UNUSED(bus);
98 static_cast<QGstPipelinePrivate *>(data)->queueMessage(message);
99 return TRUE;
100 }
101};
102
104 : QObject(parent),
105 m_bus(bus)
106{
107 // glib event loop can be disabled either by env variable or QT_NO_GLIB define, so check the dispacher
109 const bool hasGlib = dispatcher && dispatcher->inherits("QEventDispatcherGlib");
110 if (!hasGlib) {
111 m_intervalTimer = new QTimer(this);
113 connect(m_intervalTimer, SIGNAL(timeout()), SLOT(interval()));
115 } else {
116 m_tag = gst_bus_add_watch_full(bus, G_PRIORITY_DEFAULT, busCallback, this, nullptr);
117 }
118
119 gst_bus_set_sync_handler(bus, (GstBusSyncHandler)syncGstBusFilter, this, nullptr);
120}
121
123{
124 delete m_intervalTimer;
125
126 if (m_tag)
127 gst_bus_remove_watch(m_bus);
128
129 gst_bus_set_sync_handler(m_bus, nullptr, nullptr, nullptr);
130 gst_object_unref(GST_OBJECT(m_bus));
131}
132
134{
135 if (filter) {
139 }
140}
141
143{
144 if (filter) {
147 }
148}
149
151{
154}
155
157{
158 if (filter)
160}
161
163 : QGstBin(o.bin(), NeedsRef),
164 d(o.d)
165{
166 if (d)
167 d->ref();
168}
169
171{
172 if (this == &o)
173 return *this;
174 if (o.d)
175 o.d->ref();
176 if (d)
177 d->deref();
179 d = o.d;
180 return *this;
181}
182
184 : QGstBin(GST_BIN(gst_pipeline_new(name)), NeedsRef)
185{
186 d = new QGstPipelinePrivate(gst_pipeline_get_bus(pipeline()));
187 d->ref();
188}
189
191 : QGstBin(&p->bin, NeedsRef)
192{
193 d = new QGstPipelinePrivate(gst_pipeline_get_bus(pipeline()));
194 d->ref();
195}
196
198{
199 if (d)
200 d->deref();
201}
202
204{
205 Q_ASSERT(d);
206 return d->inStoppedState;
207}
208
210{
211 Q_ASSERT(d);
212 d->inStoppedState = stopped;
213}
214
216{
218}
219
221{
222 Q_ASSERT(d);
224}
225
227{
228 Q_ASSERT(d);
230}
231
233{
234 Q_ASSERT(d);
236}
237
239{
240 Q_ASSERT(d);
242}
243
244GstStateChangeReturn QGstPipeline::setState(GstState state)
245{
246 auto retval = gst_element_set_state(element(), state);
247 if (d->m_pendingFlush) {
248 d->m_pendingFlush = false;
249 flush();
250 }
251 return retval;
252}
253
255{
256 if (!d)
257 return;
258 Q_ASSERT(!isNull());
259
260 ++d->m_configCounter;
261 if (d->m_configCounter > 1)
262 return;
263
264 d->m_savedState = state();
265 if (d->m_savedState == GST_STATE_PLAYING)
266 setStateSync(GST_STATE_PAUSED);
267}
268
270{
271 if (!d)
272 return;
273 Q_ASSERT(!isNull());
274
275 --d->m_configCounter;
276 if (d->m_configCounter)
277 return;
278
280 d->m_pendingFlush = true;
281 if (d->m_savedState == GST_STATE_PLAYING)
282 setState(GST_STATE_PLAYING);
283 d->m_savedState = GST_STATE_NULL;
284}
285
287{
288 seek(position(), d->m_rate);
289}
290
292{
293 // always adjust the rate, so it can be set before playback starts
294 // setting position needs a loaded media file that's seekable
295 d->m_rate = rate;
296 qint64 from = rate > 0 ? pos : 0;
297 qint64 to = rate > 0 ? duration() : pos;
298 bool success = gst_element_seek(element(), rate, GST_FORMAT_TIME,
299 GstSeekFlags(GST_SEEK_FLAG_FLUSH),
300 GST_SEEK_TYPE_SET, from,
301 GST_SEEK_TYPE_SET, to);
302 if (!success)
303 return false;
304
305 d->m_position = pos;
306 return true;
307}
308
310{
311 if (rate == d->m_rate)
312 return false;
313 seek(position(), rate);
314 return true;
315}
316
318{
319 return d->m_rate;
320}
321
323{
324 return seek(pos, d->m_rate);
325}
326
328{
329 gint64 pos;
330 if (gst_element_query_position(element(), GST_FORMAT_TIME, &pos))
331 d->m_position = pos;
332 return d->m_position;
333}
334
336{
337 gint64 d;
338 if (!gst_element_query_duration(element(), GST_FORMAT_TIME, &d))
339 return 0.;
340 return d;
341}
342
344
345#include "qgstpipeline.moc"
346
static QAbstractEventDispatcher * eventDispatcher()
Returns a pointer to the event dispatcher object for the main thread.
GstElement * element() const
Definition qgst_p.h:526
bool setStateSync(GstState state)
Definition qgst_p.h:463
GstState state() const
Definition qgst_p.h:456
QGstObject & operator=(const QGstObject &other)
Definition qgst_p.h:251
bool isNull() const
Definition qgst_p.h:288
void installMessageFilter(QGstreamerSyncMessageFilter *filter)
QGstPipelinePrivate(GstBus *bus, QObject *parent=0)
QList< QGstreamerBusMessageFilter * > busFilters
void removeMessageFilter(QGstreamerSyncMessageFilter *filter)
static GstBusSyncReply syncGstBusFilter(GstBus *bus, GstMessage *message, QGstPipelinePrivate *d)
QList< QGstreamerSyncMessageFilter * > syncFilters
GstStateChangeReturn setState(GstState state)
GstPipeline * pipeline() const
bool inStoppedState() const
void installMessageFilter(QGstreamerSyncMessageFilter *filter)
void removeMessageFilter(QGstreamerSyncMessageFilter *filter)
qint64 duration() const
constexpr QGstPipeline()=default
qint64 position() const
QGstPipeline & operator=(const QGstPipeline &o)
double playbackRate() const
bool seek(qint64 pos, double rate)
bool setPlaybackRate(double rate)
void setInStoppedState(bool stopped)
~QGstPipeline() override
void setFlushOnConfigChanges(bool flush)
bool setPosition(qint64 pos)
Definition qlist.h:74
qsizetype removeAll(const AT &t)
Definition qlist.h:575
void append(parameter_type t)
Definition qlist.h:441
\inmodule QtCore
Definition qmutex.h:317
\inmodule QtCore
Definition qmutex.h:285
\inmodule QtCore
Definition qobject.h:90
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:311
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2823
bool inherits(const char *classname) const
Returns true if this object is an instance of a class that inherits className or a QObject subclass t...
Definition qobject.h:313
\inmodule QtCore
Definition qtimer.h:20
void start(int msec)
Starts or restarts the timer with a timeout interval of msec milliseconds.
Definition qtimer.cpp:208
void setInterval(int msec)
Definition qtimer.cpp:607
else opt state
[0]
Combined button and popup list for selecting options.
@ QueuedConnection
#define SLOT(a)
Definition qobjectdefs.h:51
#define Q_ARG(Type, data)
Definition qobjectdefs.h:62
#define SIGNAL(a)
Definition qobjectdefs.h:52
GLbitfield GLuint64 timeout
[4]
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
GLuint GLsizei const GLchar * message
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint name
GLuint GLenum * rate
GLfloat GLfloat p
[1]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_OBJECT
#define Q_SLOTS
#define Q_UNUSED(x)
long long qint64
Definition qtypes.h:55
QReadWriteLock lock
[0]
bool contains(const AT &t) const noexcept
Definition qlist.h:44
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...
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent