1 /* GStreamer
2 *
3 * Copyright 2007-2012 Collabora Ltd
4 * @author: Olivier Crete <olivier.crete@collabora.com>
5 * Copyright 2007-2008 Nokia
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22 /**
23 * SECTION:element-autoconvert
24 * @title: autoconvert
25 *
26 * The #autoconvert element has one sink and one source pad. It will look for
27 * other elements that also have one sink and one source pad.
28 * It will then pick an element that matches the caps on both sides.
29 * If the caps change, it may change the selected element if the current one
30 * no longer matches the caps.
31 *
32 * The list of element it will look into can be specified in the
33 * #GstAutoConvert:factories property, otherwise it will look at all available
34 * elements.
35 */
36
37
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
41
42 #include "gstautoconvert.h"
43
44 #include <string.h>
45
46 GST_DEBUG_CATEGORY (autoconvert_debug);
47 #define GST_CAT_DEFAULT (autoconvert_debug)
48
49 #define GST_AUTOCONVERT_LOCK(ac) GST_OBJECT_LOCK (ac)
50 #define GST_AUTOCONVERT_UNLOCK(ac) GST_OBJECT_UNLOCK (ac)
51
52 /* elementfactory information */
53 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
54 GST_PAD_SINK,
55 GST_PAD_ALWAYS,
56 GST_STATIC_CAPS_ANY);
57
58 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
59 GST_PAD_SRC,
60 GST_PAD_ALWAYS,
61 GST_STATIC_CAPS_ANY);
62
63 static GstStaticPadTemplate sink_internal_template =
64 GST_STATIC_PAD_TEMPLATE ("sink_internal",
65 GST_PAD_SINK,
66 GST_PAD_ALWAYS,
67 GST_STATIC_CAPS_ANY);
68
69 static GstStaticPadTemplate src_internal_template =
70 GST_STATIC_PAD_TEMPLATE ("src_internal",
71 GST_PAD_SRC,
72 GST_PAD_ALWAYS,
73 GST_STATIC_CAPS_ANY);
74
75 /* GstAutoConvert signals and args */
76 enum
77 {
78 /* FILL ME */
79 LAST_SIGNAL
80 };
81
82 enum
83 {
84 PROP_0,
85 PROP_FACTORIES
86 };
87
88 static void gst_auto_convert_set_property (GObject * object,
89 guint prop_id, const GValue * value, GParamSpec * pspec);
90 static void gst_auto_convert_get_property (GObject * object,
91 guint prop_id, GValue * value, GParamSpec * pspec);
92 static void gst_auto_convert_dispose (GObject * object);
93
94 static GstElement *gst_auto_convert_get_subelement (GstAutoConvert *
95 autoconvert);
96 static GstPad *gst_auto_convert_get_internal_sinkpad (GstAutoConvert *
97 autoconvert);
98 static GstPad *gst_auto_convert_get_internal_srcpad (GstAutoConvert *
99 autoconvert);
100
101 static GstIterator *gst_auto_convert_iterate_internal_links (GstPad * pad,
102 GstObject * parent);
103
104 static gboolean gst_auto_convert_sink_setcaps (GstAutoConvert * autoconvert,
105 GstCaps * caps);
106 static GstCaps *gst_auto_convert_getcaps (GstAutoConvert * autoconvert,
107 GstCaps * filter, GstPadDirection dir);
108 static GstFlowReturn gst_auto_convert_sink_chain (GstPad * pad,
109 GstObject * parent, GstBuffer * buffer);
110 static GstFlowReturn gst_auto_convert_sink_chain_list (GstPad * pad,
111 GstObject * parent, GstBufferList * list);
112 static gboolean gst_auto_convert_sink_event (GstPad * pad, GstObject * parent,
113 GstEvent * event);
114 static gboolean gst_auto_convert_sink_query (GstPad * pad, GstObject * parent,
115 GstQuery * query);
116
117 static gboolean gst_auto_convert_src_event (GstPad * pad, GstObject * parent,
118 GstEvent * event);
119 static gboolean gst_auto_convert_src_query (GstPad * pad, GstObject * parent,
120 GstQuery * query);
121
122 static GstFlowReturn gst_auto_convert_internal_sink_chain (GstPad * pad,
123 GstObject * parent, GstBuffer * buffer);
124 static GstFlowReturn gst_auto_convert_internal_sink_chain_list (GstPad * pad,
125 GstObject * parent, GstBufferList * list);
126 static gboolean gst_auto_convert_internal_sink_event (GstPad * pad,
127 GstObject * parent, GstEvent * event);
128 static gboolean gst_auto_convert_internal_sink_query (GstPad * pad,
129 GstObject * parent, GstQuery * query);
130
131 static gboolean gst_auto_convert_internal_src_event (GstPad * pad,
132 GstObject * parent, GstEvent * event);
133 static gboolean gst_auto_convert_internal_src_query (GstPad * pad,
134 GstObject * parent, GstQuery * query);
135
136 static GList *gst_auto_convert_load_factories (GstAutoConvert * autoconvert);
137 static GstElement
138 * gst_auto_convert_get_or_make_element_from_factory (GstAutoConvert *
139 autoconvert, GstElementFactory * factory);
140 static gboolean gst_auto_convert_activate_element (GstAutoConvert * autoconvert,
141 GstElement * element, GstCaps * caps);
142
143 static GQuark internal_srcpad_quark = 0;
144 static GQuark internal_sinkpad_quark = 0;
145 static GQuark parent_quark = 0;
146
147 G_DEFINE_TYPE (GstAutoConvert, gst_auto_convert, GST_TYPE_BIN);
148 GST_ELEMENT_REGISTER_DEFINE (autoconvert, "autoconvert",
149 GST_RANK_NONE, GST_TYPE_AUTO_CONVERT);
150
151 static void
gst_auto_convert_class_init(GstAutoConvertClass * klass)152 gst_auto_convert_class_init (GstAutoConvertClass * klass)
153 {
154 GObjectClass *gobject_class = (GObjectClass *) klass;
155 GstElementClass *gstelement_class = (GstElementClass *) klass;
156
157 GST_DEBUG_CATEGORY_INIT (autoconvert_debug, "autoconvert", 0,
158 "Auto convert based on caps");
159
160 internal_srcpad_quark = g_quark_from_static_string ("internal_srcpad");
161 internal_sinkpad_quark = g_quark_from_static_string ("internal_sinkpad");
162 parent_quark = g_quark_from_static_string ("parent");
163
164
165 gst_element_class_add_static_pad_template (gstelement_class, &srctemplate);
166 gst_element_class_add_static_pad_template (gstelement_class, &sinktemplate);
167
168 gst_element_class_set_static_metadata (gstelement_class,
169 "Select converter based on caps", "Generic/Bin",
170 "Selects the right transform element based on the caps",
171 "Olivier Crete <olivier.crete@collabora.com>");
172
173 gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_auto_convert_dispose);
174
175 gobject_class->set_property = gst_auto_convert_set_property;
176 gobject_class->get_property = gst_auto_convert_get_property;
177
178 g_object_class_install_property (gobject_class, PROP_FACTORIES,
179 g_param_spec_pointer ("factories",
180 "GList of GstElementFactory",
181 "GList of GstElementFactory objects to pick from (the element takes"
182 " ownership of the list (NULL means it will go through all possible"
183 " elements), can only be set once",
184 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
185 }
186
187 static void
gst_auto_convert_init(GstAutoConvert * autoconvert)188 gst_auto_convert_init (GstAutoConvert * autoconvert)
189 {
190 autoconvert->sinkpad =
191 gst_pad_new_from_static_template (&sinktemplate, "sink");
192 autoconvert->srcpad = gst_pad_new_from_static_template (&srctemplate, "src");
193
194 gst_pad_set_chain_function (autoconvert->sinkpad,
195 GST_DEBUG_FUNCPTR (gst_auto_convert_sink_chain));
196 gst_pad_set_chain_list_function (autoconvert->sinkpad,
197 GST_DEBUG_FUNCPTR (gst_auto_convert_sink_chain_list));
198 gst_pad_set_event_function (autoconvert->sinkpad,
199 GST_DEBUG_FUNCPTR (gst_auto_convert_sink_event));
200 gst_pad_set_query_function (autoconvert->sinkpad,
201 GST_DEBUG_FUNCPTR (gst_auto_convert_sink_query));
202 gst_pad_set_iterate_internal_links_function (autoconvert->sinkpad,
203 GST_DEBUG_FUNCPTR (gst_auto_convert_iterate_internal_links));
204
205 gst_pad_set_event_function (autoconvert->srcpad,
206 GST_DEBUG_FUNCPTR (gst_auto_convert_src_event));
207 gst_pad_set_query_function (autoconvert->srcpad,
208 GST_DEBUG_FUNCPTR (gst_auto_convert_src_query));
209 gst_pad_set_iterate_internal_links_function (autoconvert->sinkpad,
210 GST_DEBUG_FUNCPTR (gst_auto_convert_iterate_internal_links));
211
212 gst_element_add_pad (GST_ELEMENT (autoconvert), autoconvert->sinkpad);
213 gst_element_add_pad (GST_ELEMENT (autoconvert), autoconvert->srcpad);
214 }
215
216 static void
gst_auto_convert_dispose(GObject * object)217 gst_auto_convert_dispose (GObject * object)
218 {
219 GstAutoConvert *autoconvert = GST_AUTO_CONVERT (object);
220
221 g_clear_object (&autoconvert->current_subelement);
222 g_clear_object (&autoconvert->current_internal_sinkpad);
223 g_clear_object (&autoconvert->current_internal_srcpad);
224
225 for (;;) {
226 GList *factories = g_atomic_pointer_get (&autoconvert->factories);
227
228 if (g_atomic_pointer_compare_and_exchange (&autoconvert->factories,
229 factories, NULL)) {
230 gst_plugin_feature_list_free (factories);
231 break;
232 }
233 }
234
235 G_OBJECT_CLASS (gst_auto_convert_parent_class)->dispose (object);
236 }
237
238 static void
gst_auto_convert_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)239 gst_auto_convert_set_property (GObject * object,
240 guint prop_id, const GValue * value, GParamSpec * pspec)
241 {
242 GstAutoConvert *autoconvert = GST_AUTO_CONVERT (object);
243
244 switch (prop_id) {
245 default:
246 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
247 break;
248 case PROP_FACTORIES:
249 if (g_atomic_pointer_get (&autoconvert->factories) == NULL) {
250 GList *factories = g_value_get_pointer (value);
251 factories = g_list_copy (factories);
252 if (g_atomic_pointer_compare_and_exchange (&autoconvert->factories,
253 (GList *) NULL, factories))
254 g_list_foreach (factories, (GFunc) g_object_ref, NULL);
255 else
256 g_list_free (factories);
257 } else {
258 GST_WARNING_OBJECT (object, "Can not reset factories after they"
259 " have been set or auto-discovered");
260 }
261 break;
262 }
263 }
264
265 static void
gst_auto_convert_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)266 gst_auto_convert_get_property (GObject * object,
267 guint prop_id, GValue * value, GParamSpec * pspec)
268 {
269 GstAutoConvert *autoconvert = GST_AUTO_CONVERT (object);
270
271 switch (prop_id) {
272 default:
273 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
274 break;
275 case PROP_FACTORIES:
276 g_value_set_pointer (value,
277 g_atomic_pointer_get (&autoconvert->factories));
278 break;
279 }
280 }
281
282
283 static GstElement *
gst_auto_convert_get_element_by_type(GstAutoConvert * autoconvert,GType type)284 gst_auto_convert_get_element_by_type (GstAutoConvert * autoconvert, GType type)
285 {
286 GList *item;
287 GstBin *bin = GST_BIN (autoconvert);
288 GstElement *element = NULL;
289
290 g_return_val_if_fail (type != 0, NULL);
291
292 GST_OBJECT_LOCK (autoconvert);
293
294 for (item = bin->children; item; item = item->next) {
295 if (G_TYPE_CHECK_INSTANCE_TYPE (item->data, type)) {
296 element = gst_object_ref (item->data);
297 break;
298 }
299 }
300
301 GST_OBJECT_UNLOCK (autoconvert);
302
303 return element;
304 }
305
306 /**
307 * get_pad_by_direction:
308 * @element: The Element
309 * @direction: The direction
310 *
311 * Gets a #GstPad that goes in the requested direction. I will return NULL
312 * if there is no pad or if there is more than one pad in this direction
313 */
314
315 static GstPad *
get_pad_by_direction(GstElement * element,GstPadDirection direction)316 get_pad_by_direction (GstElement * element, GstPadDirection direction)
317 {
318 GstIterator *iter = gst_element_iterate_pads (element);
319 GstPad *selected_pad = NULL;
320 gboolean done;
321 GValue item = { 0, };
322
323 if (!iter)
324 return NULL;
325
326 done = FALSE;
327 while (!done) {
328 switch (gst_iterator_next (iter, &item)) {
329 case GST_ITERATOR_OK:
330 {
331 GstPad *pad = g_value_get_object (&item);
332
333 if (gst_pad_get_direction (pad) == direction) {
334 /* We check if there is more than one pad in this direction,
335 * if there is, we return NULL so that the element is refused
336 */
337 if (selected_pad) {
338 done = TRUE;
339 gst_object_unref (selected_pad);
340 selected_pad = NULL;
341 } else {
342 selected_pad = g_object_ref (pad);
343 }
344 }
345 g_value_unset (&item);
346 }
347 break;
348 case GST_ITERATOR_RESYNC:
349 if (selected_pad) {
350 gst_object_unref (selected_pad);
351 selected_pad = NULL;
352 }
353 gst_iterator_resync (iter);
354 break;
355 case GST_ITERATOR_ERROR:
356 GST_ERROR ("Error iterating pads of element %s",
357 GST_OBJECT_NAME (element));
358 gst_object_unref (selected_pad);
359 selected_pad = NULL;
360 done = TRUE;
361 break;
362 case GST_ITERATOR_DONE:
363 done = TRUE;
364 break;
365 }
366 }
367 g_value_unset (&item);
368 gst_iterator_free (iter);
369
370 if (!selected_pad)
371 GST_ERROR ("Did not find pad of direction %d in %s",
372 direction, GST_OBJECT_NAME (element));
373
374 return selected_pad;
375 }
376
377 static GstElement *
gst_auto_convert_get_subelement(GstAutoConvert * autoconvert)378 gst_auto_convert_get_subelement (GstAutoConvert * autoconvert)
379 {
380 GstElement *element = NULL;
381
382 GST_AUTOCONVERT_LOCK (autoconvert);
383 if (autoconvert->current_subelement)
384 element = gst_object_ref (autoconvert->current_subelement);
385 GST_AUTOCONVERT_UNLOCK (autoconvert);
386
387 return element;
388 }
389
390 static GstPad *
gst_auto_convert_get_internal_sinkpad(GstAutoConvert * autoconvert)391 gst_auto_convert_get_internal_sinkpad (GstAutoConvert * autoconvert)
392 {
393 GstPad *pad = NULL;
394
395 GST_AUTOCONVERT_LOCK (autoconvert);
396 if (autoconvert->current_internal_sinkpad)
397 pad = gst_object_ref (autoconvert->current_internal_sinkpad);
398 GST_AUTOCONVERT_UNLOCK (autoconvert);
399
400 return pad;
401 }
402
403 static GstPad *
gst_auto_convert_get_internal_srcpad(GstAutoConvert * autoconvert)404 gst_auto_convert_get_internal_srcpad (GstAutoConvert * autoconvert)
405 {
406 GstPad *pad = NULL;
407
408 GST_AUTOCONVERT_LOCK (autoconvert);
409 if (autoconvert->current_internal_srcpad)
410 pad = gst_object_ref (autoconvert->current_internal_srcpad);
411 GST_AUTOCONVERT_UNLOCK (autoconvert);
412
413 return pad;
414 }
415
416 /*
417 * This function creates and adds an element to the GstAutoConvert
418 * it then creates the internal pads and links them
419 *
420 */
421
422 static GstElement *
gst_auto_convert_add_element(GstAutoConvert * autoconvert,GstElementFactory * factory)423 gst_auto_convert_add_element (GstAutoConvert * autoconvert,
424 GstElementFactory * factory)
425 {
426 GstElement *element = NULL;
427 GstPad *internal_sinkpad = NULL;
428 GstPad *internal_srcpad = NULL;
429 GstPad *sinkpad = NULL;
430 GstPad *srcpad = NULL;
431 GstPadLinkReturn padlinkret;
432
433 GST_DEBUG_OBJECT (autoconvert, "Adding element %s to the autoconvert bin",
434 gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
435
436 element = gst_element_factory_create (factory, NULL);
437 if (!element)
438 return NULL;
439
440 if (!gst_bin_add (GST_BIN (autoconvert), element)) {
441 GST_ERROR_OBJECT (autoconvert, "Could not add element %s to the bin",
442 GST_OBJECT_NAME (element));
443 gst_object_unref (element);
444 return NULL;
445 }
446
447 srcpad = get_pad_by_direction (element, GST_PAD_SRC);
448 if (!srcpad) {
449 GST_ERROR_OBJECT (autoconvert, "Could not find source in %s",
450 GST_OBJECT_NAME (element));
451 goto error;
452 }
453
454 sinkpad = get_pad_by_direction (element, GST_PAD_SINK);
455 if (!sinkpad) {
456 GST_ERROR_OBJECT (autoconvert, "Could not find sink in %s",
457 GST_OBJECT_NAME (element));
458 goto error;
459 }
460
461 internal_sinkpad =
462 gst_pad_new_from_static_template (&sink_internal_template,
463 "sink_internal");
464 internal_srcpad =
465 gst_pad_new_from_static_template (&src_internal_template, "src_internal");
466
467 if (!internal_sinkpad || !internal_srcpad) {
468 GST_ERROR_OBJECT (autoconvert, "Could not create internal pads");
469 if (internal_srcpad)
470 gst_object_unref (internal_srcpad);
471 if (internal_sinkpad)
472 gst_object_unref (internal_sinkpad);
473 goto error;
474 }
475
476 g_object_weak_ref (G_OBJECT (element), (GWeakNotify) gst_object_unref,
477 internal_sinkpad);
478 g_object_weak_ref (G_OBJECT (element), (GWeakNotify) gst_object_unref,
479 internal_srcpad);
480
481 gst_pad_set_active (internal_sinkpad, TRUE);
482 gst_pad_set_active (internal_srcpad, TRUE);
483
484 g_object_set_qdata (G_OBJECT (internal_srcpad), parent_quark, autoconvert);
485 g_object_set_qdata (G_OBJECT (internal_sinkpad), parent_quark, autoconvert);
486
487 gst_pad_set_chain_function (internal_sinkpad,
488 GST_DEBUG_FUNCPTR (gst_auto_convert_internal_sink_chain));
489 gst_pad_set_chain_list_function (internal_sinkpad,
490 GST_DEBUG_FUNCPTR (gst_auto_convert_internal_sink_chain_list));
491 gst_pad_set_event_function (internal_sinkpad,
492 GST_DEBUG_FUNCPTR (gst_auto_convert_internal_sink_event));
493 gst_pad_set_query_function (internal_sinkpad,
494 GST_DEBUG_FUNCPTR (gst_auto_convert_internal_sink_query));
495
496 gst_pad_set_event_function (internal_srcpad,
497 GST_DEBUG_FUNCPTR (gst_auto_convert_internal_src_event));
498 gst_pad_set_query_function (internal_srcpad,
499 GST_DEBUG_FUNCPTR (gst_auto_convert_internal_src_query));
500
501 padlinkret = gst_pad_link_full (internal_srcpad, sinkpad,
502 GST_PAD_LINK_CHECK_NOTHING);
503 if (GST_PAD_LINK_FAILED (padlinkret)) {
504 GST_WARNING_OBJECT (autoconvert, "Could not links pad %s:%s to %s:%s"
505 " for reason %d",
506 GST_DEBUG_PAD_NAME (internal_srcpad),
507 GST_DEBUG_PAD_NAME (sinkpad), padlinkret);
508 goto error;
509 }
510
511 padlinkret = gst_pad_link_full (srcpad, internal_sinkpad,
512 GST_PAD_LINK_CHECK_NOTHING);
513 if (GST_PAD_LINK_FAILED (padlinkret)) {
514 GST_WARNING_OBJECT (autoconvert, "Could not links pad %s:%s to %s:%s"
515 " for reason %d",
516 GST_DEBUG_PAD_NAME (internal_srcpad),
517 GST_DEBUG_PAD_NAME (sinkpad), padlinkret);
518 goto error;
519 }
520
521 g_object_set_qdata (G_OBJECT (element),
522 internal_srcpad_quark, internal_srcpad);
523 g_object_set_qdata (G_OBJECT (element),
524 internal_sinkpad_quark, internal_sinkpad);
525
526 /* Iffy */
527 gst_element_sync_state_with_parent (element);
528
529 /* Increment the reference count we will return to the caller */
530 gst_object_ref (element);
531
532 /* unref sink and src pad */
533 gst_object_unref (srcpad);
534 gst_object_unref (sinkpad);
535 return element;
536
537 error:
538 gst_element_set_locked_state (element, TRUE);
539 gst_element_set_state (element, GST_STATE_NULL);
540 gst_bin_remove (GST_BIN (autoconvert), element);
541
542 if (srcpad)
543 gst_object_unref (srcpad);
544 if (sinkpad)
545 gst_object_unref (sinkpad);
546
547 return NULL;
548 }
549
550 static GstElement *
gst_auto_convert_get_or_make_element_from_factory(GstAutoConvert * autoconvert,GstElementFactory * factory)551 gst_auto_convert_get_or_make_element_from_factory (GstAutoConvert * autoconvert,
552 GstElementFactory * factory)
553 {
554 GstElement *element = NULL;
555 GstElementFactory *loaded_factory =
556 GST_ELEMENT_FACTORY (gst_plugin_feature_load (GST_PLUGIN_FEATURE
557 (factory)));
558
559 if (!loaded_factory)
560 return NULL;
561
562 element = gst_auto_convert_get_element_by_type (autoconvert,
563 gst_element_factory_get_element_type (loaded_factory));
564
565 if (!element) {
566 element = gst_auto_convert_add_element (autoconvert, loaded_factory);
567 }
568
569 gst_object_unref (loaded_factory);
570
571 return element;
572 }
573
574 /*
575 * This function checks if there is one and only one pad template on the
576 * factory that can accept the given caps. If there is one and only one,
577 * it returns TRUE, otherwise, its FALSE
578 */
579
580 static gboolean
factory_can_intersect(GstAutoConvert * autoconvert,GstElementFactory * factory,GstPadDirection direction,GstCaps * caps)581 factory_can_intersect (GstAutoConvert * autoconvert,
582 GstElementFactory * factory, GstPadDirection direction, GstCaps * caps)
583 {
584 const GList *templates;
585 gint has_direction = FALSE;
586 gboolean ret = FALSE;
587
588 g_return_val_if_fail (factory != NULL, FALSE);
589 g_return_val_if_fail (caps != NULL, FALSE);
590
591 templates = gst_element_factory_get_static_pad_templates (factory);
592
593 while (templates) {
594 GstStaticPadTemplate *template = (GstStaticPadTemplate *) templates->data;
595
596 if (template->direction == direction) {
597 GstCaps *tmpl_caps = NULL;
598 gboolean intersect;
599
600 /* If there is more than one pad in this direction, we return FALSE
601 * Only transform elements (with one sink and one source pad)
602 * are accepted
603 */
604 if (has_direction) {
605 GST_DEBUG_OBJECT (autoconvert, "Factory %p"
606 " has more than one static template with dir %d",
607 template, direction);
608 return FALSE;
609 }
610 has_direction = TRUE;
611
612 tmpl_caps = gst_static_caps_get (&template->static_caps);
613 intersect = gst_caps_can_intersect (tmpl_caps, caps);
614 GST_DEBUG_OBJECT (autoconvert, "Factories %" GST_PTR_FORMAT
615 " static caps %" GST_PTR_FORMAT " and caps %" GST_PTR_FORMAT
616 " can%s intersect", factory, tmpl_caps, caps,
617 intersect ? "" : " not");
618 gst_caps_unref (tmpl_caps);
619
620 ret |= intersect;
621 }
622 templates = g_list_next (templates);
623 }
624
625 return ret;
626 }
627
628 static gboolean
sticky_event_push(GstPad * pad,GstEvent ** event,gpointer user_data)629 sticky_event_push (GstPad * pad, GstEvent ** event, gpointer user_data)
630 {
631 GstAutoConvert *autoconvert = GST_AUTO_CONVERT (user_data);
632
633 gst_event_ref (*event);
634 gst_pad_push_event (autoconvert->current_internal_srcpad, *event);
635
636 return TRUE;
637 }
638
639 static gboolean
gst_auto_convert_activate_element(GstAutoConvert * autoconvert,GstElement * element,GstCaps * caps)640 gst_auto_convert_activate_element (GstAutoConvert * autoconvert,
641 GstElement * element, GstCaps * caps)
642 {
643 GstPad *internal_srcpad = g_object_get_qdata (G_OBJECT (element),
644 internal_srcpad_quark);
645 GstPad *internal_sinkpad = g_object_get_qdata (G_OBJECT (element),
646 internal_sinkpad_quark);
647
648 if (caps) {
649 /* check if the element can really accept said caps */
650 if (!gst_pad_peer_query_accept_caps (internal_srcpad, caps)) {
651 GST_DEBUG_OBJECT (autoconvert, "Could not set %s:%s to %"
652 GST_PTR_FORMAT, GST_DEBUG_PAD_NAME (internal_srcpad), caps);
653 return FALSE;
654 }
655 }
656
657 GST_AUTOCONVERT_LOCK (autoconvert);
658 gst_object_replace ((GstObject **) & autoconvert->current_subelement,
659 GST_OBJECT (element));
660 gst_object_replace ((GstObject **) & autoconvert->current_internal_srcpad,
661 GST_OBJECT (internal_srcpad));
662 gst_object_replace ((GstObject **) & autoconvert->current_internal_sinkpad,
663 GST_OBJECT (internal_sinkpad));
664 GST_AUTOCONVERT_UNLOCK (autoconvert);
665
666 gst_pad_sticky_events_foreach (autoconvert->sinkpad, sticky_event_push,
667 autoconvert);
668
669 gst_pad_push_event (autoconvert->sinkpad, gst_event_new_reconfigure ());
670
671 GST_INFO_OBJECT (autoconvert, "Selected element %s",
672 GST_OBJECT_NAME (GST_OBJECT (element)));
673
674 gst_object_unref (element);
675
676 return TRUE;
677 }
678
679 static GstIterator *
gst_auto_convert_iterate_internal_links(GstPad * pad,GstObject * parent)680 gst_auto_convert_iterate_internal_links (GstPad * pad, GstObject * parent)
681 {
682 GstAutoConvert *autoconvert = GST_AUTO_CONVERT (parent);
683 GstIterator *it = NULL;
684 GstPad *internal;
685
686 if (pad == autoconvert->sinkpad)
687 internal = gst_auto_convert_get_internal_srcpad (autoconvert);
688 else
689 internal = gst_auto_convert_get_internal_sinkpad (autoconvert);
690
691 if (internal) {
692 GValue val = { 0, };
693
694 g_value_init (&val, GST_TYPE_PAD);
695 g_value_take_object (&val, internal);
696
697 it = gst_iterator_new_single (GST_TYPE_PAD, &val);
698 g_value_unset (&val);
699 }
700
701 return it;
702 }
703
704 /*
705 * If there is already an internal element, it will try to call set_caps on it
706 *
707 * If there isn't an internal element or if the set_caps() on the internal
708 * element failed, it will try to find another element where it would succeed
709 * and will change the internal element.
710 */
711
712 static gboolean
gst_auto_convert_sink_setcaps(GstAutoConvert * autoconvert,GstCaps * caps)713 gst_auto_convert_sink_setcaps (GstAutoConvert * autoconvert, GstCaps * caps)
714 {
715 GList *elem;
716 GstCaps *other_caps = NULL;
717 GList *factories;
718 GstCaps *current_caps;
719
720 g_return_val_if_fail (autoconvert != NULL, FALSE);
721
722 current_caps = gst_pad_get_current_caps (autoconvert->sinkpad);
723 if (current_caps) {
724 if (gst_caps_is_equal_fixed (caps, current_caps)) {
725 gst_caps_unref (current_caps);
726 return TRUE;
727 }
728 gst_caps_unref (current_caps);
729 }
730
731 if (autoconvert->current_subelement) {
732 if (gst_pad_peer_query_accept_caps (autoconvert->current_internal_srcpad,
733 caps)) {
734 /* If we can set the new caps on the current element,
735 * then we just get out
736 */
737 GST_DEBUG_OBJECT (autoconvert, "Could set %s:%s to %" GST_PTR_FORMAT,
738 GST_DEBUG_PAD_NAME (autoconvert->current_internal_srcpad), caps);
739 goto get_out;
740 } else {
741 /* If the current element doesn't work,
742 * then we remove the current element before finding a new one.
743 */
744 GST_AUTOCONVERT_LOCK (autoconvert);
745 g_clear_object (&autoconvert->current_subelement);
746 g_clear_object (&autoconvert->current_internal_sinkpad);
747 g_clear_object (&autoconvert->current_internal_srcpad);
748 GST_AUTOCONVERT_UNLOCK (autoconvert);
749 }
750 }
751
752 other_caps = gst_pad_peer_query_caps (autoconvert->srcpad, NULL);
753
754 factories = g_atomic_pointer_get (&autoconvert->factories);
755
756 if (!factories)
757 factories = gst_auto_convert_load_factories (autoconvert);
758
759 for (elem = factories; elem; elem = g_list_next (elem)) {
760 GstElementFactory *factory = GST_ELEMENT_FACTORY (elem->data);
761 GstElement *element;
762
763 /* Lets first check if according to the static pad templates on the factory
764 * these caps have any chance of success
765 */
766 if (!factory_can_intersect (autoconvert, factory, GST_PAD_SINK, caps)) {
767 GST_LOG_OBJECT (autoconvert, "Factory %s does not accept sink caps %"
768 GST_PTR_FORMAT,
769 gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)), caps);
770 continue;
771 }
772 if (other_caps != NULL) {
773 if (!factory_can_intersect (autoconvert, factory, GST_PAD_SRC,
774 other_caps)) {
775 GST_LOG_OBJECT (autoconvert,
776 "Factory %s does not accept src caps %" GST_PTR_FORMAT,
777 gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)),
778 other_caps);
779 continue;
780 }
781 }
782
783 /* The element had a chance of success, lets make it */
784 element =
785 gst_auto_convert_get_or_make_element_from_factory (autoconvert,
786 factory);
787 if (!element)
788 continue;
789
790 /* And make it the current child */
791 if (gst_auto_convert_activate_element (autoconvert, element, caps))
792 break;
793 else
794 gst_object_unref (element);
795 }
796
797 get_out:
798 if (other_caps)
799 gst_caps_unref (other_caps);
800
801 if (autoconvert->current_subelement) {
802 return TRUE;
803 } else {
804 GST_WARNING_OBJECT (autoconvert,
805 "Could not find a matching element for caps");
806 return FALSE;
807 }
808 }
809
810 /*
811 * This function filters the pad pad templates, taking only transform element
812 * (with one sink and one src pad)
813 */
814
815 static gboolean
gst_auto_convert_default_filter_func(GstPluginFeature * feature,gpointer user_data)816 gst_auto_convert_default_filter_func (GstPluginFeature * feature,
817 gpointer user_data)
818 {
819 GstElementFactory *factory = NULL;
820 const GList *static_pad_templates, *tmp;
821 GstStaticPadTemplate *src = NULL, *sink = NULL;
822
823 if (!GST_IS_ELEMENT_FACTORY (feature))
824 return FALSE;
825
826 factory = GST_ELEMENT_FACTORY (feature);
827
828 static_pad_templates = gst_element_factory_get_static_pad_templates (factory);
829
830 for (tmp = static_pad_templates; tmp; tmp = g_list_next (tmp)) {
831 GstStaticPadTemplate *template = tmp->data;
832 GstCaps *caps;
833
834 if (template->presence == GST_PAD_SOMETIMES)
835 return FALSE;
836
837 if (template->presence != GST_PAD_ALWAYS)
838 continue;
839
840 switch (template->direction) {
841 case GST_PAD_SRC:
842 if (src)
843 return FALSE;
844 src = template;
845 break;
846 case GST_PAD_SINK:
847 if (sink)
848 return FALSE;
849 sink = template;
850 break;
851 default:
852 return FALSE;
853 }
854
855 caps = gst_static_pad_template_get_caps (template);
856
857 if (gst_caps_is_any (caps) || gst_caps_is_empty (caps))
858 return FALSE;
859 }
860
861 if (!src || !sink)
862 return FALSE;
863
864 return TRUE;
865 }
866
867 /* function used to sort element features
868 * Copy-pasted from decodebin */
869 static gint
compare_ranks(GstPluginFeature * f1,GstPluginFeature * f2)870 compare_ranks (GstPluginFeature * f1, GstPluginFeature * f2)
871 {
872 gint diff;
873 const gchar *rname1, *rname2;
874
875 diff = gst_plugin_feature_get_rank (f2) - gst_plugin_feature_get_rank (f1);
876 if (diff != 0)
877 return diff;
878
879 rname1 = gst_plugin_feature_get_name (f1);
880 rname2 = gst_plugin_feature_get_name (f2);
881
882 diff = strcmp (rname2, rname1);
883
884 return diff;
885 }
886
887 static GList *
gst_auto_convert_load_factories(GstAutoConvert * autoconvert)888 gst_auto_convert_load_factories (GstAutoConvert * autoconvert)
889 {
890 GList *all_factories;
891
892 all_factories =
893 gst_registry_feature_filter (gst_registry_get (),
894 gst_auto_convert_default_filter_func, FALSE, NULL);
895
896 all_factories = g_list_sort (all_factories, (GCompareFunc) compare_ranks);
897
898 g_assert (all_factories);
899
900 if (!g_atomic_pointer_compare_and_exchange (&autoconvert->factories,
901 (GList *) NULL, all_factories)) {
902 gst_plugin_feature_list_free (all_factories);
903 }
904
905 return g_atomic_pointer_get (&autoconvert->factories);
906 }
907
908 /* In this case, we should almost always have an internal element, because
909 * set_caps() should have been called first
910 */
911
912 static GstFlowReturn
gst_auto_convert_sink_chain(GstPad * pad,GstObject * parent,GstBuffer * buffer)913 gst_auto_convert_sink_chain (GstPad * pad, GstObject * parent,
914 GstBuffer * buffer)
915 {
916 GstFlowReturn ret = GST_FLOW_NOT_NEGOTIATED;
917 GstAutoConvert *autoconvert = GST_AUTO_CONVERT (parent);
918
919 if (autoconvert->current_internal_srcpad) {
920 ret = gst_pad_push (autoconvert->current_internal_srcpad, buffer);
921 if (ret != GST_FLOW_OK)
922 GST_DEBUG_OBJECT (autoconvert,
923 "Child element %" GST_PTR_FORMAT "returned flow %s",
924 autoconvert->current_subelement, gst_flow_get_name (ret));
925 } else {
926 GST_ERROR_OBJECT (autoconvert, "Got buffer without an negotiated element,"
927 " returning not-negotiated");
928 gst_buffer_unref (buffer);
929 }
930
931 return ret;
932 }
933
934 static GstFlowReturn
gst_auto_convert_sink_chain_list(GstPad * pad,GstObject * parent,GstBufferList * list)935 gst_auto_convert_sink_chain_list (GstPad * pad, GstObject * parent,
936 GstBufferList * list)
937 {
938 GstFlowReturn ret = GST_FLOW_NOT_NEGOTIATED;
939 GstAutoConvert *autoconvert = GST_AUTO_CONVERT (parent);
940
941 if (autoconvert->current_internal_srcpad) {
942 ret = gst_pad_push_list (autoconvert->current_internal_srcpad, list);
943 if (ret != GST_FLOW_OK)
944 GST_DEBUG_OBJECT (autoconvert,
945 "Child element %" GST_PTR_FORMAT "returned flow %s",
946 autoconvert->current_subelement, gst_flow_get_name (ret));
947 } else {
948 GST_ERROR_OBJECT (autoconvert, "Got buffer without an negotiated element,"
949 " returning not-negotiated");
950 gst_buffer_list_unref (list);
951 }
952
953 return ret;
954 }
955
956 static gboolean
gst_auto_convert_sink_event(GstPad * pad,GstObject * parent,GstEvent * event)957 gst_auto_convert_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
958 {
959 gboolean ret = TRUE;
960 GstAutoConvert *autoconvert = GST_AUTO_CONVERT (parent);
961 GstPad *internal_srcpad;
962
963 if (GST_EVENT_TYPE (event) == GST_EVENT_CAPS) {
964 GstCaps *caps;
965
966 gst_event_parse_caps (event, &caps);
967 ret = gst_auto_convert_sink_setcaps (autoconvert, caps);
968 if (!ret) {
969 gst_event_unref (event);
970 return ret;
971 }
972 }
973
974 internal_srcpad = gst_auto_convert_get_internal_srcpad (autoconvert);
975 if (internal_srcpad) {
976 ret = gst_pad_push_event (internal_srcpad, event);
977 gst_object_unref (internal_srcpad);
978 } else {
979 switch (GST_EVENT_TYPE (event)) {
980 case GST_EVENT_FLUSH_STOP:
981 case GST_EVENT_FLUSH_START:
982 ret = gst_pad_push_event (autoconvert->srcpad, event);
983 break;
984 default:
985 gst_event_unref (event);
986 ret = TRUE;
987 break;
988 }
989 }
990
991 return ret;
992 }
993
994 /* TODO Properly test that this code works well for queries */
995 static gboolean
gst_auto_convert_sink_query(GstPad * pad,GstObject * parent,GstQuery * query)996 gst_auto_convert_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
997 {
998 gboolean ret = TRUE;
999 GstAutoConvert *autoconvert = GST_AUTO_CONVERT (parent);
1000 GstElement *subelement;
1001
1002 if (GST_QUERY_TYPE (query) == GST_QUERY_CAPS) {
1003 GstCaps *filter, *caps;
1004
1005 gst_query_parse_caps (query, &filter);
1006 caps = gst_auto_convert_getcaps (autoconvert, filter, GST_PAD_SINK);
1007 gst_query_set_caps_result (query, caps);
1008 gst_caps_unref (caps);
1009
1010 return TRUE;
1011 }
1012
1013 subelement = gst_auto_convert_get_subelement (autoconvert);
1014 if (subelement) {
1015 GstPad *sub_sinkpad = get_pad_by_direction (subelement, GST_PAD_SINK);
1016
1017 ret = gst_pad_query (sub_sinkpad, query);
1018
1019 gst_object_unref (sub_sinkpad);
1020 gst_object_unref (subelement);
1021
1022 if (ret && GST_QUERY_TYPE (query) == GST_QUERY_ACCEPT_CAPS) {
1023 gboolean res;
1024 gst_query_parse_accept_caps_result (query, &res);
1025
1026 if (!res)
1027 goto ignore_acceptcaps_failure;
1028 }
1029 return ret;
1030 }
1031
1032 ignore_acceptcaps_failure:
1033
1034 if (GST_QUERY_TYPE (query) == GST_QUERY_ACCEPT_CAPS) {
1035 GstCaps *caps;
1036 GstCaps *accept_caps;
1037
1038 gst_query_parse_accept_caps (query, &accept_caps);
1039
1040 caps = gst_auto_convert_getcaps (autoconvert, accept_caps, GST_PAD_SINK);
1041 gst_query_set_accept_caps_result (query,
1042 gst_caps_can_intersect (caps, accept_caps));
1043 gst_caps_unref (caps);
1044
1045 return TRUE;
1046 }
1047
1048 GST_WARNING_OBJECT (autoconvert, "Got query %s while no element was"
1049 " selected, letting through",
1050 gst_query_type_get_name (GST_QUERY_TYPE (query)));
1051 return gst_pad_peer_query (autoconvert->srcpad, query);
1052 }
1053
1054 /**
1055 * gst_auto_convert_getcaps:
1056 * @pad: the sink #GstPad
1057 *
1058 * This function returns the union of the caps of all the possible element
1059 * factories, based on the static pad templates.
1060 * It also checks does a getcaps on the downstream element and ignores all
1061 * factories whose static caps can not satisfy it.
1062 *
1063 * It does not try to use each elements getcaps() function
1064 */
1065
1066 static GstCaps *
gst_auto_convert_getcaps(GstAutoConvert * autoconvert,GstCaps * filter,GstPadDirection dir)1067 gst_auto_convert_getcaps (GstAutoConvert * autoconvert, GstCaps * filter,
1068 GstPadDirection dir)
1069 {
1070 GstCaps *caps = NULL, *other_caps = NULL;
1071 GList *elem, *factories;
1072
1073 caps = gst_caps_new_empty ();
1074
1075 if (dir == GST_PAD_SINK)
1076 other_caps = gst_pad_peer_query_caps (autoconvert->srcpad, NULL);
1077 else
1078 other_caps = gst_pad_peer_query_caps (autoconvert->sinkpad, NULL);
1079
1080 GST_DEBUG_OBJECT (autoconvert,
1081 "Lets find all the element that can fit here with src caps %"
1082 GST_PTR_FORMAT, other_caps);
1083
1084 if (other_caps && gst_caps_is_empty (other_caps)) {
1085 goto out;
1086 }
1087
1088 factories = g_atomic_pointer_get (&autoconvert->factories);
1089
1090 if (!factories)
1091 factories = gst_auto_convert_load_factories (autoconvert);
1092
1093 for (elem = factories; elem; elem = g_list_next (elem)) {
1094 GstElementFactory *factory = GST_ELEMENT_FACTORY (elem->data);
1095 GstElement *element = NULL;
1096 GstCaps *element_caps;
1097 GstPad *internal_pad = NULL;
1098
1099 if (filter) {
1100 if (!factory_can_intersect (autoconvert, factory, dir, filter)) {
1101 GST_LOG_OBJECT (autoconvert,
1102 "Factory %s does not accept src caps %" GST_PTR_FORMAT,
1103 gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)),
1104 other_caps);
1105 continue;
1106 }
1107 }
1108
1109 if (other_caps != NULL) {
1110 if (!factory_can_intersect (autoconvert, factory,
1111 dir == GST_PAD_SINK ? GST_PAD_SRC : GST_PAD_SINK, other_caps)) {
1112 GST_LOG_OBJECT (autoconvert,
1113 "Factory %s does not accept src caps %" GST_PTR_FORMAT,
1114 gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)),
1115 other_caps);
1116 continue;
1117 }
1118
1119 element = gst_auto_convert_get_or_make_element_from_factory (autoconvert,
1120 factory);
1121 if (element == NULL)
1122 continue;
1123
1124 if (dir == GST_PAD_SINK)
1125 internal_pad = g_object_get_qdata (G_OBJECT (element),
1126 internal_srcpad_quark);
1127 else
1128 internal_pad = g_object_get_qdata (G_OBJECT (element),
1129 internal_sinkpad_quark);
1130
1131 element_caps = gst_pad_peer_query_caps (internal_pad, filter);
1132
1133 if (element_caps)
1134 caps = gst_caps_merge (caps, element_caps);
1135
1136 gst_object_unref (element);
1137
1138 /* Early out, any is absorbing */
1139 if (gst_caps_is_any (caps))
1140 goto out;
1141 } else {
1142 const GList *tmp;
1143
1144 for (tmp = gst_element_factory_get_static_pad_templates (factory);
1145 tmp; tmp = g_list_next (tmp)) {
1146 GstStaticPadTemplate *template = tmp->data;
1147
1148 if (GST_PAD_TEMPLATE_DIRECTION (template) == dir) {
1149 GstCaps *static_caps = gst_static_pad_template_get_caps (template);
1150
1151 if (static_caps) {
1152 caps = gst_caps_merge (caps, static_caps);
1153 }
1154
1155 /* Early out, any is absorbing */
1156 if (gst_caps_is_any (caps))
1157 goto out;
1158 }
1159 }
1160 }
1161 }
1162
1163 GST_DEBUG_OBJECT (autoconvert, "Returning unioned caps %" GST_PTR_FORMAT,
1164 caps);
1165
1166 out:
1167
1168 if (other_caps)
1169 gst_caps_unref (other_caps);
1170
1171 return caps;
1172 }
1173
1174
1175
1176 static gboolean
gst_auto_convert_src_event(GstPad * pad,GstObject * parent,GstEvent * event)1177 gst_auto_convert_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
1178 {
1179 gboolean ret = TRUE;
1180 GstAutoConvert *autoconvert = GST_AUTO_CONVERT (parent);
1181 GstPad *internal_sinkpad;
1182
1183 if (GST_EVENT_TYPE (event) == GST_EVENT_RECONFIGURE)
1184 gst_pad_push_event (autoconvert->sinkpad, gst_event_ref (event));
1185
1186 internal_sinkpad = gst_auto_convert_get_internal_sinkpad (autoconvert);
1187 if (internal_sinkpad) {
1188 ret = gst_pad_push_event (internal_sinkpad, event);
1189 gst_object_unref (internal_sinkpad);
1190 } else if (GST_EVENT_TYPE (event) != GST_EVENT_RECONFIGURE) {
1191 GST_WARNING_OBJECT (autoconvert,
1192 "Got upstream event while no element was selected," "forwarding.");
1193 ret = gst_pad_push_event (autoconvert->sinkpad, event);
1194 } else
1195 gst_event_unref (event);
1196
1197 return ret;
1198 }
1199
1200 /* TODO Properly test that this code works well for queries */
1201 static gboolean
gst_auto_convert_src_query(GstPad * pad,GstObject * parent,GstQuery * query)1202 gst_auto_convert_src_query (GstPad * pad, GstObject * parent, GstQuery * query)
1203 {
1204 gboolean ret = TRUE;
1205 GstAutoConvert *autoconvert = GST_AUTO_CONVERT (parent);
1206 GstElement *subelement;
1207
1208 if (GST_QUERY_TYPE (query) == GST_QUERY_CAPS) {
1209 GstCaps *filter, *caps;
1210
1211 gst_query_parse_caps (query, &filter);
1212 caps = gst_auto_convert_getcaps (autoconvert, filter, GST_PAD_SRC);
1213 gst_query_set_caps_result (query, caps);
1214 gst_caps_unref (caps);
1215
1216 return TRUE;
1217 }
1218
1219 subelement = gst_auto_convert_get_subelement (autoconvert);
1220 if (subelement) {
1221 GstPad *sub_srcpad = get_pad_by_direction (subelement, GST_PAD_SRC);
1222
1223 ret = gst_pad_query (sub_srcpad, query);
1224
1225 gst_object_unref (sub_srcpad);
1226 gst_object_unref (subelement);
1227 } else {
1228 GST_WARNING_OBJECT (autoconvert,
1229 "Got upstream query of type %s while no element was selected,"
1230 " forwarding.", gst_query_type_get_name (GST_QUERY_TYPE (query)));
1231 ret = gst_pad_peer_query (autoconvert->sinkpad, query);
1232 }
1233
1234 return ret;
1235 }
1236
1237 static GstFlowReturn
gst_auto_convert_internal_sink_chain(GstPad * pad,GstObject * parent,GstBuffer * buffer)1238 gst_auto_convert_internal_sink_chain (GstPad * pad, GstObject * parent,
1239 GstBuffer * buffer)
1240 {
1241 GstAutoConvert *autoconvert =
1242 GST_AUTO_CONVERT (g_object_get_qdata (G_OBJECT (pad),
1243 parent_quark));
1244
1245 return gst_pad_push (autoconvert->srcpad, buffer);
1246 }
1247
1248 static GstFlowReturn
gst_auto_convert_internal_sink_chain_list(GstPad * pad,GstObject * parent,GstBufferList * list)1249 gst_auto_convert_internal_sink_chain_list (GstPad * pad, GstObject * parent,
1250 GstBufferList * list)
1251 {
1252 GstAutoConvert *autoconvert =
1253 GST_AUTO_CONVERT (g_object_get_qdata (G_OBJECT (pad),
1254 parent_quark));
1255
1256 return gst_pad_push_list (autoconvert->srcpad, list);
1257 }
1258
1259 static gboolean
gst_auto_convert_internal_sink_event(GstPad * pad,GstObject * parent,GstEvent * event)1260 gst_auto_convert_internal_sink_event (GstPad * pad, GstObject * parent,
1261 GstEvent * event)
1262 {
1263 GstAutoConvert *autoconvert =
1264 GST_AUTO_CONVERT (g_object_get_qdata (G_OBJECT (pad),
1265 parent_quark));
1266 gboolean drop = FALSE;
1267
1268 GST_AUTOCONVERT_LOCK (autoconvert);
1269 if (autoconvert->current_internal_sinkpad != pad) {
1270 drop = TRUE;
1271 }
1272 GST_AUTOCONVERT_UNLOCK (autoconvert);
1273
1274 if (drop) {
1275 gst_event_unref (event);
1276 return TRUE;
1277 }
1278
1279 return gst_pad_push_event (autoconvert->srcpad, event);
1280 }
1281
1282 static gboolean
gst_auto_convert_internal_sink_query(GstPad * pad,GstObject * parent,GstQuery * query)1283 gst_auto_convert_internal_sink_query (GstPad * pad, GstObject * parent,
1284 GstQuery * query)
1285 {
1286 GstAutoConvert *autoconvert =
1287 GST_AUTO_CONVERT (g_object_get_qdata (G_OBJECT (pad),
1288 parent_quark));
1289
1290 if (!gst_pad_peer_query (autoconvert->srcpad, query)) {
1291 switch (GST_QUERY_TYPE (query)) {
1292 case GST_QUERY_CAPS:
1293 {
1294 GstCaps *filter;
1295
1296 gst_query_parse_caps (query, &filter);
1297 if (filter) {
1298 gst_query_set_caps_result (query, filter);
1299 } else {
1300 filter = gst_caps_new_any ();
1301 gst_query_set_caps_result (query, filter);
1302 gst_caps_unref (filter);
1303 }
1304 return TRUE;
1305 }
1306 case GST_QUERY_ACCEPT_CAPS:
1307 gst_query_set_accept_caps_result (query, TRUE);
1308 return TRUE;
1309 default:
1310 return FALSE;
1311 }
1312 }
1313
1314 return TRUE;
1315 }
1316
1317 static gboolean
gst_auto_convert_internal_src_event(GstPad * pad,GstObject * parent,GstEvent * event)1318 gst_auto_convert_internal_src_event (GstPad * pad, GstObject * parent,
1319 GstEvent * event)
1320 {
1321 GstAutoConvert *autoconvert =
1322 GST_AUTO_CONVERT (g_object_get_qdata (G_OBJECT (pad),
1323 parent_quark));
1324 gboolean drop = FALSE;
1325
1326 GST_AUTOCONVERT_LOCK (autoconvert);
1327 if (autoconvert->current_internal_srcpad != pad) {
1328 drop = TRUE;
1329 }
1330 GST_AUTOCONVERT_UNLOCK (autoconvert);
1331
1332 if (drop) {
1333 GST_DEBUG_OBJECT (autoconvert, "Dropping event %" GST_PTR_FORMAT, event);
1334 gst_event_unref (event);
1335 return TRUE;
1336 }
1337
1338 return gst_pad_push_event (autoconvert->sinkpad, event);
1339 }
1340
1341 static gboolean
gst_auto_convert_internal_src_query(GstPad * pad,GstObject * parent,GstQuery * query)1342 gst_auto_convert_internal_src_query (GstPad * pad, GstObject * parent,
1343 GstQuery * query)
1344 {
1345 GstAutoConvert *autoconvert =
1346 GST_AUTO_CONVERT (g_object_get_qdata (G_OBJECT (pad),
1347 parent_quark));
1348
1349 return gst_pad_peer_query (autoconvert->sinkpad, query);
1350 }
1351