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