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 | #ifndef QGST_P_H |
5 | #define QGST_P_H |
6 | |
7 | // |
8 | // W A R N I N G |
9 | // ------------- |
10 | // |
11 | // This file is not part of the Qt API. It exists purely as an |
12 | // implementation detail. This header file may change from version to |
13 | // version without notice, or even be removed. |
14 | // |
15 | // We mean it. |
16 | // |
17 | |
18 | #include <private/qtmultimediaglobal_p.h> |
19 | |
20 | #include <QSemaphore> |
21 | #include <QtCore/qlist.h> |
22 | |
23 | #include <QtMultimedia/qaudioformat.h> |
24 | #include <QtMultimedia/qvideoframe.h> |
25 | |
26 | #include <gst/gst.h> |
27 | #include <gst/video/video-info.h> |
28 | |
29 | #include <functional> |
30 | |
31 | #if QT_CONFIG(gstreamer_photography) |
32 | #define GST_USE_UNSTABLE_API |
33 | #include <gst/interfaces/photography.h> |
34 | #undef GST_USE_UNSTABLE_API |
35 | #endif |
36 | #ifndef QT_NO_DEBUG |
37 | #include <qdebug.h> |
38 | #endif |
39 | |
40 | QT_BEGIN_NAMESPACE |
41 | |
42 | class QSize; |
43 | class QGstStructure; |
44 | class QGstCaps; |
45 | class QGstPipelinePrivate; |
46 | class QCameraFormat; |
47 | |
48 | template <typename T> struct QGRange |
49 | { |
50 | T min; |
51 | T max; |
52 | }; |
53 | |
54 | class QGString |
55 | { |
56 | char *str; |
57 | public: |
58 | QGString(char *string) : str(string) {} |
59 | ~QGString() { g_free(mem: str); } |
60 | operator QByteArray() { return QByteArray(str); } |
61 | operator const char *() { return str; } |
62 | }; |
63 | |
64 | class QGValue |
65 | { |
66 | public: |
67 | QGValue(const GValue *v) : value(v) {} |
68 | const GValue *value; |
69 | |
70 | bool isNull() const { return !value; } |
71 | |
72 | std::optional<bool> toBool() const |
73 | { |
74 | if (!G_VALUE_HOLDS_BOOLEAN(value)) |
75 | return std::nullopt; |
76 | return g_value_get_boolean(value); |
77 | } |
78 | std::optional<int> toInt() const |
79 | { |
80 | if (!G_VALUE_HOLDS_INT(value)) |
81 | return std::nullopt; |
82 | return g_value_get_int(value); |
83 | } |
84 | std::optional<int> toInt64() const |
85 | { |
86 | if (!G_VALUE_HOLDS_INT64(value)) |
87 | return std::nullopt; |
88 | return g_value_get_int64(value); |
89 | } |
90 | template<typename T> |
91 | T *getPointer() const |
92 | { |
93 | return value ? static_cast<T *>(g_value_get_pointer(value)) : nullptr; |
94 | } |
95 | |
96 | const char *toString() const |
97 | { |
98 | return value ? g_value_get_string(value) : nullptr; |
99 | } |
100 | std::optional<float> getFraction() const |
101 | { |
102 | if (!GST_VALUE_HOLDS_FRACTION(value)) |
103 | return std::nullopt; |
104 | return (float)gst_value_get_fraction_numerator(value)/(float)gst_value_get_fraction_denominator(value); |
105 | } |
106 | |
107 | std::optional<QGRange<float>> getFractionRange() const |
108 | { |
109 | if (!GST_VALUE_HOLDS_FRACTION_RANGE(value)) |
110 | return std::nullopt; |
111 | QGValue min = gst_value_get_fraction_range_min(value); |
112 | QGValue max = gst_value_get_fraction_range_max(value); |
113 | return QGRange<float>{ .min: *min.getFraction(), .max: *max.getFraction() }; |
114 | } |
115 | |
116 | std::optional<QGRange<int>> toIntRange() const |
117 | { |
118 | if (!GST_VALUE_HOLDS_INT_RANGE(value)) |
119 | return std::nullopt; |
120 | return QGRange<int>{ .min: gst_value_get_int_range_min(value), .max: gst_value_get_int_range_max(value) }; |
121 | } |
122 | |
123 | inline QGstStructure toStructure() const; |
124 | inline QGstCaps toCaps() const; |
125 | |
126 | inline bool isList() const { return value && GST_VALUE_HOLDS_LIST(value); } |
127 | inline int listSize() const { return gst_value_list_get_size(value); } |
128 | inline QGValue at(int index) const { return gst_value_list_get_value(value, index); } |
129 | |
130 | Q_MULTIMEDIA_EXPORT QList<QAudioFormat::SampleFormat> getSampleFormats() const; |
131 | }; |
132 | |
133 | class QGstStructure { |
134 | public: |
135 | const GstStructure *structure = nullptr; |
136 | QGstStructure() = default; |
137 | QGstStructure(const GstStructure *s) : structure(s) {} |
138 | void free() { if (structure) gst_structure_free(structure: const_cast<GstStructure *>(structure)); structure = nullptr; } |
139 | |
140 | bool isNull() const { return !structure; } |
141 | |
142 | QByteArrayView name() const { return gst_structure_get_name(structure); } |
143 | |
144 | QGValue operator[](const char *name) const { return gst_structure_get_value(structure, fieldname: name); } |
145 | |
146 | Q_MULTIMEDIA_EXPORT QSize resolution() const; |
147 | Q_MULTIMEDIA_EXPORT QVideoFrameFormat::PixelFormat pixelFormat() const; |
148 | Q_MULTIMEDIA_EXPORT QGRange<float> frameRateRange() const; |
149 | |
150 | QByteArray toString() const |
151 | { |
152 | char *s = gst_structure_to_string(structure); |
153 | QByteArray str(s); |
154 | g_free(mem: s); |
155 | return str; |
156 | } |
157 | QGstStructure copy() const { return gst_structure_copy(structure); } |
158 | }; |
159 | |
160 | class QGstCaps { |
161 | GstCaps *caps = nullptr; |
162 | public: |
163 | enum RefMode { HasRef, NeedsRef }; |
164 | enum MemoryFormat { CpuMemory, GLTexture, DMABuf }; |
165 | |
166 | QGstCaps() = default; |
167 | |
168 | explicit QGstCaps(GstCaps *c, RefMode mode) : caps(c) |
169 | { |
170 | if (mode == NeedsRef) |
171 | gst_caps_ref(caps); |
172 | } |
173 | |
174 | QGstCaps(const QGstCaps &other) : caps(other.caps) |
175 | { |
176 | if (caps) |
177 | gst_caps_ref(caps); |
178 | } |
179 | |
180 | ~QGstCaps() { |
181 | if (caps) |
182 | gst_caps_unref(caps); |
183 | } |
184 | |
185 | QGstCaps &operator=(const QGstCaps &other) |
186 | { |
187 | if (this != &other) { |
188 | if (other.caps) |
189 | gst_caps_ref(caps: other.caps); |
190 | if (caps) |
191 | gst_caps_unref(caps); |
192 | caps = other.caps; |
193 | } |
194 | return *this; |
195 | } |
196 | |
197 | bool isNull() const { return !caps; } |
198 | |
199 | QByteArray toString() const { return toString(caps); } |
200 | int size() const { return int(gst_caps_get_size(caps)); } |
201 | QGstStructure at(int index) const { return gst_caps_get_structure(caps, index); } |
202 | GstCaps *get() const { return caps; } |
203 | MemoryFormat memoryFormat() const { |
204 | auto *features = gst_caps_get_features(caps, index: 0); |
205 | if (gst_caps_features_contains(features, feature: "memory:GLMemory" )) |
206 | return GLTexture; |
207 | else if (gst_caps_features_contains(features, feature: "memory:DMABuf" )) |
208 | return DMABuf; |
209 | return CpuMemory; |
210 | } |
211 | QVideoFrameFormat formatForCaps(GstVideoInfo *info) const; |
212 | |
213 | void addPixelFormats(const QList<QVideoFrameFormat::PixelFormat> &formats, const char *modifier = nullptr); |
214 | |
215 | static QGstCaps create() { |
216 | return QGstCaps(gst_caps_new_empty(), HasRef); |
217 | } |
218 | |
219 | static QByteArray toString(const GstCaps *caps) |
220 | { |
221 | gchar *c = gst_caps_to_string(caps); |
222 | QByteArray b(c); |
223 | g_free(mem: c); |
224 | return b; |
225 | } |
226 | |
227 | static QGstCaps fromCameraFormat(const QCameraFormat &format); |
228 | }; |
229 | |
230 | class QGstObject |
231 | { |
232 | protected: |
233 | GstObject *m_object = nullptr; |
234 | public: |
235 | enum RefMode { HasRef, NeedsRef }; |
236 | |
237 | QGstObject() = default; |
238 | explicit QGstObject(GstObject *o, RefMode mode = HasRef) |
239 | : m_object(o) |
240 | { |
241 | if (o && mode == NeedsRef) |
242 | // Use ref_sink to remove any floating references |
243 | gst_object_ref_sink(object: m_object); |
244 | } |
245 | QGstObject(const QGstObject &other) |
246 | : m_object(other.m_object) |
247 | { |
248 | if (m_object) |
249 | gst_object_ref(object: m_object); |
250 | } |
251 | QGstObject &operator=(const QGstObject &other) |
252 | { |
253 | if (this == &other) |
254 | return *this; |
255 | if (other.m_object) |
256 | gst_object_ref(object: other.m_object); |
257 | if (m_object) |
258 | gst_object_unref(object: m_object); |
259 | m_object = other.m_object; |
260 | return *this; |
261 | } |
262 | |
263 | QGstObject(QGstObject &&other) noexcept |
264 | : m_object(std::exchange(obj&: other.m_object, new_val: nullptr)) |
265 | {} |
266 | QGstObject &operator=(QGstObject &&other) |
267 | { |
268 | if (this != &other) { |
269 | if (m_object) |
270 | gst_object_unref(object: m_object); |
271 | m_object = std::exchange(obj&: other.m_object, new_val: nullptr); |
272 | } |
273 | return *this; |
274 | } |
275 | |
276 | virtual ~QGstObject() { |
277 | if (m_object) |
278 | gst_object_unref(object: m_object); |
279 | } |
280 | |
281 | explicit operator bool() const { return bool(m_object); } |
282 | |
283 | friend bool operator==(const QGstObject &a, const QGstObject &b) |
284 | { return a.m_object == b.m_object; } |
285 | friend bool operator!=(const QGstObject &a, const QGstObject &b) |
286 | { return a.m_object != b.m_object; } |
287 | |
288 | bool isNull() const { return !m_object; } |
289 | |
290 | void set(const char *property, const char *str) { g_object_set(object: m_object, first_property_name: property, str, nullptr); } |
291 | void set(const char *property, bool b) { g_object_set(object: m_object, first_property_name: property, gboolean(b), nullptr); } |
292 | void set(const char *property, uint i) { g_object_set(object: m_object, first_property_name: property, guint(i), nullptr); } |
293 | void set(const char *property, int i) { g_object_set(object: m_object, first_property_name: property, gint(i), nullptr); } |
294 | void set(const char *property, qint64 i) { g_object_set(object: m_object, first_property_name: property, gint64(i), nullptr); } |
295 | void set(const char *property, quint64 i) { g_object_set(object: m_object, first_property_name: property, guint64(i), nullptr); } |
296 | void set(const char *property, double d) { g_object_set(object: m_object, first_property_name: property, gdouble(d), nullptr); } |
297 | void set(const char *property, const QGstObject &o) { g_object_set(object: m_object, first_property_name: property, o.object(), nullptr); } |
298 | void set(const char *property, const QGstCaps &c) { g_object_set(object: m_object, first_property_name: property, c.get(), nullptr); } |
299 | |
300 | QGString getString(const char *property) const |
301 | { char *s = nullptr; g_object_get(object: m_object, first_property_name: property, &s, nullptr); return s; } |
302 | QGstStructure getStructure(const char *property) const |
303 | { GstStructure *s = nullptr; g_object_get(object: m_object, first_property_name: property, &s, nullptr); return QGstStructure(s); } |
304 | bool getBool(const char *property) const { gboolean b = false; g_object_get(object: m_object, first_property_name: property, &b, nullptr); return b; } |
305 | uint getUInt(const char *property) const { guint i = 0; g_object_get(object: m_object, first_property_name: property, &i, nullptr); return i; } |
306 | int getInt(const char *property) const { gint i = 0; g_object_get(object: m_object, first_property_name: property, &i, nullptr); return i; } |
307 | quint64 getUInt64(const char *property) const { guint64 i = 0; g_object_get(object: m_object, first_property_name: property, &i, nullptr); return i; } |
308 | qint64 getInt64(const char *property) const { gint64 i = 0; g_object_get(object: m_object, first_property_name: property, &i, nullptr); return i; } |
309 | float getFloat(const char *property) const { gfloat d = 0; g_object_get(object: m_object, first_property_name: property, &d, nullptr); return d; } |
310 | double getDouble(const char *property) const { gdouble d = 0; g_object_get(object: m_object, first_property_name: property, &d, nullptr); return d; } |
311 | QGstObject getObject(const char *property) const { GstObject *o = nullptr; g_object_get(object: m_object, first_property_name: property, &o, nullptr); return QGstObject(o, HasRef); } |
312 | |
313 | void connect(const char *name, GCallback callback, gpointer userData) { g_signal_connect(m_object, name, callback, userData); } |
314 | |
315 | GstObject *object() const { return m_object; } |
316 | const char *name() const { return m_object ? GST_OBJECT_NAME(m_object) : "(null)" ; } |
317 | }; |
318 | |
319 | class QGstElement; |
320 | |
321 | class QGstPad : public QGstObject |
322 | { |
323 | public: |
324 | QGstPad() = default; |
325 | QGstPad(const QGstObject &o) |
326 | : QGstPad(GST_PAD(o.object()), NeedsRef) |
327 | {} |
328 | QGstPad(GstPad *pad, RefMode mode = NeedsRef) |
329 | : QGstObject(&pad->object, mode) |
330 | {} |
331 | |
332 | QGstCaps currentCaps() const |
333 | { return QGstCaps(gst_pad_get_current_caps(pad: pad()), QGstCaps::HasRef); } |
334 | QGstCaps queryCaps() const |
335 | { return QGstCaps(gst_pad_query_caps(pad: pad(), filter: nullptr), QGstCaps::HasRef); } |
336 | |
337 | bool isLinked() const { return gst_pad_is_linked(pad: pad()); } |
338 | bool link(const QGstPad &sink) const { return gst_pad_link(srcpad: pad(), sinkpad: sink.pad()) == GST_PAD_LINK_OK; } |
339 | bool unlink(const QGstPad &sink) const { return gst_pad_unlink(srcpad: pad(), sinkpad: sink.pad()); } |
340 | bool unlinkPeer() const { return unlink(sink: peer()); } |
341 | QGstPad peer() const { return QGstPad(gst_pad_get_peer(pad: pad()), HasRef); } |
342 | inline QGstElement parent() const; |
343 | |
344 | GstPad *pad() const { return GST_PAD_CAST(object()); } |
345 | |
346 | GstEvent *stickyEvent(GstEventType type) { return gst_pad_get_sticky_event(pad: pad(), event_type: type, idx: 0); } |
347 | bool sendEvent(GstEvent *event) { return gst_pad_send_event (pad: pad(), event); } |
348 | |
349 | template<auto Member, typename T> |
350 | void addProbe(T *instance, GstPadProbeType type) { |
351 | struct Impl { |
352 | static GstPadProbeReturn callback(GstPad *pad, GstPadProbeInfo *info, gpointer userData) { |
353 | return (static_cast<T *>(userData)->*Member)(QGstPad(pad, NeedsRef), info); |
354 | }; |
355 | }; |
356 | |
357 | gst_pad_add_probe (pad(), type, Impl::callback, instance, nullptr); |
358 | } |
359 | |
360 | void doInIdleProbe(std::function<void()> work) { |
361 | struct CallbackData { |
362 | QSemaphore waitDone; |
363 | std::function<void()> work; |
364 | } cd; |
365 | cd.work = work; |
366 | |
367 | auto callback= [](GstPad *, GstPadProbeInfo *, gpointer p) { |
368 | auto cd = reinterpret_cast<CallbackData*>(p); |
369 | cd->work(); |
370 | cd->waitDone.release(); |
371 | return GST_PAD_PROBE_REMOVE; |
372 | }; |
373 | |
374 | gst_pad_add_probe(pad: pad(), mask: GST_PAD_PROBE_TYPE_IDLE, callback, user_data: &cd, destroy_data: nullptr); |
375 | cd.waitDone.acquire(); |
376 | } |
377 | |
378 | template<auto Member, typename T> |
379 | void addEosProbe(T *instance) { |
380 | struct Impl { |
381 | static GstPadProbeReturn callback(GstPad */*pad*/, GstPadProbeInfo *info, gpointer userData) { |
382 | if (GST_EVENT_TYPE(GST_PAD_PROBE_INFO_DATA(info)) != GST_EVENT_EOS) |
383 | return GST_PAD_PROBE_PASS; |
384 | (static_cast<T *>(userData)->*Member)(); |
385 | return GST_PAD_PROBE_REMOVE; |
386 | }; |
387 | }; |
388 | |
389 | gst_pad_add_probe (pad(), GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, Impl::callback, instance, nullptr); |
390 | } |
391 | }; |
392 | |
393 | class QGstClock : public QGstObject |
394 | { |
395 | public: |
396 | QGstClock() = default; |
397 | QGstClock(const QGstObject &o) |
398 | : QGstClock(GST_CLOCK(o.object())) |
399 | {} |
400 | QGstClock(GstClock *clock, RefMode mode = NeedsRef) |
401 | : QGstObject(&clock->object, mode) |
402 | {} |
403 | |
404 | GstClock *clock() const { return GST_CLOCK_CAST(object()); } |
405 | |
406 | GstClockTime time() const { return gst_clock_get_time(clock: clock()); } |
407 | }; |
408 | |
409 | class QGstElement : public QGstObject |
410 | { |
411 | public: |
412 | QGstElement() = default; |
413 | QGstElement(const QGstObject &o) |
414 | : QGstElement(GST_ELEMENT(o.object()), NeedsRef) |
415 | {} |
416 | QGstElement(GstElement *element, RefMode mode = NeedsRef) |
417 | : QGstObject(&element->object, mode) |
418 | {} |
419 | |
420 | QGstElement(const char *factory, const char *name = nullptr) |
421 | : QGstElement(gst_element_factory_make(factoryname: factory, name), NeedsRef) |
422 | { |
423 | #ifndef QT_NO_DEBUG |
424 | if (!m_object) |
425 | qWarning() << "Failed to make element" << name << "from factory" << factory; |
426 | #endif |
427 | } |
428 | |
429 | bool link(const QGstElement &next) |
430 | { return gst_element_link(src: element(), dest: next.element()); } |
431 | bool link(const QGstElement &n1, const QGstElement &n2) |
432 | { return gst_element_link_many(element_1: element(), element_2: n1.element(), n2.element(), nullptr); } |
433 | bool link(const QGstElement &n1, const QGstElement &n2, const QGstElement &n3) |
434 | { return gst_element_link_many(element_1: element(), element_2: n1.element(), n2.element(), n3.element(), nullptr); } |
435 | bool link(const QGstElement &n1, const QGstElement &n2, const QGstElement &n3, const QGstElement &n4) |
436 | { return gst_element_link_many(element_1: element(), element_2: n1.element(), n2.element(), n3.element(), n4.element(), nullptr); } |
437 | bool link(const QGstElement &n1, const QGstElement &n2, const QGstElement &n3, const QGstElement &n4, const QGstElement &n5) |
438 | { return gst_element_link_many(element_1: element(), element_2: n1.element(), n2.element(), n3.element(), n4.element(), n5.element(), nullptr); } |
439 | |
440 | void unlink(const QGstElement &next) |
441 | { gst_element_unlink(src: element(), dest: next.element()); } |
442 | |
443 | QGstPad staticPad(const char *name) const { return QGstPad(gst_element_get_static_pad(element: element(), name), HasRef); } |
444 | QGstPad src() const { return staticPad(name: "src" ); } |
445 | QGstPad sink() const { return staticPad(name: "sink" ); } |
446 | QGstPad getRequestPad(const char *name) const |
447 | { |
448 | #if GST_CHECK_VERSION(1,19,1) |
449 | return QGstPad(gst_element_request_pad_simple(element: element(), name), HasRef); |
450 | #else |
451 | return QGstPad(gst_element_get_request_pad(element(), name), HasRef); |
452 | #endif |
453 | } |
454 | void releaseRequestPad(const QGstPad &pad) const { return gst_element_release_request_pad(element: element(), pad: pad.pad()); } |
455 | |
456 | GstState state() const |
457 | { |
458 | GstState state; |
459 | gst_element_get_state(element: element(), state: &state, pending: nullptr, timeout: 0); |
460 | return state; |
461 | } |
462 | GstStateChangeReturn setState(GstState state) { return gst_element_set_state(element: element(), state); } |
463 | bool setStateSync(GstState state) |
464 | { |
465 | auto change = gst_element_set_state(element: element(), state); |
466 | if (change == GST_STATE_CHANGE_ASYNC) { |
467 | change = gst_element_get_state(element: element(), state: nullptr, pending: &state, timeout: 1000*1e6 /*nano seconds*/); |
468 | } |
469 | #ifndef QT_NO_DEBUG |
470 | if (change != GST_STATE_CHANGE_SUCCESS && change != GST_STATE_CHANGE_NO_PREROLL) |
471 | qWarning() << "Could not change state of" << name() << "to" << state << change; |
472 | #endif |
473 | return change == GST_STATE_CHANGE_SUCCESS; |
474 | } |
475 | bool syncStateWithParent() { return gst_element_sync_state_with_parent(element: element()) == TRUE; } |
476 | bool finishStateChange() |
477 | { |
478 | auto change = gst_element_get_state(element: element(), state: nullptr, pending: nullptr, timeout: 1000*1e6 /*nano seconds*/); |
479 | #ifndef QT_NO_DEBUG |
480 | if (change != GST_STATE_CHANGE_SUCCESS && change != GST_STATE_CHANGE_NO_PREROLL) |
481 | qWarning() << "Could finish change state of" << name(); |
482 | #endif |
483 | return change == GST_STATE_CHANGE_SUCCESS; |
484 | } |
485 | |
486 | void lockState(bool locked) { gst_element_set_locked_state(element: element(), locked_state: locked); } |
487 | bool isStateLocked() const { return gst_element_is_locked_state(element: element()); } |
488 | |
489 | void sendEvent(GstEvent *event) const { gst_element_send_event(element: element(), event); } |
490 | void sendEos() const { sendEvent(event: gst_event_new_eos()); } |
491 | |
492 | template<auto Member, typename T> |
493 | void onPadAdded(T *instance) { |
494 | struct Impl { |
495 | static void callback(GstElement *e, GstPad *pad, gpointer userData) { |
496 | (static_cast<T *>(userData)->*Member)(QGstElement(e), QGstPad(pad, NeedsRef)); |
497 | }; |
498 | }; |
499 | |
500 | connect(name: "pad-added" , G_CALLBACK(Impl::callback), userData: instance); |
501 | } |
502 | template<auto Member, typename T> |
503 | void onPadRemoved(T *instance) { |
504 | struct Impl { |
505 | static void callback(GstElement *e, GstPad *pad, gpointer userData) { |
506 | (static_cast<T *>(userData)->*Member)(QGstElement(e), QGstPad(pad, NeedsRef)); |
507 | }; |
508 | }; |
509 | |
510 | connect(name: "pad-removed" , G_CALLBACK(Impl::callback), userData: instance); |
511 | } |
512 | template<auto Member, typename T> |
513 | void onNoMorePads(T *instance) { |
514 | struct Impl { |
515 | static void callback(GstElement *e, gpointer userData) { |
516 | (static_cast<T *>(userData)->*Member)(QGstElement(e)); |
517 | }; |
518 | }; |
519 | |
520 | connect(name: "no-more-pads" , G_CALLBACK(Impl::callback), userData: instance); |
521 | } |
522 | |
523 | GstClockTime baseTime() const { return gst_element_get_base_time(element: element()); } |
524 | void setBaseTime(GstClockTime time) const { gst_element_set_base_time(element: element(), time); } |
525 | |
526 | GstElement *element() const { return GST_ELEMENT_CAST(m_object); } |
527 | }; |
528 | |
529 | inline QGstElement QGstPad::parent() const |
530 | { |
531 | return QGstElement(gst_pad_get_parent_element(pad: pad()), HasRef); |
532 | } |
533 | |
534 | class QGstBin : public QGstElement |
535 | { |
536 | public: |
537 | QGstBin() = default; |
538 | QGstBin(const QGstObject &o) |
539 | : QGstBin(GST_BIN(o.object()), NeedsRef) |
540 | {} |
541 | QGstBin(const char *name) |
542 | : QGstElement(gst_bin_new(name), NeedsRef) |
543 | { |
544 | } |
545 | QGstBin(GstBin *bin, RefMode mode = NeedsRef) |
546 | : QGstElement(&bin->element, mode) |
547 | {} |
548 | |
549 | void add(const QGstElement &element) |
550 | { gst_bin_add(bin: bin(), element: element.element()); } |
551 | void add(const QGstElement &e1, const QGstElement &e2) |
552 | { gst_bin_add_many(bin: bin(), element_1: e1.element(), e2.element(), nullptr); } |
553 | void add(const QGstElement &e1, const QGstElement &e2, const QGstElement &e3) |
554 | { gst_bin_add_many(bin: bin(), element_1: e1.element(), e2.element(), e3.element(), nullptr); } |
555 | void add(const QGstElement &e1, const QGstElement &e2, const QGstElement &e3, const QGstElement &e4) |
556 | { gst_bin_add_many(bin: bin(), element_1: e1.element(), e2.element(), e3.element(), e4.element(), nullptr); } |
557 | void add(const QGstElement &e1, const QGstElement &e2, const QGstElement &e3, const QGstElement &e4, const QGstElement &e5) |
558 | { gst_bin_add_many(bin: bin(), element_1: e1.element(), e2.element(), e3.element(), e4.element(), e5.element(), nullptr); } |
559 | void add(const QGstElement &e1, const QGstElement &e2, const QGstElement &e3, const QGstElement &e4, const QGstElement &e5, const QGstElement &e6) |
560 | { gst_bin_add_many(bin: bin(), element_1: e1.element(), e2.element(), e3.element(), e4.element(), e5.element(), e6.element(), nullptr); } |
561 | void remove(const QGstElement &element) |
562 | { gst_bin_remove(bin: bin(), element: element.element()); } |
563 | |
564 | GstBin *bin() const { return GST_BIN_CAST(m_object); } |
565 | |
566 | void addGhostPad(const QGstElement &child, const char *name) |
567 | { |
568 | addGhostPad(name, pad: child.staticPad(name)); |
569 | } |
570 | void addGhostPad(const char *name, const QGstPad &pad) |
571 | { |
572 | gst_element_add_pad(element: element(), pad: gst_ghost_pad_new(name, target: pad.pad())); |
573 | } |
574 | }; |
575 | |
576 | inline QGstStructure QGValue::toStructure() const |
577 | { |
578 | if (!value || !GST_VALUE_HOLDS_STRUCTURE(value)) |
579 | return QGstStructure(); |
580 | return QGstStructure(gst_value_get_structure(value)); |
581 | } |
582 | |
583 | inline QGstCaps QGValue::toCaps() const |
584 | { |
585 | if (!value || !GST_VALUE_HOLDS_CAPS(value)) |
586 | return {}; |
587 | return QGstCaps(gst_caps_copy(gst_value_get_caps(value)), QGstCaps::HasRef); |
588 | } |
589 | |
590 | inline QString errorMessageCannotFindElement(std::string_view element) |
591 | { |
592 | return QStringLiteral("Could not find the %1 GStreamer element" ).arg(a: element.data()); |
593 | } |
594 | |
595 | QT_END_NAMESPACE |
596 | |
597 | #endif |
598 | |