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