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