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
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{
19public:
20 int m_ref = 0;
21 guint m_tag = 0;
22 GstBus *m_bus = nullptr;
25 QList<QGstreamerSyncMessageFilter*> syncFilters;
26 QList<QGstreamerBusMessageFilter*> busFilters;
27 bool inStoppedState = true;
28 mutable qint64 m_position = 0;
29 double m_rate = 1.;
31 bool m_pendingFlush = false;
32
34 GstState m_savedState = GST_STATE_NULL;
35
36 explicit QGstPipelinePrivate(GstBus *bus, QObject *parent = nullptr);
38
39 void ref() { ++ m_ref; }
40 void deref() { if (!--m_ref) delete this; }
41
46
48 {
49 for (QGstreamerBusMessageFilter *filter : std::as_const(busFilters)) {
50 if (filter->processBusMessage(msg))
51 break;
52 }
53 }
54
55private:
56 static GstBusSyncReply syncGstBusFilter(GstBus *bus, GstMessage *message,
58 {
59 if (!message)
60 return GST_BUS_PASS;
61
62 Q_UNUSED(bus);
63 QMutexLocker lock(&d->filterMutex);
64
66 if (filter->processSyncMessage(
67 QGstreamerMessage{ message, QGstreamerMessage::NeedsRef })) {
68 gst_message_unref(message);
69 return GST_BUS_DROP;
70 }
71 }
72
73 return GST_BUS_PASS;
74 }
75
76 void processMessage(GstMessage *message)
77 {
78 if (!message)
79 return;
80
82 message,
84 };
85
86 processMessage(msg);
87 }
88
89 static gboolean busCallback(GstBus *, GstMessage *message, gpointer data)
90 {
92 return TRUE;
93 }
94};
95
97 : QObject(parent),
98 m_bus(bus)
99{
100 // glib event loop can be disabled either by env variable or QT_NO_GLIB define, so check the dispacher
102 const bool hasGlib = dispatcher && dispatcher->inherits("QEventDispatcherGlib");
103 if (!hasGlib) {
104 m_intervalTimer = new QTimer(this);
107 GstMessage *message;
108 while ((message = gst_bus_poll(m_bus, GST_MESSAGE_ANY, 0)) != nullptr) {
110 gst_message_unref(message);
111 }
112 });
114 } else {
115 m_tag = gst_bus_add_watch_full(bus, G_PRIORITY_DEFAULT, busCallback, this, nullptr);
116 }
117
118 gst_bus_set_sync_handler(bus, (GstBusSyncHandler)syncGstBusFilter, this, nullptr);
119}
120
122{
123 delete m_intervalTimer;
124
125 if (m_tag)
126 gst_bus_remove_watch(m_bus);
127
128 gst_bus_set_sync_handler(m_bus, nullptr, nullptr, nullptr);
129 gst_object_unref(GST_OBJECT(m_bus));
130}
131
140
148
154
160
162{
163 GstPipeline *pipeline = qGstCheckedCast<GstPipeline>(gst_pipeline_new(name));
164 return adopt(pipeline);
165}
166
167QGstPipeline QGstPipeline::adopt(GstPipeline *pipeline)
168{
169 QGstPipelinePrivate *d = new QGstPipelinePrivate(gst_pipeline_get_bus(pipeline));
170 g_object_set_data_full(qGstCheckedCast<GObject>(pipeline), "pipeline-private", d,
171 [](gpointer ptr) {
172 delete reinterpret_cast<QGstPipelinePrivate *>(ptr);
173 return;
174 });
175
176 return QGstPipeline{
177 pipeline,
179 };
180}
181
182QGstPipeline::QGstPipeline(GstPipeline *p, RefMode mode) : QGstBin(qGstCheckedCast<GstBin>(p), mode)
183{
184}
185
187
189{
190 QGstPipelinePrivate *d = getPrivate();
191 return d->inStoppedState;
192}
193
195{
196 QGstPipelinePrivate *d = getPrivate();
197 d->inStoppedState = stopped;
198}
199
201{
202 QGstPipelinePrivate *d = getPrivate();
203 d->m_flushOnConfigChanges = flush;
204}
205
207{
208 QGstPipelinePrivate *d = getPrivate();
209 d->installMessageFilter(filter);
210}
211
213{
214 QGstPipelinePrivate *d = getPrivate();
215 d->removeMessageFilter(filter);
216}
217
219{
220 QGstPipelinePrivate *d = getPrivate();
221 d->installMessageFilter(filter);
222}
223
225{
226 QGstPipelinePrivate *d = getPrivate();
227 d->removeMessageFilter(filter);
228}
229
230GstStateChangeReturn QGstPipeline::setState(GstState state)
231{
232 QGstPipelinePrivate *d = getPrivate();
233 auto retval = gst_element_set_state(element(), state);
234 if (d->m_pendingFlush) {
235 d->m_pendingFlush = false;
236 flush();
237 }
238 return retval;
239}
240
242{
243 QGstPipelinePrivate *d = getPrivate();
245 gst_bus_pop_filtered(d->m_bus, types),
247 };
248 d->processMessage(message);
249}
250
252{
253 if (isNull())
254 return;
255
256 QGstBin{ bin(), QGstBin::NeedsRef }.dumpGraph(fileName);
257}
258
259void QGstPipeline::beginConfig()
260{
261 QGstPipelinePrivate *d = getPrivate();
262 Q_ASSERT(!isNull());
263
264 ++d->m_configCounter;
265 if (d->m_configCounter > 1)
266 return;
267
268 GstState state;
269 GstState pending;
270 GstStateChangeReturn stateChangeReturn = gst_element_get_state(element(), &state, &pending, 0);
271 switch (stateChangeReturn) {
272 case GST_STATE_CHANGE_ASYNC: {
273 if (state == GST_STATE_PLAYING) {
274 // playing->paused transition in progress. wait for it to finish
275 bool stateChangeSuccessful = this->finishStateChange();
276 if (!stateChangeSuccessful)
277 qWarning() << "QGstPipeline::beginConfig: timeout when waiting for state change";
278 }
279
280 state = pending;
281 break;
282 }
283 case GST_STATE_CHANGE_FAILURE: {
284 qDebug() << "QGstPipeline::beginConfig: state change failure";
285 dumpGraph("beginConfigFailure");
286 break;
287 }
288
289 case GST_STATE_CHANGE_NO_PREROLL:
290 case GST_STATE_CHANGE_SUCCESS:
291 break;
292 }
293
294 d->m_savedState = state;
295 if (d->m_savedState == GST_STATE_PLAYING)
296 setStateSync(GST_STATE_PAUSED);
297}
298
299void QGstPipeline::endConfig()
300{
301 QGstPipelinePrivate *d = getPrivate();
302 Q_ASSERT(!isNull());
303
304 --d->m_configCounter;
305 if (d->m_configCounter)
306 return;
307
308 if (d->m_flushOnConfigChanges)
309 d->m_pendingFlush = true;
310 if (d->m_savedState == GST_STATE_PLAYING)
311 setState(GST_STATE_PLAYING);
312 d->m_savedState = GST_STATE_NULL;
313}
314
316{
317 QGstPipelinePrivate *d = getPrivate();
318 seek(position(), d->m_rate);
319}
320
322{
323 QGstPipelinePrivate *d = getPrivate();
324 // always adjust the rate, so it can be set before playback starts
325 // setting position needs a loaded media file that's seekable
326 d->m_rate = rate;
327 qint64 from = rate > 0 ? pos : 0;
328 qint64 to = rate > 0 ? duration() : pos;
329 bool success = gst_element_seek(element(), rate, GST_FORMAT_TIME,
330 GstSeekFlags(GST_SEEK_FLAG_FLUSH),
331 GST_SEEK_TYPE_SET, from,
332 GST_SEEK_TYPE_SET, to);
333 if (!success)
334 return false;
335
336 d->m_position = pos;
337 return true;
338}
339
340bool QGstPipeline::setPlaybackRate(double rate, bool applyToPipeline)
341{
342 QGstPipelinePrivate *d = getPrivate();
343 if (rate == d->m_rate)
344 return false;
345
346 if (!applyToPipeline) {
347 d->m_rate = rate;
348 return true;
349 }
350
351 constexpr GstSeekFlags seekFlags =
352#if GST_CHECK_VERSION(1, 18, 0)
353 GST_SEEK_FLAG_INSTANT_RATE_CHANGE;
354#else
355 GST_SEEK_FLAG_FLUSH;
356#endif
357
358 bool success = gst_element_seek(element(), rate, GST_FORMAT_TIME, seekFlags, GST_SEEK_TYPE_NONE,
359 GST_CLOCK_TIME_NONE, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
360 if (success)
361 d->m_rate = rate;
362
363 return success;
364}
365
367{
368 QGstPipelinePrivate *d = getPrivate();
369 return d->m_rate;
370}
371
373{
374 QGstPipelinePrivate *d = getPrivate();
375 return seek(pos, d->m_rate);
376}
377
379{
380 gint64 pos;
381 QGstPipelinePrivate *d = getPrivate();
382 if (gst_element_query_position(element(), GST_FORMAT_TIME, &pos))
383 d->m_position = pos;
384 return d->m_position;
385}
386
388{
389 gint64 d;
390 if (!gst_element_query_duration(element(), GST_FORMAT_TIME, &d))
391 return 0.;
392 return d;
393}
394
395QGstPipelinePrivate *QGstPipeline::getPrivate() const
396{
397 gpointer p = g_object_get_data(qGstCheckedCast<GObject>(object()), "pipeline-private");
398 auto *d = reinterpret_cast<QGstPipelinePrivate *>(p);
399 Q_ASSERT(d);
400 return d;
401}
402
static QAbstractEventDispatcher * eventDispatcher()
Returns a pointer to the event dispatcher object for the main thread.
GstBin * bin() const
Definition qgst.cpp:1113
GstElement * element() const
Definition qgst.cpp:1018
bool finishStateChange(std::chrono::nanoseconds timeout=std::chrono::seconds(5))
Definition qgst.cpp:975
bool setStateSync(GstState state, std::chrono::nanoseconds timeout=std::chrono::seconds(1))
Definition qgst.cpp:947
void installMessageFilter(QGstreamerSyncMessageFilter *filter)
void processMessage(const QGstreamerMessage &msg)
QList< QGstreamerBusMessageFilter * > busFilters
QGstPipelinePrivate(GstBus *bus, QObject *parent=nullptr)
void removeMessageFilter(QGstreamerSyncMessageFilter *filter)
QList< QGstreamerSyncMessageFilter * > syncFilters
GstStateChangeReturn setState(GstState state)
GstPipeline * pipeline() const
bool inStoppedState() const
void installMessageFilter(QGstreamerSyncMessageFilter *filter)
void dumpGraph(const char *fileName)
void removeMessageFilter(QGstreamerSyncMessageFilter *filter)
qint64 duration() const
constexpr QGstPipeline()=default
qint64 position() const
double playbackRate() const
bool seek(qint64 pos, double rate)
void processMessages(GstMessageType=GST_MESSAGE_ANY)
void setInStoppedState(bool stopped)
void setFlushOnConfigChanges(bool flush)
bool setPosition(qint64 pos)
bool setPlaybackRate(double rate, bool applyToPipeline=true)
static QGstPipeline create(const char *name)
static QGstPipeline adopt(GstPipeline *)
qsizetype removeAll(const AT &t)
Definition qlist.h:592
void append(parameter_type t)
Definition qlist.h:458
\inmodule QtCore
Definition qmutex.h:313
\inmodule QtCore
Definition qmutex.h:281
\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
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:348
\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:241
void setInterval(int msec)
Definition qtimer.cpp:579
void timeout(QPrivateSignal)
This signal is emitted when the timer times out.
else opt state
[0]
Combined button and popup list for selecting options.
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage return DBusPendingCall * pending
DestinationType * qGstCheckedCast(SourceType *arg)
Definition qgst_p.h:164
#define qDebug
[1]
Definition qlogging.h:164
#define qWarning
Definition qlogging.h:166
static ControlElement< T > * ptr(QWidget *widget)
GLenum mode
GLsizei GLenum GLenum * types
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
GLuint GLsizei const GLchar * message
GLuint name
GLuint GLenum * rate
GLfloat GLfloat p
[1]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_UNUSED(x)
long long qint64
Definition qtypes.h:60
QReadWriteLock lock
[0]
bool contains(const AT &t) const noexcept
Definition qlist.h:45