1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include <QtCore/qmap.h>
41#include <QtCore/qtimer.h>
42#include <QtCore/qmutex.h>
43#include <QtCore/qlist.h>
44#include <QtCore/qabstracteventdispatcher.h>
45#include <QtCore/qcoreapplication.h>
46
47#include "qgstreamerbushelper_p.h"
48
49QT_BEGIN_NAMESPACE
50
51
52class QGstreamerBusHelperPrivate : public QObject
53{
54 Q_OBJECT
55public:
56 QGstreamerBusHelperPrivate(QGstreamerBusHelper *parent, GstBus* bus) :
57 QObject(parent),
58 m_tag(0),
59 m_bus(bus),
60 m_helper(parent),
61 m_intervalTimer(nullptr)
62 {
63 // glib event loop can be disabled either by env variable or QT_NO_GLIB define, so check the dispacher
64 QAbstractEventDispatcher *dispatcher = QCoreApplication::eventDispatcher();
65 const bool hasGlib = dispatcher && dispatcher->inherits(classname: "QEventDispatcherGlib");
66 if (!hasGlib) {
67 m_intervalTimer = new QTimer(this);
68 m_intervalTimer->setInterval(250);
69 connect(asender: m_intervalTimer, SIGNAL(timeout()), SLOT(interval()));
70 m_intervalTimer->start();
71 } else {
72 m_tag = gst_bus_add_watch_full(bus, G_PRIORITY_DEFAULT, func: busCallback, user_data: this, notify: nullptr);
73 }
74 }
75
76 ~QGstreamerBusHelperPrivate()
77 {
78 m_helper = 0;
79 delete m_intervalTimer;
80
81 if (m_tag)
82#if GST_CHECK_VERSION(1, 6, 0)
83 gst_bus_remove_watch(bus: m_bus);
84#else
85 g_source_remove(m_tag);
86#endif
87 }
88
89 GstBus* bus() const { return m_bus; }
90
91private slots:
92 void interval()
93 {
94 GstMessage* message;
95 while ((message = gst_bus_poll(bus: m_bus, events: GST_MESSAGE_ANY, timeout: 0)) != 0) {
96 processMessage(message);
97 gst_message_unref(msg: message);
98 }
99 }
100
101private:
102 void processMessage(GstMessage* message)
103 {
104 QGstreamerMessage msg(message);
105 doProcessMessage(msg);
106 }
107
108 void queueMessage(GstMessage* message)
109 {
110 QGstreamerMessage msg(message);
111 QMetaObject::invokeMethod(obj: this, member: "doProcessMessage", type: Qt::QueuedConnection,
112 Q_ARG(QGstreamerMessage, msg));
113 }
114
115 static gboolean busCallback(GstBus *bus, GstMessage *message, gpointer data)
116 {
117 Q_UNUSED(bus);
118 reinterpret_cast<QGstreamerBusHelperPrivate*>(data)->queueMessage(message);
119 return TRUE;
120 }
121
122 guint m_tag;
123 GstBus* m_bus;
124 QGstreamerBusHelper* m_helper;
125 QTimer* m_intervalTimer;
126
127private slots:
128 void doProcessMessage(const QGstreamerMessage& msg)
129 {
130 for (QGstreamerBusMessageFilter *filter : qAsConst(t&: busFilters)) {
131 if (filter->processBusMessage(message: msg))
132 break;
133 }
134 emit m_helper->message(message: msg);
135 }
136
137public:
138 QMutex filterMutex;
139 QList<QGstreamerSyncMessageFilter*> syncFilters;
140 QList<QGstreamerBusMessageFilter*> busFilters;
141};
142
143
144static GstBusSyncReply syncGstBusFilter(GstBus* bus, GstMessage* message, QGstreamerBusHelperPrivate *d)
145{
146 Q_UNUSED(bus);
147 QMutexLocker lock(&d->filterMutex);
148
149 for (QGstreamerSyncMessageFilter *filter : qAsConst(t&: d->syncFilters)) {
150 if (filter->processSyncMessage(message: QGstreamerMessage(message))) {
151 gst_message_unref(msg: message);
152 return GST_BUS_DROP;
153 }
154 }
155
156 return GST_BUS_PASS;
157}
158
159
160/*!
161 \class QGstreamerBusHelper
162 \internal
163*/
164
165QGstreamerBusHelper::QGstreamerBusHelper(GstBus* bus, QObject* parent):
166 QObject(parent)
167{
168 d = new QGstreamerBusHelperPrivate(this, bus);
169#if GST_CHECK_VERSION(1,0,0)
170 gst_bus_set_sync_handler(bus, func: (GstBusSyncHandler)syncGstBusFilter, user_data: d, notify: 0);
171#else
172 gst_bus_set_sync_handler(bus, (GstBusSyncHandler)syncGstBusFilter, d);
173#endif
174 gst_object_ref(GST_OBJECT(bus));
175}
176
177QGstreamerBusHelper::~QGstreamerBusHelper()
178{
179#if GST_CHECK_VERSION(1,0,0)
180 gst_bus_set_sync_handler(bus: d->bus(), func: 0, user_data: 0, notify: 0);
181#else
182 gst_bus_set_sync_handler(d->bus(),0,0);
183#endif
184 gst_object_unref(GST_OBJECT(d->bus()));
185}
186
187void QGstreamerBusHelper::installMessageFilter(QObject *filter)
188{
189 auto syncFilter = qobject_cast<QGstreamerSyncMessageFilter*>(object: filter);
190 if (syncFilter) {
191 QMutexLocker lock(&d->filterMutex);
192 if (!d->syncFilters.contains(t: syncFilter))
193 d->syncFilters.append(t: syncFilter);
194 }
195
196 auto busFilter = qobject_cast<QGstreamerBusMessageFilter*>(object: filter);
197 if (busFilter && !d->busFilters.contains(t: busFilter))
198 d->busFilters.append(t: busFilter);
199}
200
201void QGstreamerBusHelper::removeMessageFilter(QObject *filter)
202{
203 auto syncFilter = qobject_cast<QGstreamerSyncMessageFilter*>(object: filter);
204 if (syncFilter) {
205 QMutexLocker lock(&d->filterMutex);
206 d->syncFilters.removeAll(t: syncFilter);
207 }
208
209 auto busFilter = qobject_cast<QGstreamerBusMessageFilter*>(object: filter);
210 if (busFilter)
211 d->busFilters.removeAll(t: busFilter);
212}
213
214QT_END_NAMESPACE
215
216#include "qgstreamerbushelper.moc"
217

source code of qtmultimedia/src/gsttools/qgstreamerbushelper.cpp