2 * (c) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
29 #include "gstautodetect.h"
30 #include "gstautoaudiosink.h"
31 #include "gstautoaudiosrc.h"
32 #include "gstautovideosink.h"
33 #include "gstautovideosrc.h"
35 GST_DEBUG_CATEGORY (autodetect_debug);
37 #define DEFAULT_SYNC TRUE
47 static GstStateChangeReturn gst_auto_detect_change_state (GstElement * element,
48 GstStateChange transition);
49 static void gst_auto_detect_constructed (GObject * object);
50 static void gst_auto_detect_dispose (GObject * self);
51 static void gst_auto_detect_clear_kid (GstAutoDetect * self);
52 static void gst_auto_detect_set_property (GObject * object, guint prop_id,
53 const GValue * value, GParamSpec * pspec);
54 static void gst_auto_detect_get_property (GObject * object, guint prop_id,
55 GValue * value, GParamSpec * pspec);
57 #define gst_auto_detect_parent_class parent_class
58 G_DEFINE_ABSTRACT_TYPE (GstAutoDetect, gst_auto_detect, GST_TYPE_BIN);
61 gst_auto_detect_class_init (GstAutoDetectClass * klass)
63 GObjectClass *gobject_class;
64 GstElementClass *eklass;
66 gobject_class = G_OBJECT_CLASS (klass);
67 eklass = GST_ELEMENT_CLASS (klass);
69 gobject_class->constructed = gst_auto_detect_constructed;
70 gobject_class->dispose = gst_auto_detect_dispose;
71 gobject_class->set_property = gst_auto_detect_set_property;
72 gobject_class->get_property = gst_auto_detect_get_property;
74 eklass->change_state = GST_DEBUG_FUNCPTR (gst_auto_detect_change_state);
77 * GstAutoDetect:filter-caps:
79 * This property will filter out candidate sinks that can handle the specified
80 * caps. By default only elements that support uncompressed data are selected.
82 * This property can only be set before the element goes to the READY state.
84 g_object_class_install_property (gobject_class, PROP_CAPS,
85 g_param_spec_boxed ("filter-caps", "Filter caps",
86 "Filter sink candidates using these caps.", GST_TYPE_CAPS,
87 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
89 g_object_class_install_property (gobject_class, PROP_SYNC,
90 g_param_spec_boolean ("sync", "Sync",
91 "Sync on the clock", DEFAULT_SYNC,
92 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
96 gst_auto_detect_dispose (GObject * object)
98 GstAutoDetect *self = GST_AUTO_DETECT (object);
100 gst_auto_detect_clear_kid (self);
102 if (self->filter_caps)
103 gst_caps_unref (self->filter_caps);
104 self->filter_caps = NULL;
106 G_OBJECT_CLASS (parent_class)->dispose ((GObject *) self);
110 gst_auto_detect_clear_kid (GstAutoDetect * self)
113 gst_element_set_state (self->kid, GST_STATE_NULL);
114 gst_bin_remove (GST_BIN (self), self->kid);
120 gst_auto_detect_create_fake_element_default (GstAutoDetect * self)
123 gchar dummy_factory[10], dummy_name[20];
125 sprintf (dummy_factory, "fake%s", self->type_klass_lc);
126 sprintf (dummy_name, "fake-%s-%s", self->media_klass_lc, self->type_klass_lc);
127 fake = gst_element_factory_make (dummy_factory, dummy_name);
128 g_object_set (fake, "sync", self->sync, NULL);
134 gst_auto_detect_create_fake_element (GstAutoDetect * self)
136 GstAutoDetectClass *klass = GST_AUTO_DETECT_GET_CLASS (self);
139 if (klass->create_fake_element)
140 fake = klass->create_fake_element (self);
142 fake = gst_auto_detect_create_fake_element_default (self);
148 gst_auto_detect_attach_ghost_pad (GstAutoDetect * self)
150 GstPad *target = gst_element_get_static_pad (self->kid, self->type_klass_lc);
151 gboolean res = gst_ghost_pad_set_target (GST_GHOST_PAD (self->pad), target);
152 gst_object_unref (target);
157 /* Hack to make initial linking work; ideally, this'd work even when
158 * no target has been assigned to the ghostpad yet. */
160 gst_auto_detect_reset (GstAutoDetect * self)
162 gst_auto_detect_clear_kid (self);
164 /* placeholder element */
165 self->kid = gst_auto_detect_create_fake_element (self);
166 gst_bin_add (GST_BIN (self), self->kid);
168 gst_auto_detect_attach_ghost_pad (self);
171 static GstStaticCaps raw_audio_caps = GST_STATIC_CAPS ("audio/x-raw");
172 static GstStaticCaps raw_video_caps = GST_STATIC_CAPS ("video/x-raw");
175 gst_auto_detect_init (GstAutoDetect * self)
177 self->sync = DEFAULT_SYNC;
181 gst_auto_detect_constructed (GObject * object)
183 GstAutoDetect *self = GST_AUTO_DETECT (object);
186 if (G_OBJECT_CLASS (parent_class)->constructed)
187 G_OBJECT_CLASS (parent_class)->constructed (object);
189 is_audio = !g_strcmp0 (self->media_klass, "Audio");
190 self->type_klass = (self->flag == GST_ELEMENT_FLAG_SINK) ? "Sink" : "Source";
191 self->type_klass_lc = (self->flag == GST_ELEMENT_FLAG_SINK) ? "sink" : "src";
192 self->media_klass_lc = is_audio ? "audio" : "video";
193 /* set the default raw caps */
194 self->filter_caps = gst_static_caps_get (is_audio ? &raw_audio_caps :
197 self->pad = gst_ghost_pad_new_no_target (self->type_klass_lc,
198 (self->flag == GST_ELEMENT_FLAG_SINK) ? GST_PAD_SINK : GST_PAD_SRC);
199 gst_element_add_pad (GST_ELEMENT (self), self->pad);
201 gst_auto_detect_reset (self);
203 /* mark element type */
204 GST_OBJECT_FLAG_SET (self, self->flag);
205 gst_bin_set_suppressed_flags (GST_BIN (self),
206 GST_ELEMENT_FLAG_SOURCE | GST_ELEMENT_FLAG_SINK);
210 gst_auto_detect_factory_filter (GstPluginFeature * feature, gpointer data)
212 GstAutoDetect *self = (GstAutoDetect *) data;
216 /* we only care about element factories */
217 if (!GST_IS_ELEMENT_FACTORY (feature))
221 klass = gst_element_factory_get_metadata (GST_ELEMENT_FACTORY (feature),
222 GST_ELEMENT_METADATA_KLASS);
223 if (!(strstr (klass, self->type_klass) && strstr (klass, self->media_klass)))
226 /* only select elements with autoplugging rank */
227 rank = gst_plugin_feature_get_rank (feature);
228 if (rank < GST_RANK_MARGINAL)
235 create_element_with_pretty_name (GstAutoDetect * self,
236 GstElementFactory * factory)
239 gchar *name, *marker;
241 marker = g_strdup (GST_OBJECT_NAME (factory));
242 if (g_str_has_suffix (marker, self->type_klass_lc))
243 marker[strlen (marker) - 4] = '\0';
244 if (g_str_has_prefix (marker, "gst"))
245 memmove (marker, marker + 3, strlen (marker + 3) + 1);
246 name = g_strdup_printf ("%s-actual-%s-%s", GST_OBJECT_NAME (self),
247 self->type_klass_lc, marker);
250 element = gst_element_factory_create (factory, name);
257 gst_auto_detect_find_best (GstAutoDetect * self)
260 GstElement *choice = NULL;
261 GstMessage *message = NULL;
262 GSList *errors = NULL;
263 GstBus *bus = gst_bus_new ();
264 GstPad *el_pad = NULL;
265 GstCaps *el_caps = NULL;
266 gboolean no_match = TRUE;
268 /* We don't treat sound server sinks special. Our policy is that sound
269 * server sinks that have a rank must not auto-spawn a daemon under any
270 * circumstances, so there's nothing for us to worry about here */
271 list = gst_registry_feature_filter (gst_registry_get (),
272 (GstPluginFeatureFilter) gst_auto_detect_factory_filter, FALSE, self);
274 g_list_sort (list, (GCompareFunc) gst_plugin_feature_rank_compare_func);
276 GST_LOG_OBJECT (self, "Trying to find usable %s elements ...",
277 self->media_klass_lc);
279 for (item = list; item != NULL; item = item->next) {
280 GstElementFactory *f = GST_ELEMENT_FACTORY (item->data);
283 if ((el = create_element_with_pretty_name (self, f))) {
284 GstStateChangeReturn ret;
286 GST_DEBUG_OBJECT (self, "Testing %s", GST_OBJECT_NAME (f));
288 /* If autodetect has been provided with filter caps,
289 * accept only elements that match with the filter caps */
290 if (self->filter_caps) {
291 el_pad = gst_element_get_static_pad (el, self->type_klass_lc);
292 el_caps = gst_pad_query_caps (el_pad, NULL);
293 gst_object_unref (el_pad);
294 GST_DEBUG_OBJECT (self,
295 "Checking caps: %" GST_PTR_FORMAT " vs. %" GST_PTR_FORMAT,
296 self->filter_caps, el_caps);
297 no_match = !gst_caps_can_intersect (self->filter_caps, el_caps);
298 gst_caps_unref (el_caps);
301 GST_DEBUG_OBJECT (self, "Incompatible caps");
302 gst_object_unref (el);
305 GST_DEBUG_OBJECT (self, "Found compatible caps");
309 gst_element_set_bus (el, bus);
310 ret = gst_element_set_state (el, GST_STATE_READY);
311 if (ret == GST_STATE_CHANGE_SUCCESS) {
312 GST_DEBUG_OBJECT (self, "This worked!");
313 gst_element_set_state (el, GST_STATE_NULL);
318 /* collect all error messages */
319 while ((message = gst_bus_pop_filtered (bus, GST_MESSAGE_ERROR))) {
320 GST_DEBUG_OBJECT (self, "error message %" GST_PTR_FORMAT, message);
321 errors = g_slist_append (errors, message);
324 gst_element_set_state (el, GST_STATE_NULL);
325 gst_object_unref (el);
329 GST_DEBUG_OBJECT (self, "done trying");
331 /* We post a warning and plug a fake-element. This is convenient for running
332 * tests without requiring hardware src/sinks. */
337 /* FIXME: we forward the first message for now; but later on it might make
338 * sense to forward all so that apps can actually analyse them. */
339 gst_message_parse_error (GST_MESSAGE (errors->data), &err, &dbg);
340 gst_element_post_message (GST_ELEMENT_CAST (self),
341 gst_message_new_warning (GST_OBJECT_CAST (self), err, dbg));
345 /* send warning message to application and use a fakesrc */
346 GST_ELEMENT_WARNING (self, RESOURCE, NOT_FOUND, (NULL),
347 ("Failed to find a usable %s %s", self->media_klass_lc,
348 self->type_klass_lc));
350 choice = gst_auto_detect_create_fake_element (self);
351 gst_element_set_state (choice, GST_STATE_READY);
353 gst_object_unref (bus);
354 gst_plugin_feature_list_free (list);
355 g_slist_foreach (errors, (GFunc) gst_mini_object_unref, NULL);
356 g_slist_free (errors);
362 gst_auto_detect_detect (GstAutoDetect * self)
365 GstAutoDetectClass *klass = GST_AUTO_DETECT_GET_CLASS (self);
367 gst_auto_detect_clear_kid (self);
370 GST_DEBUG_OBJECT (self, "Creating new kid");
371 if (!(kid = gst_auto_detect_find_best (self)))
375 g_object_class_find_property (G_OBJECT_GET_CLASS (kid), "sync") != NULL;
377 g_object_set (G_OBJECT (kid), "sync", self->sync, NULL);
378 if (klass->configure) {
379 klass->configure (self, kid);
384 gst_bin_add (GST_BIN (self), kid);
386 /* Ensure the child is brought up to the right state to match the parent. */
387 if (GST_STATE (self->kid) < GST_STATE (self))
388 gst_element_set_state (self->kid, GST_STATE (self));
390 /* attach ghost pad */
391 GST_DEBUG_OBJECT (self, "Re-assigning ghostpad");
392 if (!gst_auto_detect_attach_ghost_pad (self))
395 GST_DEBUG_OBJECT (self, "done changing auto %s %s", self->media_klass_lc,
396 self->type_klass_lc);
403 GST_ELEMENT_ERROR (self, LIBRARY, INIT, (NULL),
404 ("Failed to find a supported audio sink"));
409 GST_ELEMENT_ERROR (self, LIBRARY, INIT, (NULL),
410 ("Failed to set target pad"));
415 static GstStateChangeReturn
416 gst_auto_detect_change_state (GstElement * element, GstStateChange transition)
418 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
419 GstAutoDetect *sink = GST_AUTO_DETECT (element);
421 switch (transition) {
422 case GST_STATE_CHANGE_NULL_TO_READY:
423 if (!gst_auto_detect_detect (sink))
424 return GST_STATE_CHANGE_FAILURE;
430 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
431 if (ret == GST_STATE_CHANGE_FAILURE)
434 switch (transition) {
435 case GST_STATE_CHANGE_READY_TO_NULL:
436 gst_auto_detect_reset (sink);
446 gst_auto_detect_set_property (GObject * object, guint prop_id,
447 const GValue * value, GParamSpec * pspec)
449 GstAutoDetect *self = GST_AUTO_DETECT (object);
453 if (self->filter_caps)
454 gst_caps_unref (self->filter_caps);
455 self->filter_caps = gst_caps_copy (gst_value_get_caps (value));
458 self->sync = g_value_get_boolean (value);
459 if (self->kid && self->has_sync)
460 g_object_set_property (G_OBJECT (self->kid), pspec->name, value);
463 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
469 gst_auto_detect_get_property (GObject * object, guint prop_id,
470 GValue * value, GParamSpec * pspec)
472 GstAutoDetect *self = GST_AUTO_DETECT (object);
476 gst_value_set_caps (value, self->filter_caps);
479 g_value_set_boolean (value, self->sync);
482 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
488 plugin_init (GstPlugin * plugin)
490 GST_DEBUG_CATEGORY_INIT (autodetect_debug, "autodetect", 0,
491 "Autodetection audio/video output wrapper elements");
493 return gst_element_register (plugin, "autovideosink",
494 GST_RANK_NONE, GST_TYPE_AUTO_VIDEO_SINK) &&
495 gst_element_register (plugin, "autovideosrc",
496 GST_RANK_NONE, GST_TYPE_AUTO_VIDEO_SRC) &&
497 gst_element_register (plugin, "autoaudiosink",
498 GST_RANK_NONE, GST_TYPE_AUTO_AUDIO_SINK) &&
499 gst_element_register (plugin, "autoaudiosrc",
500 GST_RANK_NONE, GST_TYPE_AUTO_AUDIO_SRC);
503 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
506 "Plugin contains auto-detection plugins for video/audio in- and outputs",
507 plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)