gst-gmyth/playbinmaemo/gstplaybinmaemo.c
author renatofilho
Thu Aug 16 14:46:11 2007 +0100 (2007-08-16)
branchtrunk
changeset 807 add4025ca678
parent 797 7563dc4ed8d5
child 808 215c45290ce3
permissions -rw-r--r--
[svn r813] created a timeout function for invalid channels
     1 /* GStreamer
     2  * Copyright (C) <2007> Renato Araujo Oliveira Filho <renato.filho@indt.org.br>
     3  *
     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.
     8  *
     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.
    13  *
    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., 59 Temple Place - Suite 330,
    17  * Boston, MA 02111-1307, USA.
    18  */
    19 
    20 #ifdef HAVE_CONFIG_H
    21 #include "config.h"
    22 #endif
    23 
    24 #include <glib/gi18n.h>
    25 #include <string.h>
    26 #include <gst/gst.h>
    27 #include <gst/gsterror.h>
    28 #include <gst/gstplugin.h>
    29 #include <gst/interfaces/xoverlay.h>
    30 #include <X11/Xlib.h>
    31 //#include <gst/pbutils/pbutils.h>
    32 #include "gstplaybinmaemo.h"
    33 
    34 
    35 GST_DEBUG_CATEGORY_STATIC (gst_play_bin_maemo_debug);
    36 #define GST_CAT_DEFAULT gst_play_bin_maemo_debug
    37 
    38 #define DEFAULT_VOLUME               10
    39 #define DEFAULT_XID                 -1
    40 
    41 /* props */
    42 enum
    43 {
    44   ARG_0,
    45   ARG_URI,
    46   ARG_QUEUE_SIZE,
    47   ARG_QUEUE_MIN_THRESHOLD,
    48   ARG_SOURCE,
    49   ARG_VOLUME,
    50   ARG_PARSE_METADATA,
    51   ARG_XID
    52 };
    53 
    54 static const GstElementDetails gst_play_bin_maemo_details =
    55         GST_ELEMENT_DETAILS("playbinmaemo",
    56                             "Generic/Bin/Player",
    57                             "Autoplug and play media from an uri used on maemo plataform",
    58                             "Renato Araujo Oliveira Filho <renato.filho@indt.org.br>");
    59 
    60 static void     gst_play_bin_maemo_dispose          (GObject * object);
    61 static void     gst_play_bin_maemo_finalize         (GObject * object);
    62 static void     gst_play_bin_maemo_set_property     (GObject * object, guint prop_id,
    63                                                     const GValue * value, GParamSpec * spec);
    64 static void     gst_play_bin_maemo_get_property     (GObject * object, guint prop_id,
    65                                                     GValue * value, GParamSpec * spec);
    66 static GstStateChangeReturn
    67                 gst_play_bin_maemo_change_state     (GstElement *element,
    68                                                     GstStateChange transition);
    69 static gboolean factory_filter_sinks                (GstPluginFeature *feature,
    70                                                     GstPlayBinMaemo *pbm);
    71 static gint     compare_ranks                       (GstPluginFeature * f1,
    72                                                     GstPluginFeature * f2);
    73 static GList    *find_compatibles                   (GstPlayBinMaemo *pbm,
    74                                                      const GstCaps *caps);
    75 static GstPad   *find_sink_pad                      (GstElement * element);
    76 static void     update_volume                       (GstPlayBinMaemo *pbm);
    77 static void     update_xid                          (GstPlayBinMaemo *pbm);
    78 static void     new_decoded_pad_cb                  (GstElement *object,
    79                                                      GstPad* pad,
    80                                                      gboolean arg,
    81                                                      gpointer user_data);
    82 static void     unknown_type_cb                     (GstElement *object,
    83                                                      GstPad *pad,
    84                                                      GstCaps *casp,
    85                                                      gpointer user_data);
    86 static gboolean autoplug_continue_cb                (GstElement* object,
    87                                                      GstCaps* caps,
    88                                                      gpointer user_data);
    89 static gboolean add_element                         (GstPlayBinMaemo *pbm,
    90                                                      GstElement *child);
    91 static void     clear_elements                      (GstPlayBinMaemo *pbm);
    92 
    93 GST_BOILERPLATE(GstPlayBinMaemo, gst_play_bin_maemo, GstPipeline, GST_TYPE_PIPELINE)
    94 
    95 
    96 static void
    97 gst_play_bin_maemo_base_init (gpointer klass)
    98 {
    99     GstElementClass *element_class = GST_ELEMENT_CLASS(klass);
   100 
   101     gst_element_class_set_details (element_class, &gst_play_bin_maemo_details);
   102 }
   103 
   104 static void
   105 gst_play_bin_maemo_class_init (GstPlayBinMaemoClass * klass)
   106 {
   107   GObjectClass *gobject_klass;
   108   GstElementClass *gstelement_klass;
   109   GstBinClass *gstbin_klass;
   110 
   111   gobject_klass = (GObjectClass *) klass;
   112   gstelement_klass = (GstElementClass *) klass;
   113   gstbin_klass = (GstBinClass *) klass;
   114 
   115   parent_class = g_type_class_peek_parent (klass);
   116 
   117   gobject_klass->set_property = gst_play_bin_maemo_set_property;
   118   gobject_klass->get_property = gst_play_bin_maemo_get_property;
   119 
   120   g_object_class_install_property (gobject_klass, ARG_URI,
   121       g_param_spec_string ("uri", "URI", "URI of the media to play",
   122           NULL, G_PARAM_READWRITE));
   123 
   124   g_object_class_install_property (gobject_klass, ARG_VOLUME,
   125       g_param_spec_double ("volume", "Audio volume", "volume",
   126                             0.0, 10.0, (gdouble) DEFAULT_VOLUME, G_PARAM_READWRITE));
   127 
   128   g_object_class_install_property (gobject_klass, ARG_XID,
   129       g_param_spec_long ("xid", "xid", "X windown ID",
   130                          -1, G_MAXLONG, DEFAULT_XID, G_PARAM_READWRITE));
   131 
   132   g_object_class_install_property (gobject_klass, ARG_SOURCE,
   133       g_param_spec_object ("source", "Source", "Source element",
   134           GST_TYPE_ELEMENT, G_PARAM_READABLE));
   135 
   136   g_object_class_install_property (gobject_klass, ARG_PARSE_METADATA,
   137       g_param_spec_boolean ("parse-metadata", "Parse Metadata", "Parse metadata info",
   138           TRUE, G_PARAM_READWRITE));
   139 
   140 
   141   GST_DEBUG_CATEGORY_INIT (gst_play_bin_maemo_debug, "playbinmaemo", 0,
   142       "playbinmaemo");
   143 
   144   gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_play_bin_maemo_dispose);
   145   gobject_klass->finalize = GST_DEBUG_FUNCPTR (gst_play_bin_maemo_finalize);
   146 
   147   gstelement_klass->change_state =
   148       GST_DEBUG_FUNCPTR (gst_play_bin_maemo_change_state);
   149 }
   150 
   151 static void
   152 gst_play_bin_maemo_init (GstPlayBinMaemo * play_bin_maemo, GstPlayBinMaemoClass *class)
   153 {
   154   GList *factories;
   155 
   156   play_bin_maemo->uri = NULL;
   157   play_bin_maemo->source = NULL;
   158 
   159   play_bin_maemo->volume = DEFAULT_VOLUME * 65535 / 10;
   160   play_bin_maemo->xid = DEFAULT_XID;
   161   play_bin_maemo->parse_metadata = TRUE;
   162 
   163   factories = gst_default_registry_feature_filter ((GstPluginFeatureFilter) factory_filter_sinks,
   164                                                    FALSE, play_bin_maemo);
   165 
   166   play_bin_maemo->factories = g_list_sort (factories, (GCompareFunc) compare_ranks);
   167 }
   168 
   169 static void
   170 gst_play_bin_maemo_dispose (GObject * object)
   171 {
   172   GstPlayBinMaemo *play_bin_maemo;
   173 
   174   play_bin_maemo = GST_PLAY_BIN_MAEMO (object);
   175   g_free (play_bin_maemo->uri);
   176   play_bin_maemo->uri = NULL;
   177 
   178   G_OBJECT_CLASS (parent_class)->dispose (object);
   179 }
   180 
   181 static void
   182 gst_play_bin_maemo_finalize (GObject * object)
   183 {
   184   clear_elements (GST_PLAY_BIN_MAEMO (object));
   185   G_OBJECT_CLASS (parent_class)->finalize (object);
   186 }
   187 
   188 static gboolean
   189 array_has_value (const gchar * values[], const gchar * value)
   190 {
   191   gint i;
   192 
   193   for (i = 0; values[i]; i++) {
   194     if (g_str_has_prefix (value, values[i]))
   195       return TRUE;
   196   }
   197   return FALSE;
   198 }
   199 
   200 /* list of URIs that we consider to be streams and that need buffering.
   201  * We have no mechanism yet to figure this out with a query. */
   202 static const gchar *stream_uris[] = { "http://", "mms://", "mmsh://",
   203   "mmsu://", "mmst://", NULL
   204 };
   205 
   206 /* blacklisted URIs, we know they will always fail. */
   207 static const gchar *blacklisted_uris[] = { NULL };
   208 
   209 /* mime types that we don't consider to be media types */
   210 /*
   211 static const gchar *no_media_mimes[] = {
   212   "application/x-executable", "application/x-bzip", "application/x-gzip",
   213   "application/zip", "application/x-compress", NULL
   214 };
   215 */
   216 
   217 /* mime types we consider raw media */
   218 static const gchar *raw_mimes[] = {
   219   "audio/x-raw", "video/x-raw", NULL
   220 };
   221 
   222 #define IS_STREAM_URI(uri)          (array_has_value (stream_uris, uri))
   223 #define IS_BLACKLISTED_URI(uri)     (array_has_value (blacklisted_uris, uri))
   224 #define IS_NO_MEDIA_MIME(mime)      (array_has_value (no_media_mimes, mime))
   225 #define IS_RAW_MIME(mime)           (array_has_value (raw_mimes, mime))
   226 
   227 /*
   228  * Generate and configure a source element.
   229  */
   230 static GstElement *
   231 gen_source_element (GstPlayBinMaemo * play_bin_maemo)
   232 {
   233   GstElement *source;
   234 
   235   if (!play_bin_maemo->uri)
   236     goto no_uri;
   237 
   238   if (!gst_uri_is_valid (play_bin_maemo->uri))
   239     goto invalid_uri;
   240 
   241   if (IS_BLACKLISTED_URI (play_bin_maemo->uri))
   242     goto uri_blacklisted;
   243 
   244   source = gst_element_make_from_uri (GST_URI_SRC, play_bin_maemo->uri, "source");
   245   if (!source)
   246     goto no_source;
   247 
   248   play_bin_maemo->is_stream = IS_STREAM_URI (play_bin_maemo->uri);
   249 
   250   /* make HTTP sources send extra headers so we get icecast
   251    * metadata in case the stream is an icecast stream */
   252   if (!strncmp (play_bin_maemo->uri, "http://", 7) &&
   253       g_object_class_find_property (G_OBJECT_GET_CLASS (source),
   254           "iradio-mode")) {
   255     g_object_set (source, "iradio-mode", TRUE, NULL);
   256   }
   257   return source;
   258 
   259   /* ERRORS */
   260 no_uri:
   261   {
   262     GST_ELEMENT_ERROR (play_bin_maemo, RESOURCE, NOT_FOUND,
   263         (_("No URI specified to play from.")), (NULL));
   264     return NULL;
   265   }
   266 invalid_uri:
   267   {
   268     GST_ELEMENT_ERROR (play_bin_maemo, RESOURCE, NOT_FOUND,
   269         (_("Invalid URI \"%s\"."), play_bin_maemo->uri), (NULL));
   270     return NULL;
   271   }
   272 uri_blacklisted:
   273   {
   274     GST_ELEMENT_ERROR (play_bin_maemo, RESOURCE, FAILED,
   275         (_("RTSP streams cannot be played yet.")), (NULL));
   276     return NULL;
   277   }
   278 no_source:
   279   {
   280     gchar *prot = gst_uri_get_protocol (play_bin_maemo->uri);
   281 
   282     /* whoops, could not create the source element, dig a little deeper to
   283      * figure out what might be wrong. */
   284     if (prot) {
   285        /*
   286       gchar *desc;
   287 
   288       gst_element_post_message (GST_ELEMENT (play_bin_maemo),
   289           gst_missing_uri_source_message_new (GST_ELEMENT (play_bin_maemo),
   290               prot));
   291 
   292       desc = gst_pb_utils_get_source_description (prot);
   293       GST_ELEMENT_ERROR (play_bin_maemo, CORE, MISSING_PLUGIN,
   294           (_("A %s plugin is required to play this stream, but not installed."),
   295               desc), ("No URI handler for %s", prot));
   296       g_free (desc);
   297       */
   298       g_free (prot);
   299     } else
   300       goto invalid_uri;
   301 
   302     return NULL;
   303   }
   304 }
   305 
   306 static void
   307 prepare_elements (GstPlayBinMaemo *pbm)
   308 {
   309   GstElement *decoder;
   310   GstElement *queue;
   311 
   312   decoder = gst_element_factory_make ("decodebin2", "decode");
   313   add_element (pbm, decoder);
   314   g_signal_connect (G_OBJECT (decoder),
   315                     "autoplug-continue",
   316                     G_CALLBACK (autoplug_continue_cb),
   317                     pbm);
   318 
   319   g_signal_connect (G_OBJECT (decoder),
   320                     "unknown-type",
   321                     G_CALLBACK (unknown_type_cb),
   322                     pbm);
   323 
   324   g_signal_connect (G_OBJECT (decoder),
   325                     "new-decoded-pad",
   326                     G_CALLBACK (new_decoded_pad_cb),
   327                     pbm);
   328 
   329   queue = gst_element_factory_make ("queue", NULL);
   330   add_element (pbm, queue);
   331 
   332   if (gst_element_link_many (pbm->source, queue, decoder, NULL) == FALSE) {
   333     g_warning ("FAIL TO LINK SRC WITH DECODEBIN2");
   334   }
   335 }
   336 
   337 static gboolean
   338 setup_source (GstPlayBinMaemo *pbm)
   339 {
   340   if (!pbm->need_rebuild)
   341     return TRUE;
   342 
   343   clear_elements (pbm);
   344 
   345   GST_DEBUG_OBJECT (pbm, "setup source");
   346 
   347   pbm->has_metadata = FALSE;
   348 
   349   /* create and configure an element that can handle the uri */
   350   if (!(pbm->source = gen_source_element (pbm)))
   351     goto no_source;
   352 
   353   add_element (pbm, pbm->source);
   354 
   355 
   356 #if 0
   357     if (verify_src_have_sink (pbm)) {
   358         /* source can be linked with sinks directly */
   359         return TRUE;
   360     }
   361 #endif
   362 
   363   prepare_elements (pbm);
   364 
   365   return TRUE;
   366 
   367 no_source:
   368   return FALSE;
   369 }
   370 
   371 static void
   372 gst_play_bin_maemo_set_property (GObject *object,
   373                                  guint prop_id,
   374                                  const GValue *value,
   375                                  GParamSpec *pspec)
   376 {
   377   GstPlayBinMaemo *play_bin_maemo;
   378 
   379   g_return_if_fail (GST_IS_PLAY_BIN_MAEMO (object));
   380 
   381   play_bin_maemo = GST_PLAY_BIN_MAEMO (object);
   382 
   383   switch (prop_id) {
   384     case ARG_URI:
   385     {
   386       const gchar *uri = g_value_get_string (value);
   387 
   388       if (uri == NULL) {
   389         g_warning ("cannot set NULL uri");
   390         return;
   391       }
   392       /* if we have no previous uri, or the new uri is different from the
   393        * old one, replug */
   394       if (play_bin_maemo->uri == NULL || strcmp (play_bin_maemo->uri, uri) != 0) {
   395         g_free (play_bin_maemo->uri);
   396         play_bin_maemo->uri = g_strdup (uri);
   397 
   398         GST_DEBUG ("setting new uri to %s", uri);
   399 
   400         play_bin_maemo->need_rebuild = TRUE;
   401       }
   402       break;
   403     }
   404     case ARG_VOLUME:
   405     {
   406       gdouble d_volume = 0;
   407       guint u_volume = 0;
   408       d_volume = g_value_get_double (value);
   409 
   410       g_debug ("Getting : %5.2f", d_volume);
   411       if (d_volume != 0) {
   412         u_volume = (guint) (65535 * d_volume);
   413       }
   414 
   415       g_debug ("Converting : %d", u_volume);
   416       if (play_bin_maemo->volume != u_volume) {
   417           play_bin_maemo->volume = u_volume;
   418           update_volume (play_bin_maemo);
   419       }
   420       break;
   421     }
   422     case ARG_XID:
   423     {
   424       long xid;
   425       xid = g_value_get_long (value);
   426       if (play_bin_maemo->xid != xid)
   427       {
   428           play_bin_maemo->xid = xid;
   429           update_xid (play_bin_maemo);
   430       }
   431       break;
   432     }
   433     case ARG_PARSE_METADATA:
   434         play_bin_maemo->parse_metadata = g_value_get_boolean (value);
   435         break;
   436     default:
   437       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
   438       break;
   439   }
   440 }
   441 
   442 static void
   443 gst_play_bin_maemo_get_property (GObject * object, guint prop_id, GValue * value,
   444     GParamSpec * pspec)
   445 {
   446   GstPlayBinMaemo *play_bin_maemo;
   447 
   448   g_return_if_fail (GST_IS_PLAY_BIN_MAEMO (object));
   449 
   450   play_bin_maemo = GST_PLAY_BIN_MAEMO (object);
   451 
   452   switch (prop_id) {
   453     case ARG_URI:
   454       g_value_set_string (value, play_bin_maemo->uri);
   455       break;
   456     case ARG_SOURCE:
   457       g_value_set_object (value, play_bin_maemo->source);
   458       break;
   459     case ARG_VOLUME:
   460     {
   461       gdouble volume  = 0;
   462       if (play_bin_maemo->volume > 0) {
   463           volume = play_bin_maemo->volume / 65535;
   464       }
   465       g_value_set_double (value, volume);
   466       break;
   467     }
   468     case ARG_XID:
   469       g_value_set_long (value, play_bin_maemo->xid);
   470       break;
   471     case ARG_PARSE_METADATA:
   472       g_value_set_boolean (value, play_bin_maemo->parse_metadata);
   473       break;
   474     default:
   475       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
   476       break;
   477   }
   478 }
   479 
   480 static GstStateChangeReturn
   481 gst_play_bin_maemo_change_state (GstElement * element, GstStateChange transition)
   482 {
   483   GstStateChangeReturn ret;
   484   GstPlayBinMaemo *play_bin_maemo;
   485 
   486   play_bin_maemo = GST_PLAY_BIN_MAEMO (element);
   487 
   488   switch (transition) {
   489     case GST_STATE_CHANGE_READY_TO_PAUSED:
   490       if (!setup_source (play_bin_maemo))
   491         goto source_failed;
   492       break;
   493     default:
   494       break;
   495   }
   496 
   497   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
   498 
   499   switch (transition) {
   500     case GST_STATE_CHANGE_READY_TO_PAUSED:
   501       if (ret == GST_STATE_CHANGE_FAILURE) {
   502         play_bin_maemo->need_rebuild = TRUE;
   503         return GST_STATE_CHANGE_FAILURE;
   504       }
   505       break;
   506       /* clean-up in both cases, READY=>NULL clean-up is if there was an error */
   507     case GST_STATE_CHANGE_PAUSED_TO_READY:
   508     case GST_STATE_CHANGE_READY_TO_NULL:
   509       play_bin_maemo->need_rebuild = TRUE;
   510       clear_elements (play_bin_maemo);
   511       break;
   512     default:
   513       break;
   514   }
   515   return ret;
   516 
   517   /* ERRORS */
   518 source_failed:
   519   {
   520     play_bin_maemo->need_rebuild = TRUE;
   521 
   522     return GST_STATE_CHANGE_FAILURE;
   523   }
   524 }
   525 
   526 static gboolean
   527 factory_filter_sinks (GstPluginFeature *feature,
   528                       GstPlayBinMaemo *pbm)
   529 {
   530   guint rank;
   531   const gchar *klass;
   532 
   533   if (!GST_IS_ELEMENT_FACTORY (feature))
   534     return FALSE;
   535 
   536   klass = gst_element_factory_get_klass (GST_ELEMENT_FACTORY (feature));
   537 
   538   if ((strstr (klass, "Sink/Video") == NULL) && (strstr (klass, "Sink/Audio") == NULL))
   539     return FALSE;
   540 
   541   g_debug ("Filtered: %s", gst_element_factory_get_longname ((GST_ELEMENT_FACTORY (feature))));
   542   rank = gst_plugin_feature_get_rank (feature);
   543   if (rank < GST_RANK_MARGINAL)
   544     return FALSE;
   545 
   546   return TRUE;
   547 }
   548 
   549 static gint
   550 compare_ranks (GstPluginFeature * f1, GstPluginFeature * f2)
   551 {
   552   gint diff;
   553   const gchar *rname1, *rname2;
   554 
   555   diff = gst_plugin_feature_get_rank (f2) - gst_plugin_feature_get_rank (f1);
   556   if (diff != 0)
   557     return diff;
   558 
   559   rname1 = gst_plugin_feature_get_name (f1);
   560   rname2 = gst_plugin_feature_get_name (f2);
   561 
   562   diff = strcmp (rname2, rname1);
   563 
   564   return diff;
   565 }
   566 
   567 
   568 static GList *
   569 find_compatibles (GstPlayBinMaemo *pbm, const GstCaps *caps)
   570 {
   571   GList *factories;
   572   GList *to_try = NULL;
   573 
   574   /* loop over all the factories */
   575   for (factories = pbm->factories; factories; factories = g_list_next (factories)) {
   576     GstElementFactory *factory = GST_ELEMENT_FACTORY (factories->data);
   577     const GList *templates;
   578     GList *walk;
   579 
   580     /* get the templates from the element factory */
   581     templates = gst_element_factory_get_static_pad_templates (factory);
   582     for (walk = (GList *) templates; walk; walk = g_list_next (walk)) {
   583       GstStaticPadTemplate *templ = walk->data;
   584 
   585       /* we only care about the sink templates */
   586       if (templ->direction == GST_PAD_SINK) {
   587         GstCaps *intersect;
   588         GstCaps *tmpl_caps;
   589 
   590         /* try to intersect the caps with the caps of the template */
   591         tmpl_caps = gst_static_caps_get (&templ->static_caps);
   592 
   593         intersect = gst_caps_intersect (caps, tmpl_caps);
   594         gst_caps_unref (tmpl_caps);
   595 
   596         /* check if the intersection is empty */
   597         if (!gst_caps_is_empty (intersect)) {
   598           /* non empty intersection, we can use this element */
   599           to_try = g_list_prepend (to_try, factory);
   600           gst_caps_unref (intersect);
   601           break;
   602         }
   603         gst_caps_unref (intersect);
   604       }
   605     }
   606   }
   607   to_try = g_list_reverse (to_try);
   608 
   609   return to_try;
   610 }
   611 
   612 
   613 static gboolean
   614 autoplug_continue_cb (GstElement* object,
   615                       GstCaps* caps,
   616                       gpointer user_data)
   617 {
   618     GList *comp = NULL;
   619     gboolean ret = TRUE;
   620     GstPlayBinMaemo *pbm;
   621 
   622     pbm = GST_PLAY_BIN_MAEMO (user_data);
   623 
   624     //TODO: fix this for work with all metada elements
   625     if (pbm->parse_metadata) {
   626         gchar *caps_str = gst_caps_to_string (caps);
   627         if ((strstr (caps_str, "id3") != NULL) &&
   628             (pbm->has_metadata == FALSE)) {
   629 
   630             g_free (caps_str);
   631             pbm->has_metadata = TRUE;
   632             return ret;
   633         }
   634         g_free (caps_str);
   635     }
   636 
   637     comp = find_compatibles (GST_PLAY_BIN_MAEMO (user_data), caps);
   638     if (comp != NULL) {
   639         g_list_free (comp);
   640         ret = FALSE;
   641     }
   642 
   643     return ret;
   644 }
   645 
   646 static void
   647 unknown_type_cb (GstElement *object,
   648                  GstPad *pad,
   649                  GstCaps *caps,
   650                  gpointer user_data)
   651 {
   652   g_debug ("unknown_type_cb: %s", gst_caps_to_string (caps));
   653 }
   654 
   655 static GstPad *
   656 find_sink_pad (GstElement * element)
   657 {
   658   GstIterator *it;
   659   GstPad *pad = NULL;
   660   gpointer point;
   661 
   662   it = gst_element_iterate_sink_pads (element);
   663 
   664   if ((gst_iterator_next (it, &point)) == GST_ITERATOR_OK)
   665     pad = (GstPad *) point;
   666 
   667   gst_iterator_free (it);
   668 
   669   return pad;
   670 }
   671 
   672 static GstElement*
   673 create_element (GstPlayBinMaemo *pbm, GstElementFactory *factory)
   674 {
   675   GstElement *queue;
   676   GstElement *bin = NULL;
   677   GstElement *element;
   678   GstPad *pad;
   679 
   680   element = gst_element_factory_create (factory, NULL);
   681   if (element == NULL)
   682     return NULL;
   683 
   684 
   685   bin = gst_bin_new (NULL);
   686 
   687   queue = gst_element_factory_make ("queue", NULL);
   688   gst_bin_add (GST_BIN (bin), queue);
   689 
   690   if (strstr (gst_element_factory_get_klass (factory), "Sink/Video") != NULL) {
   691     GstElement *colorspace;
   692 
   693     colorspace = gst_element_factory_make ("ffmpegcolorspace", NULL);
   694 
   695     gst_bin_add (GST_BIN (bin), colorspace);
   696     if (gst_element_link (queue, colorspace) == FALSE) {
   697       GST_WARNING_OBJECT (pbm, "Fail to link queue and colorspace");
   698       gst_element_set_state (colorspace, GST_STATE_NULL);
   699       gst_object_unref (colorspace);
   700       goto error;
   701     }
   702 
   703     gst_bin_add (GST_BIN (bin), element);
   704     if (gst_element_link (colorspace, element) == FALSE) {
   705       GST_WARNING_OBJECT (pbm, "Fail to link colorspace and sink video: %s", GST_ELEMENT_NAME (element));
   706       gst_element_set_state (colorspace, GST_STATE_NULL);
   707       gst_object_unref (colorspace);
   708       goto error;
   709     }
   710 
   711     pbm->video_sink = element;
   712     update_xid (pbm);
   713 
   714   } else if (strstr (gst_element_factory_get_klass (factory), "Sink/Audio") != NULL) {
   715     GParamSpec *vol_spec;
   716     GstElement *prev;
   717 
   718     prev = queue;
   719     vol_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (element), "volume");
   720     if (vol_spec == NULL) {
   721       GstElement *volume;
   722 
   723       bin = gst_bin_new (NULL);
   724       volume = gst_element_factory_make ("volume", "volume");
   725       gst_bin_add (GST_BIN (bin), volume);
   726       if (gst_element_link (queue, volume) == FALSE) {
   727         GST_WARNING_OBJECT (pbm, "Fail to link queue and volume");
   728         gst_element_set_state (volume, GST_STATE_NULL);
   729         gst_object_unref (volume);
   730         goto error;
   731       }
   732 
   733       prev = volume;
   734       g_param_spec_unref (vol_spec);
   735     }
   736 
   737     gst_bin_add (GST_BIN (bin), element);
   738     if (gst_element_link (prev, element) == FALSE) {
   739       GST_WARNING_OBJECT (pbm, "Fail to link volume and sink audio: %s", GST_ELEMENT_NAME (element));
   740       if (prev != queue) {
   741         gst_element_set_state (prev, GST_STATE_NULL);
   742         gst_object_unref (prev);
   743       }
   744       goto error;
   745     }
   746 
   747     pbm->volume_element = (prev != queue) ? prev : element;
   748     update_volume (pbm);
   749   }
   750 
   751   pad = gst_element_get_pad (queue, "sink");
   752   gst_element_add_pad (bin, gst_ghost_pad_new ("sink", pad));
   753   gst_object_unref (pad);
   754 
   755   return bin;
   756 error:
   757 
   758   gst_element_set_state (bin, GST_STATE_NULL);
   759   gst_object_unref (bin);
   760 
   761   return NULL;
   762 }
   763 
   764 static void
   765 new_decoded_pad_cb (GstElement *object,
   766                     GstPad* pad,
   767                     gboolean arg,
   768                     gpointer user_data)
   769 {
   770   GList *comp = NULL;
   771   GList *walk;
   772   GstCaps *caps;
   773   gboolean linked;
   774   GstPlayBinMaemo *pbm;
   775 
   776   pbm = GST_PLAY_BIN_MAEMO (user_data);
   777   caps = gst_pad_get_caps (pad);
   778 
   779   g_debug ("new_decoded_pad_cb: %s", gst_caps_to_string (caps));
   780 
   781   comp = find_compatibles (GST_PLAY_BIN_MAEMO (user_data), caps);
   782 
   783 
   784   if (comp == NULL) {
   785     g_warning ("flow error: dont find comaptible");
   786     return;
   787   }
   788 
   789   GST_PAD_STREAM_LOCK (pad);
   790 
   791   linked = FALSE;
   792   for (walk=comp; walk != NULL; walk = walk->next) {
   793     GstElementFactory *factory = (GstElementFactory *) walk->data;
   794     GstElement *element;
   795     GstPad *sinkpad = NULL;
   796 
   797     if ((element = create_element (pbm, factory)) == NULL) {
   798       GST_WARNING_OBJECT (pbm, "Could not create an element from %s",
   799           gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
   800       g_debug ("Could not create an element from %s",
   801           gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
   802 
   803       continue;
   804     }
   805 
   806     if (!(add_element (GST_PLAY_BIN_MAEMO (user_data), element))) {
   807       GST_WARNING_OBJECT (pbm, "Couldn't set %s to READY", GST_ELEMENT_NAME (element));
   808       gst_object_unref (element);
   809       continue;
   810     }
   811 
   812     if ((gst_element_set_state (element, GST_STATE_READY))
   813                    == GST_STATE_CHANGE_FAILURE) {
   814       gst_element_set_state (element, GST_STATE_NULL);
   815       gst_object_unref (sinkpad);
   816       gst_bin_remove (GST_BIN (user_data), element);
   817       continue;
   818     }
   819 
   820     if (!(sinkpad = find_sink_pad (element))) {
   821       GST_WARNING_OBJECT (pbm, "Element %s doesn't have a sink pad", GST_ELEMENT_NAME (element));
   822       g_debug ("Element %s doesn't have a sink pad", GST_ELEMENT_NAME (element));
   823       gst_object_unref (element);
   824       continue;
   825     }
   826 
   827 
   828     if ((gst_pad_link (pad, sinkpad)) != GST_PAD_LINK_OK) {
   829         GST_WARNING_OBJECT (pbm, "Link failed on pad %s:%s", GST_DEBUG_PAD_NAME (sinkpad));
   830         gst_element_set_state (element, GST_STATE_NULL);
   831         gst_object_unref (sinkpad);
   832         gst_bin_remove (GST_BIN (user_data), element);
   833       continue;
   834     }
   835 
   836     gst_object_unref (sinkpad);
   837 
   838     if ((gst_element_set_state (element, GST_STATE_PAUSED)) == GST_STATE_CHANGE_FAILURE) {
   839         gst_element_set_state (element, GST_STATE_NULL);
   840         gst_bin_remove (GST_BIN (user_data), element);
   841       continue;
   842     }
   843 
   844     linked = TRUE;
   845     break;
   846   }
   847 
   848   g_list_free (comp);
   849   if (linked == FALSE) {
   850     g_warning ("GstFlow ERROR");
   851   }
   852   GST_PAD_STREAM_UNLOCK (pad);
   853 }
   854 
   855 static void
   856 update_volume (GstPlayBinMaemo *pbm)
   857 {
   858   if (pbm->volume_element != NULL) {
   859     if (pbm->volume > 0) {
   860       g_object_set (G_OBJECT (pbm->volume_element),
   861                     "volume", pbm->volume,
   862                     NULL);
   863     } else {
   864       g_object_set (G_OBJECT (pbm->volume_element),
   865                     "mute", TRUE,
   866                     NULL);
   867     }
   868   }
   869 }
   870 
   871 static void
   872 update_xid (GstPlayBinMaemo *pbm)
   873 {
   874   if ((pbm->video_sink != NULL) &&
   875     (pbm->xid != -1) &&
   876     (GST_IS_X_OVERLAY (pbm->video_sink))) {
   877 
   878     Display *display;
   879     g_object_set (G_OBJECT (pbm->video_sink),
   880                   "force-aspect-ratio", TRUE, NULL);
   881     display = XOpenDisplay(NULL);
   882     XMapRaised(display, pbm->xid);
   883     XSync (display, FALSE);
   884 
   885     gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (pbm->video_sink),
   886                                   pbm->xid);
   887   }
   888 }
   889 
   890 static gboolean
   891 add_element (GstPlayBinMaemo *pbm,
   892              GstElement *child)
   893 {
   894   if (gst_bin_add (GST_BIN (pbm), child)) {
   895     pbm->elements = g_list_append (pbm->elements, child);
   896     return TRUE;
   897   }
   898   return FALSE;
   899 }
   900 
   901 static void
   902 clear_elements (GstPlayBinMaemo *pbm)
   903 {
   904   GList *walk;
   905 
   906   walk = pbm->elements;
   907 
   908   for (; walk != NULL; walk = walk->next) {
   909     GstElement *e = GST_ELEMENT (walk->data);
   910 
   911     gst_element_set_state (e, GST_STATE_NULL);
   912     gst_bin_remove (GST_BIN (pbm), e);
   913   }
   914 
   915   g_list_free (pbm->elements);
   916   pbm->elements = NULL;
   917   pbm->source = NULL;
   918   pbm->volume_element = NULL;
   919   pbm->video_sink = NULL;
   920 }
   921 
   922 static gboolean
   923 plugin_init(GstPlugin * plugin)
   924 {
   925 #ifdef ENABLE_NLS
   926   setlocale(LC_ALL, "");
   927   bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
   928 #endif                          /* ENABLE_NLS */
   929 
   930   if (!gst_element_register(plugin, "playbinmaemo", GST_RANK_SECONDARY,
   931                           GST_TYPE_PLAY_BIN_MAEMO)) {
   932     return FALSE;
   933   }
   934 
   935   return TRUE;
   936 }
   937 
   938 GST_PLUGIN_DEFINE(GST_VERSION_MAJOR,
   939                   GST_VERSION_MINOR,
   940                   "playbinmaemo",
   941                   "A playbin element that uses decodebin2 for automatic playback of audio and video",
   942                   plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME,
   943                   GST_PACKAGE_ORIGIN)