gst-gmyth/playbinmaemo/gstplaybinmaemo.c
author renatofilho
Tue Aug 07 16:00:49 2007 +0100 (2007-08-07)
branchtrunk
changeset 797 7563dc4ed8d5
parent 796 2c1686735af6
child 805 a87c760e0dfa
permissions -rw-r--r--
[svn r803] copyright fixed
     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 
   354     add_element (pbm, pbm->source);
   355 
   356 
   357 #if 0
   358     if (verify_src_have_sink (pbm)) {
   359         /* source can be linked with sinks directly */
   360         return TRUE;
   361     }
   362 #endif
   363 
   364     prepare_elements (pbm);
   365 
   366     return TRUE;
   367 
   368 no_source:
   369     return FALSE;
   370 }
   371 
   372 static void
   373 gst_play_bin_maemo_set_property (GObject *object,
   374                                  guint prop_id,
   375                                  const GValue *value,
   376                                  GParamSpec *pspec)
   377 {
   378   GstPlayBinMaemo *play_bin_maemo;
   379 
   380   g_return_if_fail (GST_IS_PLAY_BIN_MAEMO (object));
   381 
   382   play_bin_maemo = GST_PLAY_BIN_MAEMO (object);
   383 
   384   switch (prop_id) {
   385     case ARG_URI:
   386     {
   387       const gchar *uri = g_value_get_string (value);
   388 
   389       if (uri == NULL) {
   390         g_warning ("cannot set NULL uri");
   391         return;
   392       }
   393       /* if we have no previous uri, or the new uri is different from the
   394        * old one, replug */
   395       if (play_bin_maemo->uri == NULL || strcmp (play_bin_maemo->uri, uri) != 0) {
   396         g_free (play_bin_maemo->uri);
   397         play_bin_maemo->uri = g_strdup (uri);
   398 
   399         GST_DEBUG ("setting new uri to %s", uri);
   400 
   401         play_bin_maemo->need_rebuild = TRUE;
   402       }
   403       break;
   404     }
   405     case ARG_VOLUME:
   406     {
   407       gdouble d_volume = 0;
   408       guint u_volume = 0;
   409       d_volume = g_value_get_double (value);
   410 
   411       g_debug ("Getting : %5.2f", d_volume);
   412       if (d_volume != 0) {
   413         u_volume = (guint) (65535 * d_volume);
   414       }
   415 
   416       g_debug ("Converting : %d", u_volume);
   417       if (play_bin_maemo->volume != u_volume) {
   418           play_bin_maemo->volume = u_volume;
   419           update_volume (play_bin_maemo);
   420       }
   421       break;
   422     }
   423     case ARG_XID:
   424     {
   425       long xid;
   426       xid = g_value_get_long (value);
   427       if (play_bin_maemo->xid != xid)
   428       {
   429           play_bin_maemo->xid = xid;
   430           update_xid (play_bin_maemo);
   431       }
   432       break;
   433     }
   434     case ARG_PARSE_METADATA:
   435         play_bin_maemo->parse_metadata = g_value_get_boolean (value);
   436         break;
   437     default:
   438       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
   439       break;
   440   }
   441 }
   442 
   443 static void
   444 gst_play_bin_maemo_get_property (GObject * object, guint prop_id, GValue * value,
   445     GParamSpec * pspec)
   446 {
   447   GstPlayBinMaemo *play_bin_maemo;
   448 
   449   g_return_if_fail (GST_IS_PLAY_BIN_MAEMO (object));
   450 
   451   play_bin_maemo = GST_PLAY_BIN_MAEMO (object);
   452 
   453   switch (prop_id) {
   454     case ARG_URI:
   455       g_value_set_string (value, play_bin_maemo->uri);
   456       break;
   457     case ARG_SOURCE:
   458       g_value_set_object (value, play_bin_maemo->source);
   459       break;
   460     case ARG_VOLUME:
   461       {
   462       gdouble volume  = 0;
   463       if (play_bin_maemo->volume > 0) {
   464           volume = play_bin_maemo->volume / 65535;
   465       }
   466       g_value_set_double (value, volume);
   467       break;
   468       }
   469     case ARG_XID:
   470       g_value_set_long (value, play_bin_maemo->xid);
   471       break;
   472     case ARG_PARSE_METADATA:
   473       g_value_set_boolean (value, play_bin_maemo->parse_metadata);
   474       break;
   475     default:
   476       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
   477       break;
   478   }
   479 }
   480 
   481 static GstStateChangeReturn
   482 gst_play_bin_maemo_change_state (GstElement * element, GstStateChange transition)
   483 {
   484   GstStateChangeReturn ret;
   485   GstPlayBinMaemo *play_bin_maemo;
   486 
   487   play_bin_maemo = GST_PLAY_BIN_MAEMO (element);
   488 
   489   switch (transition) {
   490     case GST_STATE_CHANGE_READY_TO_PAUSED:
   491       if (!setup_source (play_bin_maemo))
   492         goto source_failed;
   493       break;
   494     default:
   495       break;
   496   }
   497 
   498   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
   499 
   500   switch (transition) {
   501     case GST_STATE_CHANGE_READY_TO_PAUSED:
   502       if (ret == GST_STATE_CHANGE_FAILURE) {
   503         play_bin_maemo->need_rebuild = TRUE;
   504         return GST_STATE_CHANGE_FAILURE;
   505       }
   506       break;
   507       /* clean-up in both cases, READY=>NULL clean-up is if there was an error */
   508     case GST_STATE_CHANGE_PAUSED_TO_READY:
   509     case GST_STATE_CHANGE_READY_TO_NULL:
   510       play_bin_maemo->need_rebuild = TRUE;
   511       clear_elements (play_bin_maemo);
   512       break;
   513     default:
   514       break;
   515   }
   516   return ret;
   517 
   518   /* ERRORS */
   519 source_failed:
   520   {
   521     play_bin_maemo->need_rebuild = TRUE;
   522 
   523     return GST_STATE_CHANGE_FAILURE;
   524   }
   525 }
   526 
   527 static gboolean
   528 factory_filter_sinks (GstPluginFeature *feature,
   529                       GstPlayBinMaemo *pbm)
   530 {
   531     guint rank;
   532     const gchar *klass;
   533 
   534     if (!GST_IS_ELEMENT_FACTORY (feature))
   535         return FALSE;
   536 
   537     klass = gst_element_factory_get_klass (GST_ELEMENT_FACTORY (feature));
   538 
   539     if ((strstr (klass, "Sink/Video") == NULL) && (strstr (klass, "Sink/Audio") == NULL))
   540         return FALSE;
   541 
   542     g_debug ("Filtered: %s", gst_element_factory_get_longname ((GST_ELEMENT_FACTORY (feature))));
   543     rank = gst_plugin_feature_get_rank (feature);
   544     if (rank < GST_RANK_MARGINAL)
   545         return FALSE;
   546 
   547     return TRUE;
   548 }
   549 
   550 static gint
   551 compare_ranks (GstPluginFeature * f1, GstPluginFeature * f2)
   552 {
   553   gint diff;
   554   const gchar *rname1, *rname2;
   555 
   556   diff = gst_plugin_feature_get_rank (f2) - gst_plugin_feature_get_rank (f1);
   557   if (diff != 0)
   558     return diff;
   559 
   560   rname1 = gst_plugin_feature_get_name (f1);
   561   rname2 = gst_plugin_feature_get_name (f2);
   562 
   563   diff = strcmp (rname2, rname1);
   564 
   565   return diff;
   566 }
   567 
   568 
   569 static GList *
   570 find_compatibles (GstPlayBinMaemo *pbm, const GstCaps *caps)
   571 {
   572   GList *factories;
   573   GList *to_try = NULL;
   574 
   575   /* loop over all the factories */
   576   for (factories = pbm->factories; factories; factories = g_list_next (factories)) {
   577     GstElementFactory *factory = GST_ELEMENT_FACTORY (factories->data);
   578     const GList *templates;
   579     GList *walk;
   580 
   581     /* get the templates from the element factory */
   582     templates = gst_element_factory_get_static_pad_templates (factory);
   583     for (walk = (GList *) templates; walk; walk = g_list_next (walk)) {
   584       GstStaticPadTemplate *templ = walk->data;
   585 
   586       /* we only care about the sink templates */
   587       if (templ->direction == GST_PAD_SINK) {
   588         GstCaps *intersect;
   589         GstCaps *tmpl_caps;
   590 
   591         /* try to intersect the caps with the caps of the template */
   592         tmpl_caps = gst_static_caps_get (&templ->static_caps);
   593 
   594         intersect = gst_caps_intersect (caps, tmpl_caps);
   595         gst_caps_unref (tmpl_caps);
   596 
   597         /* check if the intersection is empty */
   598         if (!gst_caps_is_empty (intersect)) {
   599           /* non empty intersection, we can use this element */
   600           to_try = g_list_prepend (to_try, factory);
   601           gst_caps_unref (intersect);
   602           break;
   603         }
   604         gst_caps_unref (intersect);
   605       }
   606     }
   607   }
   608   to_try = g_list_reverse (to_try);
   609 
   610   return to_try;
   611 }
   612 
   613 
   614 static gboolean
   615 autoplug_continue_cb (GstElement* object,
   616                       GstCaps* caps,
   617                       gpointer user_data)
   618 {
   619     GList *comp = NULL;
   620     gboolean ret = TRUE;
   621     GstPlayBinMaemo *pbm;
   622 
   623     pbm = GST_PLAY_BIN_MAEMO (user_data);
   624 
   625     //TODO: fix this for work with all metada elements
   626     if (pbm->parse_metadata) {
   627         gchar *caps_str = gst_caps_to_string (caps);
   628         if ((strstr (caps_str, "id3") != NULL) &&
   629             (pbm->has_metadata == FALSE)) {
   630 
   631             g_free (caps_str);
   632             pbm->has_metadata = TRUE;
   633             return ret;
   634         }
   635         g_free (caps_str);
   636     }
   637 
   638     comp = find_compatibles (GST_PLAY_BIN_MAEMO (user_data), caps);
   639     if (comp != NULL) {
   640         g_list_free (comp);
   641         ret = FALSE;
   642     }
   643 
   644     return ret;
   645 }
   646 
   647 static void
   648 unknown_type_cb (GstElement *object,
   649                  GstPad *pad,
   650                  GstCaps *caps,
   651                  gpointer user_data)
   652 {
   653     g_debug ("unknown_type_cb: %s", gst_caps_to_string (caps));
   654 }
   655 
   656 static GstPad *
   657 find_sink_pad (GstElement * element)
   658 {
   659   GstIterator *it;
   660   GstPad *pad = NULL;
   661   gpointer point;
   662 
   663   it = gst_element_iterate_sink_pads (element);
   664 
   665   if ((gst_iterator_next (it, &point)) == GST_ITERATOR_OK)
   666     pad = (GstPad *) point;
   667 
   668   gst_iterator_free (it);
   669 
   670   return pad;
   671 }
   672 
   673 static GstElement*
   674 create_element (GstPlayBinMaemo *pbm, GstElementFactory *factory)
   675 {
   676     GstElement *queue;
   677     GstElement *bin = NULL;
   678     GstElement *element;
   679     GstPad *pad;
   680 
   681     element = gst_element_factory_create (factory, NULL);
   682     if (element == NULL)
   683         return NULL;
   684 
   685 
   686     bin = gst_bin_new (NULL);
   687 
   688     queue = gst_element_factory_make ("queue", NULL);
   689     gst_bin_add (GST_BIN (bin), queue);
   690 
   691     if (strstr (gst_element_factory_get_klass (factory), "Sink/Video") != NULL) {
   692         GstElement *colorspace;
   693 
   694         colorspace = gst_element_factory_make ("ffmpegcolorspace", NULL);
   695 
   696         gst_bin_add (GST_BIN (bin), colorspace);
   697         if (gst_element_link (queue, colorspace) == FALSE) {
   698             GST_WARNING_OBJECT (pbm, "Fail to link queue and colorspace");
   699             gst_element_set_state (colorspace, GST_STATE_NULL);
   700             gst_object_unref (colorspace);
   701             goto error;
   702         }
   703 
   704         gst_bin_add (GST_BIN (bin), element);
   705         if (gst_element_link (colorspace, element) == FALSE) {
   706             GST_WARNING_OBJECT (pbm, "Fail to link colorspace and sink video: %s", GST_ELEMENT_NAME (element));
   707             gst_element_set_state (colorspace, GST_STATE_NULL);
   708             gst_object_unref (colorspace);
   709             goto error;
   710         }
   711 
   712         pbm->sink_video = element;
   713         update_xid (pbm);
   714 
   715     } else if (strstr (gst_element_factory_get_klass (factory), "Sink/Audio") != NULL) {
   716         GParamSpec *vol_spec;
   717         GstElement *prev;
   718 
   719         prev = queue;
   720         vol_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (element), "volume");
   721         if (vol_spec == NULL) {
   722             GstElement *volume;
   723 
   724             bin = gst_bin_new (NULL);
   725             volume = gst_element_factory_make ("volume", "volume");
   726             gst_bin_add (GST_BIN (bin), volume);
   727             if (gst_element_link (queue, volume) == FALSE) {
   728                 GST_WARNING_OBJECT (pbm, "Fail to link queue and volume");
   729                 gst_element_set_state (volume, GST_STATE_NULL);
   730                 gst_object_unref (volume);
   731                 goto error;
   732             }
   733 
   734             prev = volume;
   735             g_param_spec_unref (vol_spec);
   736         }
   737 
   738         gst_bin_add (GST_BIN (bin), element);
   739         if (gst_element_link (prev, element) == FALSE) {
   740            GST_WARNING_OBJECT (pbm, "Fail to link volume and sink audio: %s", GST_ELEMENT_NAME (element));
   741            if (prev != queue) {
   742                gst_element_set_state (prev, GST_STATE_NULL);
   743                gst_object_unref (prev);
   744            }
   745            goto error;
   746         }
   747 
   748         pbm->volume_element = (prev != queue) ? prev : element;
   749         update_volume (pbm);
   750     }
   751 
   752     pad = gst_element_get_pad (queue, "sink");
   753     gst_element_add_pad (bin, gst_ghost_pad_new ("sink", pad));
   754     gst_object_unref (pad);
   755 
   756     return bin;
   757 error:
   758 
   759     gst_element_set_state (bin, GST_STATE_NULL);
   760     gst_object_unref (bin);
   761 
   762     return NULL;
   763 }
   764 
   765 static void
   766 new_decoded_pad_cb (GstElement *object,
   767                     GstPad* pad,
   768                     gboolean arg,
   769                     gpointer user_data)
   770 {
   771     GList *comp = NULL;
   772     GList *walk;
   773     GstCaps *caps;
   774     gboolean linked;
   775     GstPlayBinMaemo *pbm;
   776 
   777     pbm = GST_PLAY_BIN_MAEMO (user_data);
   778     caps = gst_pad_get_caps (pad);
   779 
   780     g_debug ("new_decoded_pad_cb: %s", gst_caps_to_string (caps));
   781 
   782     comp = find_compatibles (GST_PLAY_BIN_MAEMO (user_data), caps);
   783 
   784 
   785     if (comp == NULL) {
   786         g_warning ("flow error: dont find comaptible");
   787         return;
   788     }
   789 
   790     GST_PAD_STREAM_LOCK (pad);
   791 
   792     linked = FALSE;
   793     for (walk=comp; walk != NULL; walk = walk->next) {
   794         GstElementFactory *factory = (GstElementFactory *) walk->data;
   795         GstElement *element;
   796         GstPad *sinkpad = NULL;
   797 
   798         if ((element = create_element (pbm, factory)) == NULL) {
   799             GST_WARNING_OBJECT (pbm, "Could not create an element from %s",
   800                 gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
   801             g_debug ("Could not create an element from %s",
   802                 gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
   803 
   804             continue;
   805         }
   806 
   807         if (!(add_element (GST_PLAY_BIN_MAEMO (user_data), element))) {
   808             GST_WARNING_OBJECT (pbm, "Couldn't set %s to READY", GST_ELEMENT_NAME (element));
   809             gst_object_unref (element);
   810             continue;
   811         }
   812 
   813         if ((gst_element_set_state (element, GST_STATE_READY))
   814                          == GST_STATE_CHANGE_FAILURE) {
   815             gst_element_set_state (element, GST_STATE_NULL);
   816             gst_object_unref (sinkpad);
   817             gst_bin_remove (GST_BIN (user_data), element);
   818             continue;
   819         }
   820 
   821         if (!(sinkpad = find_sink_pad (element))) {
   822             GST_WARNING_OBJECT (pbm, "Element %s doesn't have a sink pad", GST_ELEMENT_NAME (element));
   823             g_debug ("Element %s doesn't have a sink pad", GST_ELEMENT_NAME (element));
   824             gst_object_unref (element);
   825             continue;
   826         }
   827 
   828 
   829         if ((gst_pad_link (pad, sinkpad)) != GST_PAD_LINK_OK) {
   830             GST_WARNING_OBJECT (pbm, "Link failed on pad %s:%s", GST_DEBUG_PAD_NAME (sinkpad));
   831             gst_element_set_state (element, GST_STATE_NULL);
   832             gst_object_unref (sinkpad);
   833             gst_bin_remove (GST_BIN (user_data), element);
   834             continue;
   835         }
   836 
   837         gst_object_unref (sinkpad);
   838 
   839         if ((gst_element_set_state (element, GST_STATE_PAUSED)) == GST_STATE_CHANGE_FAILURE) {
   840             gst_element_set_state (element, GST_STATE_NULL);
   841             gst_bin_remove (GST_BIN (user_data), element);
   842             continue;
   843         }
   844 
   845         linked = TRUE;
   846         break;
   847     }
   848 
   849     g_list_free (comp);
   850     if (linked == FALSE) {
   851         g_warning ("GstFlow ERROR");
   852     }
   853     GST_PAD_STREAM_UNLOCK (pad);
   854 }
   855 
   856 static void
   857 update_volume (GstPlayBinMaemo *pbm)
   858 {
   859     if (pbm->volume_element != NULL) {
   860         if (pbm->volume > 0) {
   861             g_object_set (G_OBJECT (pbm->volume_element),
   862                           "volume", pbm->volume,
   863                           NULL);
   864         } else {
   865             g_object_set (G_OBJECT (pbm->volume_element),
   866                           "mute", TRUE,
   867                           NULL);
   868         }
   869     }
   870 }
   871 
   872 static void
   873 update_xid (GstPlayBinMaemo *pbm)
   874 {
   875     if ((pbm->sink_video != NULL) &&
   876         (pbm->xid != -1) &&
   877         (GST_IS_X_OVERLAY (pbm->sink_video))) {
   878 
   879         Display *display;
   880         g_object_set (G_OBJECT (pbm->sink_video),
   881                       "force-aspect-ratio", TRUE, NULL);
   882         display = XOpenDisplay(NULL);
   883         XMapRaised(display, pbm->xid);
   884         XSync (display, FALSE);
   885 
   886         gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (pbm->sink_video),
   887                                       pbm->xid);
   888     }
   889 }
   890 
   891 static gboolean
   892 add_element (GstPlayBinMaemo *pbm,
   893              GstElement *child)
   894 {
   895     if (gst_bin_add (GST_BIN (pbm), child)) {
   896         pbm->elements = g_list_append (pbm->elements, child);
   897         return TRUE;
   898     }
   899     return FALSE;
   900 }
   901 
   902 static void
   903 clear_elements (GstPlayBinMaemo *pbm)
   904 {
   905     GList *walk;
   906 
   907     walk = pbm->elements;
   908 
   909     for (; walk != NULL; walk = walk->next) {
   910         GstElement *e = GST_ELEMENT (walk->data);
   911 
   912         gst_element_set_state (e, GST_STATE_NULL);
   913         gst_bin_remove (GST_BIN (pbm), e);
   914     }
   915 
   916     g_list_free (pbm->elements);
   917     pbm->elements = NULL;
   918     pbm->source = NULL;
   919     pbm->volume_element = NULL;
   920     pbm->sink_video = NULL;
   921 }
   922 
   923 static gboolean
   924 plugin_init(GstPlugin * plugin)
   925 {
   926 #ifdef ENABLE_NLS
   927     setlocale(LC_ALL, "");
   928     bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
   929 #endif                          /* ENABLE_NLS */
   930 
   931     if (!gst_element_register(plugin, "playbinmaemo", GST_RANK_SECONDARY,
   932                               GST_TYPE_PLAY_BIN_MAEMO)) {
   933         return FALSE;
   934     }
   935 
   936     return TRUE;
   937 }
   938 
   939 GST_PLUGIN_DEFINE(GST_VERSION_MAJOR,
   940                   GST_VERSION_MINOR,
   941                   "playbinmaemo",
   942                   "A playbin element that uses decodebin2 for automatic playback of audio and video",
   943                   plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME,
   944                   GST_PACKAGE_ORIGIN)