1010#include " gstqgcvideosinkbin.h"
1111#include " gstqgcelements.h"
1212
13- #include < gst/gl/gl .h>
13+ #include < gst/gst .h>
1414
1515#define GST_CAT_DEFAULT gst_qgc_video_sink_bin_debug
1616GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
1717
18- #define DEFAULT_ENABLE_LAST_SAMPLE FALSE
18+ #define DEFAULT_ENABLE_LAST_SAMPLE TRUE
1919#define DEFAULT_FORCE_ASPECT_RATIO TRUE
2020#define DEFAULT_PAR_N 0
2121#define DEFAULT_PAR_D 1
4242
4343static GParamSpec *properties[PROP_LAST];
4444
45- enum
46- {
47- SIGNAL_0,
48- SIGNAL_CREATE_ELEMENT,
49- SIGNAL_LAST
50- };
51-
52- static guint gst_qgc_video_sink_bin_signals[SIGNAL_LAST] = { 0 };
53-
5445#define gst_qgc_video_sink_bin_parent_class parent_class
5546G_DEFINE_TYPE_WITH_CODE (
5647 GstQgcVideoSinkBin,
@@ -69,10 +60,44 @@ GST_ELEMENT_REGISTER_DEFINE_WITH_CODE(qgcvideosinkbin,"qgcvideosinkbin",
6960
7061static void gst_qgc_video_sink_bin_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
7162static void gst_qgc_video_sink_bin_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
72- static GstElement *gst_qgc_video_sink_bin_on_glsinkbin_create_element (GstElement *object, gpointer udata);
7363static void gst_qgc_video_sink_bin_dispose (GObject *object);
7464static void gst_qgc_video_sink_bin_finalize (GObject *object);
7565
66+ // Query function to forward caps queries to glupload and context queries to qmlglsink
67+ static gboolean
68+ gst_qgc_video_sink_bin_sink_pad_query (GstPad *pad, GstObject *parent, GstQuery *query)
69+ {
70+ GstQgcVideoSinkBin *self = GST_QGC_VIDEO_SINK_BIN (parent);
71+ GstElement *element = NULL ;
72+
73+ switch (GST_QUERY_TYPE (query)) {
74+ case GST_QUERY_CAPS:
75+ element = self->glupload ;
76+ break ;
77+ case GST_QUERY_CONTEXT:
78+ element = self->qmlglsink ;
79+ break ;
80+ default :
81+ return gst_pad_query_default (pad, parent, query);
82+ }
83+
84+ if (!element) {
85+ GST_ERROR_OBJECT (self, " No element found for query" );
86+ return FALSE ;
87+ }
88+
89+ GstPad *sinkpad = gst_element_get_static_pad (element, " sink" );
90+ if (!sinkpad) {
91+ GST_ERROR_OBJECT (self, " No sink pad found on element" );
92+ return FALSE ;
93+ }
94+
95+ gboolean ret = gst_pad_query (sinkpad, query);
96+ gst_object_unref (sinkpad);
97+
98+ return ret;
99+ }
100+
76101static void
77102gst_qgc_video_sink_bin_class_init (GstQgcVideoSinkBinClass *klass)
78103{
@@ -100,7 +125,7 @@ gst_qgc_video_sink_bin_class_init(GstQgcVideoSinkBinClass *klass)
100125
101126 properties[PROP_WIDGET] = g_param_spec_pointer (
102127 " widget" , " QQuickItem" ,
103- " Owning QML item – handed off to qml6glsink" ,
128+ " Owning QML item - handed off to qml6glsink" ,
104129 (GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
105130 );
106131
@@ -129,17 +154,6 @@ gst_qgc_video_sink_bin_class_init(GstQgcVideoSinkBinClass *klass)
129154
130155 g_object_class_install_properties (object_class, PROP_LAST, properties);
131156
132- gst_qgc_video_sink_bin_signals[SIGNAL_CREATE_ELEMENT] = g_signal_new (
133- " create-element" , /* name */
134- G_TYPE_FROM_CLASS (klass), /* owner type */
135- G_SIGNAL_RUN_LAST, /* flags */
136- 0 , /* class offset for default handler */
137- NULL , NULL , /* accumulator / accu-data */
138- NULL , /* generic marshaller */
139- GST_TYPE_ELEMENT, /* return type */
140- 0 /* param count */
141- );
142-
143157 gst_element_class_set_static_metadata (element_class,
144158 " QGC Video Sink Bin" , " Sink/Video/Bin" ,
145159 " GL accelerated video sink wrapper used by QGroundControl" ,
@@ -150,49 +164,92 @@ gst_qgc_video_sink_bin_class_init(GstQgcVideoSinkBinClass *klass)
150164static void
151165gst_qgc_video_sink_bin_init (GstQgcVideoSinkBin *self)
152166{
153- self->glsinkbin = gst_element_factory_make (" glsinkbin" , NULL );
154- if (!self->glsinkbin ) {
155- GST_ERROR_OBJECT (self, " gst_element_factory_make('glsinkbin') failed" );
156- return ;
157- }
167+ gboolean initialized = FALSE ;
168+ GstElement *glcolorconvert = NULL ;
169+ GstPad *pad = NULL ;
170+
171+ do {
172+ // Create glupload element
173+ self->glupload = gst_element_factory_make (" glupload" , NULL );
174+ if (!self->glupload ) {
175+ GST_ERROR_OBJECT (self, " gst_element_factory_make('glupload') failed" );
176+ break ;
177+ }
158178
159- self->qmlglsink = gst_element_factory_make (" qml6glsink" , NULL );
160- if (!self->qmlglsink ) {
161- GST_ERROR_OBJECT (self, " gst_element_factory_make('qml6glsink') failed" );
162- return ;
163- }
179+ // Create qml6glsink element
180+ self->qmlglsink = gst_element_factory_make (" qml6glsink" , NULL );
181+ if (!self->qmlglsink ) {
182+ GST_ERROR_OBJECT (self, " gst_element_factory_make('qml6glsink') failed" );
183+ break ;
184+ }
164185
165- g_object_set (self->glsinkbin ,
166- " sink" , self->qmlglsink ,
167- PROP_ENABLE_LAST_SAMPLE_NAME, FALSE ,
168- NULL );
186+ // Create glcolorconvert element
187+ glcolorconvert = gst_element_factory_make (" glcolorconvert" , NULL );
188+ if (!glcolorconvert) {
189+ GST_ERROR_OBJECT (self, " gst_element_factory_make('glcolorconvert') failed" );
190+ break ;
191+ }
169192
170- g_return_if_fail (gst_bin_add (GST_BIN (self), self->glsinkbin ));
193+ // Get sink pad from glupload for ghost pad
194+ pad = gst_element_get_static_pad (self->glupload , " sink" );
195+ if (!pad) {
196+ GST_ERROR_OBJECT (self, " gst_element_get_static_pad(glupload, 'sink') failed" );
197+ break ;
198+ }
171199
172- g_signal_connect (self->glsinkbin ,
173- " create-element" ,
174- G_CALLBACK (gst_qgc_video_sink_bin_on_glsinkbin_create_element),
175- self);
200+ // Keep references to our elements
201+ gst_object_ref (self->glupload );
202+ gst_object_ref (self->qmlglsink );
176203
177- GstPad *sinkpad = gst_element_get_static_pad (self->glsinkbin , " sink" );
178- if (!sinkpad) {
179- GST_ERROR_OBJECT (self, " gst_element_get_static_pad('sink') failed" );
180- return ;
181- }
204+ // Add all elements to bin
205+ gst_bin_add_many (GST_BIN (self), self->glupload , glcolorconvert, self->qmlglsink , NULL );
182206
183- GstPad *ghostpad = gst_ghost_pad_new (" sink" , sinkpad);
184- if (!ghostpad) {
185- GST_ERROR_OBJECT (self, " gst_ghost_pad_new('sink') failed" );
186- gst_object_unref (sinkpad);
187- return ;
207+ // Link: glupload -> glcolorconvert -> qmlglsink
208+ if (!gst_element_link_many (self->glupload , glcolorconvert, self->qmlglsink , NULL )) {
209+ GST_ERROR_OBJECT (self, " gst_element_link_many() failed" );
210+ break ;
211+ }
212+
213+ // glcolorconvert is now owned by the bin, clear our reference
214+ glcolorconvert = NULL ;
215+
216+ // Create ghost pad for the bin's sink
217+ GstPad *ghostpad = gst_ghost_pad_new (" sink" , pad);
218+ if (!ghostpad) {
219+ GST_ERROR_OBJECT (self, " gst_ghost_pad_new('sink') failed" );
220+ break ;
221+ }
222+
223+ // Set custom query function to forward caps/context queries
224+ gst_pad_set_query_function (ghostpad, gst_qgc_video_sink_bin_sink_pad_query);
225+
226+ if (!gst_element_add_pad (GST_ELEMENT (self), ghostpad)) {
227+ GST_ERROR_OBJECT (self, " gst_element_add_pad() failed" );
228+ break ;
229+ }
230+
231+ initialized = TRUE ;
232+ } while (0 );
233+
234+ if (pad) {
235+ gst_object_unref (pad);
236+ pad = NULL ;
188237 }
189238
190- if (!gst_element_add_pad (GST_ELEMENT (self), ghostpad)) {
191- GST_ERROR_OBJECT (self, " gst_element_add_pad() failed" );
239+ if (glcolorconvert) {
240+ gst_object_unref (glcolorconvert);
241+ glcolorconvert = NULL ;
192242 }
193243
194- if (sinkpad) {
195- gst_object_unref (sinkpad);
244+ if (!initialized) {
245+ if (self->qmlglsink ) {
246+ gst_object_unref (self->qmlglsink );
247+ self->qmlglsink = NULL ;
248+ }
249+ if (self->glupload ) {
250+ gst_object_unref (self->glupload );
251+ self->glupload = NULL ;
252+ }
196253 }
197254}
198255
@@ -201,9 +258,13 @@ gst_qgc_video_sink_bin_set_property(GObject *object, guint prop_id, const GValue
201258{
202259 GstQgcVideoSinkBin *self = GST_QGC_VIDEO_SINK_BIN (object);
203260
261+ if (!self->qmlglsink ) {
262+ return ;
263+ }
264+
204265 switch (prop_id) {
205266 case PROP_ENABLE_LAST_SAMPLE:
206- g_object_set (self->glsinkbin ,
267+ g_object_set (self->qmlglsink ,
207268 PROP_ENABLE_LAST_SAMPLE_NAME,
208269 g_value_get_boolean (value),
209270 NULL );
@@ -215,23 +276,20 @@ gst_qgc_video_sink_bin_set_property(GObject *object, guint prop_id, const GValue
215276 NULL );
216277 break ;
217278 case PROP_FORCE_ASPECT_RATIO:
218- g_object_set (self->glsinkbin ,
279+ g_object_set (self->qmlglsink ,
219280 PROP_FORCE_ASPECT_RATIO_NAME,
220281 g_value_get_boolean (value),
221282 NULL );
222283 break ;
223- case PROP_PIXEL_ASPECT_RATIO: {
224- const gint num = gst_value_get_fraction_numerator (value);
225- const gint den = gst_value_get_fraction_denominator (value);
284+ case PROP_PIXEL_ASPECT_RATIO:
226285 g_object_set (self->qmlglsink ,
227286 PROP_PIXEL_ASPECT_RATIO_NAME,
228- num ,
229- den ,
287+ gst_value_get_fraction_numerator (value) ,
288+ gst_value_get_fraction_denominator (value) ,
230289 NULL );
231290 break ;
232- }
233291 case PROP_SYNC:
234- g_object_set (self->glsinkbin ,
292+ g_object_set (self->qmlglsink ,
235293 PROP_SYNC_NAME,
236294 g_value_get_boolean (value),
237295 NULL );
@@ -247,10 +305,14 @@ gst_qgc_video_sink_bin_get_property(GObject *object, guint prop_id, GValue *valu
247305{
248306 GstQgcVideoSinkBin *self = GST_QGC_VIDEO_SINK_BIN (object);
249307
308+ if (!self->qmlglsink ) {
309+ return ;
310+ }
311+
250312 switch (prop_id) {
251313 case PROP_ENABLE_LAST_SAMPLE: {
252314 gboolean enable = FALSE ;
253- g_object_get (self->glsinkbin ,
315+ g_object_get (self->qmlglsink ,
254316 PROP_ENABLE_LAST_SAMPLE_NAME,
255317 &enable,
256318 NULL );
@@ -259,7 +321,7 @@ gst_qgc_video_sink_bin_get_property(GObject *object, guint prop_id, GValue *valu
259321 }
260322 case PROP_LAST_SAMPLE: {
261323 GstSample *sample = NULL ;
262- g_object_get (self->glsinkbin ,
324+ g_object_get (self->qmlglsink ,
263325 PROP_LAST_SAMPLE_NAME,
264326 &sample,
265327 NULL );
@@ -280,7 +342,7 @@ gst_qgc_video_sink_bin_get_property(GObject *object, guint prop_id, GValue *valu
280342 }
281343 case PROP_FORCE_ASPECT_RATIO: {
282344 gboolean enable = FALSE ;
283- g_object_get (self->glsinkbin ,
345+ g_object_get (self->qmlglsink ,
284346 PROP_FORCE_ASPECT_RATIO_NAME,
285347 &enable,
286348 NULL );
@@ -298,7 +360,7 @@ gst_qgc_video_sink_bin_get_property(GObject *object, guint prop_id, GValue *valu
298360 }
299361 case PROP_SYNC: {
300362 gboolean enable = FALSE ;
301- g_object_get (self->glsinkbin ,
363+ g_object_get (self->qmlglsink ,
302364 PROP_SYNC_NAME,
303365 &enable,
304366 NULL );
@@ -311,38 +373,26 @@ gst_qgc_video_sink_bin_get_property(GObject *object, guint prop_id, GValue *valu
311373 }
312374}
313375
314- static GstElement *
315- gst_qgc_video_sink_bin_on_glsinkbin_create_element (GstElement *object, gpointer udata)
316- {
317- GstBin *glsinkbin = GST_BIN (object);
318- GstQgcVideoSinkBin *qgcVideoSinkBin = GST_QGC_VIDEO_SINK_BIN (udata);
319-
320- qgcVideoSinkBin->glsinkbin = GST_ELEMENT (glsinkbin);
321- qgcVideoSinkBin->qmlglsink = gst_element_factory_make (" qml6glsink" , NULL );
322- if (!qgcVideoSinkBin->qmlglsink ) {
323- GST_ERROR_OBJECT (qgcVideoSinkBin, " gst_element_factory_make('qml6glsink') failed" );
324- g_signal_emit (GST_ELEMENT (qgcVideoSinkBin), gst_qgc_video_sink_bin_signals[SIGNAL_CREATE_ELEMENT], 0 , &qgcVideoSinkBin->qmlglsink );
325- }
326-
327- return qgcVideoSinkBin->qmlglsink ;
328- }
329-
330376static void
331377gst_qgc_video_sink_bin_dispose (GObject *object)
332378{
333379 GstQgcVideoSinkBin *self = GST_QGC_VIDEO_SINK_BIN (object);
334380
335- (void ) self;
381+ if (self->qmlglsink ) {
382+ gst_object_unref (self->qmlglsink );
383+ self->qmlglsink = NULL ;
384+ }
385+
386+ if (self->glupload ) {
387+ gst_object_unref (self->glupload );
388+ self->glupload = NULL ;
389+ }
336390
337391 G_OBJECT_CLASS (parent_class)->dispose (object);
338392}
339393
340394static void
341395gst_qgc_video_sink_bin_finalize (GObject *object)
342396{
343- GstQgcVideoSinkBin *self = GST_QGC_VIDEO_SINK_BIN (object);
344-
345- (void ) self;
346-
347397 G_OBJECT_CLASS (parent_class)->finalize (object);
348398}
0 commit comments