gst_plugins_base/gst/playback/gstplaybin2.c
changeset 0 0e761a78d257
child 8 4a7fac7dd34a
equal deleted inserted replaced
-1:000000000000 0:0e761a78d257
       
     1 /* GStreamer
       
     2  * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
       
     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 /**
       
    21  * SECTION:element-playbin2
       
    22  *
       
    23  * <refsect2>
       
    24  * <para>
       
    25  * Playbin provides a stand-alone everything-in-one abstraction for an
       
    26  * audio and/or video player.
       
    27  * </para>
       
    28  * <para>
       
    29  * It can handle both audio and video files and features
       
    30  * <itemizedlist>
       
    31  * <listitem>
       
    32  * automatic file type recognition and based on that automatic
       
    33  * selection and usage of the right audio/video/subtitle demuxers/decoders
       
    34  * </listitem>
       
    35  * <listitem>
       
    36  * visualisations for audio files
       
    37  * </listitem>
       
    38  * <listitem>
       
    39  * subtitle support for video files
       
    40  * </listitem>
       
    41  * <listitem>
       
    42  * stream selection between different audio/subtitles streams
       
    43  * </listitem>
       
    44  * <listitem>
       
    45  * meta info (tag) extraction
       
    46  * </listitem>
       
    47  * <listitem>
       
    48  * easy access to the last video frame
       
    49  * </listitem>
       
    50  * <listitem>
       
    51  * buffering when playing streams over a network
       
    52  * </listitem>
       
    53  * <listitem>
       
    54  * volume control
       
    55  * </listitem>
       
    56  * </itemizedlist>
       
    57  * </para>
       
    58  * <title>Usage</title>
       
    59  * <para>
       
    60  * A playbin element can be created just like any other element using
       
    61  * gst_element_factory_make(). The file/URI to play should be set via the "uri"
       
    62  * property. This must be an absolute URI, relative file paths are not allowed.
       
    63  * Example URIs are file:///home/joe/movie.avi or http://www.joedoe.com/foo.ogg
       
    64  * </para>
       
    65  * <para>
       
    66  * Playbin is a #GstPipeline. It will notify the application of everything
       
    67  * that's happening (errors, end of stream, tags found, state changes, etc.)
       
    68  * by posting messages on its #GstBus. The application needs to watch the
       
    69  * bus.
       
    70  * </para>
       
    71  * <para>
       
    72  * Playback can be initiated by setting the element to PLAYING state using
       
    73  * gst_element_set_state(). Note that the state change will take place in
       
    74  * the background in a separate thread, when the function returns playback
       
    75  * is probably not happening yet and any errors might not have occured yet.
       
    76  * Applications using playbin should ideally be written to deal with things
       
    77  * completely asynchroneous.
       
    78  * </para>
       
    79  * <para>
       
    80  * When playback has finished (an EOS message has been received on the bus)
       
    81  * or an error has occured (an ERROR message has been received on the bus) or
       
    82  * the user wants to play a different track, playbin should be set back to
       
    83  * READY or NULL state, then the "uri" property should be set to the new
       
    84  * location and then playbin be set to PLAYING state again.
       
    85  * </para>
       
    86  * <para>
       
    87  * Seeking can be done using gst_element_seek_simple() or gst_element_seek()
       
    88  * on the playbin element. Again, the seek will not be executed
       
    89  * instantaneously, but will be done in a background thread. When the seek
       
    90  * call returns the seek will most likely still be in process. An application
       
    91  * may wait for the seek to finish (or fail) using gst_element_get_state() with
       
    92  * -1 as the timeout, but this will block the user interface and is not
       
    93  * recommended at all.
       
    94  * </para>
       
    95  * <para>
       
    96  * Applications may query the current position and duration of the stream
       
    97  * via gst_element_query_position() and gst_element_query_duration() and
       
    98  * setting the format passed to GST_FORMAT_TIME. If the query was successful,
       
    99  * the duration or position will have been returned in units of nanoseconds.
       
   100  * </para>
       
   101  * <title>Advanced Usage: specifying the audio and video sink</title>
       
   102  * <para>
       
   103  * By default, if no audio sink or video sink has been specified via the
       
   104  * "audio-sink" or "video-sink" property, playbin will use the autoaudiosink
       
   105  * and autovideosink elements to find the first-best available output method.
       
   106  * This should work in most cases, but is not always desirable. Often either
       
   107  * the user or application might want to specify more explicitly what to use
       
   108  * for audio and video output.
       
   109  * </para>
       
   110  * <para>
       
   111  * If the application wants more control over how audio or video should be
       
   112  * output, it may create the audio/video sink elements itself (for example
       
   113  * using gst_element_factory_make()) and provide them to playbin using the
       
   114  * "audio-sink" or "video-sink" property.
       
   115  * </para>
       
   116  * <para>
       
   117  * GNOME-based applications, for example, will usually want to create
       
   118  * gconfaudiosink and gconfvideosink elements and make playbin use those,
       
   119  * so that output happens to whatever the user has configured in the GNOME
       
   120  * Multimedia System Selector confinguration dialog.
       
   121  * </para>
       
   122  * <para>
       
   123  * The sink elements do not necessarily need to be ready-made sinks. It is
       
   124  * possible to create container elements that look like a sink to playbin,
       
   125  * but in reality contain a number of custom elements linked together. This
       
   126  * can be achieved by creating a #GstBin and putting elements in there and
       
   127  * linking them, and then creating a sink #GstGhostPad for the bin and pointing
       
   128  * it to the sink pad of the first element within the bin. This can be used
       
   129  * for a number of purposes, for example to force output to a particular
       
   130  * format or to modify or observe the data before it is output.
       
   131  * </para>
       
   132  * <para>
       
   133  * It is also possible to 'suppress' audio and/or video output by using
       
   134  * 'fakesink' elements (or capture it from there using the fakesink element's
       
   135  * "handoff" signal, which, nota bene, is fired from the streaming thread!).
       
   136  * </para>
       
   137  * <title>Retrieving Tags and Other Meta Data</title>
       
   138  * <para>
       
   139  * Most of the common meta data (artist, title, etc.) can be retrieved by
       
   140  * watching for TAG messages on the pipeline's bus (see above).
       
   141  * </para>
       
   142  * <para>
       
   143  * Other more specific meta information like width/height/framerate of video
       
   144  * streams or samplerate/number of channels of audio streams can be obtained
       
   145  * using the "stream-info" property, which will return a GList of stream info
       
   146  * objects, one for each stream. These are opaque objects that can only be
       
   147  * accessed via the standard GObject property interface, ie. g_object_get().
       
   148  * Each stream info object has the following properties:
       
   149  * <itemizedlist>
       
   150  * <listitem>"object" (GstObject) (the decoder source pad usually)</listitem>
       
   151  * <listitem>"type" (enum) (if this is an audio/video/subtitle stream)</listitem>
       
   152  * <listitem>"decoder" (string) (name of decoder used to decode this stream)</listitem>
       
   153  * <listitem>"mute" (boolean) (to mute or unmute this stream)</listitem>
       
   154  * <listitem>"caps" (GstCaps) (caps of the decoded stream)</listitem>
       
   155  * <listitem>"language-code" (string) (ISO-639 language code for this stream, mostly used for audio/subtitle streams)</listitem>
       
   156  * <listitem>"codec" (string) (format this stream was encoded in)</listitem>
       
   157  * </itemizedlist>
       
   158  * Stream information from the stream-info properties is best queried once
       
   159  * playbin has changed into PAUSED or PLAYING state (which can be detected
       
   160  * via a state-changed message on the bus where old_state=READY and
       
   161  * new_state=PAUSED), since before that the list might not be complete yet or
       
   162  * not contain all available information (like language-codes).
       
   163  * </para>
       
   164  * <title>Buffering</title>
       
   165  * <para>
       
   166  * Playbin handles buffering automatically for the most part, but applications
       
   167  * need to handle parts of the buffering process as well. Whenever playbin is
       
   168  * buffering, it will post BUFFERING messages on the bus with a percentage
       
   169  * value that shows the progress of the buffering process. Applications need
       
   170  * to set playbin to PLAYING or PAUSED state in response to these messages.
       
   171  * They may also want to convey the buffering progress to the user in some
       
   172  * way. Here is how to extract the percentage information from the message
       
   173  * (requires GStreamer >= 0.10.11):
       
   174  * </para>
       
   175  * <para>
       
   176  * <programlisting>
       
   177  * switch (GST_MESSAGE_TYPE (msg)) {
       
   178  *   case GST_MESSAGE_BUFFERING: {
       
   179  *     gint percent = 0;
       
   180  *     gst_message_parse_buffering (msg, &amp;percent);
       
   181  *     g_print ("Buffering (%%u percent done)", percent);
       
   182  *     break;
       
   183  *   }
       
   184  *   ...
       
   185  * }
       
   186  * </programlisting>
       
   187  * Note that applications should keep/set the pipeline in the PAUSED state when
       
   188  * a BUFFERING message is received with a buffer percent value < 100 and set
       
   189  * the pipeline back to PLAYING state when a BUFFERING message with a value
       
   190  * of 100 percent is received (if PLAYING is the desired state, that is).
       
   191  * </para>
       
   192  * <title>Embedding the video window in your application</title>
       
   193  * <para>
       
   194  * By default, playbin (or rather the video sinks used) will create their own
       
   195  * window. Applications will usually want to force output to a window of their
       
   196  * own, however. This can be done using the GstXOverlay interface, which most
       
   197  * video sinks implement. See the documentation there for more details.
       
   198  * </para>
       
   199  * <title>Specifying which CD/DVD device to use</title>
       
   200  * <para>
       
   201  * The device to use for CDs/DVDs needs to be set on the source element
       
   202  * playbin creates before it is opened. The only way to do this at the moment
       
   203  * is to connect to playbin's "notify::source" signal, which will be emitted
       
   204  * by playbin when it has created the source element for a particular URI.
       
   205  * In the signal callback you can check if the source element has a "device"
       
   206  * property and set it appropriately. In future ways might be added to specify
       
   207  * the device as part of the URI, but at the time of writing this is not
       
   208  * possible yet.
       
   209  * </para>
       
   210  * <title>Examples</title>
       
   211  * <para>
       
   212  * Here is a simple pipeline to play back a video or audio file:
       
   213  * <programlisting>
       
   214  * gst-launch -v playbin uri=file:///path/to/somefile.avi
       
   215  * </programlisting>
       
   216  * This will play back the given AVI video file, given that the video and
       
   217  * audio decoders required to decode the content are installed. Since no
       
   218  * special audio sink or video sink is supplied (not possible via gst-launch),
       
   219  * playbin will try to find a suitable audio and video sink automatically
       
   220  * using the autoaudiosink and autovideosink elements.
       
   221  * </para>
       
   222  * <para>
       
   223  * Here is a another pipeline to play track 4 of an audio CD:
       
   224  * <programlisting>
       
   225  * gst-launch -v playbin uri=cdda://4
       
   226  * </programlisting>
       
   227  * This will play back track 4 on an audio CD in your disc drive (assuming
       
   228  * the drive is detected automatically by the plugin).
       
   229  * </para>
       
   230  * <para>
       
   231  * Here is a another pipeline to play title 1 of a DVD:
       
   232  * <programlisting>
       
   233  * gst-launch -v playbin uri=dvd://1
       
   234  * </programlisting>
       
   235  * This will play back title 1 of a DVD in your disc drive (assuming
       
   236  * the drive is detected automatically by the plugin).
       
   237  * </para>
       
   238  * </refsect2>
       
   239  */
       
   240 
       
   241 #ifdef HAVE_CONFIG_H
       
   242 #include "config.h"
       
   243 #endif
       
   244 
       
   245 #include <string.h>
       
   246 #include <gst/gst.h>
       
   247 
       
   248 #include <gst/gst-i18n-plugin.h>
       
   249 #include <gst/pbutils/pbutils.h>
       
   250 
       
   251 #include "gstplay-enum.h"
       
   252 #include "gstplay-marshal.h"
       
   253 #include "gstplaysink.h"
       
   254 #include "gstfactorylists.h"
       
   255 #include "gstscreenshot.h"
       
   256 #include "gststreaminfo.h"
       
   257 #include "gststreamselector.h"
       
   258 
       
   259 #ifdef __SYMBIAN32__
       
   260 #include <glib_global.h>
       
   261 #endif
       
   262 GST_DEBUG_CATEGORY_STATIC (gst_play_bin_debug);
       
   263 #define GST_CAT_DEFAULT gst_play_bin_debug
       
   264 
       
   265 #define GST_TYPE_PLAY_BIN               (gst_play_bin_get_type())
       
   266 #define GST_PLAY_BIN(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PLAY_BIN,GstPlayBin))
       
   267 #define GST_PLAY_BIN_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PLAY_BIN,GstPlayBinClass))
       
   268 #define GST_IS_PLAY_BIN(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PLAY_BIN))
       
   269 #define GST_IS_PLAY_BIN_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PLAY_BIN))
       
   270 
       
   271 #define VOLUME_MAX_DOUBLE 10.0
       
   272 
       
   273 typedef struct _GstPlayBin GstPlayBin;
       
   274 typedef struct _GstPlayBinClass GstPlayBinClass;
       
   275 typedef struct _GstSourceGroup GstSourceGroup;
       
   276 typedef struct _GstSourceSelect GstSourceSelect;
       
   277 
       
   278 /* has the info for a selector and provides the link to the sink */
       
   279 struct _GstSourceSelect
       
   280 {
       
   281   const gchar *media;           /* the media type of the selector */
       
   282   GstPlaySinkType type;         /* the sink pad type of the selector */
       
   283 
       
   284   GstElement *selector;         /* the selector */
       
   285   GPtrArray *channels;
       
   286   GstPad *srcpad;               /* the source pad of the selector */
       
   287   GstPad *sinkpad;              /* the sinkpad of the sink when the selector is linked */
       
   288 };
       
   289 
       
   290 /* a structure to hold the objects for decoding a uri and the subtitle uri
       
   291  */
       
   292 struct _GstSourceGroup
       
   293 {
       
   294   GstPlayBin *playbin;
       
   295 
       
   296   gboolean valid;               /* the group has valid info to start playback */
       
   297   gboolean active;              /* the group is active */
       
   298 
       
   299   /* properties */
       
   300   gchar *uri;
       
   301   gchar *suburi;
       
   302   GValueArray *streaminfo;
       
   303   GstElement *source;
       
   304   gchar *subencoding;           /* encoding to propagate to the subtitle elements */
       
   305 
       
   306   GPtrArray *video_channels;    /* links to selector pads */
       
   307   GPtrArray *audio_channels;    /* links to selector pads */
       
   308   GPtrArray *text_channels;     /* links to selector pads */
       
   309 
       
   310   /* uridecodebins for uri and subtitle uri */
       
   311   GstElement *uridecodebin;
       
   312   GstElement *suburidecodebin;
       
   313 
       
   314   /* selectors for different streams */
       
   315   GstSourceSelect selector[GST_PLAY_SINK_TYPE_LAST];
       
   316 };
       
   317 
       
   318 struct _GstPlayBin
       
   319 {
       
   320   GstPipeline parent;
       
   321 
       
   322   /* the groups, we use a double buffer to switch between current and next */
       
   323   GstSourceGroup groups[2];     /* array with group info */
       
   324   GstSourceGroup *curr_group;   /* pointer to the currently playing group */
       
   325   GstSourceGroup *next_group;   /* pointer to the next group */
       
   326 
       
   327   gboolean about_to_finish;     /* the about-to-finish signal is emited */
       
   328 
       
   329   /* properties */
       
   330   guint connection_speed;       /* connection speed in bits/sec (0 = unknown) */
       
   331   gint current_video;           /* the currently selected stream */
       
   332   gint current_audio;           /* the currently selected stream */
       
   333   gint current_text;            /* the currently selected stream */
       
   334 
       
   335   /* our play sink */
       
   336   GstPlaySink *playsink;
       
   337 
       
   338   GValueArray *elements;        /* factories we can use for selecting elements */
       
   339 };
       
   340 
       
   341 struct _GstPlayBinClass
       
   342 {
       
   343   GstPipelineClass parent_class;
       
   344 
       
   345   /* notify app that the current uri finished decoding and it is possible to
       
   346    * queue a new one for gapless playback */
       
   347   void (*about_to_finish) (GstPlayBin * playbin);
       
   348 
       
   349   /* notify app that number of audio/video/text streams changed */
       
   350   void (*video_changed) (GstPlayBin * playbin);
       
   351   void (*audio_changed) (GstPlayBin * playbin);
       
   352   void (*text_changed) (GstPlayBin * playbin);
       
   353 
       
   354   /* get audio/video/text tags for a stream */
       
   355   GstTagList *(*get_video_tags) (GstPlayBin * playbin, gint stream);
       
   356   GstTagList *(*get_audio_tags) (GstPlayBin * playbin, gint stream);
       
   357   GstTagList *(*get_text_tags) (GstPlayBin * playbin, gint stream);
       
   358 
       
   359   /* get the last video frame and convert it to the given caps */
       
   360   GstBuffer *(*convert_frame) (GstPlayBin * playbin, GstCaps * caps);
       
   361 };
       
   362 
       
   363 /* props */
       
   364 #define DEFAULT_URI               NULL
       
   365 #define DEFAULT_SUBURI            NULL
       
   366 #define DEFAULT_SOURCE            NULL
       
   367 #define DEFAULT_FLAGS             GST_PLAY_FLAG_AUDIO | GST_PLAY_FLAG_VIDEO | GST_PLAY_FLAG_TEXT | \
       
   368 	                          GST_PLAY_FLAG_SOFT_VOLUME
       
   369 #define DEFAULT_N_VIDEO           0
       
   370 #define DEFAULT_CURRENT_VIDEO     -1
       
   371 #define DEFAULT_N_AUDIO           0
       
   372 #define DEFAULT_CURRENT_AUDIO     -1
       
   373 #define DEFAULT_N_TEXT            0
       
   374 #define DEFAULT_CURRENT_TEXT      -1
       
   375 #define DEFAULT_SUBTITLE_ENCODING NULL
       
   376 #define DEFAULT_AUDIO_SINK        NULL
       
   377 #define DEFAULT_VIDEO_SINK        NULL
       
   378 #define DEFAULT_VIS_PLUGIN        NULL
       
   379 #define DEFAULT_VOLUME            1.0
       
   380 #define DEFAULT_MUTE              FALSE
       
   381 #define DEFAULT_FRAME             NULL
       
   382 #define DEFAULT_FONT_DESC         NULL
       
   383 #define DEFAULT_CONNECTION_SPEED  0
       
   384 
       
   385 enum
       
   386 {
       
   387   PROP_0,
       
   388   PROP_URI,
       
   389   PROP_SUBURI,
       
   390   PROP_SOURCE,
       
   391   PROP_FLAGS,
       
   392   PROP_N_VIDEO,
       
   393   PROP_CURRENT_VIDEO,
       
   394   PROP_N_AUDIO,
       
   395   PROP_CURRENT_AUDIO,
       
   396   PROP_N_TEXT,
       
   397   PROP_CURRENT_TEXT,
       
   398   PROP_SUBTITLE_ENCODING,
       
   399   PROP_AUDIO_SINK,
       
   400   PROP_VIDEO_SINK,
       
   401   PROP_VIS_PLUGIN,
       
   402   PROP_VOLUME,
       
   403   PROP_MUTE,
       
   404   PROP_FRAME,
       
   405   PROP_FONT_DESC,
       
   406   PROP_CONNECTION_SPEED
       
   407 };
       
   408 
       
   409 /* signals */
       
   410 enum
       
   411 {
       
   412   SIGNAL_ABOUT_TO_FINISH,
       
   413   SIGNAL_VIDEO_CHANGED,
       
   414   SIGNAL_AUDIO_CHANGED,
       
   415   SIGNAL_TEXT_CHANGED,
       
   416   SIGNAL_GET_VIDEO_TAGS,
       
   417   SIGNAL_GET_AUDIO_TAGS,
       
   418   SIGNAL_GET_TEXT_TAGS,
       
   419   LAST_SIGNAL
       
   420 };
       
   421 
       
   422 static void gst_play_bin_class_init (GstPlayBinClass * klass);
       
   423 static void gst_play_bin_init (GstPlayBin * playbin);
       
   424 static void gst_play_bin_finalize (GObject * object);
       
   425 
       
   426 static void gst_play_bin_set_property (GObject * object, guint prop_id,
       
   427     const GValue * value, GParamSpec * spec);
       
   428 static void gst_play_bin_get_property (GObject * object, guint prop_id,
       
   429     GValue * value, GParamSpec * spec);
       
   430 
       
   431 static GstStateChangeReturn gst_play_bin_change_state (GstElement * element,
       
   432     GstStateChange transition);
       
   433 
       
   434 static void gst_play_bin_handle_message (GstBin * bin, GstMessage * message);
       
   435 
       
   436 static GstTagList *gst_play_bin_get_video_tags (GstPlayBin * playbin,
       
   437     gint stream);
       
   438 static GstTagList *gst_play_bin_get_audio_tags (GstPlayBin * playbin,
       
   439     gint stream);
       
   440 static GstTagList *gst_play_bin_get_text_tags (GstPlayBin * playbin,
       
   441     gint stream);
       
   442 
       
   443 static GstBuffer *gst_play_bin_convert_frame (GstPlayBin * playbin,
       
   444     GstCaps * caps);
       
   445 
       
   446 static gboolean setup_next_source (GstPlayBin * playbin);
       
   447 
       
   448 static GstElementClass *parent_class;
       
   449 
       
   450 static guint gst_play_bin_signals[LAST_SIGNAL] = { 0 };
       
   451 
       
   452 static const GstElementDetails gst_play_bin_details =
       
   453 GST_ELEMENT_DETAILS ("Player Bin 2",
       
   454     "Generic/Bin/Player",
       
   455     "Autoplug and play media from an uri",
       
   456     "Wim Taymans <wim.taymans@gmail.com>");
       
   457 
       
   458 static void
       
   459 gst_play_marshal_BUFFER__BOXED (GClosure * closure,
       
   460     GValue * return_value G_GNUC_UNUSED,
       
   461     guint n_param_values,
       
   462     const GValue * param_values,
       
   463     gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data)
       
   464 {
       
   465   typedef GstBuffer *(*GMarshalFunc_OBJECT__BOXED) (gpointer data1,
       
   466       gpointer arg_1, gpointer data2);
       
   467   register GMarshalFunc_OBJECT__BOXED callback;
       
   468   register GCClosure *cc = (GCClosure *) closure;
       
   469   register gpointer data1, data2;
       
   470   GstBuffer *v_return;
       
   471 
       
   472   g_return_if_fail (return_value != NULL);
       
   473   g_return_if_fail (n_param_values == 2);
       
   474 
       
   475   if (G_CCLOSURE_SWAP_DATA (closure)) {
       
   476     data1 = closure->data;
       
   477     data2 = g_value_peek_pointer (param_values + 0);
       
   478   } else {
       
   479     data1 = g_value_peek_pointer (param_values + 0);
       
   480     data2 = closure->data;
       
   481   }
       
   482   callback =
       
   483       (GMarshalFunc_OBJECT__BOXED) (marshal_data ? marshal_data : cc->callback);
       
   484 
       
   485   v_return = callback (data1, g_value_get_boxed (param_values + 1), data2);
       
   486 
       
   487   gst_value_take_buffer (return_value, v_return);
       
   488 }
       
   489 
       
   490 static GType
       
   491 gst_play_bin_get_type (void)
       
   492 {
       
   493   static GType gst_play_bin_type = 0;
       
   494 
       
   495   if (!gst_play_bin_type) {
       
   496     static const GTypeInfo gst_play_bin_info = {
       
   497       sizeof (GstPlayBinClass),
       
   498       NULL,
       
   499       NULL,
       
   500       (GClassInitFunc) gst_play_bin_class_init,
       
   501       NULL,
       
   502       NULL,
       
   503       sizeof (GstPlayBin),
       
   504       0,
       
   505       (GInstanceInitFunc) gst_play_bin_init,
       
   506       NULL
       
   507     };
       
   508 
       
   509     gst_play_bin_type = g_type_register_static (GST_TYPE_PIPELINE,
       
   510         "GstPlayBin2", &gst_play_bin_info, 0);
       
   511   }
       
   512 
       
   513   return gst_play_bin_type;
       
   514 }
       
   515 
       
   516 static void
       
   517 gst_play_bin_class_init (GstPlayBinClass * klass)
       
   518 {
       
   519   GObjectClass *gobject_klass;
       
   520   GstElementClass *gstelement_klass;
       
   521   GstBinClass *gstbin_klass;
       
   522 
       
   523   gobject_klass = (GObjectClass *) klass;
       
   524   gstelement_klass = (GstElementClass *) klass;
       
   525   gstbin_klass = (GstBinClass *) klass;
       
   526 
       
   527   parent_class = g_type_class_peek_parent (klass);
       
   528 
       
   529   gobject_klass->set_property = gst_play_bin_set_property;
       
   530   gobject_klass->get_property = gst_play_bin_get_property;
       
   531 
       
   532   gobject_klass->finalize = GST_DEBUG_FUNCPTR (gst_play_bin_finalize);
       
   533 
       
   534   /**
       
   535    * GstPlayBin:uri
       
   536    *
       
   537    * Set the next URI that playbin will play. This property can be set from the
       
   538    * about-to-finish signal to queue the next media file.
       
   539    */
       
   540   g_object_class_install_property (gobject_klass, PROP_URI,
       
   541       g_param_spec_string ("uri", "URI", "URI of the media to play",
       
   542           NULL, G_PARAM_READWRITE));
       
   543 
       
   544   /**
       
   545    * GstPlayBin:suburi
       
   546    *
       
   547    * Set the next subtitle URI that playbin will play. This property can be
       
   548    * set from the about-to-finish signal to queue the next subtitle media file.
       
   549    */
       
   550   g_object_class_install_property (gobject_klass, PROP_SUBURI,
       
   551       g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle",
       
   552           NULL, G_PARAM_READWRITE));
       
   553 
       
   554   g_object_class_install_property (gobject_klass, PROP_SOURCE,
       
   555       g_param_spec_object ("source", "Source", "Source element",
       
   556           GST_TYPE_ELEMENT, G_PARAM_READABLE));
       
   557 
       
   558 
       
   559   /**
       
   560    * GstPlayBin:flags
       
   561    *
       
   562    * Control the behaviour of playbin.
       
   563    */
       
   564   g_object_class_install_property (gobject_klass, PROP_FLAGS,
       
   565       g_param_spec_flags ("flags", "Flags", "Flags to control behaviour",
       
   566           GST_TYPE_PLAY_FLAGS, DEFAULT_FLAGS, G_PARAM_READWRITE));
       
   567 
       
   568   /**
       
   569    * GstPlayBin:n-video
       
   570    *
       
   571    * Get the total number of available video streams. 
       
   572    */
       
   573   g_object_class_install_property (gobject_klass, PROP_N_VIDEO,
       
   574       g_param_spec_int ("n-video", "Number Video",
       
   575           "Total number of video streams", 0, G_MAXINT, 0, G_PARAM_READABLE));
       
   576   /**
       
   577    * GstPlayBin:current-video
       
   578    *
       
   579    * Get or set the currently playing video stream. By default the first video
       
   580    * stream with data is played.
       
   581    */
       
   582   g_object_class_install_property (gobject_klass, PROP_CURRENT_VIDEO,
       
   583       g_param_spec_int ("current-video", "Current Video",
       
   584           "Currently playing video stream (-1 = auto)",
       
   585           -1, G_MAXINT, -1, G_PARAM_READWRITE));
       
   586   /**
       
   587    * GstPlayBin:n-audio
       
   588    *
       
   589    * Get the total number of available audio streams. 
       
   590    */
       
   591   g_object_class_install_property (gobject_klass, PROP_N_AUDIO,
       
   592       g_param_spec_int ("n-audio", "Number Audio",
       
   593           "Total number of audio streams", 0, G_MAXINT, 0, G_PARAM_READABLE));
       
   594   /**
       
   595    * GstPlayBin:current-audio
       
   596    *
       
   597    * Get or set the currently playing audio stream. By default the first audio
       
   598    * stream with data is played.
       
   599    */
       
   600   g_object_class_install_property (gobject_klass, PROP_CURRENT_AUDIO,
       
   601       g_param_spec_int ("current-audio", "Current audio",
       
   602           "Currently playing audio stream (-1 = auto)",
       
   603           -1, G_MAXINT, -1, G_PARAM_READWRITE));
       
   604   /**
       
   605    * GstPlayBin:n-text
       
   606    *
       
   607    * Get the total number of available subtitle streams. 
       
   608    */
       
   609   g_object_class_install_property (gobject_klass, PROP_N_TEXT,
       
   610       g_param_spec_int ("n-text", "Number Text",
       
   611           "Total number of text streams", 0, G_MAXINT, 0, G_PARAM_READABLE));
       
   612   /**
       
   613    * GstPlayBin:current-text
       
   614    *
       
   615    * Get or set the currently playing subtitle stream. By default the first
       
   616    * subtitle stream with data is played.
       
   617    */
       
   618   g_object_class_install_property (gobject_klass, PROP_CURRENT_TEXT,
       
   619       g_param_spec_int ("current-text", "Current Text",
       
   620           "Currently playing text stream (-1 = auto)",
       
   621           -1, G_MAXINT, -1, G_PARAM_READWRITE));
       
   622 
       
   623   g_object_class_install_property (gobject_klass, PROP_SUBTITLE_ENCODING,
       
   624       g_param_spec_string ("subtitle-encoding", "subtitle encoding",
       
   625           "Encoding to assume if input subtitles are not in UTF-8 encoding. "
       
   626           "If not set, the GST_SUBTITLE_ENCODING environment variable will "
       
   627           "be checked for an encoding to use. If that is not set either, "
       
   628           "ISO-8859-15 will be assumed.", NULL, G_PARAM_READWRITE));
       
   629 
       
   630   g_object_class_install_property (gobject_klass, PROP_VIDEO_SINK,
       
   631       g_param_spec_object ("video-sink", "Video Sink",
       
   632           "the video output element to use (NULL = default sink)",
       
   633           GST_TYPE_ELEMENT, G_PARAM_READWRITE));
       
   634   g_object_class_install_property (gobject_klass, PROP_AUDIO_SINK,
       
   635       g_param_spec_object ("audio-sink", "Audio Sink",
       
   636           "the audio output element to use (NULL = default sink)",
       
   637           GST_TYPE_ELEMENT, G_PARAM_READWRITE));
       
   638   g_object_class_install_property (gobject_klass, PROP_VIS_PLUGIN,
       
   639       g_param_spec_object ("vis-plugin", "Vis plugin",
       
   640           "the visualization element to use (NULL = none)",
       
   641           GST_TYPE_ELEMENT, G_PARAM_READWRITE));
       
   642 
       
   643   g_object_class_install_property (gobject_klass, PROP_VOLUME,
       
   644       g_param_spec_double ("volume", "Volume", "The audio volume",
       
   645           0.0, VOLUME_MAX_DOUBLE, 1.0, G_PARAM_READWRITE));
       
   646   g_object_class_install_property (gobject_klass, PROP_MUTE,
       
   647       g_param_spec_boolean ("mute", "Mute",
       
   648           "Mute the audio channel without changing the volume", FALSE,
       
   649           G_PARAM_READWRITE));
       
   650 
       
   651   /**
       
   652    * GstPlayBin::frame
       
   653    * @playbin: a #GstPlayBin
       
   654    *
       
   655    * Get the currently rendered or prerolled frame in the sink.
       
   656    * The #GstCaps on the buffer will describe the format of the buffer.
       
   657    */
       
   658   g_object_class_install_property (gobject_klass, PROP_FRAME,
       
   659       gst_param_spec_mini_object ("frame", "Frame",
       
   660           "The last frame (NULL = no video available)",
       
   661           GST_TYPE_BUFFER, G_PARAM_READABLE));
       
   662   g_object_class_install_property (gobject_klass, PROP_FONT_DESC,
       
   663       g_param_spec_string ("subtitle-font-desc",
       
   664           "Subtitle font description",
       
   665           "Pango font description of font "
       
   666           "to be used for subtitle rendering", NULL, G_PARAM_WRITABLE));
       
   667 
       
   668   g_object_class_install_property (gobject_klass, PROP_CONNECTION_SPEED,
       
   669       g_param_spec_uint ("connection-speed", "Connection Speed",
       
   670           "Network connection speed in kbps (0 = unknown)",
       
   671           0, G_MAXUINT, DEFAULT_CONNECTION_SPEED, G_PARAM_READWRITE));
       
   672   /**
       
   673    * GstPlayBin::about-to-finish:
       
   674    * @playbin: a #GstPlayBin
       
   675    *
       
   676    * This signal is emitted when the current uri is about to finish. You can
       
   677    * set the next-uri and next-suburi to make sure that playback continues.
       
   678    */
       
   679   gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH] =
       
   680       g_signal_new ("about-to-finish", G_TYPE_FROM_CLASS (klass),
       
   681       G_SIGNAL_RUN_LAST,
       
   682       G_STRUCT_OFFSET (GstPlayBinClass, about_to_finish), NULL, NULL,
       
   683       gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
       
   684 
       
   685   /**
       
   686    * GstPlayBin::video-changed
       
   687    * @playbin: a #GstPlayBin
       
   688    *
       
   689    * This signal is emited whenever the number or order of the video
       
   690    * streams has changed. The application will most likely want to select
       
   691    * a new video stream.
       
   692    */
       
   693   gst_play_bin_signals[SIGNAL_VIDEO_CHANGED] =
       
   694       g_signal_new ("video-changed", G_TYPE_FROM_CLASS (klass),
       
   695       G_SIGNAL_RUN_LAST,
       
   696       G_STRUCT_OFFSET (GstPlayBinClass, video_changed), NULL, NULL,
       
   697       gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
       
   698   /**
       
   699    * GstPlayBin::audio-changed
       
   700    * @playbin: a #GstPlayBin
       
   701    *
       
   702    * This signal is emited whenever the number or order of the audio
       
   703    * streams has changed. The application will most likely want to select
       
   704    * a new audio stream.
       
   705    */
       
   706   gst_play_bin_signals[SIGNAL_AUDIO_CHANGED] =
       
   707       g_signal_new ("audio-changed", G_TYPE_FROM_CLASS (klass),
       
   708       G_SIGNAL_RUN_LAST,
       
   709       G_STRUCT_OFFSET (GstPlayBinClass, audio_changed), NULL, NULL,
       
   710       gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
       
   711   /**
       
   712    * GstPlayBin::text-changed
       
   713    * @playbin: a #GstPlayBin
       
   714    *
       
   715    * This signal is emited whenever the number or order of the text
       
   716    * streams has changed. The application will most likely want to select
       
   717    * a new text stream.
       
   718    */
       
   719   gst_play_bin_signals[SIGNAL_TEXT_CHANGED] =
       
   720       g_signal_new ("text-changed", G_TYPE_FROM_CLASS (klass),
       
   721       G_SIGNAL_RUN_LAST,
       
   722       G_STRUCT_OFFSET (GstPlayBinClass, text_changed), NULL, NULL,
       
   723       gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
       
   724 
       
   725   /**
       
   726    * GstPlayBin::get-video-tags
       
   727    * @playbin: a #GstPlayBin
       
   728    * @stream: a video stream number
       
   729    *
       
   730    * Action signal to retrieve the tags of a specific video stream number.
       
   731    * This information can be used to select a stream.
       
   732    *
       
   733    * Returns: a GstTagList with tags or NULL when the stream number does not
       
   734    * exist.
       
   735    */
       
   736   gst_play_bin_signals[SIGNAL_GET_VIDEO_TAGS] =
       
   737       g_signal_new ("get-video-tags", G_TYPE_FROM_CLASS (klass),
       
   738       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
       
   739       G_STRUCT_OFFSET (GstPlayBinClass, get_video_tags), NULL, NULL,
       
   740       gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
       
   741   /**
       
   742    * GstPlayBin::get-audio-tags
       
   743    * @playbin: a #GstPlayBin
       
   744    * @stream: an audio stream number
       
   745    *
       
   746    * Action signal to retrieve the tags of a specific audio stream number.
       
   747    * This information can be used to select a stream.
       
   748    *
       
   749    * Returns: a GstTagList with tags or NULL when the stream number does not
       
   750    * exist.
       
   751    */
       
   752   gst_play_bin_signals[SIGNAL_GET_AUDIO_TAGS] =
       
   753       g_signal_new ("get-audio-tags", G_TYPE_FROM_CLASS (klass),
       
   754       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
       
   755       G_STRUCT_OFFSET (GstPlayBinClass, get_audio_tags), NULL, NULL,
       
   756       gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
       
   757   /**
       
   758    * GstPlayBin::get-text-tags
       
   759    * @playbin: a #GstPlayBin
       
   760    * @stream: a text stream number
       
   761    *
       
   762    * Action signal to retrieve the tags of a specific text stream number.
       
   763    * This information can be used to select a stream.
       
   764    *
       
   765    * Returns: a GstTagList with tags or NULL when the stream number does not
       
   766    * exist.
       
   767    */
       
   768   gst_play_bin_signals[SIGNAL_GET_TEXT_TAGS] =
       
   769       g_signal_new ("get-text-tags", G_TYPE_FROM_CLASS (klass),
       
   770       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
       
   771       G_STRUCT_OFFSET (GstPlayBinClass, get_text_tags), NULL, NULL,
       
   772       gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
       
   773   /**
       
   774    * GstPlayBin::convert-frame
       
   775    * @playbin: a #GstPlayBin
       
   776    * @caps: the target format of the frame
       
   777    *
       
   778    * Action signal to retrieve the currently playing video frame in the format
       
   779    * specified by @caps.
       
   780    * If @caps is %NULL, no conversion will be performed and this function is
       
   781    * equivalent to the #GstPlayBin::frame property.
       
   782    *
       
   783    * Returns: a #GstBuffer of the current video frame converted to #caps. 
       
   784    * The caps on the buffer will describe the final layout of the buffer data.
       
   785    * %NULL is returned when no current buffer can be retrieved or when the
       
   786    * conversion failed.
       
   787    */
       
   788   gst_play_bin_signals[SIGNAL_GET_TEXT_TAGS] =
       
   789       g_signal_new ("convert-frame", G_TYPE_FROM_CLASS (klass),
       
   790       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
       
   791       G_STRUCT_OFFSET (GstPlayBinClass, convert_frame), NULL, NULL,
       
   792       gst_play_marshal_BUFFER__BOXED, GST_TYPE_BUFFER, 1, GST_TYPE_CAPS);
       
   793 
       
   794   klass->get_video_tags = gst_play_bin_get_video_tags;
       
   795   klass->get_audio_tags = gst_play_bin_get_audio_tags;
       
   796   klass->get_text_tags = gst_play_bin_get_text_tags;
       
   797 
       
   798   klass->convert_frame = gst_play_bin_convert_frame;
       
   799 
       
   800   gst_element_class_set_details (gstelement_klass, &gst_play_bin_details);
       
   801 
       
   802   gstelement_klass->change_state =
       
   803       GST_DEBUG_FUNCPTR (gst_play_bin_change_state);
       
   804 
       
   805   gstbin_klass->handle_message =
       
   806       GST_DEBUG_FUNCPTR (gst_play_bin_handle_message);
       
   807 }
       
   808 
       
   809 static void
       
   810 init_group (GstPlayBin * playbin, GstSourceGroup * group)
       
   811 {
       
   812   /* store the array for the different channels */
       
   813   group->video_channels = g_ptr_array_new ();
       
   814   group->audio_channels = g_ptr_array_new ();
       
   815   group->text_channels = g_ptr_array_new ();
       
   816   /* init selectors */
       
   817   group->playbin = playbin;
       
   818   group->selector[0].media = "audio/x-raw-";
       
   819   group->selector[0].type = GST_PLAY_SINK_TYPE_AUDIO_RAW;
       
   820   group->selector[0].channels = group->audio_channels;
       
   821   group->selector[1].media = "audio/";
       
   822   group->selector[1].type = GST_PLAY_SINK_TYPE_AUDIO;
       
   823   group->selector[1].channels = group->audio_channels;
       
   824   group->selector[2].media = "video/x-raw-";
       
   825   group->selector[2].type = GST_PLAY_SINK_TYPE_VIDEO_RAW;
       
   826   group->selector[2].channels = group->video_channels;
       
   827   group->selector[3].media = "video/";
       
   828   group->selector[3].type = GST_PLAY_SINK_TYPE_VIDEO;
       
   829   group->selector[3].channels = group->video_channels;
       
   830   group->selector[4].media = "text/";
       
   831   group->selector[4].type = GST_PLAY_SINK_TYPE_TEXT;
       
   832   group->selector[4].channels = group->text_channels;
       
   833 }
       
   834 
       
   835 static void
       
   836 gst_play_bin_init (GstPlayBin * playbin)
       
   837 {
       
   838   GstFactoryListType type;
       
   839 
       
   840   /* init groups */
       
   841   playbin->curr_group = &playbin->groups[0];
       
   842   playbin->next_group = &playbin->groups[1];
       
   843   init_group (playbin, &playbin->groups[0]);
       
   844   init_group (playbin, &playbin->groups[1]);
       
   845 
       
   846   /* first filter out the interesting element factories */
       
   847   type = GST_FACTORY_LIST_DECODER | GST_FACTORY_LIST_SINK;
       
   848   playbin->elements = gst_factory_list_get_elements (type);
       
   849   gst_factory_list_debug (playbin->elements);
       
   850 
       
   851   /* add sink */
       
   852   playbin->playsink = g_object_new (GST_TYPE_PLAY_SINK, NULL);
       
   853   gst_bin_add (GST_BIN_CAST (playbin), GST_ELEMENT_CAST (playbin->playsink));
       
   854   gst_play_sink_set_flags (playbin->playsink, DEFAULT_FLAGS);
       
   855 
       
   856   playbin->current_video = DEFAULT_CURRENT_VIDEO;
       
   857   playbin->current_audio = DEFAULT_CURRENT_AUDIO;
       
   858   playbin->current_text = DEFAULT_CURRENT_TEXT;
       
   859 }
       
   860 
       
   861 static void
       
   862 gst_play_bin_finalize (GObject * object)
       
   863 {
       
   864   GstPlayBin *playbin;
       
   865 
       
   866   playbin = GST_PLAY_BIN (object);
       
   867 
       
   868   g_value_array_free (playbin->elements);
       
   869 
       
   870   G_OBJECT_CLASS (parent_class)->finalize (object);
       
   871 }
       
   872 
       
   873 static void
       
   874 gst_play_bin_set_uri (GstPlayBin * playbin, const gchar * uri)
       
   875 {
       
   876   GstSourceGroup *group;
       
   877 
       
   878   if (uri == NULL) {
       
   879     g_warning ("cannot set NULL uri");
       
   880     return;
       
   881   }
       
   882 
       
   883   GST_OBJECT_LOCK (playbin);
       
   884   group = playbin->next_group;
       
   885 
       
   886   /* if we have no previous uri, or the new uri is different from the
       
   887    * old one, replug */
       
   888   g_free (group->uri);
       
   889   group->uri = g_strdup (uri);
       
   890   group->valid = TRUE;
       
   891 
       
   892   GST_DEBUG ("setting new uri to %s", uri);
       
   893   GST_OBJECT_UNLOCK (playbin);
       
   894 }
       
   895 
       
   896 static void
       
   897 gst_play_bin_set_suburi (GstPlayBin * playbin, const gchar * suburi)
       
   898 {
       
   899   GstSourceGroup *group;
       
   900 
       
   901   GST_OBJECT_LOCK (playbin);
       
   902   group = playbin->next_group;
       
   903 
       
   904   if ((!suburi && !group->suburi) ||
       
   905       (suburi && group->suburi && !strcmp (group->suburi, suburi)))
       
   906     goto done;
       
   907 
       
   908   g_free (group->suburi);
       
   909   group->suburi = g_strdup (suburi);
       
   910 
       
   911   GST_DEBUG ("setting new .sub uri to %s", suburi);
       
   912 
       
   913 done:
       
   914   GST_OBJECT_UNLOCK (playbin);
       
   915 }
       
   916 
       
   917 /* get the currently playing group or if nothing is playing, the next
       
   918  * group. Must be called with the LOCK. */
       
   919 static GstSourceGroup *
       
   920 get_group (GstPlayBin * playbin)
       
   921 {
       
   922   GstSourceGroup *result;
       
   923 
       
   924   if (!(result = playbin->curr_group))
       
   925     result = playbin->next_group;
       
   926 
       
   927   return result;
       
   928 }
       
   929 
       
   930 static GstTagList *
       
   931 get_tags (GstPlayBin * playbin, GPtrArray * channels, gint stream)
       
   932 {
       
   933   GstTagList *result;
       
   934   GstPad *sinkpad;
       
   935 
       
   936   if (!channels || channels->len < stream)
       
   937     return NULL;
       
   938 
       
   939   sinkpad = g_ptr_array_index (channels, stream);
       
   940   g_object_get (sinkpad, "tags", &result, NULL);
       
   941 
       
   942   return result;
       
   943 }
       
   944 
       
   945 static GstTagList *
       
   946 gst_play_bin_get_video_tags (GstPlayBin * playbin, gint stream)
       
   947 {
       
   948   GstTagList *result;
       
   949   GstSourceGroup *group;
       
   950 
       
   951   GST_OBJECT_LOCK (playbin);
       
   952   group = get_group (playbin);
       
   953   result = get_tags (playbin, group->video_channels, stream);
       
   954   GST_OBJECT_UNLOCK (playbin);
       
   955 
       
   956   return result;
       
   957 }
       
   958 
       
   959 static GstTagList *
       
   960 gst_play_bin_get_audio_tags (GstPlayBin * playbin, gint stream)
       
   961 {
       
   962   GstTagList *result;
       
   963   GstSourceGroup *group;
       
   964 
       
   965   GST_OBJECT_LOCK (playbin);
       
   966   group = get_group (playbin);
       
   967   result = get_tags (playbin, group->audio_channels, stream);
       
   968   GST_OBJECT_UNLOCK (playbin);
       
   969 
       
   970   return result;
       
   971 }
       
   972 
       
   973 static GstTagList *
       
   974 gst_play_bin_get_text_tags (GstPlayBin * playbin, gint stream)
       
   975 {
       
   976   GstTagList *result;
       
   977   GstSourceGroup *group;
       
   978 
       
   979   GST_OBJECT_LOCK (playbin);
       
   980   group = get_group (playbin);
       
   981   result = get_tags (playbin, group->text_channels, stream);
       
   982   GST_OBJECT_UNLOCK (playbin);
       
   983 
       
   984   return result;
       
   985 }
       
   986 
       
   987 static GstBuffer *
       
   988 gst_play_bin_convert_frame (GstPlayBin * playbin, GstCaps * caps)
       
   989 {
       
   990   GstBuffer *result;
       
   991 
       
   992   result = gst_play_sink_get_last_frame (playbin->playsink);
       
   993   if (result != NULL && caps != NULL) {
       
   994     GstBuffer *temp;
       
   995 
       
   996     temp = gst_play_frame_conv_convert (result, caps);
       
   997     gst_buffer_unref (result);
       
   998     result = temp;
       
   999   }
       
  1000   return result;
       
  1001 }
       
  1002 
       
  1003 static gboolean
       
  1004 gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream)
       
  1005 {
       
  1006   GstSourceGroup *group;
       
  1007   GPtrArray *channels;
       
  1008   GstPad *sinkpad;
       
  1009 
       
  1010   GST_OBJECT_LOCK (playbin);
       
  1011   group = get_group (playbin);
       
  1012   if (!(channels = group->video_channels))
       
  1013     goto no_channels;
       
  1014 
       
  1015   if (stream == -1 || channels->len < stream) {
       
  1016     sinkpad = NULL;
       
  1017   } else {
       
  1018     /* take channel from selected stream */
       
  1019     sinkpad = g_ptr_array_index (channels, stream);
       
  1020   }
       
  1021 
       
  1022   if (sinkpad)
       
  1023     gst_object_ref (sinkpad);
       
  1024   GST_OBJECT_UNLOCK (playbin);
       
  1025 
       
  1026   if (sinkpad) {
       
  1027     GstObject *selector;
       
  1028 
       
  1029     if ((selector = gst_pad_get_parent (sinkpad))) {
       
  1030       /* activate the selected pad */
       
  1031       g_object_set (selector, "active-pad", sinkpad, NULL);
       
  1032       gst_object_unref (selector);
       
  1033     }
       
  1034     gst_object_unref (sinkpad);
       
  1035   }
       
  1036   return TRUE;
       
  1037 
       
  1038 no_channels:
       
  1039   {
       
  1040     GST_OBJECT_UNLOCK (playbin);
       
  1041     return FALSE;
       
  1042   }
       
  1043 }
       
  1044 
       
  1045 static gboolean
       
  1046 gst_play_bin_set_current_audio_stream (GstPlayBin * playbin, gint stream)
       
  1047 {
       
  1048   GstSourceGroup *group;
       
  1049   GPtrArray *channels;
       
  1050   GstPad *sinkpad;
       
  1051 
       
  1052   GST_OBJECT_LOCK (playbin);
       
  1053   group = get_group (playbin);
       
  1054   if (!(channels = group->audio_channels))
       
  1055     goto no_channels;
       
  1056 
       
  1057   if (stream == -1 || channels->len < stream) {
       
  1058     sinkpad = NULL;
       
  1059   } else {
       
  1060     /* take channel from selected stream */
       
  1061     sinkpad = g_ptr_array_index (channels, stream);
       
  1062   }
       
  1063 
       
  1064   if (sinkpad)
       
  1065     gst_object_ref (sinkpad);
       
  1066   GST_OBJECT_UNLOCK (playbin);
       
  1067 
       
  1068   if (sinkpad) {
       
  1069     GstObject *selector;
       
  1070 
       
  1071     if ((selector = gst_pad_get_parent (sinkpad))) {
       
  1072       /* activate the selected pad */
       
  1073       g_object_set (selector, "active-pad", sinkpad, NULL);
       
  1074       gst_object_unref (selector);
       
  1075     }
       
  1076     gst_object_unref (sinkpad);
       
  1077   }
       
  1078   return TRUE;
       
  1079 
       
  1080 no_channels:
       
  1081   {
       
  1082     GST_OBJECT_UNLOCK (playbin);
       
  1083     return FALSE;
       
  1084   }
       
  1085 }
       
  1086 
       
  1087 static gboolean
       
  1088 gst_play_bin_set_current_text_stream (GstPlayBin * playbin, gint stream)
       
  1089 {
       
  1090   GstSourceGroup *group;
       
  1091   GPtrArray *channels;
       
  1092   GstPad *sinkpad;
       
  1093 
       
  1094   GST_OBJECT_LOCK (playbin);
       
  1095   group = get_group (playbin);
       
  1096   if (!(channels = group->text_channels))
       
  1097     goto no_channels;
       
  1098 
       
  1099   if (stream == -1 || channels->len < stream) {
       
  1100     sinkpad = NULL;
       
  1101   } else {
       
  1102     /* take channel from selected stream */
       
  1103     sinkpad = g_ptr_array_index (channels, stream);
       
  1104   }
       
  1105 
       
  1106   if (sinkpad)
       
  1107     gst_object_ref (sinkpad);
       
  1108   GST_OBJECT_UNLOCK (playbin);
       
  1109 
       
  1110   if (sinkpad) {
       
  1111     GstObject *selector;
       
  1112 
       
  1113     if ((selector = gst_pad_get_parent (sinkpad))) {
       
  1114       /* activate the selected pad */
       
  1115       g_object_set (selector, "active-pad", sinkpad, NULL);
       
  1116       gst_object_unref (selector);
       
  1117     }
       
  1118     gst_object_unref (sinkpad);
       
  1119   }
       
  1120   return TRUE;
       
  1121 
       
  1122 no_channels:
       
  1123   {
       
  1124     GST_OBJECT_UNLOCK (playbin);
       
  1125     return FALSE;
       
  1126   }
       
  1127 }
       
  1128 
       
  1129 static void
       
  1130 gst_play_bin_set_property (GObject * object, guint prop_id,
       
  1131     const GValue * value, GParamSpec * pspec)
       
  1132 {
       
  1133   GstPlayBin *playbin;
       
  1134 
       
  1135   playbin = GST_PLAY_BIN (object);
       
  1136 
       
  1137   switch (prop_id) {
       
  1138     case PROP_URI:
       
  1139       gst_play_bin_set_uri (playbin, g_value_get_string (value));
       
  1140       break;
       
  1141     case PROP_SUBURI:
       
  1142       gst_play_bin_set_suburi (playbin, g_value_get_string (value));
       
  1143       break;
       
  1144     case PROP_FLAGS:
       
  1145       gst_play_sink_set_flags (playbin->playsink, g_value_get_flags (value));
       
  1146       break;
       
  1147     case PROP_CURRENT_VIDEO:
       
  1148       gst_play_bin_set_current_video_stream (playbin, g_value_get_int (value));
       
  1149       break;
       
  1150     case PROP_CURRENT_AUDIO:
       
  1151       gst_play_bin_set_current_audio_stream (playbin, g_value_get_int (value));
       
  1152       break;
       
  1153     case PROP_CURRENT_TEXT:
       
  1154       gst_play_bin_set_current_text_stream (playbin, g_value_get_int (value));
       
  1155       break;
       
  1156     case PROP_SUBTITLE_ENCODING:
       
  1157       break;
       
  1158     case PROP_VIDEO_SINK:
       
  1159       break;
       
  1160     case PROP_AUDIO_SINK:
       
  1161       break;
       
  1162     case PROP_VIS_PLUGIN:
       
  1163       gst_play_sink_set_vis_plugin (playbin->playsink,
       
  1164           g_value_get_object (value));
       
  1165       break;
       
  1166     case PROP_VOLUME:
       
  1167       gst_play_sink_set_volume (playbin->playsink, g_value_get_double (value));
       
  1168       break;
       
  1169     case PROP_MUTE:
       
  1170       gst_play_sink_set_mute (playbin->playsink, g_value_get_boolean (value));
       
  1171       break;
       
  1172     case PROP_FONT_DESC:
       
  1173       break;
       
  1174     case PROP_CONNECTION_SPEED:
       
  1175       GST_OBJECT_LOCK (playbin);
       
  1176       playbin->connection_speed = g_value_get_uint (value) * 1000;
       
  1177       GST_OBJECT_UNLOCK (playbin);
       
  1178       break;
       
  1179     default:
       
  1180       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       
  1181       break;
       
  1182   }
       
  1183 }
       
  1184 
       
  1185 static void
       
  1186 gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
       
  1187     GParamSpec * pspec)
       
  1188 {
       
  1189   GstPlayBin *playbin;
       
  1190 
       
  1191   playbin = GST_PLAY_BIN (object);
       
  1192 
       
  1193   switch (prop_id) {
       
  1194     case PROP_URI:
       
  1195     {
       
  1196       GstSourceGroup *group;
       
  1197 
       
  1198       GST_OBJECT_LOCK (playbin);
       
  1199       group = get_group (playbin);
       
  1200       g_value_set_string (value, group->uri);
       
  1201       GST_OBJECT_UNLOCK (playbin);
       
  1202       break;
       
  1203     }
       
  1204     case PROP_SUBURI:
       
  1205     {
       
  1206       GstSourceGroup *group;
       
  1207 
       
  1208       GST_OBJECT_LOCK (playbin);
       
  1209       group = get_group (playbin);
       
  1210       g_value_set_string (value, group->suburi);
       
  1211       GST_OBJECT_UNLOCK (playbin);
       
  1212       break;
       
  1213     }
       
  1214     case PROP_SOURCE:
       
  1215       break;
       
  1216     case PROP_FLAGS:
       
  1217       g_value_set_flags (value, gst_play_sink_get_flags (playbin->playsink));
       
  1218       break;
       
  1219     case PROP_N_VIDEO:
       
  1220     {
       
  1221       GstSourceGroup *group;
       
  1222       gint n_video;
       
  1223 
       
  1224       GST_OBJECT_LOCK (playbin);
       
  1225       group = get_group (playbin);
       
  1226       n_video = (group->video_channels ? group->video_channels->len : 0);
       
  1227       g_value_set_int (value, n_video);
       
  1228       GST_OBJECT_UNLOCK (playbin);
       
  1229       break;
       
  1230     }
       
  1231     case PROP_CURRENT_VIDEO:
       
  1232       GST_OBJECT_LOCK (playbin);
       
  1233       g_value_set_int (value, playbin->current_video);
       
  1234       GST_OBJECT_UNLOCK (playbin);
       
  1235       break;
       
  1236     case PROP_N_AUDIO:
       
  1237     {
       
  1238       GstSourceGroup *group;
       
  1239       gint n_audio;
       
  1240 
       
  1241       GST_OBJECT_LOCK (playbin);
       
  1242       group = get_group (playbin);
       
  1243       n_audio = (group->audio_channels ? group->audio_channels->len : 0);
       
  1244       g_value_set_int (value, n_audio);
       
  1245       GST_OBJECT_UNLOCK (playbin);
       
  1246       break;
       
  1247     }
       
  1248     case PROP_CURRENT_AUDIO:
       
  1249       GST_OBJECT_LOCK (playbin);
       
  1250       g_value_set_int (value, playbin->current_audio);
       
  1251       GST_OBJECT_UNLOCK (playbin);
       
  1252       break;
       
  1253     case PROP_N_TEXT:
       
  1254     {
       
  1255       GstSourceGroup *group;
       
  1256       gint n_text;
       
  1257 
       
  1258       GST_OBJECT_LOCK (playbin);
       
  1259       group = get_group (playbin);
       
  1260       n_text = (group->text_channels ? group->text_channels->len : 0);
       
  1261       g_value_set_int (value, n_text);
       
  1262       GST_OBJECT_UNLOCK (playbin);
       
  1263       break;
       
  1264     }
       
  1265     case PROP_CURRENT_TEXT:
       
  1266       GST_OBJECT_LOCK (playbin);
       
  1267       g_value_set_int (value, playbin->current_text);
       
  1268       GST_OBJECT_UNLOCK (playbin);
       
  1269       break;
       
  1270     case PROP_SUBTITLE_ENCODING:
       
  1271       break;
       
  1272     case PROP_VIDEO_SINK:
       
  1273       break;
       
  1274     case PROP_AUDIO_SINK:
       
  1275       break;
       
  1276     case PROP_VIS_PLUGIN:
       
  1277       break;
       
  1278     case PROP_VOLUME:
       
  1279       g_value_set_double (value, gst_play_sink_get_volume (playbin->playsink));
       
  1280       break;
       
  1281     case PROP_MUTE:
       
  1282       g_value_set_boolean (value, gst_play_sink_get_mute (playbin->playsink));
       
  1283       break;
       
  1284     case PROP_FRAME:
       
  1285       gst_value_take_buffer (value, gst_play_bin_convert_frame (playbin, NULL));
       
  1286       break;
       
  1287     case PROP_FONT_DESC:
       
  1288       break;
       
  1289     case PROP_CONNECTION_SPEED:
       
  1290       GST_OBJECT_LOCK (playbin);
       
  1291       g_value_set_uint (value, playbin->connection_speed / 1000);
       
  1292       GST_OBJECT_UNLOCK (playbin);
       
  1293       break;
       
  1294     default:
       
  1295       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       
  1296       break;
       
  1297   }
       
  1298 }
       
  1299 
       
  1300 /* mime types we are not handling on purpose right now, don't post a
       
  1301  * missing-plugin message for these */
       
  1302 static const gchar *blacklisted_mimes[] = {
       
  1303   "video/x-dvd-subpicture", NULL
       
  1304 };
       
  1305 
       
  1306 static void
       
  1307 gst_play_bin_handle_message (GstBin * bin, GstMessage * msg)
       
  1308 {
       
  1309   if (gst_is_missing_plugin_message (msg)) {
       
  1310     gchar *detail;
       
  1311     guint i;
       
  1312 
       
  1313     detail = gst_missing_plugin_message_get_installer_detail (msg);
       
  1314     for (i = 0; detail != NULL && blacklisted_mimes[i] != NULL; ++i) {
       
  1315       if (strstr (detail, "|decoder-") && strstr (detail, blacklisted_mimes[i])) {
       
  1316         GST_LOG_OBJECT (bin, "suppressing message %" GST_PTR_FORMAT, msg);
       
  1317         gst_message_unref (msg);
       
  1318         g_free (detail);
       
  1319         return;
       
  1320       }
       
  1321     }
       
  1322     g_free (detail);
       
  1323   }
       
  1324   GST_BIN_CLASS (parent_class)->handle_message (bin, msg);
       
  1325 }
       
  1326 
       
  1327 /* this function is called when a new pad is added to decodebin. We check the
       
  1328  * type of the pad and add it to the selecter element of the group. 
       
  1329  */
       
  1330 static void
       
  1331 pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
       
  1332 {
       
  1333   GstPlayBin *playbin;
       
  1334   GstCaps *caps;
       
  1335   const GstStructure *s;
       
  1336   const gchar *name;
       
  1337   GstPad *sinkpad;
       
  1338   GstPadLinkReturn res;
       
  1339   GstSourceSelect *select = NULL;
       
  1340   gint i;
       
  1341 
       
  1342   playbin = group->playbin;
       
  1343 
       
  1344   caps = gst_pad_get_caps (pad);
       
  1345   s = gst_caps_get_structure (caps, 0);
       
  1346   name = gst_structure_get_name (s);
       
  1347 
       
  1348   GST_DEBUG_OBJECT (playbin,
       
  1349       "pad %s:%s with caps %" GST_PTR_FORMAT " added in group %p",
       
  1350       GST_DEBUG_PAD_NAME (pad), caps, group);
       
  1351 
       
  1352   /* major type of the pad, this determines the selector to use */
       
  1353   for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
       
  1354     if (g_str_has_prefix (name, group->selector[i].media)) {
       
  1355       select = &group->selector[i];
       
  1356       break;
       
  1357     }
       
  1358   }
       
  1359   /* no selector found for the media type, don't bother linking it to a
       
  1360    * selector. This will leave the pad unlinked and thus ignored. */
       
  1361   if (select == NULL)
       
  1362     goto unknown_type;
       
  1363 
       
  1364   if (select->selector == NULL) {
       
  1365     /* no selector, create one */
       
  1366     GST_DEBUG_OBJECT (playbin, "creating new selector");
       
  1367     select->selector = g_object_new (GST_TYPE_STREAM_SELECTOR, NULL);
       
  1368     if (select->selector == NULL)
       
  1369       goto no_selector;
       
  1370 
       
  1371     GST_DEBUG_OBJECT (playbin, "adding new selector %p", select->selector);
       
  1372     gst_bin_add (GST_BIN_CAST (playbin), select->selector);
       
  1373     gst_element_set_state (select->selector, GST_STATE_PAUSED);
       
  1374 
       
  1375     /* save source pad */
       
  1376     select->srcpad = gst_element_get_pad (select->selector, "src");
       
  1377   }
       
  1378 
       
  1379   /* get sinkpad for the new stream */
       
  1380   if ((sinkpad = gst_element_get_request_pad (select->selector, "sink%d"))) {
       
  1381     GST_DEBUG_OBJECT (playbin, "got pad %s:%s from selector",
       
  1382         GST_DEBUG_PAD_NAME (sinkpad));
       
  1383 
       
  1384     /* store the selector for the pad */
       
  1385     g_object_set_data (G_OBJECT (sinkpad), "playbin2.select", select);
       
  1386 
       
  1387     /* store the pad in the array */
       
  1388     GST_DEBUG_OBJECT (playbin, "pad %p added to array", sinkpad);
       
  1389     g_ptr_array_add (select->channels, sinkpad);
       
  1390 
       
  1391     res = gst_pad_link (pad, sinkpad);
       
  1392     if (GST_PAD_LINK_FAILED (res))
       
  1393       goto link_failed;
       
  1394 
       
  1395     /* store selector pad so we can release it */
       
  1396     g_object_set_data (G_OBJECT (pad), "playbin2.sinkpad", sinkpad);
       
  1397   }
       
  1398   GST_DEBUG_OBJECT (playbin, "linked pad %s:%s to selector %p",
       
  1399       GST_DEBUG_PAD_NAME (pad), select->selector);
       
  1400 
       
  1401   return;
       
  1402 
       
  1403   /* ERRORS */
       
  1404 unknown_type:
       
  1405   {
       
  1406     GST_ERROR_OBJECT (playbin, "unknown type %s for pad %s:%s",
       
  1407         name, GST_DEBUG_PAD_NAME (pad));
       
  1408     return;
       
  1409   }
       
  1410 no_selector:
       
  1411   {
       
  1412     GST_ERROR_OBJECT (playbin, "could not create selector for pad %s:%s",
       
  1413         GST_DEBUG_PAD_NAME (pad));
       
  1414     return;
       
  1415   }
       
  1416 link_failed:
       
  1417   {
       
  1418     GST_ERROR_OBJECT (playbin,
       
  1419         "failed to link pad %s:%s to selector, reason %d",
       
  1420         GST_DEBUG_PAD_NAME (pad), res);
       
  1421     return;
       
  1422   }
       
  1423 }
       
  1424 
       
  1425 /* called when a pad is removed form the uridecodebin. We unlink the pad from
       
  1426  * the selector. This will make the selector select a new pad. */
       
  1427 static void
       
  1428 pad_removed_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
       
  1429 {
       
  1430   GstPlayBin *playbin;
       
  1431   GstPad *peer;
       
  1432   GstElement *selector;
       
  1433   GstSourceSelect *select;
       
  1434 
       
  1435   playbin = group->playbin;
       
  1436 
       
  1437   GST_DEBUG_OBJECT (playbin,
       
  1438       "pad %s:%s removed from group %p", GST_DEBUG_PAD_NAME (pad), group);
       
  1439 
       
  1440   /* get the selector sinkpad */
       
  1441   if (!(peer = g_object_get_data (G_OBJECT (pad), "playbin2.sinkpad")))
       
  1442     goto not_linked;
       
  1443 
       
  1444   if ((select = g_object_get_data (G_OBJECT (peer), "playbin2.select"))) {
       
  1445     /* remove the pad from the array */
       
  1446     g_ptr_array_remove (select->channels, peer);
       
  1447     GST_DEBUG_OBJECT (playbin, "pad %p removed from array", peer);
       
  1448   }
       
  1449 
       
  1450   /* unlink the pad now (can fail, the pad is unlinked before it's removed) */
       
  1451   gst_pad_unlink (pad, peer);
       
  1452 
       
  1453   /* get selector, this can be NULL when the element is removing the pads
       
  1454    * because it's being disposed. */
       
  1455   selector = GST_ELEMENT_CAST (gst_pad_get_parent (peer));
       
  1456   if (!selector)
       
  1457     goto no_selector;
       
  1458 
       
  1459   /* release the pad to the selector, this will make the selector choose a new
       
  1460    * pad. */
       
  1461   gst_element_release_request_pad (selector, peer);
       
  1462 
       
  1463   gst_object_unref (selector);
       
  1464 
       
  1465   return;
       
  1466 
       
  1467   /* ERRORS */
       
  1468 not_linked:
       
  1469   {
       
  1470     GST_DEBUG_OBJECT (playbin, "pad not linked");
       
  1471     return;
       
  1472   }
       
  1473 no_selector:
       
  1474   {
       
  1475     GST_DEBUG_OBJECT (playbin, "selector not found");
       
  1476     return;
       
  1477   }
       
  1478 }
       
  1479 
       
  1480 /* we get called when all pads are available and we must connect the sinks to
       
  1481  * them.
       
  1482  * The main purpose of the code is to see if we have video/audio and subtitles
       
  1483  * and pick the right pipelines to display them.
       
  1484  *
       
  1485  * The selectors installed on the group tell us about the presence of
       
  1486  * audio/video and subtitle streams. This allows us to see if we need
       
  1487  * visualisation, video or/and audio.
       
  1488  */
       
  1489 static void
       
  1490 no_more_pads_cb (GstElement * decodebin, GstSourceGroup * group)
       
  1491 {
       
  1492   GstPlayBin *playbin;
       
  1493   GstPadLinkReturn res;
       
  1494   gint i;
       
  1495 
       
  1496   playbin = group->playbin;
       
  1497 
       
  1498   GST_DEBUG_OBJECT (playbin, "no more pads in group %p", group);
       
  1499 
       
  1500   for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
       
  1501     GstSourceSelect *select = &group->selector[i];
       
  1502 
       
  1503     if (select->selector) {
       
  1504       select->sinkpad =
       
  1505           gst_play_sink_request_pad (playbin->playsink, select->type);
       
  1506       res = gst_pad_link (select->srcpad, select->sinkpad);
       
  1507       GST_DEBUG_OBJECT (playbin, "linked type %s, result: %d", select->media,
       
  1508           res);
       
  1509     }
       
  1510   }
       
  1511   /* configure the modes now */
       
  1512   gst_play_sink_reconfigure (playbin->playsink);
       
  1513 }
       
  1514 
       
  1515 /* send an EOS event to all of the selectors */
       
  1516 static void
       
  1517 perform_eos (GstPlayBin * playbin, GstSourceGroup * group)
       
  1518 {
       
  1519   GstEvent *event;
       
  1520   gint i;
       
  1521 
       
  1522   GST_DEBUG_OBJECT (playbin, "doing EOS in group %p", group);
       
  1523 
       
  1524   event = gst_event_new_eos ();
       
  1525   for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
       
  1526     GstSourceSelect *select = &group->selector[i];
       
  1527 
       
  1528     if (select->selector) {
       
  1529       GST_DEBUG_OBJECT (playbin, "send EOS in selector %s", select->media);
       
  1530       gst_event_ref (event);
       
  1531       gst_pad_push_event (select->srcpad, event);
       
  1532     }
       
  1533   }
       
  1534   gst_event_unref (event);
       
  1535 }
       
  1536 
       
  1537 static void
       
  1538 drained_cb (GstElement * decodebin, GstSourceGroup * group)
       
  1539 {
       
  1540   GstPlayBin *playbin;
       
  1541 
       
  1542   playbin = group->playbin;
       
  1543 
       
  1544   GST_DEBUG_OBJECT (playbin, "about to finish in group %p", group);
       
  1545 
       
  1546   /* mark use as sending out the about-to-finish signal. When the app sets a URI
       
  1547    * when this signal is emited, we're marking it as next-uri */
       
  1548   playbin->about_to_finish = TRUE;
       
  1549 
       
  1550   /* after this call, we should have a next group to activate or we EOS */
       
  1551   g_signal_emit (G_OBJECT (playbin),
       
  1552       gst_play_bin_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL);
       
  1553 
       
  1554   playbin->about_to_finish = FALSE;
       
  1555 
       
  1556   /* now activate the next group. If the app did not set a next-uri, this will
       
  1557    * fail and we can do EOS */
       
  1558   if (!setup_next_source (playbin)) {
       
  1559     perform_eos (playbin, group);
       
  1560   }
       
  1561 }
       
  1562 
       
  1563 /* Called when we must provide a list of factories to plug to @pad with @caps.
       
  1564  * We first check if we have a sink that can handle the format and if we do, we
       
  1565  * return NULL, to expose the pad. If we have no sink (or the sink does not
       
  1566  * work), we return the list of elements that can connect. */
       
  1567 static GValueArray *
       
  1568 autoplug_factories_cb (GstElement * decodebin, GstPad * pad,
       
  1569     GstCaps * caps, GstSourceGroup * group)
       
  1570 {
       
  1571   GstPlayBin *playbin;
       
  1572   GValueArray *result;
       
  1573 
       
  1574   playbin = group->playbin;
       
  1575 
       
  1576   GST_DEBUG_OBJECT (playbin, "factories group %p for %s:%s, %" GST_PTR_FORMAT,
       
  1577       group, GST_DEBUG_PAD_NAME (pad), caps);
       
  1578 
       
  1579   /* filter out the elements based on the caps. */
       
  1580   result = gst_factory_list_filter (playbin->elements, caps);
       
  1581 
       
  1582   GST_DEBUG_OBJECT (playbin, "found factories %p", result);
       
  1583   gst_factory_list_debug (result);
       
  1584 
       
  1585   return result;
       
  1586 }
       
  1587 
       
  1588 /* We are asked to select an element. See if the next element to check
       
  1589  * is a sink. If this is the case, we see if the sink works by setting it to
       
  1590  * READY. If the sink works, we return -2 to make decodebin expose the raw pad
       
  1591  * so that we can setup the mixers. */
       
  1592 static GstAutoplugSelectResult
       
  1593 autoplug_select_cb (GstElement * decodebin, GstPad * pad,
       
  1594     GstCaps * caps, GstElementFactory * factory, GstSourceGroup * group)
       
  1595 {
       
  1596   GstPlayBin *playbin;
       
  1597   GstElement *element;
       
  1598   const gchar *klass;
       
  1599 
       
  1600   playbin = group->playbin;
       
  1601 
       
  1602   GST_DEBUG_OBJECT (playbin, "select group %p for %s:%s, %" GST_PTR_FORMAT,
       
  1603       group, GST_DEBUG_PAD_NAME (pad), caps);
       
  1604 
       
  1605   GST_DEBUG_OBJECT (playbin, "checking factory %s",
       
  1606       GST_PLUGIN_FEATURE_NAME (factory));
       
  1607 
       
  1608   /* if it's not a sink, we just make decodebin try it */
       
  1609   if (!gst_factory_list_is_type (factory, GST_FACTORY_LIST_SINK))
       
  1610     return GST_AUTOPLUG_SELECT_TRY;
       
  1611 
       
  1612   /* it's a sink, see if an instance of it actually works */
       
  1613   GST_DEBUG_OBJECT (playbin, "we found a sink");
       
  1614 
       
  1615   if ((element = gst_element_factory_create (factory, NULL)) == NULL) {
       
  1616     GST_WARNING_OBJECT (playbin, "Could not create an element from %s",
       
  1617         gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
       
  1618     return GST_AUTOPLUG_SELECT_SKIP;
       
  1619   }
       
  1620 
       
  1621   /* ... activate it ... We do this before adding it to the bin so that we
       
  1622    * don't accidentally make it post error messages that will stop
       
  1623    * everything. */
       
  1624   if ((gst_element_set_state (element,
       
  1625               GST_STATE_READY)) == GST_STATE_CHANGE_FAILURE) {
       
  1626     GST_WARNING_OBJECT (playbin, "Couldn't set %s to READY",
       
  1627         GST_ELEMENT_NAME (element));
       
  1628     gst_object_unref (element);
       
  1629     return GST_AUTOPLUG_SELECT_SKIP;
       
  1630   }
       
  1631 
       
  1632   /* at this point, we have the sink working, configure it in playsink */
       
  1633   klass = gst_element_factory_get_klass (factory);
       
  1634 
       
  1635   /* get klass to figure out if it's audio or video */
       
  1636   if (strstr (klass, "Audio")) {
       
  1637     GST_DEBUG_OBJECT (playbin, "configure audio sink");
       
  1638     gst_play_sink_set_audio_sink (playbin->playsink, element);
       
  1639   } else if (strstr (klass, "Video")) {
       
  1640     GST_DEBUG_OBJECT (playbin, "configure video sink");
       
  1641     gst_play_sink_set_video_sink (playbin->playsink, element);
       
  1642   } else {
       
  1643     GST_WARNING_OBJECT (playbin, "unknown sink klass %s found", klass);
       
  1644   }
       
  1645 
       
  1646   /* tell decodebin to expose the pad because we are going to use this
       
  1647    * sink */
       
  1648   GST_DEBUG_OBJECT (playbin, "we found a working sink, expose pad");
       
  1649 
       
  1650   return GST_AUTOPLUG_SELECT_EXPOSE;
       
  1651 }
       
  1652 
       
  1653 static gboolean
       
  1654 activate_group (GstPlayBin * playbin, GstSourceGroup * group)
       
  1655 {
       
  1656   GstElement *uridecodebin;
       
  1657 
       
  1658   g_return_val_if_fail (group->valid, FALSE);
       
  1659   g_return_val_if_fail (!group->active, FALSE);
       
  1660 
       
  1661   if (group->uridecodebin) {
       
  1662     gst_element_set_state (group->uridecodebin, GST_STATE_NULL);
       
  1663     gst_bin_remove (GST_BIN_CAST (playbin), group->uridecodebin);
       
  1664     group->uridecodebin = NULL;
       
  1665   }
       
  1666 
       
  1667   uridecodebin = gst_element_factory_make ("uridecodebin", NULL);
       
  1668   if (!uridecodebin)
       
  1669     goto no_decodebin;
       
  1670 
       
  1671   /* configure connection speed */
       
  1672   g_object_set (uridecodebin, "connection-speed", playbin->connection_speed,
       
  1673       NULL);
       
  1674   /* configure uri */
       
  1675   g_object_set (uridecodebin, "uri", group->uri, NULL);
       
  1676 
       
  1677   /* connect pads and other things */
       
  1678   g_signal_connect (uridecodebin, "pad-added", G_CALLBACK (pad_added_cb),
       
  1679       group);
       
  1680   g_signal_connect (uridecodebin, "pad-removed", G_CALLBACK (pad_removed_cb),
       
  1681       group);
       
  1682   g_signal_connect (uridecodebin, "no-more-pads", G_CALLBACK (no_more_pads_cb),
       
  1683       group);
       
  1684   /* is called when the uridecodebin is out of data and we can switch to the
       
  1685    * next uri */
       
  1686   g_signal_connect (uridecodebin, "drained", G_CALLBACK (drained_cb), group);
       
  1687 
       
  1688   /* will be called when a new media type is found. We return a list of decoders
       
  1689    * including sinks for decodebin to try */
       
  1690   g_signal_connect (uridecodebin, "autoplug-factories",
       
  1691       G_CALLBACK (autoplug_factories_cb), group);
       
  1692 
       
  1693   g_signal_connect (uridecodebin, "autoplug-select",
       
  1694       G_CALLBACK (autoplug_select_cb), group);
       
  1695 
       
  1696   /*  */
       
  1697   gst_bin_add (GST_BIN_CAST (playbin), uridecodebin);
       
  1698   group->uridecodebin = uridecodebin;
       
  1699 
       
  1700   gst_element_set_state (uridecodebin, GST_STATE_PAUSED);
       
  1701 
       
  1702   group->active = TRUE;
       
  1703 
       
  1704   return TRUE;
       
  1705 
       
  1706   /* ERRORS */
       
  1707 no_decodebin:
       
  1708   {
       
  1709     return FALSE;
       
  1710   }
       
  1711 }
       
  1712 
       
  1713 /* unlink a group of uridecodebins from the sink */
       
  1714 static gboolean
       
  1715 deactivate_group (GstPlayBin * playbin, GstSourceGroup * group)
       
  1716 {
       
  1717   gint i;
       
  1718 
       
  1719   g_return_val_if_fail (group->valid, FALSE);
       
  1720   g_return_val_if_fail (group->active, FALSE);
       
  1721 
       
  1722   GST_DEBUG_OBJECT (playbin, "unlinking group %p", group);
       
  1723 
       
  1724   for (i = 0; i < GST_PLAY_SINK_TYPE_LAST; i++) {
       
  1725     GstSourceSelect *select = &group->selector[i];
       
  1726 
       
  1727     if (!select->selector)
       
  1728       continue;
       
  1729 
       
  1730     GST_DEBUG_OBJECT (playbin, "unlinking selector %s", select->media);
       
  1731     gst_pad_unlink (select->srcpad, select->sinkpad);
       
  1732 
       
  1733     /* release back */
       
  1734     gst_play_sink_release_pad (playbin->playsink, select->sinkpad);
       
  1735     select->sinkpad = NULL;
       
  1736 
       
  1737     gst_object_unref (select->srcpad);
       
  1738     select->srcpad = NULL;
       
  1739 
       
  1740     gst_element_set_state (select->selector, GST_STATE_NULL);
       
  1741     gst_bin_remove (GST_BIN_CAST (playbin), select->selector);
       
  1742     select->selector = NULL;
       
  1743   }
       
  1744   group->active = FALSE;
       
  1745 
       
  1746   return TRUE;
       
  1747 }
       
  1748 
       
  1749 /* setup the next group to play, this assumes the next_group is valid and
       
  1750  * configured. It swaps out the current_group and activates the valid 
       
  1751  * next_group. */
       
  1752 static gboolean
       
  1753 setup_next_source (GstPlayBin * playbin)
       
  1754 {
       
  1755   GstSourceGroup *new_group, *old_group;
       
  1756 
       
  1757   GST_DEBUG_OBJECT (playbin, "setup sources");
       
  1758 
       
  1759   /* see if there is a next group */
       
  1760   new_group = playbin->next_group;
       
  1761   if (!new_group || !new_group->valid)
       
  1762     goto no_next_group;
       
  1763 
       
  1764   /* first unlink the current source, if any */
       
  1765   old_group = playbin->curr_group;
       
  1766   if (old_group && old_group->valid) {
       
  1767     /* unlink our pads with the sink */
       
  1768     deactivate_group (playbin, old_group);
       
  1769     old_group->valid = FALSE;
       
  1770   }
       
  1771 
       
  1772   /* activate the new group */
       
  1773   if (!activate_group (playbin, new_group))
       
  1774     goto activate_failed;
       
  1775 
       
  1776   /* swap old and new */
       
  1777   playbin->curr_group = new_group;
       
  1778   playbin->next_group = old_group;
       
  1779 
       
  1780   return TRUE;
       
  1781 
       
  1782   /* ERRORS */
       
  1783 no_next_group:
       
  1784   {
       
  1785     GST_DEBUG_OBJECT (playbin, "no next group");
       
  1786     return FALSE;
       
  1787   }
       
  1788 activate_failed:
       
  1789   {
       
  1790     GST_DEBUG_OBJECT (playbin, "activate failed");
       
  1791     return FALSE;
       
  1792   }
       
  1793 }
       
  1794 
       
  1795 /* The group that is currently playing is copied again to the
       
  1796  * next_group.
       
  1797  */
       
  1798 static gboolean
       
  1799 save_current_group (GstPlayBin * playbin)
       
  1800 {
       
  1801   GstSourceGroup *curr_group;
       
  1802 
       
  1803   GST_DEBUG_OBJECT (playbin, "save current group");
       
  1804 
       
  1805   /* see if there is a current group */
       
  1806   curr_group = playbin->curr_group;
       
  1807   if (curr_group && curr_group->valid) {
       
  1808     /* unlink our pads with the sink */
       
  1809     deactivate_group (playbin, curr_group);
       
  1810   }
       
  1811   /* swap old and new */
       
  1812   playbin->curr_group = playbin->next_group;
       
  1813   playbin->next_group = curr_group;
       
  1814 
       
  1815   return TRUE;
       
  1816 }
       
  1817 
       
  1818 static GstStateChangeReturn
       
  1819 gst_play_bin_change_state (GstElement * element, GstStateChange transition)
       
  1820 {
       
  1821   GstStateChangeReturn ret;
       
  1822   GstPlayBin *playbin;
       
  1823 
       
  1824   playbin = GST_PLAY_BIN (element);
       
  1825 
       
  1826   switch (transition) {
       
  1827     case GST_STATE_CHANGE_READY_TO_PAUSED:
       
  1828       if (!setup_next_source (playbin))
       
  1829         goto source_failed;
       
  1830       break;
       
  1831     default:
       
  1832       break;
       
  1833   }
       
  1834 
       
  1835   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
       
  1836   if (ret == GST_STATE_CHANGE_FAILURE)
       
  1837     return ret;
       
  1838 
       
  1839   switch (transition) {
       
  1840     case GST_STATE_CHANGE_READY_TO_PAUSED:
       
  1841       break;
       
  1842     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
       
  1843       /* FIXME Release audio device when we implement that */
       
  1844       break;
       
  1845     case GST_STATE_CHANGE_PAUSED_TO_READY:
       
  1846       save_current_group (playbin);
       
  1847       break;
       
  1848     default:
       
  1849       break;
       
  1850   }
       
  1851 
       
  1852   return ret;
       
  1853 
       
  1854   /* ERRORS */
       
  1855 source_failed:
       
  1856   {
       
  1857     return GST_STATE_CHANGE_FAILURE;
       
  1858   }
       
  1859 }
       
  1860 #ifdef __SYMBIAN32__
       
  1861 EXPORT_C
       
  1862 #endif
       
  1863 
       
  1864 
       
  1865 gboolean
       
  1866 gst_play_bin2_plugin_init (GstPlugin * plugin)
       
  1867 {
       
  1868   GST_DEBUG_CATEGORY_INIT (gst_play_bin_debug, "playbin2", 0, "play bin");
       
  1869 
       
  1870   return gst_element_register (plugin, "playbin2", GST_RANK_NONE,
       
  1871       GST_TYPE_PLAY_BIN);
       
  1872 }