QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
GstContextBridgeCommon.cc
Go to the documentation of this file.
2
3#if defined(QGC_HAS_ANY_GPU_PATH)
4
5#include <QtCore/QLoggingCategory>
6#include <QtCore/QMutexLocker>
7#include <glib.h>
8
10
11namespace GstContextBridge {
12
13const char* matchContextType(const BridgeVTable& vt, const char* type)
14{
15 if (!type) {
16 return nullptr;
17 }
18 for (int i = 0; i < vt.contextTypeCount; ++i) {
19 if (g_strcmp0(type, vt.contextTypes[i]) == 0) {
20 return vt.contextTypes[i];
21 }
22 }
23 return nullptr;
24}
25
26namespace {
27
28// Shared snapshot path for both NEED_CONTEXT and GST_QUERY_CONTEXT: prime + ref the object under the bridge mutex, then
29// build the GstContext with the lock released. The built context holds its own ref on the object, so our snapshot ref
30// is dropped here. Returns the context, or null when not primed / object unavailable / build failed.
31GstContext* snapshotContext(const BridgeVTable& vt, void* user, const char* matched)
32{
33 GstObject* object = nullptr;
34 {
35 QMutexLocker lock(&vt.mutex(user));
36 if (!vt.primeLocked(user)) {
37 return nullptr;
38 }
39 object = vt.refObject(user, matched);
40 }
41 if (!object) {
42 return nullptr;
43 }
44 GstContext* ctx = vt.buildContext(user, matched, object);
45 gst_object_unref(object);
46 return ctx;
47}
48
49} // namespace
50
51GstBusSyncReply handleSyncMessage(const BridgeVTable& vt, void* user, GstMessage* message)
52{
53 if (GST_MESSAGE_TYPE(message) != GST_MESSAGE_NEED_CONTEXT) {
54 return GST_BUS_PASS;
55 }
56 const gchar* contextType = nullptr;
57 if (!gst_message_parse_context_type(message, &contextType) || !contextType) {
58 return GST_BUS_PASS;
59 }
60 const char* matched = matchContextType(vt, contextType);
61 if (!matched) {
62 return GST_BUS_PASS;
63 }
64 GstElement* element = GST_ELEMENT(GST_MESSAGE_SRC(message));
65 if (!element) {
66 return GST_BUS_PASS;
67 }
68
69 GstContext* ctx = snapshotContext(vt, user, matched);
70 if (!ctx) {
71 return GST_BUS_PASS;
72 }
73 gst_element_set_context(element, ctx);
74 gst_context_unref(ctx);
75
76 if (vt.onHandoff) {
77 vt.onHandoff(user, element, matched);
78 } else {
79 qCDebug(vt.cat(user)) << "Provided" << vt.apiName << matched << "context to" << GST_ELEMENT_NAME(element);
80 }
81 // `element` is borrowed from the message (transfer-none); unref the message only after the
82 // last use of `element`, or the message could drop the final ref under us.
83 gst_message_unref(message);
84 return GST_BUS_DROP;
85}
86
87bool answerContextQuery(const BridgeVTable& vt, void* user, GstQuery* query)
88{
89 if (!query || GST_QUERY_TYPE(query) != GST_QUERY_CONTEXT) {
90 return false;
91 }
92 const gchar* contextType = nullptr;
93 if (!gst_query_parse_context_type(query, &contextType) || !contextType) {
94 return false;
95 }
96 const char* matched = matchContextType(vt, contextType);
97 if (!matched) {
98 return false;
99 }
100
101 GstContext* ctx = snapshotContext(vt, user, matched);
102 if (!ctx) {
103 return false;
104 }
105 gst_query_set_context(query, ctx);
106 gst_context_unref(ctx);
107 return true;
108}
109
110void registerBridge(const QLoggingCategory& cat, const char* apiName, GstBusSyncReply (*handler)(GstMessage*),
111 void (*reset)())
112{
113 // Register both unconditionally so resetAllBridges() always reaches the bridge's reset(); registry warns on
114 // overflow.
115 const auto h = GstContextBridgeRegistry::registerBridgeHandler(handler);
116 const auto r = GstContextBridgeRegistry::registerResetCallback(reset);
117 if ((h == GstContextBridgeRegistry::kInvalidHandle) || (r == GstContextBridgeRegistry::kInvalidHandle)) {
118 qCWarning(cat) << apiName << "bridge registration incomplete (registry full); GPU path inactive";
119 }
120}
121
122} // namespace GstContextBridge
123
124#endif // QGC_HAS_ANY_GPU_PATH
struct _GstElement GstElement