QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
gstqgcvideosinkbin.cc
Go to the documentation of this file.
2#include "gstqgcelements.h"
3
4#include <gst/gl/gl.h>
5
6#define GST_CAT_DEFAULT gst_qgc_video_sink_bin_debug
8
9#define DEFAULT_ENABLE_LAST_SAMPLE FALSE
10#define DEFAULT_FORCE_ASPECT_RATIO TRUE
11#define DEFAULT_PAR_N 0
12#define DEFAULT_PAR_D 1
13#define DEFAULT_SYNC TRUE
14
15#define PROP_ENABLE_LAST_SAMPLE_NAME "enable-last-sample"
16#define PROP_LAST_SAMPLE_NAME "last-sample"
17#define PROP_WIDGET_NAME "widget"
18#define PROP_FORCE_ASPECT_RATIO_NAME "force-aspect-ratio"
19#define PROP_PIXEL_ASPECT_RATIO_NAME "pixel-aspect-ratio"
20#define PROP_SYNC_NAME "sync"
21
22enum
23{
32};
33
34static GParamSpec *properties[PROP_LAST];
35
36enum
37{
41};
42
44
45#define gst_qgc_video_sink_bin_parent_class parent_class
47 GstQgcVideoSinkBin,
48 gst_qgc_video_sink_bin,
49 GST_TYPE_BIN,
50 GST_DEBUG_CATEGORY_INIT(
52 "qgcsinkbin",
53 0,
54 "QGC Video Sink Bin"));
55
56GST_ELEMENT_REGISTER_DEFINE_WITH_CODE(qgcvideosinkbin,"qgcvideosinkbin",
57 GST_RANK_NONE,
59 qgc_element_init(plugin));
60
61static void gst_qgc_video_sink_bin_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
62static void gst_qgc_video_sink_bin_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
64static void gst_qgc_video_sink_bin_dispose(GObject *object);
65static void gst_qgc_video_sink_bin_finalize(GObject *object);
66
67static void
68gst_qgc_video_sink_bin_class_init(GstQgcVideoSinkBinClass *klass)
69{
70 GObjectClass *object_class = G_OBJECT_CLASS(klass);
71 GstElementClass *element_class = GST_ELEMENT_CLASS(klass);
72
73 object_class->set_property = gst_qgc_video_sink_bin_set_property;
74 object_class->get_property = gst_qgc_video_sink_bin_get_property;
75 object_class->dispose = gst_qgc_video_sink_bin_dispose;
76 object_class->finalize = gst_qgc_video_sink_bin_finalize;
77
78 properties[PROP_ENABLE_LAST_SAMPLE] = g_param_spec_boolean(
79 "enable-last-sample", "Enable last sample",
80 "Retain the most recent buffer for UI snapshotting",
82 (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
83 );
84
85 properties[PROP_LAST_SAMPLE] = g_param_spec_boxed(
86 "last-sample", "Last sample",
87 "Last preroll/played sample held by the sink",
88 GST_TYPE_SAMPLE,
89 (GParamFlags)(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)
90 );
91
92 properties[PROP_WIDGET] = g_param_spec_pointer(
93 "widget", "QQuickItem",
94 "Owning QML item – handed off to qml6glsink",
95 (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
96 );
97
98 properties[PROP_FORCE_ASPECT_RATIO] = g_param_spec_boolean(
99 "force-aspect-ratio", "Force aspect ratio",
100 "Maintain original pixel aspect during scaling",
102 (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
103 );
104
105 properties[PROP_PIXEL_ASPECT_RATIO] = gst_param_spec_fraction(
106 "pixel-aspect-ratio", "Pixel aspect ratio",
107 "Pixel aspect ratio of the display surface",
109 G_MAXINT, 1,
110 1, 1,
111 (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
112 );
113
114 properties[PROP_SYNC] = g_param_spec_boolean(
115 "sync", "Sync",
116 "Synchronise frame presentation to the pipeline clock",
118 (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
119 );
120
121 g_object_class_install_properties(object_class, PROP_LAST, properties);
122
124 "create-element", /* name */
125 G_TYPE_FROM_CLASS(klass), /* owner type */
126 G_SIGNAL_RUN_LAST, /* flags */
127 0, /* class offset for default handler */
128 NULL, NULL, /* accumulator / accu-data */
129 NULL, /* generic marshaller */
130 GST_TYPE_ELEMENT, /* return type */
131 0 /* param count */
132 );
133
134 gst_element_class_set_static_metadata(element_class,
135 "QGC Video Sink Bin", "Sink/Video/Bin",
136 "GL accelerated video sink wrapper used by QGroundControl",
137 "QGroundControl team"
138 );
139}
140
141static void
142gst_qgc_video_sink_bin_init(GstQgcVideoSinkBin *self)
143{
144 self->glsinkbin = gst_element_factory_make("glsinkbin", NULL);
145 if (!self->glsinkbin) {
146 GST_ERROR_OBJECT(self, "gst_element_factory_make('glsinkbin') failed");
147 return;
148 }
149
150 self->qmlglsink = gst_element_factory_make("qml6glsink", NULL);
151 if (!self->qmlglsink) {
152 GST_ERROR_OBJECT(self, "gst_element_factory_make('qml6glsink') failed");
153 return;
154 }
155
156 g_object_set(self->glsinkbin,
157 "sink", self->qmlglsink,
159 NULL);
160
161 g_return_if_fail(gst_bin_add(GST_BIN(self), self->glsinkbin));
162
163 g_signal_connect(self->glsinkbin,
164 "create-element",
166 self);
167
168 GstPad *sinkpad = gst_element_get_static_pad(self->glsinkbin, "sink");
169 if (!sinkpad) {
170 GST_ERROR_OBJECT(self, "gst_element_get_static_pad('sink') failed");
171 return;
172 }
173
174 GstPad *ghostpad = gst_ghost_pad_new("sink", sinkpad);
175 if (!ghostpad) {
176 GST_ERROR_OBJECT(self, "gst_ghost_pad_new('sink') failed");
177 gst_object_unref(sinkpad);
178 return;
179 }
180
181 if (!gst_element_add_pad(GST_ELEMENT(self), ghostpad)) {
182 GST_ERROR_OBJECT(self, "gst_element_add_pad() failed");
183 }
184
185 if (sinkpad) {
186 gst_object_unref(sinkpad);
187 }
188}
189
190static void
191gst_qgc_video_sink_bin_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
192{
193 GstQgcVideoSinkBin *self = GST_QGC_VIDEO_SINK_BIN(object);
194
195 switch (prop_id) {
197 g_object_set(self->glsinkbin,
199 g_value_get_boolean(value),
200 NULL);
201 break;
202 case PROP_WIDGET:
203 g_object_set(self->qmlglsink,
205 g_value_get_pointer(value),
206 NULL);
207 break;
209 g_object_set(self->glsinkbin,
211 g_value_get_boolean(value),
212 NULL);
213 break;
215 const gint num = gst_value_get_fraction_numerator(value);
216 const gint den = gst_value_get_fraction_denominator(value);
217 g_object_set(self->qmlglsink,
219 num,
220 den,
221 NULL);
222 break;
223 }
224 case PROP_SYNC:
225 g_object_set(self->glsinkbin,
227 g_value_get_boolean(value),
228 NULL);
229 break;
230 default:
231 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
232 break;
233 }
234}
235
236static void
237gst_qgc_video_sink_bin_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
238{
239 GstQgcVideoSinkBin *self = GST_QGC_VIDEO_SINK_BIN(object);
240
241 switch (prop_id) {
243 gboolean enable = FALSE;
244 g_object_get(self->glsinkbin,
246 &enable,
247 NULL);
248 g_value_set_boolean(value, enable);
249 break;
250 }
251 case PROP_LAST_SAMPLE: {
252 GstSample *sample = NULL;
253 g_object_get(self->glsinkbin,
255 &sample,
256 NULL);
257 gst_value_set_sample(value, sample);
258 if (sample) {
259 gst_sample_unref(sample);
260 }
261 break;
262 }
263 case PROP_WIDGET: {
264 gpointer widget = NULL;
265 g_object_get(self->qmlglsink,
267 &widget,
268 NULL);
269 g_value_set_pointer(value, widget);
270 break;
271 }
273 gboolean enable = FALSE;
274 g_object_get(self->glsinkbin,
276 &enable,
277 NULL);
278 g_value_set_boolean(value, enable);
279 break;
280 }
282 gint num = 0, den = 1;
283 g_object_get(self->qmlglsink,
285 &num, &den,
286 NULL);
287 gst_value_set_fraction(value, num, den);
288 break;
289 }
290 case PROP_SYNC: {
291 gboolean enable = FALSE;
292 g_object_get(self->glsinkbin,
294 &enable,
295 NULL);
296 g_value_set_boolean(value, enable);
297 break;
298 }
299 default:
300 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
301 break;
302 }
303}
304
305static GstElement *
307{
308 GstBin *glsinkbin = GST_BIN(object);
309 GstQgcVideoSinkBin *qgcVideoSinkBin = GST_QGC_VIDEO_SINK_BIN(udata);
310
311 qgcVideoSinkBin->glsinkbin = GST_ELEMENT(glsinkbin);
312 qgcVideoSinkBin->qmlglsink = gst_element_factory_make("qml6glsink", NULL);
313 if (!qgcVideoSinkBin->qmlglsink) {
314 GST_ERROR_OBJECT(qgcVideoSinkBin, "gst_element_factory_make('qml6glsink') failed");
315 g_signal_emit(GST_ELEMENT(qgcVideoSinkBin), gst_qgc_video_sink_bin_signals[SIGNAL_CREATE_ELEMENT], 0, &qgcVideoSinkBin->qmlglsink);
316 }
317
318 return qgcVideoSinkBin->qmlglsink;
319}
320
321static void
323{
324 GstQgcVideoSinkBin *self = GST_QGC_VIDEO_SINK_BIN(object);
325
326 (void) self;
327
328 G_OBJECT_CLASS(parent_class)->dispose(object);
329}
330
331static void
333{
334 GstQgcVideoSinkBin *self = GST_QGC_VIDEO_SINK_BIN(object);
335
336 (void) self;
337
338 G_OBJECT_CLASS(parent_class)->finalize(object);
339}
struct _GstElement GstElement
void qgc_element_init(GstPlugin *plugin)
#define DEFAULT_PAR_D
static void gst_qgc_video_sink_bin_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
G_DEFINE_TYPE_WITH_CODE(GstQgcVideoSinkBin, gst_qgc_video_sink_bin, GST_TYPE_BIN, GST_DEBUG_CATEGORY_INIT(gst_qgc_video_sink_bin_debug, "qgcsinkbin", 0, "QGC Video Sink Bin"))
@ PROP_ENABLE_LAST_SAMPLE
@ PROP_FORCE_ASPECT_RATIO
@ PROP_PIXEL_ASPECT_RATIO
@ PROP_LAST
@ PROP_WIDGET
@ PROP_LAST_SAMPLE
@ PROP_SYNC
static GParamSpec * properties[PROP_LAST]
GST_ELEMENT_REGISTER_DEFINE_WITH_CODE(qgcvideosinkbin,"qgcvideosinkbin", GST_RANK_NONE,(gst_qgc_video_sink_bin_get_type()), qgc_element_init(plugin))
static void gst_qgc_video_sink_bin_class_init(GstQgcVideoSinkBinClass *klass)
#define PROP_FORCE_ASPECT_RATIO_NAME
#define DEFAULT_FORCE_ASPECT_RATIO
#define PROP_WIDGET_NAME
#define PROP_ENABLE_LAST_SAMPLE_NAME
#define DEFAULT_ENABLE_LAST_SAMPLE
#define DEFAULT_SYNC
static GstElement * gst_qgc_video_sink_bin_on_glsinkbin_create_element(GstElement *object, gpointer udata)
#define PROP_PIXEL_ASPECT_RATIO_NAME
#define PROP_SYNC_NAME
@ SIGNAL_CREATE_ELEMENT
@ SIGNAL_LAST
static void gst_qgc_video_sink_bin_finalize(GObject *object)
#define DEFAULT_PAR_N
GST_DEBUG_CATEGORY_STATIC(gst_qgc_video_sink_bin_debug)
#define GST_CAT_DEFAULT
static void gst_qgc_video_sink_bin_dispose(GObject *object)
static void gst_qgc_video_sink_bin_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
#define PROP_LAST_SAMPLE_NAME
static guint gst_qgc_video_sink_bin_signals[SIGNAL_LAST]
static void gst_qgc_video_sink_bin_init(GstQgcVideoSinkBin *self)
#define GST_TYPE_QGC_VIDEO_SINK_BIN