gst_plugins_base/gst/playback/gstplaybin.c
changeset 8 4a7fac7dd34a
parent 0 0e761a78d257
child 30 7e817e7e631c
equal deleted inserted replaced
7:71e347f905f2 8:4a7fac7dd34a
    18  */
    18  */
    19 
    19 
    20 /**
    20 /**
    21  * SECTION:element-playbin
    21  * SECTION:element-playbin
    22  *
    22  *
    23  * <refsect2>
       
    24  * <para>
       
    25  * Playbin provides a stand-alone everything-in-one abstraction for an
    23  * Playbin provides a stand-alone everything-in-one abstraction for an
    26  * audio and/or video player.
    24  * audio and/or video player.
    27  * </para>
    25  *
    28  * <para>
       
    29  * It can handle both audio and video files and features
    26  * It can handle both audio and video files and features
    30  * <itemizedlist>
    27  * <itemizedlist>
    31  * <listitem>
    28  * <listitem>
    32  * automatic file type recognition and based on that automatic
    29  * automatic file type recognition and based on that automatic
    33  * selection and usage of the right audio/video/subtitle demuxers/decoders
    30  * selection and usage of the right audio/video/subtitle demuxers/decoders
    52  * </listitem>
    49  * </listitem>
    53  * <listitem>
    50  * <listitem>
    54  * volume control
    51  * volume control
    55  * </listitem>
    52  * </listitem>
    56  * </itemizedlist>
    53  * </itemizedlist>
    57  * </para>
    54  *
       
    55  * <refsect2>
    58  * <title>Usage</title>
    56  * <title>Usage</title>
    59  * <para>
    57  * <para>
    60  * A playbin element can be created just like any other element using
    58  * 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"
    59  * gst_element_factory_make(). The file/URI to play should be set via the #GstPlayBin:uri
    62  * property. This must be an absolute URI, relative file paths are not allowed.
    60  * 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
    61  * Example URIs are file:///home/joe/movie.avi or http://www.joedoe.com/foo.ogg
    64  * </para>
    62  *
    65  * <para>
       
    66  * Playbin is a #GstPipeline. It will notify the application of everything
    63  * Playbin is a #GstPipeline. It will notify the application of everything
    67  * that's happening (errors, end of stream, tags found, state changes, etc.)
    64  * 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
    65  * by posting messages on its #GstBus. The application needs to watch the
    69  * bus.
    66  * bus.
    70  * </para>
    67  *
    71  * <para>
       
    72  * Playback can be initiated by setting the element to PLAYING state using
    68  * 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
    69  * 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
    70  * 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.
    71  * 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
    72  * Applications using playbin should ideally be written to deal with things
    77  * completely asynchroneous.
    73  * completely asynchroneous.
    78  * </para>
    74  *
    79  * <para>
       
    80  * When playback has finished (an EOS message has been received on the bus)
    75  * 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
    76  * 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
    77  * 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
    78  * READY or NULL state, then the #GstPlayBin:uri property should be set to the
    84  * location and then playbin be set to PLAYING state again.
    79  * new location and then playbin be set to PLAYING state again.
    85  * </para>
    80  *
    86  * <para>
       
    87  * Seeking can be done using gst_element_seek_simple() or gst_element_seek()
    81  * 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
    82  * on the playbin element. Again, the seek will not be executed
    89  * instantaneously, but will be done in a background thread. When the seek
    83  * 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
    84  * 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
    85  * 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
    86  * -1 as the timeout, but this will block the user interface and is not
    93  * recommended at all.
    87  * recommended at all.
    94  * </para>
    88  *
    95  * <para>
       
    96  * Applications may query the current position and duration of the stream
    89  * Applications may query the current position and duration of the stream
    97  * via gst_element_query_position() and gst_element_query_duration() and
    90  * 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,
    91  * 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.
    92  * the duration or position will have been returned in units of nanoseconds.
   100  * </para>
    93  * </para>
       
    94  * </refsect2>
       
    95  * <refsect2>
   101  * <title>Advanced Usage: specifying the audio and video sink</title>
    96  * <title>Advanced Usage: specifying the audio and video sink</title>
   102  * <para>
    97  * <para>
   103  * By default, if no audio sink or video sink has been specified via the
    98  * 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
    99  * #GstPlayBin:audio-sink or #GstPlayBin:video-sink property, playbin will use
   105  * and autovideosink elements to find the first-best available output method.
   100  * the autoaudiosink and autovideosink elements to find the first-best
       
   101  * available output method.
   106  * This should work in most cases, but is not always desirable. Often either
   102  * 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
   103  * the user or application might want to specify more explicitly what to use
   108  * for audio and video output.
   104  * for audio and video output.
   109  * </para>
   105  *
   110  * <para>
       
   111  * If the application wants more control over how audio or video should be
   106  * 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
   107  * 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
   108  * using gst_element_factory_make()) and provide them to playbin using the
   114  * "audio-sink" or "video-sink" property.
   109  * #GstPlayBin:audio-sink or #GstPlayBin:video-sink property.
   115  * </para>
   110  *
   116  * <para>
       
   117  * GNOME-based applications, for example, will usually want to create
   111  * GNOME-based applications, for example, will usually want to create
   118  * gconfaudiosink and gconfvideosink elements and make playbin use those,
   112  * gconfaudiosink and gconfvideosink elements and make playbin use those,
   119  * so that output happens to whatever the user has configured in the GNOME
   113  * so that output happens to whatever the user has configured in the GNOME
   120  * Multimedia System Selector confinguration dialog.
   114  * Multimedia System Selector confinguration dialog.
   121  * </para>
   115  *
   122  * <para>
       
   123  * The sink elements do not necessarily need to be ready-made sinks. It is
   116  * 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,
   117  * 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
   118  * 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
   119  * 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
   120  * 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
   121  * 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
   122  * 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.
   123  * format or to modify or observe the data before it is output.
   131  * </para>
   124  *
   132  * <para>
       
   133  * It is also possible to 'suppress' audio and/or video output by using
   125  * 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
   126  * 'fakesink' elements (or capture it from there using the fakesink element's
   135  * "handoff" signal, which, nota bene, is fired from the streaming thread!).
   127  * "handoff" signal, which, nota bene, is fired from the streaming thread!).
   136  * </para>
   128  * </para>
       
   129  * </refsect2>
       
   130  * <refsect2>
   137  * <title>Retrieving Tags and Other Meta Data</title>
   131  * <title>Retrieving Tags and Other Meta Data</title>
   138  * <para>
   132  * <para>
   139  * Most of the common meta data (artist, title, etc.) can be retrieved by
   133  * 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).
   134  * watching for TAG messages on the pipeline's bus (see above).
   141  * </para>
   135  *
   142  * <para>
       
   143  * Other more specific meta information like width/height/framerate of video
   136  * Other more specific meta information like width/height/framerate of video
   144  * streams or samplerate/number of channels of audio streams can be obtained
   137  * 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
   138  * using the  #GstPlayBaseBin:stream-info property, which will return a GList of
   146  * objects, one for each stream. These are opaque objects that can only be
   139  * stream info objects, one for each stream. These are opaque objects that can
   147  * accessed via the standard GObject property interface, ie. g_object_get().
   140  * only be accessed via the standard GObject property interface, ie. g_object_get().
   148  * Each stream info object has the following properties:
   141  * Each stream info object has the following properties:
   149  * <itemizedlist>
   142  * <itemizedlist>
   150  * <listitem>"object" (GstObject) (the decoder source pad usually)</listitem>
   143  * <listitem>"object" (GstObject) (the decoder source pad usually)</listitem>
   151  * <listitem>"type" (enum) (if this is an audio/video/subtitle stream)</listitem>
   144  * <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>
   145  * <listitem>"decoder" (string) (name of decoder used to decode this stream)</listitem>
   153  * <listitem>"mute" (boolean) (to mute or unmute this stream)</listitem>
   146  * <listitem>"mute" (boolean) (to mute or unmute this stream)</listitem>
   154  * <listitem>"caps" (GstCaps) (caps of the decoded stream)</listitem>
   147  * <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>
   148  * <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>
   149  * <listitem>"codec" (string) (format this stream was encoded in)</listitem>
   157  * </itemizedlist>
   150  * </itemizedlist>
   158  * Stream information from the stream-info properties is best queried once
   151  * Stream information from the #GstPlayBaseBin:stream-info property is best queried once
   159  * playbin has changed into PAUSED or PLAYING state (which can be detected
   152  * 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
   153  * via a state-changed message on the #GstBus where old_state=READY and
   161  * new_state=PAUSED), since before that the list might not be complete yet or
   154  * new_state=PAUSED), since before that the list might not be complete yet or
   162  * not contain all available information (like language-codes).
   155  * not contain all available information (like language-codes).
   163  * </para>
   156  * </para>
       
   157  * </refsect2>
       
   158  * <refsect2>
   164  * <title>Buffering</title>
   159  * <title>Buffering</title>
   165  * <para>
       
   166  * Playbin handles buffering automatically for the most part, but applications
   160  * Playbin handles buffering automatically for the most part, but applications
   167  * need to handle parts of the buffering process as well. Whenever playbin is
   161  * 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
   162  * buffering, it will post BUFFERING messages on the bus with a percentage
   169  * value that shows the progress of the buffering process. Applications need
   163  * 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.
   164  * 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
   165  * 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
   166  * way. Here is how to extract the percentage information from the message
   173  * (requires GStreamer >= 0.10.11):
   167  * (requires GStreamer >= 0.10.11):
   174  * </para>
   168  * |[
   175  * <para>
       
   176  * <programlisting>
       
   177  * switch (GST_MESSAGE_TYPE (msg)) {
   169  * switch (GST_MESSAGE_TYPE (msg)) {
   178  *   case GST_MESSAGE_BUFFERING: {
   170  *   case GST_MESSAGE_BUFFERING: {
   179  *     gint percent = 0;
   171  *     gint percent = 0;
   180  *     gst_message_parse_buffering (msg, &amp;percent);
   172  *     gst_message_parse_buffering (msg, &amp;percent);
   181  *     g_print ("Buffering (%%u percent done)", percent);
   173  *     g_print ("Buffering (%%u percent done)", percent);
   182  *     break;
   174  *     break;
   183  *   }
   175  *   }
   184  *   ...
   176  *   ...
   185  * }
   177  * }
   186  * </programlisting>
   178  * ]|
   187  * Note that applications should keep/set the pipeline in the PAUSED state when
   179  * 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
   180  * 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
   181  * 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).
   182  * of 100 percent is received (if PLAYING is the desired state, that is).
   191  * </para>
   183  * </refsect2>
       
   184  * <refsect2>
   192  * <title>Embedding the video window in your application</title>
   185  * <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
   186  * 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
   187  * 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
   188  * own, however. This can be done using the #GstXOverlay interface, which most
   197  * video sinks implement. See the documentation there for more details.
   189  * video sinks implement. See the documentation there for more details.
   198  * </para>
   190  * </refsect2>
       
   191  * <refsect2>
   199  * <title>Specifying which CD/DVD device to use</title>
   192  * <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
   193  * 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
   194  * 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
   195  * 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.
   196  * 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"
   197  * 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
   198  * 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
   199  * the device as part of the URI, but at the time of writing this is not
   208  * possible yet.
   200  * possible yet.
   209  * </para>
   201  * </refsect2>
       
   202  * <refsect2>
   210  * <title>Examples</title>
   203  * <title>Examples</title>
   211  * <para>
   204  * |[
   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
   205  * gst-launch -v playbin uri=file:///path/to/somefile.avi
   215  * </programlisting>
   206  * ]| This will play back the given AVI video file, given that the video and
   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
   207  * 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),
   208  * 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
   209  * playbin will try to find a suitable audio and video sink automatically
   220  * using the autoaudiosink and autovideosink elements.
   210  * using the autoaudiosink and autovideosink elements.
   221  * </para>
   211  * |[
   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
   212  * gst-launch -v playbin uri=cdda://4
   226  * </programlisting>
   213  * ]| This will play back track 4 on an audio CD in your disc drive (assuming
   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).
   214  * the drive is detected automatically by the plugin).
   229  * </para>
   215  * |[
   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
   216  * gst-launch -v playbin uri=dvd://1
   234  * </programlisting>
   217  * ]| This will play back title 1 of a DVD in your disc drive (assuming
   235  * This will play back title 1 of a DVD in your disc drive (assuming
       
   236  * the drive is detected automatically by the plugin).
   218  * the drive is detected automatically by the plugin).
   237  * </para>
       
   238  * </refsect2>
   219  * </refsect2>
   239  */
   220  */
   240 
   221 
   241 #ifdef HAVE_CONFIG_H
   222 #ifdef HAVE_CONFIG_H
   242 #include "config.h"
   223 #include "config.h"
   247 
   228 
   248 #include <gst/gst-i18n-plugin.h>
   229 #include <gst/gst-i18n-plugin.h>
   249 #include <gst/pbutils/pbutils.h>
   230 #include <gst/pbutils/pbutils.h>
   250 
   231 
   251 #include "gstplaybasebin.h"
   232 #include "gstplaybasebin.h"
   252 
       
   253 #ifdef __SYMBIAN32__
       
   254 #include <glib_global.h>
       
   255 #endif
       
   256 
   233 
   257 GST_DEBUG_CATEGORY_STATIC (gst_play_bin_debug);
   234 GST_DEBUG_CATEGORY_STATIC (gst_play_bin_debug);
   258 #define GST_CAT_DEFAULT gst_play_bin_debug
   235 #define GST_CAT_DEFAULT gst_play_bin_debug
   259 
   236 
   260 #define GST_TYPE_PLAY_BIN               (gst_play_bin_get_type())
   237 #define GST_TYPE_PLAY_BIN               (gst_play_bin_get_type())
   266 #define VOLUME_MAX_DOUBLE 10.0
   243 #define VOLUME_MAX_DOUBLE 10.0
   267 
   244 
   268 typedef struct _GstPlayBin GstPlayBin;
   245 typedef struct _GstPlayBin GstPlayBin;
   269 typedef struct _GstPlayBinClass GstPlayBinClass;
   246 typedef struct _GstPlayBinClass GstPlayBinClass;
   270 
   247 
       
   248 /**
       
   249  * GstPlayBin:
       
   250  *
       
   251  * High-level player element
       
   252  */
   271 struct _GstPlayBin
   253 struct _GstPlayBin
   272 {
   254 {
   273   GstPlayBaseBin parent;
   255   GstPlayBaseBin parent;
   274 
   256 
   275   /* the configurable elements */
   257   /* the configurable elements */
   278   GstElement *video_sink;
   260   GstElement *video_sink;
   279   GstElement *visualisation;
   261   GstElement *visualisation;
   280   GstElement *pending_visualisation;
   262   GstElement *pending_visualisation;
   281   GstElement *volume_element;
   263   GstElement *volume_element;
   282   GstElement *textoverlay_element;
   264   GstElement *textoverlay_element;
       
   265   GstElement *spu_element;
   283   gfloat volume;
   266   gfloat volume;
   284 
   267 
   285   /* these are the currently active sinks */
   268   /* these are the currently active sinks */
   286   GList *sinks;
   269   GList *sinks;
   287 
   270 
   328 static gboolean setup_sinks (GstPlayBaseBin * play_base_bin,
   311 static gboolean setup_sinks (GstPlayBaseBin * play_base_bin,
   329     GstPlayBaseGroup * group);
   312     GstPlayBaseGroup * group);
   330 static void remove_sinks (GstPlayBin * play_bin);
   313 static void remove_sinks (GstPlayBin * play_bin);
   331 static void playbin_set_subtitles_visible (GstPlayBaseBin * play_base_bin,
   314 static void playbin_set_subtitles_visible (GstPlayBaseBin * play_base_bin,
   332     gboolean visible);
   315     gboolean visible);
       
   316 static void playbin_set_audio_mute (GstPlayBaseBin * play_base_bin,
       
   317     gboolean mute);
   333 
   318 
   334 static void gst_play_bin_set_property (GObject * object, guint prop_id,
   319 static void gst_play_bin_set_property (GObject * object, guint prop_id,
   335     const GValue * value, GParamSpec * spec);
   320     const GValue * value, GParamSpec * spec);
   336 static void gst_play_bin_get_property (GObject * object, guint prop_id,
   321 static void gst_play_bin_get_property (GObject * object, guint prop_id,
   337     GValue * value, GParamSpec * spec);
   322     GValue * value, GParamSpec * spec);
   398   gobject_klass->get_property = gst_play_bin_get_property;
   383   gobject_klass->get_property = gst_play_bin_get_property;
   399 
   384 
   400   g_object_class_install_property (gobject_klass, ARG_VIDEO_SINK,
   385   g_object_class_install_property (gobject_klass, ARG_VIDEO_SINK,
   401       g_param_spec_object ("video-sink", "Video Sink",
   386       g_param_spec_object ("video-sink", "Video Sink",
   402           "the video output element to use (NULL = default sink)",
   387           "the video output element to use (NULL = default sink)",
   403           GST_TYPE_ELEMENT, G_PARAM_READWRITE));
   388           GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
   404   g_object_class_install_property (gobject_klass, ARG_AUDIO_SINK,
   389   g_object_class_install_property (gobject_klass, ARG_AUDIO_SINK,
   405       g_param_spec_object ("audio-sink", "Audio Sink",
   390       g_param_spec_object ("audio-sink", "Audio Sink",
   406           "the audio output element to use (NULL = default sink)",
   391           "the audio output element to use (NULL = default sink)",
   407           GST_TYPE_ELEMENT, G_PARAM_READWRITE));
   392           GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
   408   g_object_class_install_property (gobject_klass, ARG_VIS_PLUGIN,
   393   g_object_class_install_property (gobject_klass, ARG_VIS_PLUGIN,
   409       g_param_spec_object ("vis-plugin", "Vis plugin",
   394       g_param_spec_object ("vis-plugin", "Vis plugin",
   410           "the visualization element to use (NULL = none)",
   395           "the visualization element to use (NULL = none)",
   411           GST_TYPE_ELEMENT, G_PARAM_READWRITE));
   396           GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
   412   g_object_class_install_property (gobject_klass, ARG_VOLUME,
   397   g_object_class_install_property (gobject_klass, ARG_VOLUME,
   413       g_param_spec_double ("volume", "volume", "volume",
   398       g_param_spec_double ("volume", "volume", "volume",
   414           0.0, VOLUME_MAX_DOUBLE, 1.0, G_PARAM_READWRITE));
   399           0.0, VOLUME_MAX_DOUBLE, 1.0,
       
   400           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
   415   g_object_class_install_property (gobject_klass, ARG_FRAME,
   401   g_object_class_install_property (gobject_klass, ARG_FRAME,
   416       gst_param_spec_mini_object ("frame", "Frame",
   402       gst_param_spec_mini_object ("frame", "Frame",
   417           "The last frame (NULL = no video available)",
   403           "The last frame (NULL = no video available)", GST_TYPE_BUFFER,
   418           GST_TYPE_BUFFER, G_PARAM_READABLE));
   404           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
   419   g_object_class_install_property (gobject_klass, ARG_FONT_DESC,
   405   g_object_class_install_property (gobject_klass, ARG_FONT_DESC,
   420       g_param_spec_string ("subtitle-font-desc",
   406       g_param_spec_string ("subtitle-font-desc", "Subtitle font description",
   421           "Subtitle font description",
   407           "Pango font description of font " "to be used for subtitle rendering",
   422           "Pango font description of font "
   408           NULL, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
   423           "to be used for subtitle rendering", NULL, G_PARAM_WRITABLE));
       
   424 
   409 
   425   gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_play_bin_dispose);
   410   gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_play_bin_dispose);
   426 
   411 
   427   gst_element_class_set_details (gstelement_klass, &gst_play_bin_details);
   412   gst_element_class_set_details (gstelement_klass, &gst_play_bin_details);
   428 
   413 
   433   gstbin_klass->handle_message =
   418   gstbin_klass->handle_message =
   434       GST_DEBUG_FUNCPTR (gst_play_bin_handle_message);
   419       GST_DEBUG_FUNCPTR (gst_play_bin_handle_message);
   435 
   420 
   436   playbasebin_klass->setup_output_pads = setup_sinks;
   421   playbasebin_klass->setup_output_pads = setup_sinks;
   437   playbasebin_klass->set_subtitles_visible = playbin_set_subtitles_visible;
   422   playbasebin_klass->set_subtitles_visible = playbin_set_subtitles_visible;
       
   423   playbasebin_klass->set_audio_mute = playbin_set_audio_mute;
   438 }
   424 }
   439 
   425 
   440 static void
   426 static void
   441 gst_play_bin_init (GstPlayBin * play_bin)
   427 gst_play_bin_init (GstPlayBin * play_bin)
   442 {
   428 {
   444   play_bin->audio_sink = NULL;
   430   play_bin->audio_sink = NULL;
   445   play_bin->visualisation = NULL;
   431   play_bin->visualisation = NULL;
   446   play_bin->pending_visualisation = NULL;
   432   play_bin->pending_visualisation = NULL;
   447   play_bin->volume_element = NULL;
   433   play_bin->volume_element = NULL;
   448   play_bin->textoverlay_element = NULL;
   434   play_bin->textoverlay_element = NULL;
       
   435   play_bin->spu_element = NULL;
   449   play_bin->volume = 1.0;
   436   play_bin->volume = 1.0;
   450   play_bin->sinks = NULL;
   437   play_bin->sinks = NULL;
   451   play_bin->frame = NULL;
   438   play_bin->frame = NULL;
   452   play_bin->font_desc = NULL;
   439   play_bin->font_desc = NULL;
   453   play_bin->cache = g_hash_table_new_full (g_str_hash, g_str_equal,
   440   play_bin->cache = g_hash_table_new_full (g_str_hash, g_str_equal,
   489   }
   476   }
   490   if (play_bin->textoverlay_element != NULL) {
   477   if (play_bin->textoverlay_element != NULL) {
   491     gst_object_unref (play_bin->textoverlay_element);
   478     gst_object_unref (play_bin->textoverlay_element);
   492     play_bin->textoverlay_element = NULL;
   479     play_bin->textoverlay_element = NULL;
   493   }
   480   }
       
   481   if (play_bin->spu_element != NULL) {
       
   482     gst_object_unref (play_bin->spu_element);
       
   483     play_bin->spu_element = NULL;
       
   484   }
   494   g_free (play_bin->font_desc);
   485   g_free (play_bin->font_desc);
   495   play_bin->font_desc = NULL;
   486   play_bin->font_desc = NULL;
   496 
   487 
   497   G_OBJECT_CLASS (parent_class)->dispose (object);
   488   G_OBJECT_CLASS (parent_class)->dispose (object);
   498 }
   489 }
   536 
   527 
   537   if (!GST_IS_BIN (vis_bin) || !GST_IS_PAD (tee_pad)) {
   528   if (!GST_IS_BIN (vis_bin) || !GST_IS_PAD (tee_pad)) {
   538     goto beach;
   529     goto beach;
   539   }
   530   }
   540 
   531 
   541   vis_src_pad = gst_element_get_pad (play_bin->visualisation, "src");
   532   vis_src_pad = gst_element_get_static_pad (play_bin->visualisation, "src");
   542   vis_sink_pad = gst_pad_get_peer (tee_pad);
   533   vis_sink_pad = gst_pad_get_peer (tee_pad);
   543 
   534 
   544   /* Can be fakesink */
   535   /* Can be fakesink */
   545   if (GST_IS_PAD (vis_src_pad)) {
   536   if (GST_IS_PAD (vis_src_pad)) {
   546     vqueue_pad = gst_pad_get_peer (vis_src_pad);
   537     vqueue_pad = gst_pad_get_peer (vis_src_pad);
   579     /* Add the new one */
   570     /* Add the new one */
   580     gst_bin_add (vis_bin, pending_visualisation);
   571     gst_bin_add (vis_bin, pending_visualisation);
   581     /* Synchronizing state */
   572     /* Synchronizing state */
   582     gst_element_set_state (pending_visualisation, bin_state);
   573     gst_element_set_state (pending_visualisation, bin_state);
   583 
   574 
   584     vis_sink_pad = gst_element_get_pad (pending_visualisation, "sink");
   575     vis_sink_pad = gst_element_get_static_pad (pending_visualisation, "sink");
   585     vis_src_pad = gst_element_get_pad (pending_visualisation, "src");
   576     vis_src_pad = gst_element_get_static_pad (pending_visualisation, "src");
   586 
   577 
   587     if (!GST_IS_PAD (vis_sink_pad) || !GST_IS_PAD (vis_src_pad)) {
   578     if (!GST_IS_PAD (vis_sink_pad) || !GST_IS_PAD (vis_src_pad)) {
   588       goto beach;
   579       goto beach;
   589     }
   580     }
   590 
   581 
   680           /* Check if the visualisation is already in a bin */
   671           /* Check if the visualisation is already in a bin */
   681           if (GST_IS_BIN (vis_bin)) {
   672           if (GST_IS_BIN (vis_bin)) {
   682             GstPad *vis_sink_pad = NULL, *tee_pad = NULL;
   673             GstPad *vis_sink_pad = NULL, *tee_pad = NULL;
   683 
   674 
   684             /* Now get tee pad and block it async */
   675             /* Now get tee pad and block it async */
   685             vis_sink_pad = gst_element_get_pad (play_bin->visualisation,
   676             vis_sink_pad = gst_element_get_static_pad (play_bin->visualisation,
   686                 "sink");
   677                 "sink");
   687             if (!GST_IS_PAD (vis_sink_pad)) {
   678             if (!GST_IS_PAD (vis_sink_pad)) {
   688               goto beach;
   679               goto beach;
   689             }
   680             }
   690             tee_pad = gst_pad_get_peer (vis_sink_pad);
   681             tee_pad = gst_pad_get_peer (vis_sink_pad);
   779   /* applications need to know the buffer caps,
   770   /* applications need to know the buffer caps,
   780    * make sure they are always set on the frame */
   771    * make sure they are always set on the frame */
   781   if (GST_BUFFER_CAPS (frame) == NULL) {
   772   if (GST_BUFFER_CAPS (frame) == NULL) {
   782     GstPad *pad;
   773     GstPad *pad;
   783 
   774 
   784     if ((pad = gst_element_get_pad (identity, "sink"))) {
   775     if ((pad = gst_element_get_static_pad (identity, "sink"))) {
   785       gst_buffer_set_caps (frame, GST_PAD_CAPS (pad));
   776       gst_buffer_set_caps (frame, GST_PAD_CAPS (pad));
   786       gst_object_unref (pad);
   777       gst_object_unref (pad);
   787     }
   778     }
   788   }
   779   }
   789 
   780 
   868   /* be more careful with the pad from the custom sink element, it might not
   859   /* be more careful with the pad from the custom sink element, it might not
   869    * be named 'sink' */
   860    * be named 'sink' */
   870   if (!gst_element_link_pads (scale, "src", sink, NULL))
   861   if (!gst_element_link_pads (scale, "src", sink, NULL))
   871     goto link_failed;
   862     goto link_failed;
   872 
   863 
   873   pad = gst_element_get_pad (identity, "sink");
   864   pad = gst_element_get_static_pad (identity, "sink");
   874   gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad));
   865   gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad));
   875   gst_object_unref (pad);
   866   gst_object_unref (pad);
   876 
   867 
   877   gst_element_set_state (element, GST_STATE_READY);
   868   gst_element_set_state (element, GST_STATE_READY);
   878 
   869 
   924  *
   915  *
   925  *  +--------------------------------------------------+
   916  *  +--------------------------------------------------+
   926  *  | tbin                  +-------------+            |
   917  *  | tbin                  +-------------+            |
   927  *  |          +-----+      | textoverlay |   +------+ |
   918  *  |          +-----+      | textoverlay |   +------+ |
   928  *  |          | csp | +--video_sink      |   | vbin | |
   919  *  |          | csp | +--video_sink      |   | vbin | |
   929  * video_sink-sink  src+ +-text_sink     src-sink    | |
   920  * video_sink-sink  src+ +-text_sink    src---sink   | |
   930  *  |          +-----+   |  +-------------+   +------+ |
   921  *  |          +-----+   |  +-------------+   +------+ |
   931  * text_sink-------------+                             |
   922  * text_sink-------------+                             |
   932  *  +--------------------------------------------------+
   923  *  +--------------------------------------------------+
   933  *
   924  *
   934  *  If there is no subtitle renderer this function will simply return the
   925  *  If there is no subtitle renderer this function will simply return the
   935  *  videosink without the text_sink pad.
   926  *  videosink without the text_sink pad.
   936  */
   927  */
   937 static GstElement *
   928 static GstElement *
   938 gen_text_element (GstPlayBin * play_bin)
   929 add_text_element (GstPlayBin * play_bin, GstElement * vbin)
   939 {
   930 {
   940   GstElement *element, *csp, *overlay, *vbin;
   931   GstElement *element, *csp, *overlay;
   941   GstPad *pad;
   932   GstPad *pad;
   942 
       
   943   /* Create the video rendering bin, error is posted when this fails. */
       
   944   vbin = gen_video_element (play_bin);
       
   945   if (!vbin)
       
   946     return NULL;
       
   947 
   933 
   948   /* Text overlay */
   934   /* Text overlay */
   949   overlay = gst_element_factory_make ("textoverlay", "overlay");
   935   overlay = gst_element_factory_make ("textoverlay", "overlay");
   950 
   936 
   951   /* If no overlay return the video bin without subtitle support. */
   937   /* If no overlay return the video bin without subtitle support. */
   974   /* Link */
   960   /* Link */
   975   gst_element_link_pads (csp, "src", overlay, "video_sink");
   961   gst_element_link_pads (csp, "src", overlay, "video_sink");
   976   gst_element_link_pads (overlay, "src", vbin, "sink");
   962   gst_element_link_pads (overlay, "src", vbin, "sink");
   977 
   963 
   978   /* Add ghost pads on the subtitle bin */
   964   /* Add ghost pads on the subtitle bin */
   979   pad = gst_element_get_pad (overlay, "text_sink");
   965   pad = gst_element_get_static_pad (overlay, "text_sink");
   980   gst_element_add_pad (element, gst_ghost_pad_new ("text_sink", pad));
   966   gst_element_add_pad (element, gst_ghost_pad_new ("text_sink", pad));
   981   gst_object_unref (pad);
   967   gst_object_unref (pad);
   982 
   968 
   983   pad = gst_element_get_pad (csp, "sink");
   969   pad = gst_element_get_static_pad (csp, "sink");
   984   gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad));
   970   gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad));
   985   gst_object_unref (pad);
   971   gst_object_unref (pad);
       
   972 
       
   973   /* If the vbin provides a subpicture sink pad, ghost it too */
       
   974   pad = gst_element_get_static_pad (vbin, "subpicture_sink");
       
   975   if (pad) {
       
   976     gst_element_add_pad (element, gst_ghost_pad_new ("subpicture_sink", pad));
       
   977     gst_object_unref (pad);
       
   978   }
   986 
   979 
   987   /* Set state to READY */
   980   /* Set state to READY */
   988   gst_element_set_state (element, GST_STATE_READY);
   981   gst_element_set_state (element, GST_STATE_READY);
   989 
   982 
   990   return element;
   983   return element;
   993 no_overlay:
   986 no_overlay:
   994   {
   987   {
   995     post_missing_element_message (play_bin, "textoverlay");
   988     post_missing_element_message (play_bin, "textoverlay");
   996     GST_WARNING_OBJECT (play_bin,
   989     GST_WARNING_OBJECT (play_bin,
   997         "No overlay (pango) element, subtitles disabled");
   990         "No overlay (pango) element, subtitles disabled");
       
   991     return vbin;
       
   992   }
       
   993 }
       
   994 
       
   995 /* make an element for rendering DVD subpictures onto output video
       
   996  *
       
   997  *  +---------------------------------------------+
       
   998  *  | tbin                   +--------+           |
       
   999  *  |          +-----+       |        |  +------+ |
       
  1000  *  |          | csp | src-videosink  |  | vbin | |
       
  1001  * video_sink-sink  src+     |       src-sink   | |
       
  1002  *  |          +-----+   +subpicture  |  +------+ |
       
  1003  * subpicture_pad--------+   +--------+           |
       
  1004  *  +---------- ----------------------------------+
       
  1005  *
       
  1006  */
       
  1007 static GstElement *
       
  1008 add_spu_element (GstPlayBin * play_bin, GstElement * vbin)
       
  1009 {
       
  1010   GstElement *element, *csp, *overlay;
       
  1011   GstPad *pad;
       
  1012 
       
  1013   /* DVD spu overlay */
       
  1014   GST_DEBUG_OBJECT (play_bin, "Attempting to insert DVD SPU element");
       
  1015 
       
  1016   overlay = gst_element_factory_make ("dvdspu", "overlay");
       
  1017 
       
  1018   /* If no overlay return the video bin without subpicture support. */
       
  1019   if (!overlay)
       
  1020     goto no_overlay;
       
  1021 
       
  1022   /* Create our bin */
       
  1023   element = gst_bin_new ("spubin");
       
  1024 
       
  1025   /* Take a ref */
       
  1026   play_bin->spu_element = GST_ELEMENT_CAST (gst_object_ref (overlay));
       
  1027 
       
  1028   /* we know this will succeed, as the video bin already created one before */
       
  1029   csp = gst_element_factory_make ("ffmpegcolorspace", "spucsp");
       
  1030 
       
  1031   /* Add our elements */
       
  1032   gst_bin_add_many (GST_BIN_CAST (element), csp, overlay, vbin, NULL);
       
  1033 
       
  1034   /* Link */
       
  1035   gst_element_link_pads (csp, "src", overlay, "video");
       
  1036   gst_element_link_pads (overlay, "src", vbin, "sink");
       
  1037 
       
  1038   /* Add ghost pad on the subpicture bin so it looks like vbin */
       
  1039   pad = gst_element_get_static_pad (csp, "sink");
       
  1040   gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad));
       
  1041   gst_object_unref (pad);
       
  1042 
       
  1043   pad = gst_element_get_static_pad (overlay, "subpicture");
       
  1044   gst_element_add_pad (element, gst_ghost_pad_new ("subpicture_sink", pad));
       
  1045   gst_object_unref (pad);
       
  1046 
       
  1047   /* Set state to READY */
       
  1048   gst_element_set_state (element, GST_STATE_READY);
       
  1049 
       
  1050   return element;
       
  1051 
       
  1052   /* ERRORS */
       
  1053 no_overlay:
       
  1054   {
       
  1055     post_missing_element_message (play_bin, "dvdspu");
       
  1056     GST_WARNING_OBJECT (play_bin,
       
  1057         "No DVD overlay (dvdspu) element. "
       
  1058         "menu highlight/subtitles unavailable");
   998     return vbin;
  1059     return vbin;
   999   }
  1060   }
  1000 }
  1061 }
  1001 
  1062 
  1002 /* make the element (bin) that contains the elements needed to perform
  1063 /* make the element (bin) that contains the elements needed to perform
  1056 
  1117 
  1057   scale = gst_element_factory_make ("audioresample", "aresample");
  1118   scale = gst_element_factory_make ("audioresample", "aresample");
  1058   if (scale == NULL)
  1119   if (scale == NULL)
  1059     goto no_audioresample;
  1120     goto no_audioresample;
  1060   gst_bin_add (GST_BIN_CAST (element), scale);
  1121   gst_bin_add (GST_BIN_CAST (element), scale);
  1061 #ifndef __SYMBIAN32__
  1122 
  1062   volume = gst_element_factory_make ("volume", "volume");
  1123   volume = gst_element_factory_make ("volume", "volume");
  1063   if (volume == NULL)
  1124   if (volume == NULL)
  1064     goto no_volume;
  1125     goto no_volume;
  1065   g_object_set (G_OBJECT (volume), "volume", play_bin->volume, NULL);
  1126   g_object_set (G_OBJECT (volume), "volume", play_bin->volume, NULL);
  1066   play_bin->volume_element = volume;
  1127   play_bin->volume_element = volume;
  1067   gst_bin_add (GST_BIN_CAST (element), volume);
  1128   gst_bin_add (GST_BIN_CAST (element), volume);
  1068 #endif
       
  1069 
  1129 
  1070   res = gst_element_link_pads (conv, "src", scale, "sink");
  1130   res = gst_element_link_pads (conv, "src", scale, "sink");
  1071 #ifndef __SYMBIAN32__
       
  1072   res &= gst_element_link_pads (scale, "src", volume, "sink");
  1131   res &= gst_element_link_pads (scale, "src", volume, "sink");
  1073 #else
       
  1074   res &= gst_element_link_pads (scale, "src", sink, NULL);
       
  1075 #endif
       
  1076 #ifndef __SYMBIAN32__
       
  1077   res &= gst_element_link_pads (volume, "src", sink, NULL);
  1132   res &= gst_element_link_pads (volume, "src", sink, NULL);
  1078 #endif
       
  1079   if (!res)
  1133   if (!res)
  1080     goto link_failed;
  1134     goto link_failed;
  1081 
  1135 
  1082   pad = gst_element_get_pad (conv, "sink");
  1136   pad = gst_element_get_static_pad (conv, "sink");
  1083   gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad));
  1137   gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad));
  1084   gst_object_unref (pad);
  1138   gst_object_unref (pad);
  1085 
  1139 
  1086   gst_element_set_state (element, GST_STATE_READY);
  1140   gst_element_set_state (element, GST_STATE_READY);
  1087 
  1141 
  1227   res &= gst_element_link_pads (conv2, "src", vis, "sink");
  1281   res &= gst_element_link_pads (conv2, "src", vis, "sink");
  1228   res &= gst_element_link_pads (vis, "src", vsink, "sink");
  1282   res &= gst_element_link_pads (vis, "src", vsink, "sink");
  1229   if (!res)
  1283   if (!res)
  1230     goto link_failed;
  1284     goto link_failed;
  1231 
  1285 
  1232   pad = gst_element_get_pad (aqueue, "sink");
  1286   pad = gst_element_get_static_pad (aqueue, "sink");
  1233   rpad = gst_element_get_request_pad (tee, "src%d");
  1287   rpad = gst_element_get_request_pad (tee, "src%d");
  1234   gst_pad_link (rpad, pad);
  1288   gst_pad_link (rpad, pad);
  1235   gst_object_unref (rpad);
  1289   gst_object_unref (rpad);
  1236   gst_object_unref (pad);
  1290   gst_object_unref (pad);
  1237   gst_element_link_pads (aqueue, "src", asink, "sink");
  1291   gst_element_link_pads (aqueue, "src", asink, "sink");
  1238 
  1292 
  1239   pad = gst_element_get_pad (vqueue, "sink");
  1293   pad = gst_element_get_static_pad (vqueue, "sink");
  1240   rpad = gst_element_get_request_pad (tee, "src%d");
  1294   rpad = gst_element_get_request_pad (tee, "src%d");
  1241   gst_pad_link (rpad, pad);
  1295   gst_pad_link (rpad, pad);
  1242   gst_object_unref (rpad);
  1296   gst_object_unref (rpad);
  1243   gst_object_unref (pad);
  1297   gst_object_unref (pad);
  1244 
  1298 
  1245   pad = gst_element_get_pad (tee, "sink");
  1299   pad = gst_element_get_static_pad (tee, "sink");
  1246   gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad));
  1300   gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad));
  1247   gst_object_unref (pad);
  1301   gst_object_unref (pad);
  1248 
  1302 
  1249   return element;
  1303   return element;
  1250 
  1304 
  1308       play_bin->sinks = g_list_remove (play_bin->sinks, element);
  1362       play_bin->sinks = g_list_remove (play_bin->sinks, element);
  1309       gst_element_set_state (element, GST_STATE_NULL);
  1363       gst_element_set_state (element, GST_STATE_NULL);
  1310       gst_bin_remove (GST_BIN_CAST (parent), element);
  1364       gst_bin_remove (GST_BIN_CAST (parent), element);
  1311       gst_object_unref (parent);
  1365       gst_object_unref (parent);
  1312     }
  1366     }
  1313     pad = gst_element_get_pad (element, "sink");
  1367     pad = gst_element_get_static_pad (element, "sink");
  1314     if (pad != NULL) {
  1368     if (pad != NULL) {
  1315       peer = gst_pad_get_peer (pad);
  1369       peer = gst_pad_get_peer (pad);
  1316       if (peer != NULL) {
  1370       if (peer != NULL) {
  1317         gst_pad_unlink (peer, pad);
  1371         gst_pad_unlink (peer, pad);
  1318         gst_object_unref (peer);
  1372         gst_object_unref (peer);
  1327       play_bin->sinks = g_list_remove (play_bin->sinks, element);
  1381       play_bin->sinks = g_list_remove (play_bin->sinks, element);
  1328       gst_element_set_state (element, GST_STATE_NULL);
  1382       gst_element_set_state (element, GST_STATE_NULL);
  1329       gst_bin_remove (GST_BIN_CAST (parent), element);
  1383       gst_bin_remove (GST_BIN_CAST (parent), element);
  1330       gst_object_unref (parent);
  1384       gst_object_unref (parent);
  1331     }
  1385     }
  1332     pad = gst_element_get_pad (element, "sink");
  1386     pad = gst_element_get_static_pad (element, "sink");
  1333     if (pad != NULL) {
  1387     if (pad != NULL) {
  1334       peer = gst_pad_get_peer (pad);
  1388       peer = gst_pad_get_peer (pad);
  1335       if (peer != NULL) {
  1389       if (peer != NULL) {
  1336         gst_pad_unlink (peer, pad);
  1390         gst_pad_unlink (peer, pad);
  1337         gst_object_unref (peer);
  1391         gst_object_unref (peer);
  1343   for (sinks = play_bin->sinks; sinks; sinks = g_list_next (sinks)) {
  1397   for (sinks = play_bin->sinks; sinks; sinks = g_list_next (sinks)) {
  1344     GstElement *element = GST_ELEMENT_CAST (sinks->data);
  1398     GstElement *element = GST_ELEMENT_CAST (sinks->data);
  1345     GstPad *pad;
  1399     GstPad *pad;
  1346     GstPad *peer;
  1400     GstPad *peer;
  1347 
  1401 
  1348     pad = gst_element_get_pad (element, "sink");
  1402     pad = gst_element_get_static_pad (element, "sink");
  1349 
  1403 
  1350     GST_LOG ("removing sink %p", element);
  1404     GST_LOG ("removing sink %p", element);
  1351 
  1405 
  1352     peer = gst_pad_get_peer (pad);
  1406     peer = gst_pad_get_peer (pad);
  1353     if (peer) {
  1407     if (peer) {
  1427   stateret = gst_element_set_state (sink, state);
  1481   stateret = gst_element_set_state (sink, state);
  1428   if (stateret == GST_STATE_CHANGE_FAILURE)
  1482   if (stateret == GST_STATE_CHANGE_FAILURE)
  1429     goto state_failed;
  1483     goto state_failed;
  1430 
  1484 
  1431   /* we found a sink for this stream, now try to install it */
  1485   /* we found a sink for this stream, now try to install it */
  1432   sinkpad = gst_element_get_pad (sink, "sink");
  1486   sinkpad = gst_element_get_static_pad (sink, "sink");
  1433   linkres = gst_pad_link (srcpad, sinkpad);
  1487   linkres = gst_pad_link (srcpad, sinkpad);
  1434   gst_object_unref (sinkpad);
  1488   gst_object_unref (sinkpad);
  1435 
  1489 
  1436   /* try to link the pad of the sink to the stream */
  1490   /* try to link the pad of the sink to the stream */
  1437   if (GST_PAD_LINK_FAILED (linkres))
  1491   if (GST_PAD_LINK_FAILED (linkres))
  1438     goto link_failed;
  1492     goto link_failed;
  1439 
  1493 
  1440   if (GST_IS_PAD (subtitle_pad)) {
  1494   if (GST_IS_PAD (subtitle_pad)) {
  1441     sinkpad = gst_element_get_pad (sink, "text_sink");
  1495     sinkpad = gst_element_get_static_pad (sink, "text_sink");
  1442     linkres = gst_pad_link (subtitle_pad, sinkpad);
  1496     linkres = gst_pad_link (subtitle_pad, sinkpad);
  1443     gst_object_unref (sinkpad);
  1497     gst_object_unref (sinkpad);
  1444   }
  1498   }
  1445 
  1499 
  1446   /* try to link the subtitle pad of the sink to the stream, this is not
  1500   /* try to link the subtitle pad of the sink to the stream, this is not
  1503 
  1557 
  1504 static gboolean
  1558 static gboolean
  1505 setup_sinks (GstPlayBaseBin * play_base_bin, GstPlayBaseGroup * group)
  1559 setup_sinks (GstPlayBaseBin * play_base_bin, GstPlayBaseGroup * group)
  1506 {
  1560 {
  1507   GstPlayBin *play_bin = GST_PLAY_BIN (play_base_bin);
  1561   GstPlayBin *play_bin = GST_PLAY_BIN (play_base_bin);
  1508   GList *streaminfo = NULL, *s;
  1562   gboolean have_video = FALSE;
  1509   gboolean need_vis = FALSE;
  1563   gboolean need_vis = FALSE;
  1510   gboolean need_text = FALSE;
  1564   gboolean need_text = FALSE;
       
  1565   gboolean need_spu = FALSE;
  1511   GstPad *textsrcpad = NULL, *pad = NULL, *origtextsrcpad = NULL;
  1566   GstPad *textsrcpad = NULL, *pad = NULL, *origtextsrcpad = NULL;
  1512   GstElement *sink;
  1567   GstElement *sink;
  1513   gboolean res = TRUE;
  1568   gboolean res = TRUE;
  1514 
  1569 
  1515   /* get rid of existing sinks */
  1570   /* get rid of existing sinks */
  1517     remove_sinks (play_bin);
  1572     remove_sinks (play_bin);
  1518   }
  1573   }
  1519   GST_DEBUG_OBJECT (play_base_bin, "setupsinks");
  1574   GST_DEBUG_OBJECT (play_base_bin, "setupsinks");
  1520 
  1575 
  1521   /* find out what to do */
  1576   /* find out what to do */
  1522   if (group->type[GST_STREAM_TYPE_VIDEO - 1].npads > 0 &&
  1577   have_video = (group->type[GST_STREAM_TYPE_VIDEO - 1].npads > 0);
  1523       group->type[GST_STREAM_TYPE_TEXT - 1].npads > 0) {
  1578   need_spu = (group->type[GST_STREAM_TYPE_SUBPICTURE - 1].npads != 0);
       
  1579 
       
  1580   if (have_video && group->type[GST_STREAM_TYPE_TEXT - 1].npads > 0) {
  1524     need_text = TRUE;
  1581     need_text = TRUE;
  1525   } else if (group->type[GST_STREAM_TYPE_VIDEO - 1].npads == 0 &&
  1582   } else if (!have_video &&
  1526       group->type[GST_STREAM_TYPE_AUDIO - 1].npads > 0 &&
  1583       group->type[GST_STREAM_TYPE_AUDIO - 1].npads > 0 &&
  1527       play_bin->visualisation != NULL) {
  1584       play_bin->visualisation != NULL) {
  1528     need_vis = TRUE;
  1585     need_vis = TRUE;
  1529   }
  1586   }
  1530 
  1587 
  1531   /* now actually connect everything */
  1588   /* now actually connect everything */
  1532   g_object_get (G_OBJECT (play_base_bin), "stream-info", &streaminfo, NULL);
       
  1533   for (s = streaminfo; s; s = g_list_next (s)) {
       
  1534     GObject *obj = G_OBJECT (s->data);
       
  1535     gint type;
       
  1536     GstObject *object;
       
  1537 
       
  1538     g_object_get (obj, "type", &type, NULL);
       
  1539     g_object_get (obj, "object", &object, NULL);
       
  1540   }
       
  1541 
  1589 
  1542   /* link audio */
  1590   /* link audio */
  1543   if (group->type[GST_STREAM_TYPE_AUDIO - 1].npads > 0) {
  1591   if (group->type[GST_STREAM_TYPE_AUDIO - 1].npads > 0) {
  1544     if (need_vis) {
  1592     if (need_vis) {
  1545       sink = gen_vis_element (play_bin);
  1593       sink = gen_vis_element (play_bin);
  1547       sink = gen_audio_element (play_bin);
  1595       sink = gen_audio_element (play_bin);
  1548     }
  1596     }
  1549     if (!sink)
  1597     if (!sink)
  1550       return FALSE;
  1598       return FALSE;
  1551 
  1599 
  1552     pad = gst_element_get_pad (group->type[GST_STREAM_TYPE_AUDIO - 1].preroll,
  1600     pad =
  1553         "src");
  1601         gst_element_get_static_pad (group->type[GST_STREAM_TYPE_AUDIO -
       
  1602             1].preroll, "src");
  1554     res = add_sink (play_bin, sink, pad, NULL);
  1603     res = add_sink (play_bin, sink, pad, NULL);
  1555     gst_object_unref (pad);
  1604     gst_object_unref (pad);
  1556   }
  1605   }
  1557 
  1606 
  1558   /* link video */
  1607   /* link video */
  1559   if (group->type[GST_STREAM_TYPE_VIDEO - 1].npads > 0) {
  1608   if (have_video) {
       
  1609     /* Create the video rendering bin, error is posted when this fails. */
       
  1610     sink = gen_video_element (play_bin);
       
  1611     if (!sink)
       
  1612       return FALSE;
       
  1613     if (need_spu) {
       
  1614       sink = add_spu_element (play_bin, sink);
       
  1615     }
       
  1616 
  1560     if (need_text) {
  1617     if (need_text) {
  1561       GstObject *parent = NULL, *grandparent = NULL;
  1618       GstObject *parent = NULL, *grandparent = NULL;
  1562       GstPad *ghost = NULL;
  1619       GstPad *ghost = NULL;
  1563 
  1620 
  1564       sink = gen_text_element (play_bin);
  1621       /* Add the subtitle overlay element into the video sink */
       
  1622       sink = add_text_element (play_bin, sink);
       
  1623 
       
  1624       /* Link the incoming subtitle stream into the output bin */
  1565       textsrcpad =
  1625       textsrcpad =
  1566           gst_element_get_pad (group->type[GST_STREAM_TYPE_TEXT - 1].preroll,
  1626           gst_element_get_static_pad (group->type[GST_STREAM_TYPE_TEXT -
  1567           "src");
  1627               1].preroll, "src");
  1568 
  1628 
  1569       /* This pad is from subtitle-bin, we need to create a ghost pad to have
  1629       /* This pad is from subtitle-bin, we need to create a ghost pad to have
  1570          common grandparents */
  1630          common grandparents */
  1571       parent = gst_object_get_parent (GST_OBJECT_CAST (textsrcpad));
  1631       parent = gst_object_get_parent (GST_OBJECT_CAST (textsrcpad));
  1572       if (!parent) {
  1632       if (!parent) {
  1622             "no changes to hierarchy needed");
  1682             "no changes to hierarchy needed");
  1623       }
  1683       }
  1624 
  1684 
  1625       gst_object_unref (parent);
  1685       gst_object_unref (parent);
  1626       gst_object_unref (grandparent);
  1686       gst_object_unref (grandparent);
  1627     } else {
       
  1628       sink = gen_video_element (play_bin);
       
  1629     }
  1687     }
  1630   beach:
  1688   beach:
  1631     if (!sink)
  1689     if (!sink)
  1632       return FALSE;
  1690       return FALSE;
  1633     pad = gst_element_get_pad (group->type[GST_STREAM_TYPE_VIDEO - 1].preroll,
  1691     pad =
  1634         "src");
  1692         gst_element_get_static_pad (group->type[GST_STREAM_TYPE_VIDEO -
       
  1693             1].preroll, "src");
  1635     res = add_sink (play_bin, sink, pad, textsrcpad);
  1694     res = add_sink (play_bin, sink, pad, textsrcpad);
  1636     gst_object_unref (pad);
  1695     gst_object_unref (pad);
  1637     if (textsrcpad)
  1696     if (textsrcpad)
  1638       gst_object_unref (textsrcpad);
  1697       gst_object_unref (textsrcpad);
  1639     if (origtextsrcpad) {
  1698     if (origtextsrcpad) {
  1640       gst_pad_set_blocked_async (origtextsrcpad, FALSE, dummy_blocked_cb, NULL);
  1699       gst_pad_set_blocked_async (origtextsrcpad, FALSE, dummy_blocked_cb, NULL);
  1641       gst_object_unref (origtextsrcpad);
  1700       gst_object_unref (origtextsrcpad);
  1642     }
  1701     }
       
  1702 
       
  1703     /* If we have a DVD subpicture stream, link it to the SPU now */
       
  1704     if (need_spu) {
       
  1705       GstPad *subpic_pad;
       
  1706       GstPad *spu_sink_pad;
       
  1707 
       
  1708       subpic_pad =
       
  1709           gst_element_get_static_pad (group->type[GST_STREAM_TYPE_SUBPICTURE
       
  1710               - 1].preroll, "src");
       
  1711       spu_sink_pad = gst_element_get_static_pad (sink, "subpicture_sink");
       
  1712       if (subpic_pad && spu_sink_pad) {
       
  1713         GST_LOG_OBJECT (play_bin, "Linking DVD subpicture stream onto SPU");
       
  1714         gst_pad_set_blocked_async (subpic_pad, TRUE, dummy_blocked_cb, NULL);
       
  1715         if (gst_pad_link (subpic_pad, spu_sink_pad) != GST_PAD_LINK_OK) {
       
  1716           GST_WARNING_OBJECT (play_bin,
       
  1717               "Failed to link DVD subpicture stream onto SPU");
       
  1718         }
       
  1719         gst_pad_set_blocked_async (subpic_pad, FALSE, dummy_blocked_cb, NULL);
       
  1720       }
       
  1721       if (subpic_pad)
       
  1722         gst_object_unref (subpic_pad);
       
  1723       if (spu_sink_pad)
       
  1724         gst_object_unref (spu_sink_pad);
       
  1725     }
  1643   }
  1726   }
  1644 
  1727 
  1645   /* remove the sinks now, pipeline get_state will now wait for the
  1728   /* remove the sinks now, pipeline get_state will now wait for the
  1646    * sinks to preroll */
  1729    * sinks to preroll */
  1647   if (play_bin->fakesink) {
  1730   if (play_bin->fakesink) {
  1662    * before textoverlay is set up (which is probably okay, since playbasebin
  1745    * before textoverlay is set up (which is probably okay, since playbasebin
  1663    * will just select the first subtitle stream as active stream regardless) */
  1746    * will just select the first subtitle stream as active stream regardless) */
  1664   if (playbin->textoverlay_element != NULL) {
  1747   if (playbin->textoverlay_element != NULL) {
  1665     GST_LOG_OBJECT (playbin, "setting subtitle visibility to %d", visible);
  1748     GST_LOG_OBJECT (playbin, "setting subtitle visibility to %d", visible);
  1666     g_object_set (playbin->textoverlay_element, "silent", !visible, NULL);
  1749     g_object_set (playbin->textoverlay_element, "silent", !visible, NULL);
       
  1750   }
       
  1751 }
       
  1752 
       
  1753 static void
       
  1754 playbin_set_audio_mute (GstPlayBaseBin * play_base_bin, gboolean mute)
       
  1755 {
       
  1756   GstPlayBin *playbin = GST_PLAY_BIN (play_base_bin);
       
  1757 
       
  1758   if (playbin->volume_element) {
       
  1759     g_object_set (G_OBJECT (playbin->volume_element), "mute", mute, NULL);
  1667   }
  1760   }
  1668 }
  1761 }
  1669 
  1762 
  1670 /* Send an event to our sinks until one of them works; don't then send to the
  1763 /* Send an event to our sinks until one of them works; don't then send to the
  1671  * remaining sinks (unlike GstBin)
  1764  * remaining sinks (unlike GstBin)