gst_plugins_base/gst/playback/gstplaysink.c
branchRCL_3
changeset 30 7e817e7e631c
parent 29 567bb019e3e3
equal deleted inserted replaced
29:567bb019e3e3 30:7e817e7e631c
    27 #include <gst/gst-i18n-plugin.h>
    27 #include <gst/gst-i18n-plugin.h>
    28 #include <gst/pbutils/pbutils.h>
    28 #include <gst/pbutils/pbutils.h>
    29 
    29 
    30 #include "gstplaysink.h"
    30 #include "gstplaysink.h"
    31 
    31 
       
    32 #ifdef __SYMBIAN32__
       
    33 #include <glib_global.h>
       
    34 #endif
    32 GST_DEBUG_CATEGORY_STATIC (gst_play_sink_debug);
    35 GST_DEBUG_CATEGORY_STATIC (gst_play_sink_debug);
    33 #define GST_CAT_DEFAULT gst_play_sink_debug
    36 #define GST_CAT_DEFAULT gst_play_sink_debug
    34 
    37 
    35 #define VOLUME_MAX_DOUBLE 10.0
    38 #define VOLUME_MAX_DOUBLE 10.0
    36 
       
    37 #define GST_PLAY_CHAIN(c) ((GstPlayChain *)(c))
       
    38 
    39 
    39 /* holds the common data fields for the audio and video pipelines. We keep them
    40 /* holds the common data fields for the audio and video pipelines. We keep them
    40  * in a structure to more easily have all the info available. */
    41  * in a structure to more easily have all the info available. */
    41 typedef struct
    42 typedef struct
    42 {
    43 {
    43   GstPlaySink *playsink;
    44   GstPlaySink *playsink;
       
    45   GstPad *sinkpad;
    44   GstElement *bin;
    46   GstElement *bin;
    45   gboolean added;
    47   gboolean added;
    46   gboolean activated;
    48   gboolean activated;
    47   gboolean raw;
       
    48 } GstPlayChain;
    49 } GstPlayChain;
    49 
    50 
    50 typedef struct
    51 typedef struct
    51 {
    52 {
    52   GstPlayChain chain;
    53   GstPlayChain chain;
    53   GstPad *sinkpad;
       
    54   GstElement *queue;
    54   GstElement *queue;
    55   GstElement *conv;
    55   GstElement *conv;
    56   GstElement *resample;
    56   GstElement *resample;
    57   GstElement *volume;           /* element with the volume property */
    57   GstElement *volume;           /* element with the volume property */
    58   gboolean sink_volume;         /* if the volume was provided by the sink */
       
    59   GstElement *mute;             /* element with the mute property */
    58   GstElement *mute;             /* element with the mute property */
    60   GstElement *sink;
    59   GstElement *sink;
    61 } GstPlayAudioChain;
    60 } GstPlayAudioChain;
    62 
    61 
    63 typedef struct
    62 typedef struct
    64 {
    63 {
    65   GstPlayChain chain;
    64   GstPlayChain chain;
    66   GstPad *sinkpad;
       
    67   GstElement *queue;
    65   GstElement *queue;
    68   GstElement *conv;
    66   GstElement *conv;
    69   GstElement *scale;
    67   GstElement *scale;
    70   GstElement *sink;
    68   GstElement *sink;
    71   gboolean async;
    69   gboolean async;
    72 } GstPlayVideoChain;
    70 } GstPlayVideoChain;
    73 
    71 
    74 typedef struct
    72 typedef struct
    75 {
    73 {
    76   GstPlayChain chain;
    74   GstPlayChain chain;
    77   GstPad *sinkpad;
       
    78   GstElement *queue;
    75   GstElement *queue;
    79   GstElement *conv;
    76   GstElement *conv;
    80   GstElement *resample;
    77   GstElement *resample;
    81   GstPad *blockpad;             /* srcpad of resample, used for switching the vis */
    78   GstPad *blockpad;             /* srcpad of resample, used for switching the vis */
    82   GstPad *vissinkpad;           /* visualisation sinkpad, */
    79   GstPad *vissinkpad;           /* visualisation sinkpad, */
    84   GstPad *vissrcpad;            /* visualisation srcpad, */
    81   GstPad *vissrcpad;            /* visualisation srcpad, */
    85   GstPad *srcpad;               /* outgoing srcpad, used to connect to the next
    82   GstPad *srcpad;               /* outgoing srcpad, used to connect to the next
    86                                  * chain */
    83                                  * chain */
    87 } GstPlayVisChain;
    84 } GstPlayVisChain;
    88 
    85 
    89 typedef struct
       
    90 {
       
    91   GstPlayChain chain;
       
    92   GstPad *sinkpad;
       
    93   GstElement *conv;
       
    94   GstElement *overlay;
       
    95   GstPad *videosinkpad;
       
    96   GstPad *textsinkpad;
       
    97   GstPad *srcpad;               /* outgoing srcpad, used to connect to the next
       
    98                                  * chain */
       
    99   GstElement *sink;             /* custom sink to receive subtitle buffers */
       
   100 } GstPlayTextChain;
       
   101 
       
   102 typedef struct
       
   103 {
       
   104   GstPlayChain chain;
       
   105   GstPad *sinkpad;
       
   106   GstElement *queue;
       
   107   GstElement *conv;
       
   108   GstElement *overlay;
       
   109   GstPad *videosinkpad;
       
   110   GstPad *subpsinkpad;
       
   111   GstPad *srcpad;               /* outgoing srcpad, used to connect to the next
       
   112                                  * chain */
       
   113   GstElement *sink;             /* custom sink to receive subpicture buffers */
       
   114 } GstPlaySubpChain;
       
   115 
       
   116 #define GST_PLAY_SINK_GET_LOCK(playsink) (((GstPlaySink *)playsink)->lock)
    86 #define GST_PLAY_SINK_GET_LOCK(playsink) (((GstPlaySink *)playsink)->lock)
   117 #define GST_PLAY_SINK_LOCK(playsink)     g_mutex_lock (GST_PLAY_SINK_GET_LOCK (playsink))
    87 #define GST_PLAY_SINK_LOCK(playsink)     g_mutex_lock (GST_PLAY_SINK_GET_LOCK (playsink))
   118 #define GST_PLAY_SINK_UNLOCK(playsink)   g_mutex_unlock (GST_PLAY_SINK_GET_LOCK (playsink))
    88 #define GST_PLAY_SINK_UNLOCK(playsink)   g_mutex_unlock (GST_PLAY_SINK_GET_LOCK (playsink))
   119 
    89 
   120 struct _GstPlaySink
    90 struct _GstPlaySink
   121 {
    91 {
   122   GstBin bin;
    92   GstBin bin;
   123 
    93 
   124   GMutex *lock;
    94   GMutex *lock;
   125 
    95 
   126   gboolean async_pending;
       
   127   gboolean need_async_start;
       
   128 
       
   129   GstPlayFlags flags;
    96   GstPlayFlags flags;
   130 
    97 
   131   /* chains */
    98   GstPlayChain *audiochain;
   132   GstPlayAudioChain *audiochain;
    99   GstPlayChain *videochain;
   133   GstPlayVideoChain *videochain;
   100   GstPlayChain *vischain;
   134   GstPlayVisChain *vischain;
   101 
   135   GstPlayTextChain *textchain;
       
   136   GstPlaySubpChain *subpchain;
       
   137 
       
   138   /* audio */
       
   139   GstPad *audio_pad;
   102   GstPad *audio_pad;
   140   gboolean audio_pad_raw;
   103   gboolean audio_pad_raw;
   141   /* audio tee */
       
   142   GstElement *audio_tee;
   104   GstElement *audio_tee;
   143   GstPad *audio_tee_sink;
   105   GstPad *audio_tee_sink;
   144   GstPad *audio_tee_asrc;
   106   GstPad *audio_tee_asrc;
   145   GstPad *audio_tee_vissrc;
   107   GstPad *audio_tee_vissrc;
   146   /* video */
   108 
   147   GstPad *video_pad;
   109   GstPad *video_pad;
   148   gboolean video_pad_raw;
   110   gboolean video_pad_raw;
   149   /* text */
   111 
   150   GstPad *text_pad;
   112   GstPad *text_pad;
   151   /* subpictures */
       
   152   GstPad *subp_pad;
       
   153 
   113 
   154   /* properties */
   114   /* properties */
   155   GstElement *audio_sink;
   115   GstElement *audio_sink;
   156   GstElement *video_sink;
   116   GstElement *video_sink;
   157   GstElement *visualisation;
   117   GstElement *visualisation;
   158   GstElement *text_sink;
       
   159   GstElement *subp_sink;
       
   160   gfloat volume;
   118   gfloat volume;
   161   gboolean mute;
   119   gboolean mute;
   162   gchar *font_desc;             /* font description */
   120   gchar *font_desc;             /* font description */
   163   guint connection_speed;       /* connection speed in bits/sec (0 = unknown) */
   121   guint connection_speed;       /* connection speed in bits/sec (0 = unknown) */
   164   gint count;
   122 
   165   gboolean volume_changed;      /* volume/mute changed while no audiochain */
   123   /* internal elements */
   166   gboolean mute_changed;        /* ... has been reated yet */
   124   GstElement *textoverlay_element;
   167 };
   125 };
   168 
   126 
   169 struct _GstPlaySinkClass
   127 struct _GstPlaySinkClass
   170 {
   128 {
   171   GstBinClass parent_class;
   129   GstBinClass parent_class;
   174 
   132 
   175 /* props */
   133 /* props */
   176 enum
   134 enum
   177 {
   135 {
   178   PROP_0,
   136   PROP_0,
       
   137   PROP_AUDIO_SINK,
       
   138   PROP_VIDEO_SINK,
       
   139   PROP_VIS_PLUGIN,
       
   140   PROP_VOLUME,
       
   141   PROP_FRAME,
       
   142   PROP_FONT_DESC,
   179   PROP_LAST
   143   PROP_LAST
   180 };
   144 };
   181 
   145 
   182 /* signals */
   146 /* signals */
   183 enum
   147 enum
   188 static void gst_play_sink_class_init (GstPlaySinkClass * klass);
   152 static void gst_play_sink_class_init (GstPlaySinkClass * klass);
   189 static void gst_play_sink_init (GstPlaySink * playsink);
   153 static void gst_play_sink_init (GstPlaySink * playsink);
   190 static void gst_play_sink_dispose (GObject * object);
   154 static void gst_play_sink_dispose (GObject * object);
   191 static void gst_play_sink_finalize (GObject * object);
   155 static void gst_play_sink_finalize (GObject * object);
   192 
   156 
       
   157 static void gst_play_sink_set_property (GObject * object, guint prop_id,
       
   158     const GValue * value, GParamSpec * spec);
       
   159 static void gst_play_sink_get_property (GObject * object, guint prop_id,
       
   160     GValue * value, GParamSpec * spec);
       
   161 
   193 static gboolean gst_play_sink_send_event (GstElement * element,
   162 static gboolean gst_play_sink_send_event (GstElement * element,
   194     GstEvent * event);
   163     GstEvent * event);
   195 static GstStateChangeReturn gst_play_sink_change_state (GstElement * element,
   164 static GstStateChangeReturn gst_play_sink_change_state (GstElement * element,
   196     GstStateChange transition);
   165     GstStateChange transition);
   197 
   166 
   198 static void gst_play_sink_handle_message (GstBin * bin, GstMessage * message);
   167 static GstElementClass *parent_class;
   199 
   168 
   200 /* static guint gst_play_sink_signals[LAST_SIGNAL] = { 0 }; */
   169 /* static guint gst_play_sink_signals[LAST_SIGNAL] = { 0 }; */
   201 
   170 
   202 static const GstElementDetails gst_play_sink_details =
   171 static const GstElementDetails gst_play_sink_details =
   203 GST_ELEMENT_DETAILS ("Player Sink",
   172 GST_ELEMENT_DETAILS ("Player Sink",
   204     "Generic/Bin/Player",
   173     "Generic/Bin/Player",
   205     "Autoplug and play media from an uri",
   174     "Autoplug and play media from an uri",
   206     "Wim Taymans <wim.taymans@gmail.com>");
   175     "Wim Taymans <wim.taymans@gmail.com>");
   207 
   176 #ifdef __SYMBIAN32__
   208 G_DEFINE_TYPE (GstPlaySink, gst_play_sink, GST_TYPE_BIN);
   177 EXPORT_C
       
   178 #endif
       
   179 
       
   180 
       
   181 GType
       
   182 gst_play_sink_get_type (void)
       
   183 {
       
   184   static GType gst_play_sink_type = 0;
       
   185 
       
   186   if (!gst_play_sink_type) {
       
   187     static const GTypeInfo gst_play_sink_info = {
       
   188       sizeof (GstPlaySinkClass),
       
   189       NULL,
       
   190       NULL,
       
   191       (GClassInitFunc) gst_play_sink_class_init,
       
   192       NULL,
       
   193       NULL,
       
   194       sizeof (GstPlaySink),
       
   195       0,
       
   196       (GInstanceInitFunc) gst_play_sink_init,
       
   197       NULL
       
   198     };
       
   199 
       
   200     gst_play_sink_type = g_type_register_static (GST_TYPE_BIN,
       
   201         "GstPlaySink", &gst_play_sink_info, 0);
       
   202   }
       
   203 
       
   204   return gst_play_sink_type;
       
   205 }
   209 
   206 
   210 static void
   207 static void
   211 gst_play_sink_class_init (GstPlaySinkClass * klass)
   208 gst_play_sink_class_init (GstPlaySinkClass * klass)
   212 {
   209 {
   213   GObjectClass *gobject_klass;
   210   GObjectClass *gobject_klass;
   216 
   213 
   217   gobject_klass = (GObjectClass *) klass;
   214   gobject_klass = (GObjectClass *) klass;
   218   gstelement_klass = (GstElementClass *) klass;
   215   gstelement_klass = (GstElementClass *) klass;
   219   gstbin_klass = (GstBinClass *) klass;
   216   gstbin_klass = (GstBinClass *) klass;
   220 
   217 
       
   218   parent_class = g_type_class_peek_parent (klass);
       
   219 
       
   220   gobject_klass->set_property = gst_play_sink_set_property;
       
   221   gobject_klass->get_property = gst_play_sink_get_property;
       
   222 
   221   gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_play_sink_dispose);
   223   gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_play_sink_dispose);
   222   gobject_klass->finalize = GST_DEBUG_FUNCPTR (gst_play_sink_finalize);
   224   gobject_klass->finalize = GST_DEBUG_FUNCPTR (gst_play_sink_finalize);
       
   225 
       
   226   g_object_class_install_property (gobject_klass, PROP_VIDEO_SINK,
       
   227       g_param_spec_object ("video-sink", "Video Sink",
       
   228           "the video output element to use (NULL = default sink)",
       
   229           GST_TYPE_ELEMENT, G_PARAM_READWRITE));
       
   230   g_object_class_install_property (gobject_klass, PROP_AUDIO_SINK,
       
   231       g_param_spec_object ("audio-sink", "Audio Sink",
       
   232           "the audio output element to use (NULL = default sink)",
       
   233           GST_TYPE_ELEMENT, G_PARAM_READWRITE));
       
   234   g_object_class_install_property (gobject_klass, PROP_VIS_PLUGIN,
       
   235       g_param_spec_object ("vis-plugin", "Vis plugin",
       
   236           "the visualization element to use (NULL = none)",
       
   237           GST_TYPE_ELEMENT, G_PARAM_READWRITE));
       
   238   g_object_class_install_property (gobject_klass, PROP_VOLUME,
       
   239       g_param_spec_double ("volume", "volume", "volume",
       
   240           0.0, VOLUME_MAX_DOUBLE, 1.0, G_PARAM_READWRITE));
       
   241   g_object_class_install_property (gobject_klass, PROP_FRAME,
       
   242       gst_param_spec_mini_object ("frame", "Frame",
       
   243           "The last video frame (NULL = no video available)",
       
   244           GST_TYPE_BUFFER, G_PARAM_READABLE));
       
   245   g_object_class_install_property (gobject_klass, PROP_FONT_DESC,
       
   246       g_param_spec_string ("subtitle-font-desc",
       
   247           "Subtitle font description",
       
   248           "Pango font description of font "
       
   249           "to be used for subtitle rendering", NULL, G_PARAM_WRITABLE));
   223 
   250 
   224   gst_element_class_set_details (gstelement_klass, &gst_play_sink_details);
   251   gst_element_class_set_details (gstelement_klass, &gst_play_sink_details);
   225 
   252 
   226   gstelement_klass->change_state =
   253   gstelement_klass->change_state =
   227       GST_DEBUG_FUNCPTR (gst_play_sink_change_state);
   254       GST_DEBUG_FUNCPTR (gst_play_sink_change_state);
   228   gstelement_klass->send_event = GST_DEBUG_FUNCPTR (gst_play_sink_send_event);
   255   gstelement_klass->send_event = GST_DEBUG_FUNCPTR (gst_play_sink_send_event);
   229 
       
   230   gstbin_klass->handle_message =
       
   231       GST_DEBUG_FUNCPTR (gst_play_sink_handle_message);
       
   232 
   256 
   233   GST_DEBUG_CATEGORY_INIT (gst_play_sink_debug, "playsink", 0, "play bin");
   257   GST_DEBUG_CATEGORY_INIT (gst_play_sink_debug, "playsink", 0, "play bin");
   234 }
   258 }
   235 
   259 
   236 static void
   260 static void
   238 {
   262 {
   239   /* init groups */
   263   /* init groups */
   240   playsink->video_sink = NULL;
   264   playsink->video_sink = NULL;
   241   playsink->audio_sink = NULL;
   265   playsink->audio_sink = NULL;
   242   playsink->visualisation = NULL;
   266   playsink->visualisation = NULL;
   243   playsink->text_sink = NULL;
   267   playsink->textoverlay_element = NULL;
   244   playsink->volume = 1.0;
   268   playsink->volume = 1.0;
   245   playsink->font_desc = NULL;
   269   playsink->font_desc = NULL;
   246   playsink->flags = GST_PLAY_FLAG_SOFT_VOLUME;
   270   playsink->flags = GST_PLAY_FLAG_SOFT_VOLUME;
   247 
   271 
   248   playsink->lock = g_mutex_new ();
   272   playsink->lock = g_mutex_new ();
   249   playsink->need_async_start = TRUE;
       
   250   GST_OBJECT_FLAG_SET (playsink, GST_ELEMENT_IS_SINK);
       
   251 }
       
   252 
       
   253 static void
       
   254 free_chain (GstPlayChain * chain)
       
   255 {
       
   256   if (chain) {
       
   257     if (chain->bin)
       
   258       gst_object_unref (chain->bin);
       
   259     g_free (chain);
       
   260   }
       
   261 }
   273 }
   262 
   274 
   263 static void
   275 static void
   264 gst_play_sink_dispose (GObject * object)
   276 gst_play_sink_dispose (GObject * object)
   265 {
   277 {
   280   if (playsink->visualisation != NULL) {
   292   if (playsink->visualisation != NULL) {
   281     gst_element_set_state (playsink->visualisation, GST_STATE_NULL);
   293     gst_element_set_state (playsink->visualisation, GST_STATE_NULL);
   282     gst_object_unref (playsink->visualisation);
   294     gst_object_unref (playsink->visualisation);
   283     playsink->visualisation = NULL;
   295     playsink->visualisation = NULL;
   284   }
   296   }
   285   if (playsink->text_sink != NULL) {
   297   if (playsink->textoverlay_element != NULL) {
   286     gst_element_set_state (playsink->text_sink, GST_STATE_NULL);
   298     gst_object_unref (playsink->textoverlay_element);
   287     gst_object_unref (playsink->text_sink);
   299     playsink->textoverlay_element = NULL;
   288     playsink->text_sink = NULL;
   300   }
   289   }
       
   290 
       
   291   free_chain ((GstPlayChain *) playsink->videochain);
       
   292   playsink->videochain = NULL;
       
   293   free_chain ((GstPlayChain *) playsink->audiochain);
       
   294   playsink->audiochain = NULL;
       
   295   free_chain ((GstPlayChain *) playsink->vischain);
       
   296   playsink->vischain = NULL;
       
   297   free_chain ((GstPlayChain *) playsink->textchain);
       
   298   playsink->textchain = NULL;
       
   299 
       
   300   if (playsink->audio_tee_sink) {
       
   301     gst_object_unref (playsink->audio_tee_sink);
       
   302     playsink->audio_tee_sink = NULL;
       
   303   }
       
   304 
       
   305   if (playsink->audio_tee_vissrc) {
       
   306     gst_element_release_request_pad (playsink->audio_tee,
       
   307         playsink->audio_tee_vissrc);
       
   308     gst_object_unref (playsink->audio_tee_vissrc);
       
   309     playsink->audio_tee_vissrc = NULL;
       
   310   }
       
   311 
       
   312   if (playsink->audio_tee_asrc) {
       
   313     gst_element_release_request_pad (playsink->audio_tee,
       
   314         playsink->audio_tee_asrc);
       
   315     gst_object_unref (playsink->audio_tee_asrc);
       
   316     playsink->audio_tee_asrc = NULL;
       
   317   }
       
   318 
       
   319   g_free (playsink->font_desc);
   301   g_free (playsink->font_desc);
   320   playsink->font_desc = NULL;
   302   playsink->font_desc = NULL;
   321 
   303 
   322   G_OBJECT_CLASS (gst_play_sink_parent_class)->dispose (object);
   304   G_OBJECT_CLASS (parent_class)->dispose (object);
   323 }
   305 }
   324 
   306 
   325 static void
   307 static void
   326 gst_play_sink_finalize (GObject * object)
   308 gst_play_sink_finalize (GObject * object)
   327 {
   309 {
   329 
   311 
   330   playsink = GST_PLAY_SINK (object);
   312   playsink = GST_PLAY_SINK (object);
   331 
   313 
   332   g_mutex_free (playsink->lock);
   314   g_mutex_free (playsink->lock);
   333 
   315 
   334   G_OBJECT_CLASS (gst_play_sink_parent_class)->finalize (object);
   316   G_OBJECT_CLASS (parent_class)->finalize (object);
   335 }
   317 }
   336 #ifdef __SYMBIAN32__
   318 #ifdef __SYMBIAN32__
   337 EXPORT_C
   319 EXPORT_C
   338 #endif
   320 #endif
   339 
   321 
       
   322 
   340 void
   323 void
   341 gst_play_sink_set_sink (GstPlaySink * playsink, GstPlaySinkType type,
   324 gst_play_sink_set_video_sink (GstPlaySink * playsink, GstElement * sink)
   342     GstElement * sink)
   325 {
   343 {
   326   GST_OBJECT_LOCK (playsink);
   344   GstElement **elem = NULL, *old = NULL;
   327   if (playsink->video_sink)
   345 
   328     gst_object_unref (playsink->video_sink);
   346   GST_LOG ("Setting sink %" GST_PTR_FORMAT " as sink type %d", sink, type);
   329 
   347 
   330   if (sink) {
   348   GST_PLAY_SINK_LOCK (playsink);
   331     gst_object_ref (sink);
   349   switch (type) {
   332     gst_object_sink (sink);
   350     case GST_PLAY_SINK_TYPE_AUDIO:
   333   }
   351     case GST_PLAY_SINK_TYPE_AUDIO_RAW:
   334   playsink->video_sink = sink;
   352       elem = &playsink->audio_sink;
   335   GST_OBJECT_UNLOCK (playsink);
   353       break;
   336 }
   354     case GST_PLAY_SINK_TYPE_VIDEO:
       
   355     case GST_PLAY_SINK_TYPE_VIDEO_RAW:
       
   356       elem = &playsink->video_sink;
       
   357       break;
       
   358     case GST_PLAY_SINK_TYPE_TEXT:
       
   359       elem = &playsink->text_sink;
       
   360       break;
       
   361     case GST_PLAY_SINK_TYPE_SUBPIC:
       
   362       elem = &playsink->subp_sink;
       
   363       break;
       
   364     default:
       
   365       break;
       
   366   }
       
   367   if (elem) {
       
   368     old = *elem;
       
   369     if (sink)
       
   370       gst_object_ref (sink);
       
   371     *elem = sink;
       
   372   }
       
   373   GST_PLAY_SINK_UNLOCK (playsink);
       
   374 
       
   375   if (old)
       
   376     gst_object_unref (old);
       
   377 }
       
   378 
       
   379 #ifdef __SYMBIAN32__
   337 #ifdef __SYMBIAN32__
   380 EXPORT_C
   338 EXPORT_C
   381 #endif
   339 #endif
   382 
   340 
   383 GstElement *
   341 
   384 gst_play_sink_get_sink (GstPlaySink * playsink, GstPlaySinkType type)
   342 void
   385 {
   343 gst_play_sink_set_audio_sink (GstPlaySink * playsink, GstElement * sink)
   386   GstElement *result = NULL;
   344 {
   387   GstElement *elem = NULL, *chainp = NULL;
   345   GST_OBJECT_LOCK (playsink);
   388 
   346   if (playsink->audio_sink)
   389   GST_PLAY_SINK_LOCK (playsink);
   347     gst_object_unref (playsink->audio_sink);
   390   switch (type) {
   348 
   391     case GST_PLAY_SINK_TYPE_AUDIO:
   349   if (sink) {
   392     {
   350     gst_object_ref (sink);
   393       GstPlayAudioChain *chain;
   351     gst_object_sink (sink);
   394       if ((chain = (GstPlayAudioChain *) playsink->audiochain))
   352   }
   395         chainp = chain->sink;
   353   playsink->audio_sink = sink;
   396       elem = playsink->audio_sink;
   354   GST_OBJECT_UNLOCK (playsink);
   397       break;
       
   398     }
       
   399     case GST_PLAY_SINK_TYPE_VIDEO:
       
   400     {
       
   401       GstPlayVideoChain *chain;
       
   402       if ((chain = (GstPlayVideoChain *) playsink->videochain))
       
   403         chainp = chain->sink;
       
   404       elem = playsink->video_sink;
       
   405       break;
       
   406     }
       
   407     case GST_PLAY_SINK_TYPE_TEXT:
       
   408     {
       
   409       GstPlayTextChain *chain;
       
   410       if ((chain = (GstPlayTextChain *) playsink->textchain))
       
   411         chainp = chain->sink;
       
   412       elem = playsink->text_sink;
       
   413       break;
       
   414     }
       
   415     case GST_PLAY_SINK_TYPE_SUBPIC:
       
   416     {
       
   417       GstPlaySubpChain *chain;
       
   418       if ((chain = (GstPlaySubpChain *) playsink->subpchain))
       
   419         chainp = chain->sink;
       
   420       elem = playsink->subp_sink;
       
   421       break;
       
   422     }
       
   423     default:
       
   424       break;
       
   425   }
       
   426   if (chainp) {
       
   427     /* we have an active chain with a sink, get the sink */
       
   428     result = gst_object_ref (chainp);
       
   429   }
       
   430   /* nothing found, return last configured sink */
       
   431   if (result == NULL && elem)
       
   432     result = gst_object_ref (elem);
       
   433   GST_PLAY_SINK_UNLOCK (playsink);
       
   434 
       
   435   return result;
       
   436 }
   355 }
   437 
   356 
   438 static void
   357 static void
   439 gst_play_sink_vis_unblocked (GstPad * tee_pad, gboolean blocked,
   358 gst_play_sink_vis_unblocked (GstPad * tee_pad, gboolean blocked,
   440     gpointer user_data)
   359     gpointer user_data)
   469   /* set the old plugin to NULL and remove */
   388   /* set the old plugin to NULL and remove */
   470   gst_element_set_state (chain->vis, GST_STATE_NULL);
   389   gst_element_set_state (chain->vis, GST_STATE_NULL);
   471   gst_bin_remove (GST_BIN_CAST (chain->chain.bin), chain->vis);
   390   gst_bin_remove (GST_BIN_CAST (chain->chain.bin), chain->vis);
   472 
   391 
   473   /* add new plugin and set state to playing */
   392   /* add new plugin and set state to playing */
   474   chain->vis = playsink->visualisation;
   393   chain->vis = gst_object_ref (playsink->visualisation);
   475   gst_bin_add (GST_BIN_CAST (chain->chain.bin), chain->vis);
   394   gst_bin_add (GST_BIN_CAST (chain->chain.bin), chain->vis);
   476   gst_element_set_state (chain->vis, GST_STATE_PLAYING);
   395   gst_element_set_state (chain->vis, GST_STATE_PLAYING);
   477 
   396 
   478   /* get pads */
   397   /* get pads */
   479   chain->vissinkpad = gst_element_get_static_pad (chain->vis, "sink");
   398   chain->vissinkpad = gst_element_get_pad (chain->vis, "sink");
   480   chain->vissrcpad = gst_element_get_static_pad (chain->vis, "src");
   399   chain->vissrcpad = gst_element_get_pad (chain->vis, "src");
   481 
   400 
   482   /* link pads */
   401   /* link pads */
   483   gst_pad_link (chain->blockpad, chain->vissinkpad);
   402   gst_pad_link (chain->blockpad, chain->vissinkpad);
   484   gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (chain->srcpad),
   403   gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (chain->srcpad),
   485       chain->vissrcpad);
   404       chain->vissrcpad);
   498 void
   417 void
   499 gst_play_sink_set_vis_plugin (GstPlaySink * playsink, GstElement * vis)
   418 gst_play_sink_set_vis_plugin (GstPlaySink * playsink, GstElement * vis)
   500 {
   419 {
   501   GstPlayVisChain *chain;
   420   GstPlayVisChain *chain;
   502 
   421 
   503   /* setting NULL means creating the default vis plugin */
       
   504   if (vis == NULL)
       
   505     vis = gst_element_factory_make ("goom", "vis");
       
   506 
       
   507   /* simply return if we don't have a vis plugin here */
       
   508   if (vis == NULL)
       
   509     return;
       
   510 
       
   511   GST_PLAY_SINK_LOCK (playsink);
   422   GST_PLAY_SINK_LOCK (playsink);
   512   /* first store the new vis */
   423   /* first store the new vis */
   513   if (playsink->visualisation)
   424   if (playsink->visualisation)
   514     gst_object_unref (playsink->visualisation);
   425     gst_object_unref (playsink->visualisation);
   515   /* take ownership */
   426   playsink->visualisation = gst_object_ref (vis);
   516   gst_object_ref (vis);
       
   517   gst_object_sink (vis);
       
   518   playsink->visualisation = vis;
       
   519 
   427 
   520   /* now try to change the plugin in the running vis chain, if we have no chain,
   428   /* now try to change the plugin in the running vis chain, if we have no chain,
   521    * we don't bother, any future vis chain will be created with the new vis
   429    * we don't bother, any future vis chain will be created with the new vis
   522    * plugin. */
   430    * plugin. */
   523   if (!(chain = (GstPlayVisChain *) playsink->vischain))
   431   if (!(chain = (GstPlayVisChain *) playsink->vischain))
   524     goto done;
   432     goto done;
   525 
   433 
   526   /* block the pad, the next time the callback is called we can change the
   434   /* block the pad, the next time the callback is called we can change the
   527    * visualisation. It's possible that this never happens or that the pad was
   435    * visualisation. It's possible that this never happens or that the pad was
   528    * already blocked. If the callback never happens, we don't have new data so
   436    * already blocked. */
   529    * we don't need the new vis plugin. If the pad was already blocked, the
       
   530    * function returns FALSE but the previous pad block will do the right thing
       
   531    * anyway. */
       
   532   GST_DEBUG_OBJECT (playsink, "blocking vis pad");
   437   GST_DEBUG_OBJECT (playsink, "blocking vis pad");
   533   gst_pad_set_blocked_async (chain->blockpad, TRUE, gst_play_sink_vis_blocked,
   438   gst_pad_set_blocked_async (chain->blockpad, TRUE, gst_play_sink_vis_blocked,
   534       playsink);
   439       playsink);
   535 done:
   440 done:
   536   GST_PLAY_SINK_UNLOCK (playsink);
   441   GST_PLAY_SINK_UNLOCK (playsink);
   540 #ifdef __SYMBIAN32__
   445 #ifdef __SYMBIAN32__
   541 EXPORT_C
   446 EXPORT_C
   542 #endif
   447 #endif
   543 
   448 
   544 
   449 
   545 GstElement *
       
   546 gst_play_sink_get_vis_plugin (GstPlaySink * playsink)
       
   547 {
       
   548   GstElement *result = NULL;
       
   549   GstPlayVisChain *chain;
       
   550 
       
   551   GST_PLAY_SINK_LOCK (playsink);
       
   552   if ((chain = (GstPlayVisChain *) playsink->vischain)) {
       
   553     /* we have an active chain, get the sink */
       
   554     if (chain->vis)
       
   555       result = gst_object_ref (chain->vis);
       
   556   }
       
   557   /* nothing found, return last configured sink */
       
   558   if (result == NULL && playsink->visualisation)
       
   559     result = gst_object_ref (playsink->visualisation);
       
   560   GST_PLAY_SINK_UNLOCK (playsink);
       
   561 
       
   562   return result;
       
   563 }
       
   564 #ifdef __SYMBIAN32__
       
   565 EXPORT_C
       
   566 #endif
       
   567 
       
   568 
       
   569 void
   450 void
   570 gst_play_sink_set_volume (GstPlaySink * playsink, gdouble volume)
   451 gst_play_sink_set_volume (GstPlaySink * playsink, gdouble volume)
   571 {
   452 {
   572   GstPlayAudioChain *chain;
   453   GstPlayAudioChain *chain;
   573 
   454 
   574   GST_PLAY_SINK_LOCK (playsink);
   455   GST_PLAY_SINK_LOCK (playsink);
   575   playsink->volume = volume;
   456   playsink->volume = volume;
   576   chain = (GstPlayAudioChain *) playsink->audiochain;
   457   chain = (GstPlayAudioChain *) playsink->audiochain;
   577   if (chain && chain->volume) {
   458   if (chain && chain->volume) {
   578     GST_LOG_OBJECT (playsink, "elements: volume=%" GST_PTR_FORMAT ", mute=%"
   459     g_object_set (chain->volume, "volume", volume, NULL);
   579         GST_PTR_FORMAT "; new volume=%.03f, mute=%d", chain->volume,
       
   580         chain->mute, volume, playsink->mute);
       
   581     /* if there is a mute element or we are not muted, set the volume */
       
   582     if (chain->mute || !playsink->mute)
       
   583       g_object_set (chain->volume, "volume", volume, NULL);
       
   584   } else {
       
   585     GST_LOG_OBJECT (playsink, "no volume element");
       
   586     playsink->volume_changed = TRUE;
       
   587   }
   460   }
   588   GST_PLAY_SINK_UNLOCK (playsink);
   461   GST_PLAY_SINK_UNLOCK (playsink);
   589 }
   462 }
   590 #ifdef __SYMBIAN32__
   463 #ifdef __SYMBIAN32__
   591 EXPORT_C
   464 EXPORT_C
   598   gdouble result;
   471   gdouble result;
   599   GstPlayAudioChain *chain;
   472   GstPlayAudioChain *chain;
   600 
   473 
   601   GST_PLAY_SINK_LOCK (playsink);
   474   GST_PLAY_SINK_LOCK (playsink);
   602   chain = (GstPlayAudioChain *) playsink->audiochain;
   475   chain = (GstPlayAudioChain *) playsink->audiochain;
   603   result = playsink->volume;
       
   604   if (chain && chain->volume) {
   476   if (chain && chain->volume) {
   605     if (chain->mute || !playsink->mute) {
   477     g_object_get (chain->volume, "volume", &result, NULL);
   606       g_object_get (chain->volume, "volume", &result, NULL);
   478     playsink->volume = result;
   607       playsink->volume = result;
   479   } else {
   608     }
   480     result = playsink->volume;
   609   }
   481   }
   610   GST_PLAY_SINK_UNLOCK (playsink);
   482   GST_PLAY_SINK_UNLOCK (playsink);
   611 
   483 
   612   return result;
   484   return result;
   613 }
   485 }
   622   GstPlayAudioChain *chain;
   494   GstPlayAudioChain *chain;
   623 
   495 
   624   GST_PLAY_SINK_LOCK (playsink);
   496   GST_PLAY_SINK_LOCK (playsink);
   625   playsink->mute = mute;
   497   playsink->mute = mute;
   626   chain = (GstPlayAudioChain *) playsink->audiochain;
   498   chain = (GstPlayAudioChain *) playsink->audiochain;
   627   if (chain) {
   499   if (chain && chain->mute) {
   628     if (chain->mute) {
   500     g_object_set (chain->mute, "mute", mute, NULL);
   629       g_object_set (chain->mute, "mute", mute, NULL);
       
   630     } else if (chain->volume) {
       
   631       if (mute)
       
   632         g_object_set (chain->volume, "volume", (gdouble) 0.0, NULL);
       
   633       else
       
   634         g_object_set (chain->volume, "volume", (gdouble) playsink->volume,
       
   635             NULL);
       
   636     }
       
   637   } else {
       
   638     playsink->mute_changed = TRUE;
       
   639   }
   501   }
   640   GST_PLAY_SINK_UNLOCK (playsink);
   502   GST_PLAY_SINK_UNLOCK (playsink);
   641 }
   503 }
   642 #ifdef __SYMBIAN32__
   504 #ifdef __SYMBIAN32__
   643 EXPORT_C
   505 EXPORT_C
   662 
   524 
   663   return result;
   525   return result;
   664 }
   526 }
   665 
   527 
   666 static void
   528 static void
       
   529 gst_play_sink_set_property (GObject * object, guint prop_id,
       
   530     const GValue * value, GParamSpec * pspec)
       
   531 {
       
   532   GstPlaySink *playsink;
       
   533 
       
   534   playsink = GST_PLAY_SINK (object);
       
   535 
       
   536   switch (prop_id) {
       
   537     case PROP_VIDEO_SINK:
       
   538       gst_play_sink_set_video_sink (playsink, g_value_get_object (value));
       
   539       break;
       
   540     case PROP_AUDIO_SINK:
       
   541       gst_play_sink_set_audio_sink (playsink, g_value_get_object (value));
       
   542       break;
       
   543     case PROP_VIS_PLUGIN:
       
   544       gst_play_sink_set_vis_plugin (playsink, g_value_get_object (value));
       
   545       break;
       
   546     case PROP_VOLUME:
       
   547       gst_play_sink_set_volume (playsink, g_value_get_double (value));
       
   548       break;
       
   549     case PROP_FONT_DESC:
       
   550       GST_OBJECT_LOCK (playsink);
       
   551       g_free (playsink->font_desc);
       
   552       playsink->font_desc = g_strdup (g_value_get_string (value));
       
   553       if (playsink->textoverlay_element) {
       
   554         g_object_set (G_OBJECT (playsink->textoverlay_element),
       
   555             "font-desc", g_value_get_string (value), NULL);
       
   556       }
       
   557       GST_OBJECT_UNLOCK (playsink);
       
   558       break;
       
   559     default:
       
   560       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       
   561       break;
       
   562   }
       
   563 }
       
   564 
       
   565 static void
       
   566 gst_play_sink_get_property (GObject * object, guint prop_id, GValue * value,
       
   567     GParamSpec * pspec)
       
   568 {
       
   569   GstPlaySink *playsink;
       
   570 
       
   571   playsink = GST_PLAY_SINK (object);
       
   572 
       
   573   switch (prop_id) {
       
   574     case PROP_VIDEO_SINK:
       
   575       GST_OBJECT_LOCK (playsink);
       
   576       g_value_set_object (value, playsink->video_sink);
       
   577       GST_OBJECT_UNLOCK (playsink);
       
   578       break;
       
   579     case PROP_AUDIO_SINK:
       
   580       GST_OBJECT_LOCK (playsink);
       
   581       g_value_set_object (value, playsink->audio_sink);
       
   582       GST_OBJECT_UNLOCK (playsink);
       
   583       break;
       
   584     case PROP_VIS_PLUGIN:
       
   585       GST_OBJECT_LOCK (playsink);
       
   586       g_value_set_object (value, playsink->visualisation);
       
   587       GST_OBJECT_UNLOCK (playsink);
       
   588       break;
       
   589     case PROP_VOLUME:
       
   590       g_value_set_double (value, gst_play_sink_get_volume (playsink));
       
   591       break;
       
   592     case PROP_FRAME:
       
   593     {
       
   594       break;
       
   595     }
       
   596     default:
       
   597       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       
   598       break;
       
   599   }
       
   600 }
       
   601 
       
   602 static void
   667 post_missing_element_message (GstPlaySink * playsink, const gchar * name)
   603 post_missing_element_message (GstPlaySink * playsink, const gchar * name)
   668 {
   604 {
   669   GstMessage *msg;
   605   GstMessage *msg;
   670 
   606 
   671   msg = gst_missing_element_message_new (GST_ELEMENT_CAST (playsink), name);
   607   msg = gst_missing_element_message_new (GST_ELEMENT_CAST (playsink), name);
   672   gst_element_post_message (GST_ELEMENT_CAST (playsink), msg);
   608   gst_element_post_message (GST_ELEMENT_CAST (playsink), msg);
       
   609 }
       
   610 
       
   611 static void
       
   612 free_chain (GstPlayChain * chain)
       
   613 {
       
   614   if (chain->bin)
       
   615     gst_object_unref (chain->bin);
       
   616   gst_object_unref (chain->playsink);
       
   617   g_free (chain);
   673 }
   618 }
   674 
   619 
   675 static gboolean
   620 static gboolean
   676 add_chain (GstPlayChain * chain, gboolean add)
   621 add_chain (GstPlayChain * chain, gboolean add)
   677 {
   622 {
   689 }
   634 }
   690 
   635 
   691 static gboolean
   636 static gboolean
   692 activate_chain (GstPlayChain * chain, gboolean activate)
   637 activate_chain (GstPlayChain * chain, gboolean activate)
   693 {
   638 {
   694   GstState state;
       
   695 
       
   696   if (chain->activated == activate)
   639   if (chain->activated == activate)
   697     return TRUE;
   640     return TRUE;
   698 
   641 
   699   GST_OBJECT_LOCK (chain->playsink);
       
   700   state = GST_STATE_TARGET (chain->playsink);
       
   701   GST_OBJECT_UNLOCK (chain->playsink);
       
   702 
       
   703   if (activate)
   642   if (activate)
   704     gst_element_set_state (chain->bin, state);
   643     gst_element_set_state (chain->bin, GST_STATE_PAUSED);
   705   else
   644   else
   706     gst_element_set_state (chain->bin, GST_STATE_NULL);
   645     gst_element_set_state (chain->bin, GST_STATE_NULL);
   707 
   646 
   708   chain->activated = activate;
   647   chain->activated = activate;
   709 
   648 
   744       result = obj;
   683       result = obj;
   745       gst_object_ref (obj);
   684       gst_object_ref (obj);
   746     }
   685     }
   747   }
   686   }
   748   return result;
   687   return result;
   749 }
       
   750 
       
   751 static gint
       
   752 find_property_sink (GstElement * element, const gchar * name)
       
   753 {
       
   754   gint res;
       
   755   gboolean is_sink;
       
   756 
       
   757   GST_OBJECT_LOCK (element);
       
   758   is_sink = GST_OBJECT_FLAG_IS_SET (element, GST_ELEMENT_IS_SINK);
       
   759   GST_OBJECT_UNLOCK (element);
       
   760 
       
   761   if (is_sink &&
       
   762       g_object_class_find_property (G_OBJECT_GET_CLASS (element), name)) {
       
   763     res = 0;
       
   764     GST_DEBUG_OBJECT (element, "found %s property on sink", name);
       
   765   } else {
       
   766     GST_DEBUG_OBJECT (element, "did not find %s property", name);
       
   767     res = 1;
       
   768     gst_object_unref (element);
       
   769   }
       
   770   return res;
       
   771 }
       
   772 
       
   773 /* find a sink in the hierarchy with a property named @name. This function does
       
   774  * not increase the refcount of the returned object and thus remains valid as
       
   775  * long as the bin is valid. */
       
   776 static GstElement *
       
   777 gst_play_sink_find_property_sinks (GstPlaySink * playsink, GstElement * obj,
       
   778     const gchar * name)
       
   779 {
       
   780   GstElement *result = NULL;
       
   781   GstIterator *it;
       
   782 
       
   783   if (g_object_class_find_property (G_OBJECT_GET_CLASS (obj), name)) {
       
   784     result = obj;
       
   785   } else if (GST_IS_BIN (obj)) {
       
   786     it = gst_bin_iterate_recurse (GST_BIN_CAST (obj));
       
   787     result = gst_iterator_find_custom (it,
       
   788         (GCompareFunc) find_property_sink, (gpointer) name);
       
   789     gst_iterator_free (it);
       
   790     /* we don't need the extra ref */
       
   791     if (result)
       
   792       gst_object_unref (result);
       
   793   }
       
   794   return result;
       
   795 }
       
   796 
       
   797 static void
       
   798 do_async_start (GstPlaySink * playsink)
       
   799 {
       
   800   GstMessage *message;
       
   801 
       
   802   if (!playsink->need_async_start)
       
   803     return;
       
   804 
       
   805   playsink->async_pending = TRUE;
       
   806 
       
   807   GST_INFO_OBJECT (playsink, "Sending async_start message");
       
   808   message = gst_message_new_async_start (GST_OBJECT_CAST (playsink), FALSE);
       
   809   GST_BIN_CLASS (gst_play_sink_parent_class)->handle_message (GST_BIN_CAST
       
   810       (playsink), message);
       
   811 }
       
   812 
       
   813 static void
       
   814 do_async_done (GstPlaySink * playsink)
       
   815 {
       
   816   GstMessage *message;
       
   817 
       
   818   if (playsink->async_pending) {
       
   819     GST_INFO_OBJECT (playsink, "Sending async_done message");
       
   820     message = gst_message_new_async_done (GST_OBJECT_CAST (playsink));
       
   821     GST_BIN_CLASS (gst_play_sink_parent_class)->handle_message (GST_BIN_CAST
       
   822         (playsink), message);
       
   823 
       
   824     playsink->async_pending = FALSE;
       
   825   }
       
   826 
       
   827   playsink->need_async_start = FALSE;
       
   828 }
       
   829 
       
   830 /* try to change the state of an element. This function returns the element when
       
   831  * the state change could be performed. When this function returns NULL an error
       
   832  * occured and the element is unreffed if @unref is TRUE. */
       
   833 static GstElement *
       
   834 try_element (GstPlaySink * playsink, GstElement * element, gboolean unref)
       
   835 {
       
   836   GstStateChangeReturn ret;
       
   837 
       
   838   if (element) {
       
   839     ret = gst_element_set_state (element, GST_STATE_READY);
       
   840     if (ret == GST_STATE_CHANGE_FAILURE) {
       
   841       GST_DEBUG_OBJECT (playsink, "failed state change..");
       
   842       gst_element_set_state (element, GST_STATE_NULL);
       
   843       if (unref)
       
   844         gst_object_unref (element);
       
   845       element = NULL;
       
   846     }
       
   847   }
       
   848   return element;
       
   849 }
   688 }
   850 
   689 
   851 /* make the element (bin) that contains the elements needed to perform
   690 /* make the element (bin) that contains the elements needed to perform
   852  * video display. 
   691  * video display. 
   853  *
   692  *
   859  *  |   |  +-------+   +----------+   +----------+   +---------+ |
   698  *  |   |  +-------+   +----------+   +----------+   +---------+ |
   860  * sink-+                                                        |
   699  * sink-+                                                        |
   861  *  +------------------------------------------------------------+
   700  *  +------------------------------------------------------------+
   862  *           
   701  *           
   863  */
   702  */
   864 static GstPlayVideoChain *
   703 static GstPlayChain *
   865 gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async,
   704 gen_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async)
   866     gboolean queue)
       
   867 {
   705 {
   868   GstPlayVideoChain *chain;
   706   GstPlayVideoChain *chain;
   869   GstBin *bin;
   707   GstBin *bin;
   870   GstPad *pad;
   708   GstPad *pad;
   871   GstElement *head, *prev, *elem;
       
   872 
   709 
   873   chain = g_new0 (GstPlayVideoChain, 1);
   710   chain = g_new0 (GstPlayVideoChain, 1);
   874   chain->chain.playsink = playsink;
   711   chain->chain.playsink = gst_object_ref (playsink);
   875   chain->chain.raw = raw;
       
   876 
       
   877   GST_DEBUG_OBJECT (playsink, "making video chain %p", chain);
       
   878 
   712 
   879   if (playsink->video_sink) {
   713   if (playsink->video_sink) {
   880     GST_DEBUG_OBJECT (playsink, "trying configured videosink");
   714     chain->sink = playsink->video_sink;
   881     chain->sink = try_element (playsink, playsink->video_sink, FALSE);
   715   } else {
   882   }
   716     chain->sink = gst_element_factory_make ("autovideosink", "videosink");
   883   if (chain->sink == NULL) {
   717     if (chain->sink == NULL) {
   884     GST_DEBUG_OBJECT (playsink, "trying autovideosink");
   718       chain->sink = gst_element_factory_make ("xvimagesink", "videosink");
   885     elem = gst_element_factory_make ("autovideosink", "videosink");
   719     }
   886     chain->sink = try_element (playsink, elem, TRUE);
   720     if (chain->sink == NULL)
   887   }
   721       goto no_sinks;
   888   /* FIXME: if DEFAULT_VIDEOSINK != "autovideosink" try this now */
   722   }
   889   if (chain->sink == NULL) {
       
   890     GST_DEBUG_OBJECT (playsink, "trying xvimagesink");
       
   891     elem = gst_element_factory_make ("xvimagesink", "videosink");
       
   892     chain->sink = try_element (playsink, elem, TRUE);
       
   893   }
       
   894   if (chain->sink == NULL)
       
   895     goto no_sinks;
       
   896 
   723 
   897   /* if we can disable async behaviour of the sink, we can avoid adding a
   724   /* if we can disable async behaviour of the sink, we can avoid adding a
   898    * queue for the audio chain. */
   725    * queue for the audio chain. We can't use the deep property here because the
   899   elem = gst_play_sink_find_property_sinks (playsink, chain->sink, "async");
   726    * sink might change it's internal sink element later. */
   900   if (elem) {
   727   if (g_object_class_find_property (G_OBJECT_GET_CLASS (chain->sink), "async")) {
   901     GST_DEBUG_OBJECT (playsink, "setting async property to %d on element %s",
   728     GST_DEBUG_OBJECT (playsink, "setting async property to %d on video sink",
   902         async, GST_ELEMENT_NAME (elem));
   729         async);
   903     g_object_set (elem, "async", async, NULL);
   730     g_object_set (chain->sink, "async", async, NULL);
   904     chain->async = async;
   731     chain->async = async;
   905   } else {
   732   } else
   906     GST_DEBUG_OBJECT (playsink, "no async property on the sink");
       
   907     chain->async = TRUE;
   733     chain->async = TRUE;
   908   }
       
   909 
   734 
   910   /* create a bin to hold objects, as we create them we add them to this bin so
   735   /* create a bin to hold objects, as we create them we add them to this bin so
   911    * that when something goes wrong we only need to unref the bin */
   736    * that when something goes wrong we only need to unref the bin */
   912   chain->chain.bin = gst_bin_new ("vbin");
   737   chain->chain.bin = gst_bin_new ("vbin");
   913   bin = GST_BIN_CAST (chain->chain.bin);
   738   bin = GST_BIN_CAST (chain->chain.bin);
   914   gst_object_ref (bin);
   739   gst_object_ref (bin);
   915   gst_object_sink (bin);
   740   gst_object_sink (bin);
   916   gst_bin_add (bin, chain->sink);
   741   gst_bin_add (bin, chain->sink);
   917 
   742 
   918   if (queue) {
   743   if (raw) {
   919     /* decouple decoder from sink, this improves playback quite a lot since the
   744     chain->conv = gst_element_factory_make ("ffmpegcolorspace", "vconv");
   920      * decoder can continue while the sink blocks for synchronisation. We don't
   745     if (chain->conv == NULL)
   921      * need a lot of buffers as this consumes a lot of memory and we don't want
   746       goto no_colorspace;
   922      * too little because else we would be context switching too quickly. */
   747     gst_bin_add (bin, chain->conv);
   923     chain->queue = gst_element_factory_make ("queue", "vqueue");
   748 
   924     g_object_set (G_OBJECT (chain->queue), "max-size-buffers", 3,
   749     chain->scale = gst_element_factory_make ("videoscale", "vscale");
   925         "max-size-bytes", 0, "max-size-time", (gint64) 0, NULL);
   750     if (chain->scale == NULL)
   926     gst_bin_add (bin, chain->queue);
   751       goto no_videoscale;
   927     head = prev = chain->queue;
   752     gst_bin_add (bin, chain->scale);
       
   753   }
       
   754 
       
   755   /* decouple decoder from sink, this improves playback quite a lot since the
       
   756    * decoder can continue while the sink blocks for synchronisation. We don't
       
   757    * need a lot of buffers as this consumes a lot of memory and we don't want
       
   758    * too little because else we would be context switching too quickly. */
       
   759   chain->queue = gst_element_factory_make ("queue", "vqueue");
       
   760   g_object_set (G_OBJECT (chain->queue), "max-size-buffers", 3,
       
   761       "max-size-bytes", 0, "max-size-time", (gint64) 0, NULL);
       
   762   gst_bin_add (bin, chain->queue);
       
   763 
       
   764   if (raw) {
       
   765     gst_element_link_pads (chain->queue, "src", chain->conv, "sink");
       
   766     gst_element_link_pads (chain->conv, "src", chain->scale, "sink");
       
   767     /* be more careful with the pad from the custom sink element, it might not
       
   768      * be named 'sink' */
       
   769     if (!gst_element_link_pads (chain->scale, "src", chain->sink, NULL))
       
   770       goto link_failed;
       
   771 
       
   772     pad = gst_element_get_pad (chain->queue, "sink");
   928   } else {
   773   } else {
   929     head = chain->sink;
   774     if (!gst_element_link_pads (chain->queue, "src", chain->sink, NULL))
   930     prev = NULL;
       
   931   }
       
   932 
       
   933   if (raw && !(playsink->flags & GST_PLAY_FLAG_NATIVE_VIDEO)) {
       
   934     GST_DEBUG_OBJECT (playsink, "creating ffmpegcolorspace");
       
   935     chain->conv = gst_element_factory_make ("ffmpegcolorspace", "vconv");
       
   936     if (chain->conv == NULL) {
       
   937       post_missing_element_message (playsink, "ffmpegcolorspace");
       
   938       GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN,
       
   939           (_("Missing element '%s' - check your GStreamer installation."),
       
   940               "ffmpegcolorspace"), ("video rendering might fail"));
       
   941     } else {
       
   942       gst_bin_add (bin, chain->conv);
       
   943       if (prev) {
       
   944         if (!gst_element_link_pads (prev, "src", chain->conv, "sink"))
       
   945           goto link_failed;
       
   946       } else {
       
   947         head = chain->conv;
       
   948       }
       
   949       prev = chain->conv;
       
   950     }
       
   951 
       
   952     GST_DEBUG_OBJECT (playsink, "creating videoscale");
       
   953     chain->scale = gst_element_factory_make ("videoscale", "vscale");
       
   954     if (chain->scale == NULL) {
       
   955       post_missing_element_message (playsink, "videoscale");
       
   956       GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN,
       
   957           (_("Missing element '%s' - check your GStreamer installation."),
       
   958               "videoscale"), ("possibly a liboil version mismatch?"));
       
   959     } else {
       
   960       gst_bin_add (bin, chain->scale);
       
   961       if (prev) {
       
   962         if (!gst_element_link_pads (prev, "src", chain->scale, "sink"))
       
   963           goto link_failed;
       
   964       } else {
       
   965         head = chain->scale;
       
   966       }
       
   967       prev = chain->scale;
       
   968     }
       
   969   }
       
   970 
       
   971   if (prev) {
       
   972     GST_DEBUG_OBJECT (playsink, "linking to sink");
       
   973     if (!gst_element_link_pads (prev, "src", chain->sink, NULL))
       
   974       goto link_failed;
   775       goto link_failed;
   975   }
   776     pad = gst_element_get_pad (chain->queue, "sink");
   976 
   777   }
   977   pad = gst_element_get_static_pad (head, "sink");
   778 
   978   chain->sinkpad = gst_ghost_pad_new ("sink", pad);
   779   chain->chain.sinkpad = gst_ghost_pad_new ("sink", pad);
   979   gst_object_unref (pad);
   780   gst_object_unref (pad);
   980 
   781   gst_element_add_pad (chain->chain.bin, chain->chain.sinkpad);
   981   gst_element_add_pad (chain->chain.bin, chain->sinkpad);
   782 
   982 
   783   return (GstPlayChain *) chain;
   983   return chain;
       
   984 
   784 
   985   /* ERRORS */
   785   /* ERRORS */
   986 no_sinks:
   786 no_sinks:
   987   {
   787   {
   988     if (!elem) {
   788     post_missing_element_message (playsink, "autovideosink");
   989       post_missing_element_message (playsink, "autovideosink");
   789     GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
   990       GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
   790         (_("Both autovideosink and xvimagesink elements are missing.")),
   991           (_("Both autovideosink and xvimagesink elements are missing.")),
   791         (NULL));
   992           (NULL));
   792     free_chain ((GstPlayChain *) chain);
   993     } else {
   793     return NULL;
   994       GST_ELEMENT_ERROR (playsink, CORE, STATE_CHANGE,
   794   }
   995           (_("Both autovideosink and xvimagesink elements are not working.")),
   795 no_colorspace:
   996           (NULL));
   796   {
   997     }
   797     post_missing_element_message (playsink, "ffmpegcolorspace");
       
   798     GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
       
   799         (_("Missing element '%s' - check your GStreamer installation."),
       
   800             "ffmpegcolorspace"), (NULL));
       
   801     free_chain ((GstPlayChain *) chain);
       
   802     return NULL;
       
   803   }
       
   804 
       
   805 no_videoscale:
       
   806   {
       
   807     post_missing_element_message (playsink, "videoscale");
       
   808     GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
       
   809         (_("Missing element '%s' - check your GStreamer installation."),
       
   810             "videoscale"), ("possibly a liboil version mismatch?"));
   998     free_chain ((GstPlayChain *) chain);
   811     free_chain ((GstPlayChain *) chain);
   999     return NULL;
   812     return NULL;
  1000   }
   813   }
  1001 link_failed:
   814 link_failed:
  1002   {
   815   {
  1005     free_chain ((GstPlayChain *) chain);
   818     free_chain ((GstPlayChain *) chain);
  1006     return NULL;
   819     return NULL;
  1007   }
   820   }
  1008 }
   821 }
  1009 
   822 
  1010 static gboolean
   823 #if 0
  1011 setup_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async,
       
  1012     gboolean queue)
       
  1013 {
       
  1014   GstElement *elem;
       
  1015   GstPlayVideoChain *chain;
       
  1016   GstStateChangeReturn ret;
       
  1017 
       
  1018   chain = playsink->videochain;
       
  1019 
       
  1020   /* if the chain was active we don't do anything */
       
  1021   if (GST_PLAY_CHAIN (chain)->activated == TRUE)
       
  1022     return TRUE;
       
  1023 
       
  1024   if (chain->chain.raw != raw)
       
  1025     return FALSE;
       
  1026 
       
  1027   /* try to set the sink element to READY again */
       
  1028   ret = gst_element_set_state (chain->sink, GST_STATE_READY);
       
  1029   if (ret == GST_STATE_CHANGE_FAILURE)
       
  1030     return FALSE;
       
  1031 
       
  1032   /* if we can disable async behaviour of the sink, we can avoid adding a
       
  1033    * queue for the audio chain. */
       
  1034   elem = gst_play_sink_find_property_sinks (playsink, chain->sink, "async");
       
  1035   if (elem) {
       
  1036     GST_DEBUG_OBJECT (playsink, "setting async property to %d on element %s",
       
  1037         async, GST_ELEMENT_NAME (elem));
       
  1038     g_object_set (elem, "async", async, NULL);
       
  1039     chain->async = async;
       
  1040   } else {
       
  1041     GST_DEBUG_OBJECT (playsink, "no async property on the sink");
       
  1042     chain->async = TRUE;
       
  1043   }
       
  1044   return TRUE;
       
  1045 }
       
  1046 
       
  1047 /* make an element for playback of video with subtitles embedded.
   824 /* make an element for playback of video with subtitles embedded.
  1048  *
   825  *
  1049  *  +----------------------------------------------+
   826  *  +--------------------------------------------------+
  1050  *  | tbin                  +-------------+        |
   827  *  | tbin                  +-------------+            |
  1051  *  |          +-----+      | textoverlay |        |
   828  *  |          +-----+      | textoverlay |   +------+ |
  1052  *  |          | csp | +--video_sink      |        |
   829  *  |          | csp | +--video_sink      |   | vbin | |
  1053  * sink-------sink  src+ +-text_sink     src--+    |
   830  * video_sink-sink  src+ +-text_sink     src-sink    | |
  1054  *  |          +-----+   |  +-------------+   +-- src   
   831  *  |          +-----+   |  +-------------+   +------+ |
  1055  * text_sink-------------+                         |
   832  * text_sink-------------+                             |
  1056  *  +----------------------------------------------+
   833  *  +--------------------------------------------------+
       
   834  *
       
   835  *  If there is no subtitle renderer this function will simply return the
       
   836  *  videosink without the text_sink pad.
  1057  */
   837  */
  1058 static GstPlayTextChain *
   838 static GstElement *
  1059 gen_text_chain (GstPlaySink * playsink)
   839 gen_text_element (GstPlaySink * playsink)
  1060 {
   840 {
  1061   GstPlayTextChain *chain;
   841   GstElement *element, *csp, *overlay, *vbin;
  1062   GstBin *bin;
   842   GstPad *pad;
  1063   GstElement *elem;
   843 
  1064   GstPad *videosinkpad, *textsinkpad, *srcpad;
   844   /* Create the video rendering bin, error is posted when this fails. */
  1065 
   845   vbin = gen_video_element (playsink);
  1066   chain = g_new0 (GstPlayTextChain, 1);
   846   if (!vbin)
  1067   chain->chain.playsink = playsink;
   847     return NULL;
  1068 
   848 
  1069   GST_DEBUG_OBJECT (playsink, "making text chain %p", chain);
   849   /* Text overlay */
  1070 
   850   overlay = gst_element_factory_make ("textoverlay", "overlay");
  1071   chain->chain.bin = gst_bin_new ("tbin");
   851 
  1072   bin = GST_BIN_CAST (chain->chain.bin);
   852   /* If no overlay return the video bin without subtitle support. */
  1073   gst_object_ref (bin);
   853   if (!overlay)
  1074   gst_object_sink (bin);
   854     goto no_overlay;
  1075 
   855 
  1076   videosinkpad = textsinkpad = srcpad = NULL;
   856   /* Create our bin */
  1077 
   857   element = gst_bin_new ("textbin");
  1078   /* first try to hook the text pad to the custom sink */
   858 
  1079   if (playsink->text_sink) {
   859   /* Set some parameters */
  1080     GST_DEBUG_OBJECT (playsink, "trying configured textsink");
   860   g_object_set (G_OBJECT (overlay),
  1081     chain->sink = try_element (playsink, playsink->text_sink, FALSE);
   861       "halign", "center", "valign", "bottom", NULL);
  1082     if (chain->sink) {
   862   if (playsink->font_desc) {
  1083       elem = gst_play_sink_find_property_sinks (playsink, chain->sink, "async");
   863     g_object_set (G_OBJECT (overlay), "font-desc", playsink->font_desc, NULL);
  1084       if (elem) {
   864   }
  1085         /* make sure the sparse subtitles don't participate in the preroll */
   865 
  1086         g_object_set (elem, "async", FALSE, NULL);
   866   /* Take a ref */
  1087         /* we have a custom sink, this will be our textsinkpad */
   867   playsink->textoverlay_element = GST_ELEMENT_CAST (gst_object_ref (overlay));
  1088         textsinkpad = gst_element_get_static_pad (chain->sink, "sink");
   868 
  1089         if (textsinkpad) {
   869   /* we know this will succeed, as the video bin already created one before */
  1090           /* we're all fine now and we can add the sink to the chain */
   870   csp = gst_element_factory_make ("ffmpegcolorspace", "subtitlecsp");
  1091           GST_DEBUG_OBJECT (playsink, "adding custom text sink");
   871 
  1092           gst_bin_add (bin, chain->sink);
   872   /* Add our elements */
  1093         } else {
   873   gst_bin_add_many (GST_BIN_CAST (element), csp, overlay, vbin, NULL);
  1094           GST_WARNING_OBJECT (playsink,
   874 
  1095               "can't find a sink pad on custom text sink");
   875   /* Link */
  1096           gst_object_unref (chain->sink);
   876   gst_element_link_pads (csp, "src", overlay, "video_sink");
  1097           chain->sink = NULL;
   877   gst_element_link_pads (overlay, "src", vbin, "sink");
  1098         }
   878 
  1099         /* try to set sync to true but it's no biggie when we can't */
   879   /* Add ghost pads on the subtitle bin */
  1100         if ((elem =
   880   pad = gst_element_get_pad (overlay, "text_sink");
  1101                 gst_play_sink_find_property_sinks (playsink, chain->sink,
   881   gst_element_add_pad (element, gst_ghost_pad_new ("text_sink", pad));
  1102                     "sync")))
   882   gst_object_unref (pad);
  1103           g_object_set (elem, "sync", TRUE, NULL);
   883 
  1104       } else {
   884   pad = gst_element_get_pad (csp, "sink");
  1105         GST_WARNING_OBJECT (playsink,
   885   gst_element_add_pad (element, gst_ghost_pad_new ("sink", pad));
  1106             "can't find async property in custom text sink");
   886   gst_object_unref (pad);
  1107       }
   887 
  1108     }
   888   /* Set state to READY */
  1109     if (textsinkpad == NULL) {
   889   gst_element_set_state (element, GST_STATE_READY);
  1110       GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN,
   890 
  1111           (_("Custom text sink element is not usable.")),
   891   return element;
  1112           ("fallback to default textoverlay"));
   892 
  1113     }
   893   /* ERRORS */
  1114   }
   894 no_overlay:
  1115 
   895   {
  1116   if (textsinkpad == NULL) {
   896     post_missing_element_message (playsink, "textoverlay");
  1117     if (!(playsink->flags & GST_PLAY_FLAG_NATIVE_VIDEO)) {
   897     GST_WARNING_OBJECT (playsink,
  1118       /* no custom sink, try to setup the colorspace and textoverlay elements */
   898         "No overlay (pango) element, subtitles disabled");
  1119       chain->conv = gst_element_factory_make ("ffmpegcolorspace", "tconv");
   899     return vbin;
  1120       if (chain->conv == NULL) {
   900   }
  1121         /* not really needed, it might work without colorspace */
   901 }
  1122         post_missing_element_message (playsink, "ffmpegcolorspace");
   902 #endif
  1123         GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN,
   903 
  1124             (_("Missing element '%s' - check your GStreamer installation."),
       
  1125                 "ffmpegcolorspace"), ("subtitle rendering might fail"));
       
  1126       } else {
       
  1127         gst_bin_add (bin, chain->conv);
       
  1128         videosinkpad = gst_element_get_static_pad (chain->conv, "sink");
       
  1129       }
       
  1130     }
       
  1131 
       
  1132     chain->overlay = gst_element_factory_make ("textoverlay", "overlay");
       
  1133     if (chain->overlay == NULL) {
       
  1134       post_missing_element_message (playsink, "textoverlay");
       
  1135       GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN,
       
  1136           (_("Missing element '%s' - check your GStreamer installation."),
       
  1137               "textoverlay"), ("subtitle rendering disabled"));
       
  1138     } else {
       
  1139       gst_bin_add (bin, chain->overlay);
       
  1140 
       
  1141       /* Set some parameters */
       
  1142       g_object_set (G_OBJECT (chain->overlay),
       
  1143           "halign", "center", "valign", "bottom", NULL);
       
  1144       if (playsink->font_desc) {
       
  1145         g_object_set (G_OBJECT (chain->overlay), "font-desc",
       
  1146             playsink->font_desc, NULL);
       
  1147       }
       
  1148       g_object_set (G_OBJECT (chain->overlay), "wait-text", FALSE, NULL);
       
  1149 
       
  1150       textsinkpad = gst_element_get_static_pad (chain->overlay, "text_sink");
       
  1151 
       
  1152       srcpad = gst_element_get_static_pad (chain->overlay, "src");
       
  1153 
       
  1154       if (videosinkpad) {
       
  1155         /* if we had a videosinkpad, we had a converter and we can link it, we
       
  1156          * know that this will work */
       
  1157         gst_element_link_pads (chain->conv, "src", chain->overlay,
       
  1158             "video_sink");
       
  1159       } else {
       
  1160         /* no videopad, expose our own video pad then */
       
  1161         videosinkpad =
       
  1162             gst_element_get_static_pad (chain->overlay, "video_sink");
       
  1163       }
       
  1164     }
       
  1165   }
       
  1166 
       
  1167   if (videosinkpad == NULL) {
       
  1168     /* if we still don't have a videosink, we don't have a converter nor an
       
  1169      * overlay. the only thing we can do is insert an identity and ghost the src
       
  1170      * and sink pads. */
       
  1171     chain->conv = gst_element_factory_make ("identity", "tidentity");
       
  1172     g_object_set (chain->conv, "signal-handoffs", FALSE, NULL);
       
  1173     g_object_set (chain->conv, "silent", TRUE, NULL);
       
  1174     gst_bin_add (bin, chain->conv);
       
  1175     srcpad = gst_element_get_static_pad (chain->conv, "src");
       
  1176     videosinkpad = gst_element_get_static_pad (chain->conv, "sink");
       
  1177   } else {
       
  1178     /* we have a videosink but maybe not a srcpad because there was no
       
  1179      * overlay */
       
  1180     if (srcpad == NULL) {
       
  1181       /* ghost the source pad of the converter then */
       
  1182       srcpad = gst_element_get_static_pad (chain->conv, "src");
       
  1183     }
       
  1184   }
       
  1185 
       
  1186   /* expose the ghostpads */
       
  1187   if (videosinkpad) {
       
  1188     chain->videosinkpad = gst_ghost_pad_new ("sink", videosinkpad);
       
  1189     gst_object_unref (videosinkpad);
       
  1190     gst_element_add_pad (chain->chain.bin, chain->videosinkpad);
       
  1191   }
       
  1192   if (textsinkpad) {
       
  1193     chain->textsinkpad = gst_ghost_pad_new ("text_sink", textsinkpad);
       
  1194     gst_object_unref (textsinkpad);
       
  1195     gst_element_add_pad (chain->chain.bin, chain->textsinkpad);
       
  1196   }
       
  1197   if (srcpad) {
       
  1198     chain->srcpad = gst_ghost_pad_new ("src", srcpad);
       
  1199     gst_object_unref (srcpad);
       
  1200     gst_element_add_pad (chain->chain.bin, chain->srcpad);
       
  1201   }
       
  1202 
       
  1203   return chain;
       
  1204 }
       
  1205 
       
  1206 /* make an element for playback of video with subpictures embedded.
       
  1207  *
       
  1208  *  +--------------------------------------------------------+
       
  1209  *  | pbin                            +-------------+        |
       
  1210  *  |       +-------+    +-----+      |   dvdspu    |        |
       
  1211  *  |       | queue |    | csp | +---video          |        |
       
  1212  * sink----sink    src--sink  src+ +-subpicture    src--+    |
       
  1213  *  |       +-------+    +-----+   |  +-------------+   +-- src   
       
  1214  * subpicture----------------------+                         |
       
  1215  *  +--------------------------------------------------------+
       
  1216  */
       
  1217 static GstPlaySubpChain *
       
  1218 gen_subp_chain (GstPlaySink * playsink)
       
  1219 {
       
  1220   GstPlaySubpChain *chain;
       
  1221   GstBin *bin;
       
  1222   GstElement *elem, *head;
       
  1223   GstPad *videosinkpad, *subpsinkpad, *srcpad;
       
  1224 
       
  1225   chain = g_new0 (GstPlaySubpChain, 1);
       
  1226   chain->chain.playsink = playsink;
       
  1227 
       
  1228   GST_DEBUG_OBJECT (playsink, "making subpicture chain %p", chain);
       
  1229 
       
  1230   chain->chain.bin = gst_bin_new ("pbin");
       
  1231   bin = GST_BIN_CAST (chain->chain.bin);
       
  1232   gst_object_ref (bin);
       
  1233   gst_object_sink (bin);
       
  1234 
       
  1235   videosinkpad = subpsinkpad = srcpad = NULL;
       
  1236 
       
  1237   /* first try to hook the text pad to the custom sink */
       
  1238   if (playsink->subp_sink) {
       
  1239     GST_DEBUG_OBJECT (playsink, "trying configured subpsink");
       
  1240     chain->sink = try_element (playsink, playsink->text_sink, FALSE);
       
  1241     if (chain->sink) {
       
  1242       elem = gst_play_sink_find_property_sinks (playsink, chain->sink, "async");
       
  1243       if (elem) {
       
  1244         /* make sure the sparse subtitles don't participate in the preroll */
       
  1245         g_object_set (elem, "async", FALSE, NULL);
       
  1246         /* we have a custom sink, this will be our subpsinkpad */
       
  1247         subpsinkpad = gst_element_get_static_pad (chain->sink, "sink");
       
  1248         if (subpsinkpad) {
       
  1249           /* we're all fine now and we can add the sink to the chain */
       
  1250           GST_DEBUG_OBJECT (playsink, "adding custom text sink");
       
  1251           gst_bin_add (bin, chain->sink);
       
  1252         } else {
       
  1253           GST_WARNING_OBJECT (playsink,
       
  1254               "can't find a sink pad on custom text sink");
       
  1255           gst_object_unref (chain->sink);
       
  1256           chain->sink = NULL;
       
  1257         }
       
  1258         /* try to set sync to true but it's no biggie when we can't */
       
  1259         if ((elem =
       
  1260                 gst_play_sink_find_property_sinks (playsink, chain->sink,
       
  1261                     "sync")))
       
  1262           g_object_set (elem, "sync", TRUE, NULL);
       
  1263       } else {
       
  1264         GST_WARNING_OBJECT (playsink,
       
  1265             "can't find async property in custom text sink");
       
  1266       }
       
  1267     }
       
  1268     if (subpsinkpad == NULL) {
       
  1269       GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN,
       
  1270           (_("Custom text sink element is not usable.")),
       
  1271           ("fallback to default dvdspu overlay"));
       
  1272     }
       
  1273   }
       
  1274 
       
  1275   /* make a little queue */
       
  1276   chain->queue = gst_element_factory_make ("queue", "vqueue");
       
  1277   g_object_set (G_OBJECT (chain->queue), "max-size-buffers", 3,
       
  1278       "max-size-bytes", 0, "max-size-time", (gint64) 0, NULL);
       
  1279   gst_bin_add (bin, chain->queue);
       
  1280   head = chain->queue;
       
  1281 
       
  1282   /* video goes into the queue */
       
  1283   videosinkpad = gst_element_get_static_pad (chain->queue, "sink");
       
  1284 
       
  1285   if (subpsinkpad == NULL) {
       
  1286     if (!(playsink->flags & GST_PLAY_FLAG_NATIVE_VIDEO)) {
       
  1287       /* no custom sink, try to setup the colorspace and textoverlay elements */
       
  1288       chain->conv = gst_element_factory_make ("ffmpegcolorspace", "tconv");
       
  1289       if (chain->conv == NULL) {
       
  1290         /* not really needed, it might work without colorspace */
       
  1291         post_missing_element_message (playsink, "ffmpegcolorspace");
       
  1292         GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN,
       
  1293             (_("Missing element '%s' - check your GStreamer installation."),
       
  1294                 "ffmpegcolorspace"), ("subpicture rendering might fail"));
       
  1295       } else {
       
  1296         gst_bin_add (bin, chain->conv);
       
  1297         gst_element_link_pads (head, "src", chain->conv, "sink");
       
  1298         head = chain->conv;
       
  1299       }
       
  1300     }
       
  1301 
       
  1302     chain->overlay = gst_element_factory_make ("dvdspu", "spuoverlay");
       
  1303     if (chain->overlay == NULL) {
       
  1304       post_missing_element_message (playsink, "dvdspu");
       
  1305       GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN,
       
  1306           (_("Missing element '%s' - check your GStreamer installation."),
       
  1307               "dvdspu"), ("subpicture rendering disabled"));
       
  1308     } else {
       
  1309       gst_bin_add (bin, chain->overlay);
       
  1310       /* Set some parameters */
       
  1311       subpsinkpad = gst_element_get_static_pad (chain->overlay, "subpicture");
       
  1312       /* link to the next element */
       
  1313       gst_element_link_pads (head, "src", chain->overlay, "video");
       
  1314       head = chain->overlay;
       
  1315     }
       
  1316   }
       
  1317   srcpad = gst_element_get_static_pad (head, "src");
       
  1318   chain->srcpad = gst_ghost_pad_new ("src", srcpad);
       
  1319   gst_object_unref (srcpad);
       
  1320   gst_element_add_pad (chain->chain.bin, chain->srcpad);
       
  1321 
       
  1322   /* expose the ghostpads */
       
  1323   chain->videosinkpad = gst_ghost_pad_new ("sink", videosinkpad);
       
  1324   gst_object_unref (videosinkpad);
       
  1325   gst_element_add_pad (chain->chain.bin, chain->videosinkpad);
       
  1326 
       
  1327   if (subpsinkpad) {
       
  1328     chain->subpsinkpad = gst_ghost_pad_new ("subpicture", subpsinkpad);
       
  1329     gst_object_unref (subpsinkpad);
       
  1330     gst_element_add_pad (chain->chain.bin, chain->subpsinkpad);
       
  1331   }
       
  1332   return chain;
       
  1333 }
       
  1334 
   904 
  1335 /* make the chain that contains the elements needed to perform
   905 /* make the chain that contains the elements needed to perform
  1336  * audio playback. 
   906  * audio playback. 
  1337  *
   907  *
  1338  * We add a tee as the first element so that we can link the visualisation chain
   908  * We add a tee as the first element so that we can link the visualisation chain
  1345  *  |   +-srck      src-sink       src-sink      src-sink       | |
   915  *  |   +-srck      src-sink       src-sink      src-sink       | |
  1346  *  |   |  +---------+   +----------+   +---------+   +---------+ |
   916  *  |   |  +---------+   +----------+   +---------+   +---------+ |
  1347  * sink-+                                                         |
   917  * sink-+                                                         |
  1348  *  +-------------------------------------------------------------+
   918  *  +-------------------------------------------------------------+
  1349  */
   919  */
  1350 static GstPlayAudioChain *
   920 static GstPlayChain *
  1351 gen_audio_chain (GstPlaySink * playsink, gboolean raw, gboolean queue)
   921 gen_audio_chain (GstPlaySink * playsink, gboolean raw, gboolean queue)
  1352 {
   922 {
  1353   GstPlayAudioChain *chain;
   923   GstPlayAudioChain *chain;
  1354   GstBin *bin;
   924   GstBin *bin;
  1355   gboolean have_volume;
   925   gboolean res;
  1356   GstPad *pad;
   926   GstPad *pad;
  1357   GstElement *head, *prev, *elem;
       
  1358 
   927 
  1359   chain = g_new0 (GstPlayAudioChain, 1);
   928   chain = g_new0 (GstPlayAudioChain, 1);
  1360   chain->chain.playsink = playsink;
   929   chain->chain.playsink = gst_object_ref (playsink);
  1361   chain->chain.raw = raw;
       
  1362 
       
  1363   GST_DEBUG_OBJECT (playsink, "making audio chain %p", chain);
       
  1364 
   930 
  1365   if (playsink->audio_sink) {
   931   if (playsink->audio_sink) {
  1366     GST_DEBUG_OBJECT (playsink, "trying configured audiosink %" GST_PTR_FORMAT,
   932     chain->sink = playsink->audio_sink;
  1367         playsink->audio_sink);
   933   } else {
  1368     chain->sink = try_element (playsink, playsink->audio_sink, FALSE);
   934     chain->sink = gst_element_factory_make ("autoaudiosink", "audiosink");
  1369   }
   935     if (chain->sink == NULL) {
  1370   if (chain->sink == NULL) {
   936       chain->sink = gst_element_factory_make ("alsasink", "audiosink");
  1371     GST_DEBUG_OBJECT (playsink, "trying autoaudiosink");
   937     }
  1372     elem = gst_element_factory_make ("autoaudiosink", "audiosink");
   938     if (chain->sink == NULL)
  1373     chain->sink = try_element (playsink, elem, TRUE);
   939       goto no_sinks;
  1374   }
   940   }
  1375   /* FIXME: if DEFAULT_AUDIOSINK != "autoaudiosink" try this now */
       
  1376   if (chain->sink == NULL) {
       
  1377     GST_DEBUG_OBJECT (playsink, "trying alsasink");
       
  1378     elem = gst_element_factory_make ("alsasink", "audiosink");
       
  1379     chain->sink = try_element (playsink, elem, TRUE);
       
  1380   }
       
  1381   if (chain->sink == NULL)
       
  1382     goto no_sinks;
       
  1383 
       
  1384   chain->chain.bin = gst_bin_new ("abin");
   941   chain->chain.bin = gst_bin_new ("abin");
  1385   bin = GST_BIN_CAST (chain->chain.bin);
   942   bin = GST_BIN_CAST (chain->chain.bin);
  1386   gst_object_ref (bin);
   943   gst_object_ref (bin);
  1387   gst_object_sink (bin);
   944   gst_object_sink (bin);
  1388   gst_bin_add (bin, chain->sink);
   945   gst_bin_add (bin, chain->sink);
  1391     /* we have to add a queue when we need to decouple for the video sink in
   948     /* we have to add a queue when we need to decouple for the video sink in
  1392      * visualisations */
   949      * visualisations */
  1393     GST_DEBUG_OBJECT (playsink, "adding audio queue");
   950     GST_DEBUG_OBJECT (playsink, "adding audio queue");
  1394     chain->queue = gst_element_factory_make ("queue", "aqueue");
   951     chain->queue = gst_element_factory_make ("queue", "aqueue");
  1395     gst_bin_add (bin, chain->queue);
   952     gst_bin_add (bin, chain->queue);
  1396     prev = head = chain->queue;
   953   }
       
   954 
       
   955   if (raw) {
       
   956     chain->conv = gst_element_factory_make ("audioconvert", "aconv");
       
   957     if (chain->conv == NULL)
       
   958       goto no_audioconvert;
       
   959     gst_bin_add (bin, chain->conv);
       
   960 
       
   961     chain->resample = gst_element_factory_make ("audioresample", "aresample");
       
   962     if (chain->resample == NULL)
       
   963       goto no_audioresample;
       
   964     gst_bin_add (bin, chain->resample);
       
   965 
       
   966     res = gst_element_link_pads (chain->conv, "src", chain->resample, "sink");
       
   967 
       
   968     /* FIXME check if the sink has the volume property */
       
   969 
       
   970     if (playsink->flags & GST_PLAY_FLAG_SOFT_VOLUME) {
       
   971       chain->volume = gst_element_factory_make ("volume", "volume");
       
   972       if (chain->volume == NULL)
       
   973         goto no_volume;
       
   974 
       
   975       /* volume also has the mute property */
       
   976       chain->mute = gst_object_ref (chain->volume);
       
   977 
       
   978       /* configure with the latest volume */
       
   979       g_object_set (G_OBJECT (chain->volume), "volume", playsink->volume, NULL);
       
   980       gst_bin_add (bin, chain->volume);
       
   981 
       
   982       res &=
       
   983           gst_element_link_pads (chain->resample, "src", chain->volume, "sink");
       
   984       res &= gst_element_link_pads (chain->volume, "src", chain->sink, NULL);
       
   985     } else {
       
   986       res &= gst_element_link_pads (chain->resample, "src", chain->sink, NULL);
       
   987     }
       
   988     if (!res)
       
   989       goto link_failed;
       
   990 
       
   991     if (queue) {
       
   992       res = gst_element_link_pads (chain->queue, "src", chain->conv, "sink");
       
   993       pad = gst_element_get_pad (chain->queue, "sink");
       
   994     } else {
       
   995       pad = gst_element_get_pad (chain->conv, "sink");
       
   996     }
  1397   } else {
   997   } else {
  1398     head = chain->sink;
   998     if (queue) {
  1399     prev = NULL;
   999       res = gst_element_link_pads (chain->queue, "src", chain->sink, "sink");
  1400   }
  1000       pad = gst_element_get_pad (chain->queue, "sink");
  1401 
       
  1402   /* check if the sink, or something within the sink, has the volume property.
       
  1403    * If it does we don't need to add a volume element.  */
       
  1404   elem = gst_play_sink_find_property_sinks (playsink, chain->sink, "volume");
       
  1405   if (elem) {
       
  1406     chain->volume = elem;
       
  1407 
       
  1408     GST_DEBUG_OBJECT (playsink, "the sink has a volume property");
       
  1409     have_volume = TRUE;
       
  1410     chain->sink_volume = TRUE;
       
  1411     /* if the sink also has a mute property we can use this as well. We'll only
       
  1412      * use the mute property if there is a volume property. We can simulate the
       
  1413      * mute with the volume otherwise. */
       
  1414     chain->mute =
       
  1415         gst_play_sink_find_property_sinks (playsink, chain->sink, "mute");
       
  1416     if (chain->mute) {
       
  1417       GST_DEBUG_OBJECT (playsink, "the sink has a mute property");
       
  1418     }
       
  1419     /* use the sink to control the volume and mute */
       
  1420     if (playsink->volume_changed) {
       
  1421       g_object_set (G_OBJECT (chain->volume), "volume", playsink->volume, NULL);
       
  1422     }
       
  1423     if (playsink->mute_changed) {
       
  1424       if (chain->mute) {
       
  1425         g_object_set (chain->mute, "mute", playsink->mute, NULL);
       
  1426       } else {
       
  1427         if (playsink->mute)
       
  1428           g_object_set (chain->volume, "volume", (gdouble) 0.0, NULL);
       
  1429       }
       
  1430     }
       
  1431   } else {
       
  1432     /* no volume, we need to add a volume element when we can */
       
  1433     GST_DEBUG_OBJECT (playsink, "the sink has no volume property");
       
  1434     have_volume = FALSE;
       
  1435     chain->sink_volume = FALSE;
       
  1436   }
       
  1437 
       
  1438   if (raw && !(playsink->flags & GST_PLAY_FLAG_NATIVE_AUDIO)) {
       
  1439     GST_DEBUG_OBJECT (playsink, "creating audioconvert");
       
  1440     chain->conv = gst_element_factory_make ("audioconvert", "aconv");
       
  1441     if (chain->conv == NULL) {
       
  1442       post_missing_element_message (playsink, "audioconvert");
       
  1443       GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN,
       
  1444           (_("Missing element '%s' - check your GStreamer installation."),
       
  1445               "audioconvert"), ("possibly a liboil version mismatch?"));
       
  1446     } else {
  1001     } else {
  1447       gst_bin_add (bin, chain->conv);
  1002       pad = gst_element_get_pad (chain->sink, "sink");
  1448       if (prev) {
  1003     }
  1449         if (!gst_element_link_pads (prev, "src", chain->conv, "sink"))
  1004   }
  1450           goto link_failed;
  1005   chain->chain.sinkpad = gst_ghost_pad_new ("sink", pad);
  1451       } else {
       
  1452         head = chain->conv;
       
  1453       }
       
  1454       prev = chain->conv;
       
  1455     }
       
  1456 
       
  1457     GST_DEBUG_OBJECT (playsink, "creating audioresample");
       
  1458     chain->resample = gst_element_factory_make ("audioresample", "aresample");
       
  1459     if (chain->resample == NULL) {
       
  1460       post_missing_element_message (playsink, "audioresample");
       
  1461       GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN,
       
  1462           (_("Missing element '%s' - check your GStreamer installation."),
       
  1463               "audioresample"), ("possibly a liboil version mismatch?"));
       
  1464     } else {
       
  1465       gst_bin_add (bin, chain->resample);
       
  1466       if (prev) {
       
  1467         if (!gst_element_link_pads (prev, "src", chain->resample, "sink"))
       
  1468           goto link_failed;
       
  1469       } else {
       
  1470         head = chain->resample;
       
  1471       }
       
  1472       prev = chain->resample;
       
  1473     }
       
  1474 
       
  1475     if (!have_volume && playsink->flags & GST_PLAY_FLAG_SOFT_VOLUME) {
       
  1476       GST_DEBUG_OBJECT (playsink, "creating volume");
       
  1477       chain->volume = gst_element_factory_make ("volume", "volume");
       
  1478       if (chain->volume == NULL) {
       
  1479         post_missing_element_message (playsink, "volume");
       
  1480         GST_ELEMENT_WARNING (playsink, CORE, MISSING_PLUGIN,
       
  1481             (_("Missing element '%s' - check your GStreamer installation."),
       
  1482                 "volume"), ("possibly a liboil version mismatch?"));
       
  1483       } else {
       
  1484         have_volume = TRUE;
       
  1485 
       
  1486         /* volume also has the mute property */
       
  1487         chain->mute = chain->volume;
       
  1488 
       
  1489         /* configure with the latest volume and mute */
       
  1490         g_object_set (G_OBJECT (chain->volume), "volume", playsink->volume,
       
  1491             NULL);
       
  1492         g_object_set (G_OBJECT (chain->mute), "mute", playsink->mute, NULL);
       
  1493         gst_bin_add (bin, chain->volume);
       
  1494 
       
  1495         if (prev) {
       
  1496           if (!gst_element_link_pads (prev, "src", chain->volume, "sink"))
       
  1497             goto link_failed;
       
  1498         } else {
       
  1499           head = chain->volume;
       
  1500         }
       
  1501         prev = chain->volume;
       
  1502       }
       
  1503     }
       
  1504   }
       
  1505 
       
  1506   if (prev) {
       
  1507     /* we only have to link to the previous element if we have something in
       
  1508      * front of the sink */
       
  1509     GST_DEBUG_OBJECT (playsink, "linking to sink");
       
  1510     if (!gst_element_link_pads (prev, "src", chain->sink, NULL))
       
  1511       goto link_failed;
       
  1512   }
       
  1513 
       
  1514   /* post a warning if we have no way to configure the volume */
       
  1515   if (!have_volume) {
       
  1516     GST_ELEMENT_WARNING (playsink, STREAM, NOT_IMPLEMENTED,
       
  1517         (_("No volume control found")), ("Volume/mute is not available"));
       
  1518   }
       
  1519 
       
  1520   /* and ghost the sinkpad of the headmost element */
       
  1521   GST_DEBUG_OBJECT (playsink, "ghosting sink pad");
       
  1522   pad = gst_element_get_static_pad (head, "sink");
       
  1523   chain->sinkpad = gst_ghost_pad_new ("sink", pad);
       
  1524   gst_object_unref (pad);
  1006   gst_object_unref (pad);
  1525   gst_element_add_pad (chain->chain.bin, chain->sinkpad);
  1007   gst_element_add_pad (chain->chain.bin, chain->chain.sinkpad);
  1526 
  1008 
  1527   return chain;
  1009   return (GstPlayChain *) chain;
  1528 
  1010 
  1529   /* ERRORS */
  1011   /* ERRORS */
  1530 no_sinks:
  1012 no_sinks:
  1531   {
  1013   {
  1532     if (!elem) {
  1014     post_missing_element_message (playsink, "autoaudiosink");
  1533       post_missing_element_message (playsink, "autoaudiosink");
  1015     GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
  1534       GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
  1016         (_("Both autoaudiosink and alsasink elements are missing.")), (NULL));
  1535           (_("Both autoaudiosink and alsasink elements are missing.")), (NULL));
  1017     free_chain ((GstPlayChain *) chain);
  1536     } else {
  1018     return NULL;
  1537       GST_ELEMENT_ERROR (playsink, CORE, STATE_CHANGE,
  1019   }
  1538           (_("Both autoaudiosink and alsasink elements are not working.")),
  1020 no_audioconvert:
  1539           (NULL));
  1021   {
  1540     }
  1022     post_missing_element_message (playsink, "audioconvert");
       
  1023     GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
       
  1024         (_("Missing element '%s' - check your GStreamer installation."),
       
  1025             "audioconvert"), ("possibly a liboil version mismatch?"));
       
  1026     free_chain ((GstPlayChain *) chain);
       
  1027     return NULL;
       
  1028   }
       
  1029 no_audioresample:
       
  1030   {
       
  1031     post_missing_element_message (playsink, "audioresample");
       
  1032     GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
       
  1033         (_("Missing element '%s' - check your GStreamer installation."),
       
  1034             "audioresample"), ("possibly a liboil version mismatch?"));
       
  1035     free_chain ((GstPlayChain *) chain);
       
  1036     return NULL;
       
  1037   }
       
  1038 no_volume:
       
  1039   {
       
  1040     post_missing_element_message (playsink, "volume");
       
  1041     GST_ELEMENT_ERROR (playsink, CORE, MISSING_PLUGIN,
       
  1042         (_("Missing element '%s' - check your GStreamer installation."),
       
  1043             "volume"), ("possibly a liboil version mismatch?"));
  1541     free_chain ((GstPlayChain *) chain);
  1044     free_chain ((GstPlayChain *) chain);
  1542     return NULL;
  1045     return NULL;
  1543   }
  1046   }
  1544 link_failed:
  1047 link_failed:
  1545   {
  1048   {
  1546     GST_ELEMENT_ERROR (playsink, CORE, PAD,
  1049     GST_ELEMENT_ERROR (playsink, CORE, PAD,
  1547         (NULL), ("Failed to configure the audio sink."));
  1050         (NULL), ("Failed to configure the audio sink."));
  1548     free_chain ((GstPlayChain *) chain);
  1051     free_chain ((GstPlayChain *) chain);
  1549     return NULL;
  1052     return NULL;
  1550   }
  1053   }
  1551 }
       
  1552 
       
  1553 static gboolean
       
  1554 setup_audio_chain (GstPlaySink * playsink, gboolean raw, gboolean queue)
       
  1555 {
       
  1556   GstElement *elem;
       
  1557   GstPlayAudioChain *chain;
       
  1558   GstStateChangeReturn ret;
       
  1559 
       
  1560   chain = playsink->audiochain;
       
  1561 
       
  1562   /* if the chain was active we don't do anything */
       
  1563   if (GST_PLAY_CHAIN (chain)->activated == TRUE)
       
  1564     return TRUE;
       
  1565 
       
  1566   if (chain->chain.raw != raw)
       
  1567     return FALSE;
       
  1568 
       
  1569   /* try to set the sink element to READY again */
       
  1570   ret = gst_element_set_state (chain->sink, GST_STATE_READY);
       
  1571   if (ret == GST_STATE_CHANGE_FAILURE)
       
  1572     return FALSE;
       
  1573 
       
  1574   /* check if the sink, or something within the sink, has the volume property.
       
  1575    * If it does we don't need to add a volume element.  */
       
  1576   elem = gst_play_sink_find_property_sinks (playsink, chain->sink, "volume");
       
  1577   if (elem) {
       
  1578     chain->volume = elem;
       
  1579 
       
  1580     if (playsink->volume_changed) {
       
  1581       GST_DEBUG_OBJECT (playsink, "the sink has a volume property, setting %f",
       
  1582           playsink->volume);
       
  1583       /* use the sink to control the volume */
       
  1584       g_object_set (G_OBJECT (chain->volume), "volume", playsink->volume, NULL);
       
  1585     }
       
  1586     /* if the sink also has a mute property we can use this as well. We'll only
       
  1587      * use the mute property if there is a volume property. We can simulate the
       
  1588      * mute with the volume otherwise. */
       
  1589     chain->mute =
       
  1590         gst_play_sink_find_property_sinks (playsink, chain->sink, "mute");
       
  1591     if (chain->mute) {
       
  1592       GST_DEBUG_OBJECT (playsink, "the sink has a mute property");
       
  1593     }
       
  1594   } else {
       
  1595     /* no volume, we need to add a volume element when we can */
       
  1596     GST_DEBUG_OBJECT (playsink, "the sink has no volume property");
       
  1597     if (!raw) {
       
  1598       GST_LOG_OBJECT (playsink, "non-raw format, can't do soft volume control");
       
  1599       chain->volume = NULL;
       
  1600       chain->mute = NULL;
       
  1601     } else {
       
  1602       /* both last and current chain are raw audio, there should be a volume
       
  1603        * element already, unless the sink changed from one with a volume
       
  1604        * property to one that hasn't got a volume property, in which case we
       
  1605        * re-generate the chain */
       
  1606       if (chain->volume == NULL) {
       
  1607         GST_DEBUG_OBJECT (playsink, "no existing volume element to re-use");
       
  1608         return FALSE;
       
  1609       }
       
  1610 
       
  1611       GST_DEBUG_OBJECT (playsink, "reusing existing volume element");
       
  1612     }
       
  1613   }
       
  1614   return TRUE;
       
  1615 }
  1054 }
  1616 
  1055 
  1617 /*
  1056 /*
  1618  *  +-------------------------------------------------------------------+
  1057  *  +-------------------------------------------------------------------+
  1619  *  | visbin                                                            |
  1058  *  | visbin                                                            |
  1623  *  |   |  +----------+   +------------+   +----------+   +-------+  |  |
  1062  *  |   |  +----------+   +------------+   +----------+   +-------+  |  |
  1624  * sink-+                                                            +-src
  1063  * sink-+                                                            +-src
  1625  *  +-------------------------------------------------------------------+
  1064  *  +-------------------------------------------------------------------+
  1626  *           
  1065  *           
  1627  */
  1066  */
  1628 static GstPlayVisChain *
  1067 static GstPlayChain *
  1629 gen_vis_chain (GstPlaySink * playsink)
  1068 gen_vis_chain (GstPlaySink * playsink)
  1630 {
  1069 {
  1631   GstPlayVisChain *chain;
  1070   GstPlayVisChain *chain;
  1632   GstBin *bin;
  1071   GstBin *bin;
  1633   gboolean res;
  1072   gboolean res;
  1634   GstPad *pad;
  1073   GstPad *pad;
  1635   GstElement *elem;
       
  1636 
  1074 
  1637   chain = g_new0 (GstPlayVisChain, 1);
  1075   chain = g_new0 (GstPlayVisChain, 1);
  1638   chain->chain.playsink = playsink;
  1076   chain->chain.playsink = gst_object_ref (playsink);
  1639 
       
  1640   GST_DEBUG_OBJECT (playsink, "making vis chain %p", chain);
       
  1641 
  1077 
  1642   chain->chain.bin = gst_bin_new ("visbin");
  1078   chain->chain.bin = gst_bin_new ("visbin");
  1643   bin = GST_BIN_CAST (chain->chain.bin);
  1079   bin = GST_BIN_CAST (chain->chain.bin);
  1644   gst_object_ref (bin);
  1080   gst_object_ref (bin);
  1645   gst_object_sink (bin);
  1081   gst_object_sink (bin);
  1659     goto no_audioresample;
  1095     goto no_audioresample;
  1660   gst_bin_add (bin, chain->resample);
  1096   gst_bin_add (bin, chain->resample);
  1661 
  1097 
  1662   /* this pad will be used for blocking the dataflow and switching the vis
  1098   /* this pad will be used for blocking the dataflow and switching the vis
  1663    * plugin */
  1099    * plugin */
  1664   chain->blockpad = gst_element_get_static_pad (chain->resample, "src");
  1100   chain->blockpad = gst_element_get_pad (chain->resample, "src");
  1665 
  1101 
  1666   if (playsink->visualisation) {
  1102   if (playsink->visualisation) {
  1667     GST_DEBUG_OBJECT (playsink, "trying configure vis");
  1103     chain->vis = gst_object_ref (playsink->visualisation);
  1668     chain->vis = try_element (playsink, playsink->visualisation, FALSE);
  1104   } else {
  1669   }
  1105     chain->vis = gst_element_factory_make ("goom", "vis");
  1670   if (chain->vis == NULL) {
  1106     if (!chain->vis)
  1671     GST_DEBUG_OBJECT (playsink, "trying goom");
  1107       goto no_goom;
  1672     elem = gst_element_factory_make ("goom", "vis");
  1108   }
  1673     chain->vis = try_element (playsink, elem, TRUE);
       
  1674   }
       
  1675   if (chain->vis == NULL)
       
  1676     goto no_goom;
       
  1677 
       
  1678   gst_bin_add (bin, chain->vis);
  1109   gst_bin_add (bin, chain->vis);
  1679 
  1110 
  1680   res = gst_element_link_pads (chain->queue, "src", chain->conv, "sink");
  1111   res = gst_element_link_pads (chain->queue, "src", chain->conv, "sink");
  1681   res &= gst_element_link_pads (chain->conv, "src", chain->resample, "sink");
  1112   res &= gst_element_link_pads (chain->conv, "src", chain->resample, "sink");
  1682   res &= gst_element_link_pads (chain->resample, "src", chain->vis, "sink");
  1113   res &= gst_element_link_pads (chain->resample, "src", chain->vis, "sink");
  1683   if (!res)
  1114   if (!res)
  1684     goto link_failed;
  1115     goto link_failed;
  1685 
  1116 
  1686   chain->vissinkpad = gst_element_get_static_pad (chain->vis, "sink");
  1117   chain->vissinkpad = gst_element_get_pad (chain->vis, "sink");
  1687   chain->vissrcpad = gst_element_get_static_pad (chain->vis, "src");
  1118   chain->vissrcpad = gst_element_get_pad (chain->vis, "src");
  1688 
  1119 
  1689   pad = gst_element_get_static_pad (chain->queue, "sink");
  1120   pad = gst_element_get_pad (chain->queue, "sink");
  1690   chain->sinkpad = gst_ghost_pad_new ("sink", pad);
  1121   chain->chain.sinkpad = gst_ghost_pad_new ("sink", pad);
  1691   gst_object_unref (pad);
  1122   gst_object_unref (pad);
  1692   gst_element_add_pad (chain->chain.bin, chain->sinkpad);
  1123   gst_element_add_pad (chain->chain.bin, chain->chain.sinkpad);
  1693 
  1124 
  1694   chain->srcpad = gst_ghost_pad_new ("src", chain->vissrcpad);
  1125   chain->srcpad = gst_ghost_pad_new ("src", chain->vissrcpad);
  1695   gst_element_add_pad (chain->chain.bin, chain->srcpad);
  1126   gst_element_add_pad (chain->chain.bin, chain->srcpad);
  1696 
  1127 
  1697   return chain;
  1128   return (GstPlayChain *) chain;
  1698 
  1129 
  1699   /* ERRORS */
  1130   /* ERRORS */
  1700 no_audioconvert:
  1131 no_audioconvert:
  1701   {
  1132   {
  1702     post_missing_element_message (playsink, "audioconvert");
  1133     post_missing_element_message (playsink, "audioconvert");
  1731     free_chain ((GstPlayChain *) chain);
  1162     free_chain ((GstPlayChain *) chain);
  1732     return NULL;
  1163     return NULL;
  1733   }
  1164   }
  1734 }
  1165 }
  1735 
  1166 
       
  1167 #if 0
       
  1168 static gboolean
       
  1169 activate_vis (GstPlaySink * playsink, gboolean activate)
       
  1170 {
       
  1171   /* need to have an audio chain */
       
  1172   if (!playsink->audiochain || !playsink->vischain)
       
  1173     return FALSE;
       
  1174 
       
  1175   if (playsink->vischain->activated == activate)
       
  1176     return TRUE;
       
  1177 
       
  1178   if (activate) {
       
  1179     /* activation: Add the vis chain to the sink bin . Take a new srcpad from
       
  1180      * the tee of the audio chain and link it to the sinkpad of the vis chain.
       
  1181      */
       
  1182 
       
  1183   } else {
       
  1184     /* deactivation: release the srcpad from the tee of the audio chain. Set the
       
  1185      * vis chain to NULL and remove it from the sink bin */
       
  1186 
       
  1187   }
       
  1188   return TRUE;
       
  1189 }
       
  1190 #endif
       
  1191 
  1736 /* this function is called when all the request pads are requested and when we
  1192 /* this function is called when all the request pads are requested and when we
  1737  * have to construct the final pipeline. Based on the flags we construct the
  1193  * have to construct the final pipeline.
  1738  * final output pipelines.
       
  1739  */
  1194  */
  1740 #ifdef __SYMBIAN32__
  1195 #ifdef __SYMBIAN32__
  1741 EXPORT_C
  1196 EXPORT_C
  1742 #endif
  1197 #endif
  1743 
  1198 
  1744 gboolean
  1199 gboolean
  1745 gst_play_sink_reconfigure (GstPlaySink * playsink)
  1200 gst_play_sink_reconfigure (GstPlaySink * playsink)
  1746 {
  1201 {
  1747   GstPlayFlags flags;
  1202   GstPlayFlags flags;
  1748   gboolean need_audio, need_video, need_vis, need_text, need_subp;
  1203   gboolean need_audio, need_video, need_vis;
  1749 
  1204 
  1750   GST_DEBUG_OBJECT (playsink, "reconfiguring");
  1205   GST_DEBUG_OBJECT (playsink, "reconfiguring");
  1751 
  1206 
  1752   /* assume we need nothing */
  1207   /* assume we need nothing */
  1753   need_audio = need_video = need_vis = need_text = need_subp = FALSE;
  1208   need_audio = need_video = need_vis = FALSE;
  1754 
  1209 
  1755   GST_PLAY_SINK_LOCK (playsink);
  1210   GST_PLAY_SINK_LOCK (playsink);
  1756   GST_OBJECT_LOCK (playsink);
  1211   GST_OBJECT_LOCK (playsink);
  1757   /* get flags, there are protected with the object lock */
  1212   /* get flags, there are protected with the object lock */
  1758   flags = playsink->flags;
  1213   flags = playsink->flags;
  1759   GST_OBJECT_UNLOCK (playsink);
  1214   GST_OBJECT_UNLOCK (playsink);
  1760 
  1215 
  1761   /* figure out which components we need */
  1216   /* figure out which components we need */
  1762   if (flags & GST_PLAY_FLAG_TEXT && (playsink->text_pad || playsink->subp_pad)) {
  1217   if (flags & GST_PLAY_FLAG_VIDEO && playsink->video_pad) {
  1763     /* we have a text_pad and we need text rendering, in this case we need a
       
  1764      * video_pad to combine the video with the text */
       
  1765     if (!playsink->video_pad)
       
  1766       goto subs_but_no_video;
       
  1767 
       
  1768     /* we have subtitles and we are requested to show it, we also need to show
       
  1769      * video in this case. */
       
  1770     need_video = TRUE;
       
  1771     need_text = (playsink->text_pad != NULL);
       
  1772     need_subp = (playsink->subp_pad != NULL);
       
  1773 
       
  1774     /* we can't handle both of them yet */
       
  1775     if (need_text && need_subp)
       
  1776       goto subs_and_text;
       
  1777   } else if (flags & GST_PLAY_FLAG_VIDEO && playsink->video_pad) {
       
  1778     /* we have video and we are requested to show it */
  1218     /* we have video and we are requested to show it */
  1779     need_video = TRUE;
  1219     need_video = TRUE;
  1780   }
  1220   }
  1781   if (playsink->audio_pad) {
  1221   if (playsink->audio_pad) {
  1782     if (flags & GST_PLAY_FLAG_AUDIO) {
  1222     if (flags & GST_PLAY_FLAG_AUDIO) {
  1783       need_audio = TRUE;
  1223       need_audio = TRUE;
  1784     }
  1224     }
  1785     if (playsink->audio_pad_raw) {
  1225     if (flags & GST_PLAY_FLAG_VIS && !need_video) {
  1786       /* only can do vis with raw uncompressed audio */
  1226       /* also add video when we add visualisation */
  1787       if (flags & GST_PLAY_FLAG_VIS && !need_video) {
  1227       need_video = TRUE;
  1788         /* also add video when we add visualisation */
  1228       need_vis = TRUE;
  1789         need_video = TRUE;
  1229     }
  1790         need_vis = TRUE;
  1230   }
  1791       }
  1231 
  1792     }
       
  1793   }
       
  1794 
       
  1795   /* set up video pipeline */
       
  1796   if (need_video) {
  1232   if (need_video) {
  1797     gboolean raw, async, queue;
       
  1798 
       
  1799     /* we need a raw sink when we do vis or when we have a raw pad */
       
  1800     raw = need_vis ? TRUE : playsink->video_pad_raw;
       
  1801     /* we try to set the sink async=FALSE when we need vis, this way we can
       
  1802      * avoid a queue in the audio chain. */
       
  1803     async = !need_vis;
       
  1804     /* put a little queue in front of the video but only if we are not doing
       
  1805      * subpictures because then we will add the queue in front of the subpicture
       
  1806      * mixer to minimize latency. */
       
  1807     queue = (need_subp == FALSE);
       
  1808 
       
  1809     GST_DEBUG_OBJECT (playsink, "adding video, raw %d",
  1233     GST_DEBUG_OBJECT (playsink, "adding video, raw %d",
  1810         playsink->video_pad_raw);
  1234         playsink->video_pad_raw);
  1811 
  1235     if (!playsink->videochain) {
       
  1236       gboolean raw, async;
       
  1237 
       
  1238       /* we need a raw sink when we do vis or when we have a raw pad */
       
  1239       raw = need_vis ? TRUE : playsink->video_pad_raw;
       
  1240       /* we try to set the sink async=FALSE when we need vis, this way we can
       
  1241        * avoid a queue in the audio chain. */
       
  1242       async = !need_vis;
       
  1243 
       
  1244       playsink->videochain = gen_video_chain (playsink, raw, async);
       
  1245     }
       
  1246     add_chain (playsink->videochain, TRUE);
       
  1247     activate_chain (playsink->videochain, TRUE);
       
  1248     if (!need_vis)
       
  1249       gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->video_pad),
       
  1250           playsink->videochain->sinkpad);
       
  1251   } else {
  1812     if (playsink->videochain) {
  1252     if (playsink->videochain) {
  1813       /* try to reactivate the chain */
  1253       add_chain (playsink->videochain, FALSE);
  1814       if (!setup_video_chain (playsink, raw, async, queue)) {
  1254       activate_chain (playsink->videochain, FALSE);
  1815         add_chain (GST_PLAY_CHAIN (playsink->videochain), FALSE);
       
  1816         activate_chain (GST_PLAY_CHAIN (playsink->videochain), FALSE);
       
  1817         free_chain ((GstPlayChain *) playsink->videochain);
       
  1818         playsink->videochain = NULL;
       
  1819       }
       
  1820     }
       
  1821 
       
  1822     if (!playsink->videochain) {
       
  1823       playsink->videochain = gen_video_chain (playsink, raw, async, queue);
       
  1824     }
       
  1825     if (playsink->videochain) {
       
  1826       GST_DEBUG_OBJECT (playsink, "adding video chain");
       
  1827       add_chain (GST_PLAY_CHAIN (playsink->videochain), TRUE);
       
  1828       activate_chain (GST_PLAY_CHAIN (playsink->videochain), TRUE);
       
  1829       /* if we are not part of vis or subtitles, set the ghostpad target */
       
  1830       if (!need_vis && !need_text && playsink->text_pad == NULL) {
       
  1831         GST_DEBUG_OBJECT (playsink, "ghosting video sinkpad");
       
  1832         gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->video_pad),
       
  1833             playsink->videochain->sinkpad);
       
  1834       }
       
  1835     }
       
  1836   } else {
       
  1837     GST_DEBUG_OBJECT (playsink, "no video needed");
       
  1838     if (playsink->videochain) {
       
  1839       GST_DEBUG_OBJECT (playsink, "removing video chain");
       
  1840       if (playsink->vischain) {
       
  1841         GstPad *srcpad;
       
  1842 
       
  1843         GST_DEBUG_OBJECT (playsink, "unlinking vis chain");
       
  1844 
       
  1845         /* also had visualisation, release the tee srcpad before we then 
       
  1846          * unlink the video from it */
       
  1847         if (playsink->audio_tee_vissrc) {
       
  1848           gst_element_release_request_pad (playsink->audio_tee,
       
  1849               playsink->audio_tee_vissrc);
       
  1850           gst_object_unref (playsink->audio_tee_vissrc);
       
  1851           playsink->audio_tee_vissrc = NULL;
       
  1852         }
       
  1853         srcpad =
       
  1854             gst_element_get_static_pad (playsink->vischain->chain.bin, "src");
       
  1855         gst_pad_unlink (srcpad, playsink->videochain->sinkpad);
       
  1856       }
       
  1857       add_chain (GST_PLAY_CHAIN (playsink->videochain), FALSE);
       
  1858       activate_chain (GST_PLAY_CHAIN (playsink->videochain), FALSE);
       
  1859     }
  1255     }
  1860     if (playsink->video_pad)
  1256     if (playsink->video_pad)
  1861       gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->video_pad), NULL);
  1257       gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->video_pad), NULL);
  1862   }
  1258   }
  1863 
  1259 
  1864   if (need_text) {
  1260   if (need_audio) {
  1865     GST_DEBUG_OBJECT (playsink, "adding text");
  1261     GST_DEBUG_OBJECT (playsink, "adding audio");
  1866     if (!playsink->textchain) {
  1262     if (!playsink->audiochain) {
  1867       GST_DEBUG_OBJECT (playsink, "creating text chain");
  1263       gboolean raw, queue;
  1868       playsink->textchain = gen_text_chain (playsink);
  1264 
  1869     }
  1265       /* get a raw sink if we are asked for a raw pad */
  1870     if (playsink->textchain) {
  1266       raw = playsink->audio_pad_raw;
  1871       GST_DEBUG_OBJECT (playsink, "adding text chain");
  1267       if (need_vis) {
  1872       add_chain (GST_PLAY_CHAIN (playsink->textchain), TRUE);
  1268         /* If we are dealing with visualisations, we need to add a queue to
  1873       gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->text_pad),
  1269          * decouple the audio from the video part. We only have to do this when
  1874           playsink->textchain->textsinkpad);
  1270          * the video part is async=true */
  1875       gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->video_pad),
  1271         queue = ((GstPlayVideoChain *) playsink->videochain)->async;
  1876           playsink->textchain->videosinkpad);
  1272         GST_DEBUG_OBJECT (playsink, "need audio queue for vis: %d", queue);
  1877       gst_pad_link (playsink->textchain->srcpad, playsink->videochain->sinkpad);
  1273       } else {
  1878       activate_chain (GST_PLAY_CHAIN (playsink->textchain), TRUE);
  1274         /* no vis, we can avoid a queue */
  1879       if (playsink->textchain->overlay)
  1275         GST_DEBUG_OBJECT (playsink, "don't need audio queue");
  1880         g_object_set (playsink->textchain->overlay, "silent", FALSE, NULL);
  1276         queue = FALSE;
  1881     }
  1277       }
       
  1278 
       
  1279       playsink->audiochain = gen_audio_chain (playsink, raw, queue);
       
  1280     }
       
  1281     add_chain (playsink->audiochain, TRUE);
       
  1282     gst_pad_link (playsink->audio_tee_asrc, playsink->audiochain->sinkpad);
       
  1283     activate_chain (playsink->audiochain, TRUE);
  1882   } else {
  1284   } else {
  1883     GST_DEBUG_OBJECT (playsink, "no text needed");
       
  1884     /* we have no subtitles/text or we are requested to not show them */
       
  1885     if (playsink->textchain) {
       
  1886       if (playsink->text_pad == NULL) {
       
  1887         /* no text pad, remove the chain entirely */
       
  1888         GST_DEBUG_OBJECT (playsink, "removing text chain");
       
  1889         add_chain (GST_PLAY_CHAIN (playsink->textchain), FALSE);
       
  1890         activate_chain (GST_PLAY_CHAIN (playsink->textchain), FALSE);
       
  1891       } else {
       
  1892         /* we have a chain and a textpad, turn the subtitles off */
       
  1893         GST_DEBUG_OBJECT (playsink, "turning off the text");
       
  1894         if (playsink->textchain->overlay)
       
  1895           g_object_set (playsink->textchain->overlay, "silent", TRUE, NULL);
       
  1896       }
       
  1897     }
       
  1898     if (!need_video && playsink->video_pad)
       
  1899       gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->video_pad), NULL);
       
  1900     if (playsink->text_pad)
       
  1901       gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->text_pad), NULL);
       
  1902   }
       
  1903 
       
  1904   if (need_subp && playsink->videochain) {
       
  1905     GST_DEBUG_OBJECT (playsink, "adding subpicture");
       
  1906     if (!playsink->subpchain) {
       
  1907       GST_DEBUG_OBJECT (playsink, "creating subpicture chain");
       
  1908       playsink->subpchain = gen_subp_chain (playsink);
       
  1909     }
       
  1910     if (playsink->subpchain) {
       
  1911       GST_DEBUG_OBJECT (playsink, "adding subp chain");
       
  1912       add_chain (GST_PLAY_CHAIN (playsink->subpchain), TRUE);
       
  1913       gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->subp_pad),
       
  1914           playsink->subpchain->subpsinkpad);
       
  1915       gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->video_pad),
       
  1916           playsink->subpchain->videosinkpad);
       
  1917       gst_pad_link (playsink->subpchain->srcpad, playsink->videochain->sinkpad);
       
  1918       activate_chain (GST_PLAY_CHAIN (playsink->subpchain), TRUE);
       
  1919     }
       
  1920   } else {
       
  1921     GST_DEBUG_OBJECT (playsink, "no subpicture needed");
       
  1922     /* we have no subpicture or we are requested to not show them */
       
  1923     if (playsink->subpchain) {
       
  1924       if (playsink->subp_pad == NULL) {
       
  1925         /* no subpicture pad, remove the chain entirely */
       
  1926         GST_DEBUG_OBJECT (playsink, "removing subp chain");
       
  1927         add_chain (GST_PLAY_CHAIN (playsink->subpchain), FALSE);
       
  1928         activate_chain (GST_PLAY_CHAIN (playsink->subpchain), FALSE);
       
  1929       } else {
       
  1930         /* we have a chain and a subpicture pad, turn the subtitles off */
       
  1931         GST_DEBUG_OBJECT (playsink, "turning off the subp");
       
  1932       }
       
  1933     }
       
  1934     if (!need_video && playsink->video_pad)
       
  1935       gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->video_pad), NULL);
       
  1936     if (playsink->subp_pad)
       
  1937       gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (playsink->subp_pad), NULL);
       
  1938   }
       
  1939 
       
  1940   if (need_audio) {
       
  1941     gboolean raw, queue;
       
  1942 
       
  1943     GST_DEBUG_OBJECT (playsink, "adding audio");
       
  1944 
       
  1945     /* get a raw sink if we are asked for a raw pad */
       
  1946     raw = playsink->audio_pad_raw;
       
  1947     if (need_vis && playsink->videochain) {
       
  1948       /* If we are dealing with visualisations, we need to add a queue to
       
  1949        * decouple the audio from the video part. We only have to do this when
       
  1950        * the video part is async=true */
       
  1951       queue = ((GstPlayVideoChain *) playsink->videochain)->async;
       
  1952       GST_DEBUG_OBJECT (playsink, "need audio queue for vis: %d", queue);
       
  1953     } else {
       
  1954       /* no vis, we can avoid a queue */
       
  1955       GST_DEBUG_OBJECT (playsink, "don't need audio queue");
       
  1956       queue = FALSE;
       
  1957     }
       
  1958 
       
  1959     if (playsink->audiochain) {
       
  1960       /* try to reactivate the chain */
       
  1961       if (!setup_audio_chain (playsink, raw, queue)) {
       
  1962         GST_DEBUG_OBJECT (playsink, "removing current audio chain");
       
  1963         if (playsink->audio_tee_asrc) {
       
  1964           gst_element_release_request_pad (playsink->audio_tee,
       
  1965               playsink->audio_tee_asrc);
       
  1966           gst_object_unref (playsink->audio_tee_asrc);
       
  1967           playsink->audio_tee_asrc = NULL;
       
  1968         }
       
  1969         add_chain (GST_PLAY_CHAIN (playsink->audiochain), FALSE);
       
  1970         activate_chain (GST_PLAY_CHAIN (playsink->audiochain), FALSE);
       
  1971         playsink->audiochain->volume = NULL;
       
  1972         playsink->audiochain->mute = NULL;
       
  1973         free_chain ((GstPlayChain *) playsink->audiochain);
       
  1974         playsink->audiochain = NULL;
       
  1975         playsink->volume_changed = playsink->mute_changed = FALSE;
       
  1976       }
       
  1977     }
       
  1978 
       
  1979     if (!playsink->audiochain) {
       
  1980       GST_DEBUG_OBJECT (playsink, "creating new audio chain");
       
  1981       playsink->audiochain = gen_audio_chain (playsink, raw, queue);
       
  1982     }
       
  1983 
       
  1984     if (playsink->audiochain) {
       
  1985       GST_DEBUG_OBJECT (playsink, "adding audio chain");
       
  1986       if (playsink->audio_tee_asrc == NULL) {
       
  1987         playsink->audio_tee_asrc =
       
  1988             gst_element_get_request_pad (playsink->audio_tee, "src%d");
       
  1989       }
       
  1990       add_chain (GST_PLAY_CHAIN (playsink->audiochain), TRUE);
       
  1991       activate_chain (GST_PLAY_CHAIN (playsink->audiochain), TRUE);
       
  1992       gst_pad_link (playsink->audio_tee_asrc, playsink->audiochain->sinkpad);
       
  1993     }
       
  1994   } else {
       
  1995     GST_DEBUG_OBJECT (playsink, "no audio needed");
       
  1996     /* we have no audio or we are requested to not play audio */
  1285     /* we have no audio or we are requested to not play audio */
  1997     if (playsink->audiochain) {
  1286     if (playsink->audiochain) {
  1998       GST_DEBUG_OBJECT (playsink, "removing audio chain");
  1287       gst_pad_unlink (playsink->audio_tee_asrc, playsink->audiochain->sinkpad);
  1999       /* release the audio pad */
  1288       add_chain (playsink->audiochain, FALSE);
  2000       if (playsink->audio_tee_asrc) {
  1289       activate_chain (playsink->audiochain, FALSE);
  2001         gst_element_release_request_pad (playsink->audio_tee,
       
  2002             playsink->audio_tee_asrc);
       
  2003         gst_object_unref (playsink->audio_tee_asrc);
       
  2004         playsink->audio_tee_asrc = NULL;
       
  2005       }
       
  2006       if (playsink->audiochain->sink_volume) {
       
  2007         playsink->audiochain->volume = NULL;
       
  2008         playsink->audiochain->mute = NULL;
       
  2009       }
       
  2010       add_chain (GST_PLAY_CHAIN (playsink->audiochain), FALSE);
       
  2011       activate_chain (GST_PLAY_CHAIN (playsink->audiochain), FALSE);
       
  2012     }
  1290     }
  2013   }
  1291   }
  2014 
  1292 
  2015   if (need_vis) {
  1293   if (need_vis) {
  2016     GstPad *srcpad;
  1294     GstPad *srcpad;
  2018     if (!playsink->vischain)
  1296     if (!playsink->vischain)
  2019       playsink->vischain = gen_vis_chain (playsink);
  1297       playsink->vischain = gen_vis_chain (playsink);
  2020 
  1298 
  2021     GST_DEBUG_OBJECT (playsink, "adding visualisation");
  1299     GST_DEBUG_OBJECT (playsink, "adding visualisation");
  2022 
  1300 
       
  1301     srcpad =
       
  1302         gst_element_get_pad (GST_ELEMENT_CAST (playsink->vischain->bin), "src");
       
  1303     add_chain (playsink->vischain, TRUE);
       
  1304     gst_pad_link (playsink->audio_tee_vissrc, playsink->vischain->sinkpad);
       
  1305     gst_pad_link (srcpad, playsink->videochain->sinkpad);
       
  1306     gst_object_unref (srcpad);
       
  1307     activate_chain (playsink->vischain, TRUE);
       
  1308   } else {
  2023     if (playsink->vischain) {
  1309     if (playsink->vischain) {
  2024       GST_DEBUG_OBJECT (playsink, "setting up vis chain");
  1310       add_chain (playsink->vischain, FALSE);
  2025       srcpad =
  1311       activate_chain (playsink->vischain, FALSE);
  2026           gst_element_get_static_pad (playsink->vischain->chain.bin, "src");
  1312     }
  2027       add_chain (GST_PLAY_CHAIN (playsink->vischain), TRUE);
  1313   }
  2028       activate_chain (GST_PLAY_CHAIN (playsink->vischain), TRUE);
       
  2029       if (playsink->audio_tee_vissrc == NULL) {
       
  2030         playsink->audio_tee_vissrc =
       
  2031             gst_element_get_request_pad (playsink->audio_tee, "src%d");
       
  2032       }
       
  2033       gst_pad_link (playsink->audio_tee_vissrc, playsink->vischain->sinkpad);
       
  2034       gst_pad_link (srcpad, playsink->videochain->sinkpad);
       
  2035       gst_object_unref (srcpad);
       
  2036     }
       
  2037   } else {
       
  2038     GST_DEBUG_OBJECT (playsink, "no vis needed");
       
  2039     if (playsink->vischain) {
       
  2040       if (playsink->audio_tee_vissrc) {
       
  2041         gst_element_release_request_pad (playsink->audio_tee,
       
  2042             playsink->audio_tee_vissrc);
       
  2043         gst_object_unref (playsink->audio_tee_vissrc);
       
  2044         playsink->audio_tee_vissrc = NULL;
       
  2045       }
       
  2046       GST_DEBUG_OBJECT (playsink, "removing vis chain");
       
  2047       add_chain (GST_PLAY_CHAIN (playsink->vischain), FALSE);
       
  2048       activate_chain (GST_PLAY_CHAIN (playsink->vischain), FALSE);
       
  2049     }
       
  2050   }
       
  2051   do_async_done (playsink);
       
  2052   GST_PLAY_SINK_UNLOCK (playsink);
  1314   GST_PLAY_SINK_UNLOCK (playsink);
  2053 
  1315 
  2054   return TRUE;
  1316   return TRUE;
  2055 
  1317 }
  2056   /* ERRORS */
       
  2057 subs_but_no_video:
       
  2058   {
       
  2059     GST_ELEMENT_ERROR (playsink, STREAM, FORMAT,
       
  2060         (_("Can't play a text file without video.")),
       
  2061         ("Have text pad but no video pad"));
       
  2062     GST_PLAY_SINK_UNLOCK (playsink);
       
  2063     return FALSE;
       
  2064   }
       
  2065 subs_and_text:
       
  2066   {
       
  2067     GST_ELEMENT_ERROR (playsink, STREAM, FORMAT,
       
  2068         (_("Can't play a text subtitles and subpictures.")),
       
  2069         ("Have text pad and subpicture pad"));
       
  2070     GST_PLAY_SINK_UNLOCK (playsink);
       
  2071     return FALSE;
       
  2072   }
       
  2073 }
       
  2074 
       
  2075 /**
       
  2076  * gst_play_sink_set_flags:
       
  2077  * @playsink: a #GstPlaySink
       
  2078  * @flags: #GstPlayFlags
       
  2079  *
       
  2080  * Configure @flags on @playsink. The flags control the behaviour of @playsink
       
  2081  * when constructing the sink pipelins.
       
  2082  *
       
  2083  * Returns: TRUE if the flags could be configured.
       
  2084  */
       
  2085 #ifdef __SYMBIAN32__
  1318 #ifdef __SYMBIAN32__
  2086 EXPORT_C
  1319 EXPORT_C
  2087 #endif
  1320 #endif
       
  1321 
  2088 
  1322 
  2089 gboolean
  1323 gboolean
  2090 gst_play_sink_set_flags (GstPlaySink * playsink, GstPlayFlags flags)
  1324 gst_play_sink_set_flags (GstPlaySink * playsink, GstPlayFlags flags)
  2091 {
  1325 {
  2092   g_return_val_if_fail (GST_IS_PLAY_SINK (playsink), FALSE);
  1326   g_return_val_if_fail (GST_IS_PLAY_SINK (playsink), FALSE);
  2095   playsink->flags = flags;
  1329   playsink->flags = flags;
  2096   GST_OBJECT_UNLOCK (playsink);
  1330   GST_OBJECT_UNLOCK (playsink);
  2097 
  1331 
  2098   return TRUE;
  1332   return TRUE;
  2099 }
  1333 }
  2100 
       
  2101 /**
       
  2102  * gst_play_sink_get_flags:
       
  2103  * @playsink: a #GstPlaySink
       
  2104  *
       
  2105  * Get the flags of @playsink. That flags control the behaviour of the sink when
       
  2106  * it constructs the sink pipelines.
       
  2107  *
       
  2108  * Returns: the currently configured #GstPlayFlags.
       
  2109  */
       
  2110 #ifdef __SYMBIAN32__
  1334 #ifdef __SYMBIAN32__
  2111 EXPORT_C
  1335 EXPORT_C
  2112 #endif
  1336 #endif
       
  1337 
  2113 
  1338 
  2114 GstPlayFlags
  1339 GstPlayFlags
  2115 gst_play_sink_get_flags (GstPlaySink * playsink)
  1340 gst_play_sink_get_flags (GstPlaySink * playsink)
  2116 {
  1341 {
  2117   GstPlayFlags res;
  1342   GstPlayFlags res;
  2126 }
  1351 }
  2127 #ifdef __SYMBIAN32__
  1352 #ifdef __SYMBIAN32__
  2128 EXPORT_C
  1353 EXPORT_C
  2129 #endif
  1354 #endif
  2130 
  1355 
  2131 
       
  2132 void
       
  2133 gst_play_sink_set_font_desc (GstPlaySink * playsink, const gchar * desc)
       
  2134 {
       
  2135   GstPlayTextChain *chain;
       
  2136 
       
  2137   GST_PLAY_SINK_LOCK (playsink);
       
  2138   chain = (GstPlayTextChain *) playsink->textchain;
       
  2139   g_free (playsink->font_desc);
       
  2140   playsink->font_desc = g_strdup (desc);
       
  2141   if (chain && chain->overlay) {
       
  2142     g_object_set (chain->overlay, "font-desc", desc, NULL);
       
  2143   }
       
  2144   GST_PLAY_SINK_UNLOCK (playsink);
       
  2145 }
       
  2146 #ifdef __SYMBIAN32__
       
  2147 EXPORT_C
       
  2148 #endif
       
  2149 
       
  2150 
       
  2151 gchar *
       
  2152 gst_play_sink_get_font_desc (GstPlaySink * playsink)
       
  2153 {
       
  2154   gchar *result = NULL;
       
  2155   GstPlayTextChain *chain;
       
  2156 
       
  2157   GST_PLAY_SINK_LOCK (playsink);
       
  2158   chain = (GstPlayTextChain *) playsink->textchain;
       
  2159   if (chain && chain->overlay) {
       
  2160     g_object_get (chain->overlay, "font-desc", &result, NULL);
       
  2161     playsink->font_desc = g_strdup (result);
       
  2162   } else {
       
  2163     result = g_strdup (playsink->font_desc);
       
  2164   }
       
  2165   GST_PLAY_SINK_UNLOCK (playsink);
       
  2166 
       
  2167   return result;
       
  2168 }
       
  2169 
       
  2170 /**
       
  2171  * gst_play_sink_get_last_frame:
       
  2172  * @playsink: a #GstPlaySink
       
  2173  *
       
  2174  * Get the last displayed frame from @playsink. This frame is in the native
       
  2175  * format of the sink element, the caps on the result buffer contain the format
       
  2176  * of the frame data.
       
  2177  *
       
  2178  * Returns: a #GstBuffer with the frame data or %NULL when no video frame is
       
  2179  * available.
       
  2180  */
       
  2181 #ifdef __SYMBIAN32__
       
  2182 EXPORT_C
       
  2183 #endif
       
  2184 
  1356 
  2185 GstBuffer *
  1357 GstBuffer *
  2186 gst_play_sink_get_last_frame (GstPlaySink * playsink)
  1358 gst_play_sink_get_last_frame (GstPlaySink * playsink)
  2187 {
  1359 {
  2188   GstBuffer *result = NULL;
  1360   GstBuffer *result = NULL;
  2211   }
  1383   }
  2212   GST_PLAY_SINK_UNLOCK (playsink);
  1384   GST_PLAY_SINK_UNLOCK (playsink);
  2213 
  1385 
  2214   return result;
  1386   return result;
  2215 }
  1387 }
  2216 
       
  2217 /**
       
  2218  * gst_play_sink_request_pad
       
  2219  * @playsink: a #GstPlaySink
       
  2220  * @type: a #GstPlaySinkType
       
  2221  *
       
  2222  * Create or return a pad of @type.
       
  2223  *
       
  2224  * Returns: a #GstPad of @type or %NULL when the pad could not be created.
       
  2225  */
       
  2226 #ifdef __SYMBIAN32__
  1388 #ifdef __SYMBIAN32__
  2227 EXPORT_C
  1389 EXPORT_C
  2228 #endif
  1390 #endif
       
  1391 
  2229 
  1392 
  2230 GstPad *
  1393 GstPad *
  2231 gst_play_sink_request_pad (GstPlaySink * playsink, GstPlaySinkType type)
  1394 gst_play_sink_request_pad (GstPlaySink * playsink, GstPlaySinkType type)
  2232 {
  1395 {
  2233   GstPad *res = NULL;
  1396   GstPad *res = NULL;
  2234   gboolean created = FALSE;
  1397   gboolean created = FALSE;
  2235   gboolean raw = FALSE;
  1398   gboolean raw = FALSE;
  2236   gboolean activate = TRUE;
       
  2237 
       
  2238   GST_DEBUG_OBJECT (playsink, "request pad type %d", type);
       
  2239 
  1399 
  2240   GST_PLAY_SINK_LOCK (playsink);
  1400   GST_PLAY_SINK_LOCK (playsink);
  2241   switch (type) {
  1401   switch (type) {
  2242     case GST_PLAY_SINK_TYPE_AUDIO_RAW:
  1402     case GST_PLAY_SINK_TYPE_AUDIO_RAW:
  2243       raw = TRUE;
  1403       raw = TRUE;
  2244     case GST_PLAY_SINK_TYPE_AUDIO:
  1404     case GST_PLAY_SINK_TYPE_AUDIO:
  2245       if (!playsink->audio_tee) {
  1405       if (!playsink->audio_tee) {
  2246         GST_LOG_OBJECT (playsink, "creating tee");
       
  2247         /* create tee when needed. This element will feed the audio sink chain
  1406         /* create tee when needed. This element will feed the audio sink chain
  2248          * and the vis chain. */
  1407          * and the vis chain. */
  2249         playsink->audio_tee = gst_element_factory_make ("tee", "audiotee");
  1408         playsink->audio_tee = gst_element_factory_make ("tee", "audiotee");
  2250         playsink->audio_tee_sink =
  1409         playsink->audio_tee_sink =
  2251             gst_element_get_static_pad (playsink->audio_tee, "sink");
  1410             gst_element_get_pad (playsink->audio_tee, "sink");
       
  1411         /* get two request pads */
       
  1412         playsink->audio_tee_vissrc =
       
  1413             gst_element_get_request_pad (playsink->audio_tee, "src%d");
       
  1414         playsink->audio_tee_asrc =
       
  1415             gst_element_get_request_pad (playsink->audio_tee, "src%d");
  2252         gst_bin_add (GST_BIN_CAST (playsink), playsink->audio_tee);
  1416         gst_bin_add (GST_BIN_CAST (playsink), playsink->audio_tee);
  2253         gst_element_set_state (playsink->audio_tee, GST_STATE_PAUSED);
       
  2254       } else {
       
  2255         gst_element_set_state (playsink->audio_tee, GST_STATE_PAUSED);
  1417         gst_element_set_state (playsink->audio_tee, GST_STATE_PAUSED);
  2256       }
  1418       }
  2257       if (!playsink->audio_pad) {
  1419       if (!playsink->audio_pad) {
  2258         GST_LOG_OBJECT (playsink, "ghosting tee sinkpad");
       
  2259         playsink->audio_pad =
  1420         playsink->audio_pad =
  2260             gst_ghost_pad_new ("audio_sink", playsink->audio_tee_sink);
  1421             gst_ghost_pad_new ("audio_sink", playsink->audio_tee_sink);
  2261         created = TRUE;
  1422         created = TRUE;
  2262       }
  1423       }
  2263       playsink->audio_pad_raw = raw;
  1424       playsink->audio_pad_raw = raw;
  2265       break;
  1426       break;
  2266     case GST_PLAY_SINK_TYPE_VIDEO_RAW:
  1427     case GST_PLAY_SINK_TYPE_VIDEO_RAW:
  2267       raw = TRUE;
  1428       raw = TRUE;
  2268     case GST_PLAY_SINK_TYPE_VIDEO:
  1429     case GST_PLAY_SINK_TYPE_VIDEO:
  2269       if (!playsink->video_pad) {
  1430       if (!playsink->video_pad) {
  2270         GST_LOG_OBJECT (playsink, "ghosting videosink");
       
  2271         playsink->video_pad =
  1431         playsink->video_pad =
  2272             gst_ghost_pad_new_no_target ("video_sink", GST_PAD_SINK);
  1432             gst_ghost_pad_new_no_target ("video_sink", GST_PAD_SINK);
  2273         created = TRUE;
  1433         created = TRUE;
  2274       }
  1434       }
  2275       playsink->video_pad_raw = raw;
  1435       playsink->video_pad_raw = raw;
  2276       res = playsink->video_pad;
  1436       res = playsink->video_pad;
  2277       break;
  1437       break;
  2278     case GST_PLAY_SINK_TYPE_TEXT:
  1438     case GST_PLAY_SINK_TYPE_TEXT:
  2279       GST_LOG_OBJECT (playsink, "ghosting text");
       
  2280       if (!playsink->text_pad) {
  1439       if (!playsink->text_pad) {
  2281         playsink->text_pad =
  1440         playsink->text_pad =
  2282             gst_ghost_pad_new_no_target ("text_sink", GST_PAD_SINK);
  1441             gst_ghost_pad_new_no_target ("text_sink", GST_PAD_SINK);
  2283         created = TRUE;
  1442         created = TRUE;
  2284       }
  1443       }
  2285       res = playsink->text_pad;
  1444       res = playsink->text_pad;
  2286       break;
  1445       break;
  2287     case GST_PLAY_SINK_TYPE_FLUSHING:
       
  2288     {
       
  2289       gchar *padname;
       
  2290 
       
  2291       /* we need a unique padname for the flushing pad. */
       
  2292       padname = g_strdup_printf ("flushing_%d", playsink->count);
       
  2293       res = gst_ghost_pad_new_no_target (padname, GST_PAD_SINK);
       
  2294       g_free (padname);
       
  2295       playsink->count++;
       
  2296       activate = FALSE;
       
  2297       created = TRUE;
       
  2298       break;
       
  2299     }
       
  2300     case GST_PLAY_SINK_TYPE_SUBPIC:
       
  2301       GST_LOG_OBJECT (playsink, "ghosting subpicture pad");
       
  2302       if (!playsink->subp_pad) {
       
  2303         playsink->subp_pad =
       
  2304             gst_ghost_pad_new_no_target ("subp_sink", GST_PAD_SINK);
       
  2305         created = TRUE;
       
  2306       }
       
  2307       res = playsink->subp_pad;
       
  2308       break;
       
  2309     default:
  1446     default:
  2310       res = NULL;
  1447       res = NULL;
  2311       break;
  1448       break;
  2312   }
  1449   }
  2313   GST_PLAY_SINK_UNLOCK (playsink);
  1450   GST_PLAY_SINK_UNLOCK (playsink);
  2314 
  1451 
  2315   if (created && res) {
  1452   if (created && res) {
  2316     /* we have to add the pad when it's active or we get an error when the
       
  2317      * element is 'running' */
       
  2318     gst_pad_set_active (res, TRUE);
  1453     gst_pad_set_active (res, TRUE);
  2319     gst_element_add_pad (GST_ELEMENT_CAST (playsink), res);
  1454     gst_element_add_pad (GST_ELEMENT_CAST (playsink), res);
  2320     if (!activate)
       
  2321       gst_pad_set_active (res, activate);
       
  2322   }
  1455   }
  2323 
  1456 
  2324   return res;
  1457   return res;
  2325 }
  1458 }
  2326 #ifdef __SYMBIAN32__
  1459 #ifdef __SYMBIAN32__
  2330 
  1463 
  2331 void
  1464 void
  2332 gst_play_sink_release_pad (GstPlaySink * playsink, GstPad * pad)
  1465 gst_play_sink_release_pad (GstPlaySink * playsink, GstPad * pad)
  2333 {
  1466 {
  2334   GstPad **res = NULL;
  1467   GstPad **res = NULL;
  2335   gboolean untarget = TRUE;
       
  2336 
       
  2337   GST_DEBUG_OBJECT (playsink, "release pad %" GST_PTR_FORMAT, pad);
       
  2338 
  1468 
  2339   GST_PLAY_SINK_LOCK (playsink);
  1469   GST_PLAY_SINK_LOCK (playsink);
  2340   if (pad == playsink->video_pad) {
  1470   if (pad == playsink->video_pad) {
  2341     res = &playsink->video_pad;
  1471     res = &playsink->video_pad;
  2342   } else if (pad == playsink->audio_pad) {
  1472   } else if (pad == playsink->audio_pad) {
  2343     res = &playsink->audio_pad;
  1473     res = &playsink->audio_pad;
  2344   } else if (pad == playsink->text_pad) {
  1474   } else if (pad == playsink->text_pad) {
  2345     res = &playsink->text_pad;
  1475     res = &playsink->text_pad;
  2346   } else if (pad == playsink->subp_pad) {
       
  2347     res = &playsink->subp_pad;
       
  2348   } else {
       
  2349     /* try to release the given pad anyway, these could be the FLUSHING pads. */
       
  2350     res = &pad;
       
  2351     untarget = FALSE;
       
  2352   }
  1476   }
  2353   GST_PLAY_SINK_UNLOCK (playsink);
  1477   GST_PLAY_SINK_UNLOCK (playsink);
  2354 
  1478 
  2355   if (*res) {
  1479   if (*res) {
  2356     GST_DEBUG_OBJECT (playsink, "deactivate pad %" GST_PTR_FORMAT, *res);
       
  2357     gst_pad_set_active (*res, FALSE);
  1480     gst_pad_set_active (*res, FALSE);
  2358     if (untarget) {
       
  2359       GST_DEBUG_OBJECT (playsink, "untargeting pad %" GST_PTR_FORMAT, *res);
       
  2360       gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (*res), NULL);
       
  2361     }
       
  2362     GST_DEBUG_OBJECT (playsink, "remove pad %" GST_PTR_FORMAT, *res);
       
  2363     gst_element_remove_pad (GST_ELEMENT_CAST (playsink), *res);
  1481     gst_element_remove_pad (GST_ELEMENT_CAST (playsink), *res);
  2364     *res = NULL;
  1482     *res = NULL;
  2365   }
       
  2366 }
       
  2367 
       
  2368 static void
       
  2369 gst_play_sink_handle_message (GstBin * bin, GstMessage * message)
       
  2370 {
       
  2371   GstPlaySink *playsink;
       
  2372 
       
  2373   playsink = GST_PLAY_SINK_CAST (bin);
       
  2374 
       
  2375   switch (GST_MESSAGE_TYPE (message)) {
       
  2376     case GST_MESSAGE_STEP_DONE:
       
  2377     {
       
  2378       GstFormat format;
       
  2379       guint64 amount;
       
  2380       gdouble rate;
       
  2381       gboolean flush, intermediate, res, eos;
       
  2382       guint64 duration;
       
  2383 
       
  2384       GST_INFO_OBJECT (playsink, "Handling step-done message");
       
  2385       gst_message_parse_step_done (message, &format, &amount, &rate, &flush,
       
  2386           &intermediate, &duration, &eos);
       
  2387 
       
  2388       if (format == GST_FORMAT_BUFFERS) {
       
  2389         /* for the buffer format, we align the other streams */
       
  2390         if (playsink->audiochain) {
       
  2391           GstEvent *event;
       
  2392 
       
  2393           event =
       
  2394               gst_event_new_step (GST_FORMAT_TIME, duration, rate, flush,
       
  2395               intermediate);
       
  2396 
       
  2397           if (!(res =
       
  2398                   gst_element_send_event (playsink->audiochain->chain.bin,
       
  2399                       event))) {
       
  2400             GST_DEBUG_OBJECT (playsink, "Event failed when sent to audio sink");
       
  2401           }
       
  2402         }
       
  2403       }
       
  2404       GST_BIN_CLASS (gst_play_sink_parent_class)->handle_message (bin, message);
       
  2405       break;
       
  2406     }
       
  2407     default:
       
  2408       GST_BIN_CLASS (gst_play_sink_parent_class)->handle_message (bin, message);
       
  2409       break;
       
  2410   }
  1483   }
  2411 }
  1484 }
  2412 
  1485 
  2413 /* Send an event to our sinks until one of them works; don't then send to the
  1486 /* Send an event to our sinks until one of them works; don't then send to the
  2414  * remaining sinks (unlike GstBin)
  1487  * remaining sinks (unlike GstBin)
  2416 static gboolean
  1489 static gboolean
  2417 gst_play_sink_send_event_to_sink (GstPlaySink * playsink, GstEvent * event)
  1490 gst_play_sink_send_event_to_sink (GstPlaySink * playsink, GstEvent * event)
  2418 {
  1491 {
  2419   gboolean res = TRUE;
  1492   gboolean res = TRUE;
  2420 
  1493 
       
  1494   if (playsink->audiochain) {
       
  1495     gst_event_ref (event);
       
  1496     if ((res = gst_element_send_event (playsink->audiochain->bin, event))) {
       
  1497       GST_DEBUG_OBJECT (playsink, "Sent event succesfully to audio sink");
       
  1498       goto done;
       
  1499     }
       
  1500     GST_DEBUG_OBJECT (playsink, "Event failed when sent to audio sink");
       
  1501   }
  2421   if (playsink->videochain) {
  1502   if (playsink->videochain) {
  2422     gst_event_ref (event);
  1503     gst_event_ref (event);
  2423     if ((res = gst_element_send_event (playsink->videochain->chain.bin, event))) {
  1504     if ((res = gst_element_send_event (playsink->videochain->bin, event))) {
  2424       GST_DEBUG_OBJECT (playsink, "Sent event succesfully to video sink");
  1505       GST_DEBUG_OBJECT (playsink, "Sent event succesfully to video sink");
  2425       goto done;
  1506       goto done;
  2426     }
  1507     }
  2427     GST_DEBUG_OBJECT (playsink, "Event failed when sent to video sink");
  1508     GST_DEBUG_OBJECT (playsink, "Event failed when sent to video sink");
  2428   }
       
  2429   if (playsink->audiochain) {
       
  2430     gst_event_ref (event);
       
  2431     if ((res = gst_element_send_event (playsink->audiochain->chain.bin, event))) {
       
  2432       GST_DEBUG_OBJECT (playsink, "Sent event succesfully to audio sink");
       
  2433       goto done;
       
  2434     }
       
  2435     GST_DEBUG_OBJECT (playsink, "Event failed when sent to audio sink");
       
  2436   }
  1509   }
  2437 done:
  1510 done:
  2438   gst_event_unref (event);
  1511   gst_event_unref (event);
  2439   return res;
  1512   return res;
  2440 }
  1513 }
  2445 static gboolean
  1518 static gboolean
  2446 gst_play_sink_send_event (GstElement * element, GstEvent * event)
  1519 gst_play_sink_send_event (GstElement * element, GstEvent * event)
  2447 {
  1520 {
  2448   gboolean res = FALSE;
  1521   gboolean res = FALSE;
  2449   GstEventType event_type = GST_EVENT_TYPE (event);
  1522   GstEventType event_type = GST_EVENT_TYPE (event);
  2450   GstPlaySink *playsink;
       
  2451 
       
  2452   playsink = GST_PLAY_SINK_CAST (element);
       
  2453 
  1523 
  2454   switch (event_type) {
  1524   switch (event_type) {
  2455     case GST_EVENT_SEEK:
  1525     case GST_EVENT_SEEK:
  2456       GST_DEBUG_OBJECT (element, "Sending event to a sink");
  1526       GST_DEBUG_OBJECT (element, "Sending seek event to a sink");
  2457       res = gst_play_sink_send_event_to_sink (playsink, event);
  1527       res = gst_play_sink_send_event_to_sink (GST_PLAY_SINK (element), event);
  2458       break;
  1528       break;
  2459     case GST_EVENT_STEP:
       
  2460     {
       
  2461       GstFormat format;
       
  2462       guint64 amount;
       
  2463       gdouble rate;
       
  2464       gboolean flush, intermediate;
       
  2465 
       
  2466       gst_event_parse_step (event, &format, &amount, &rate, &flush,
       
  2467           &intermediate);
       
  2468 
       
  2469       if (format == GST_FORMAT_BUFFERS) {
       
  2470         /* for buffers, we will try to step video frames, for other formats we
       
  2471          * send the step to all sinks */
       
  2472         res = gst_play_sink_send_event_to_sink (playsink, event);
       
  2473       } else {
       
  2474         res =
       
  2475             GST_ELEMENT_CLASS (gst_play_sink_parent_class)->send_event (element,
       
  2476             event);
       
  2477       }
       
  2478       break;
       
  2479     }
       
  2480     default:
  1529     default:
  2481       res =
  1530       res = parent_class->send_event (element, event);
  2482           GST_ELEMENT_CLASS (gst_play_sink_parent_class)->send_event (element,
       
  2483           event);
       
  2484       break;
  1531       break;
  2485   }
  1532   }
  2486   return res;
  1533   return res;
  2487 }
  1534 }
  2488 
  1535 
  2489 static GstStateChangeReturn
  1536 static GstStateChangeReturn
  2490 gst_play_sink_change_state (GstElement * element, GstStateChange transition)
  1537 gst_play_sink_change_state (GstElement * element, GstStateChange transition)
  2491 {
  1538 {
  2492   GstStateChangeReturn ret;
  1539   GstStateChangeReturn ret;
  2493   GstStateChangeReturn bret;
       
  2494 
       
  2495   GstPlaySink *playsink;
  1540   GstPlaySink *playsink;
  2496 
  1541 
  2497   playsink = GST_PLAY_SINK (element);
  1542   playsink = GST_PLAY_SINK (element);
  2498 
  1543 
  2499   switch (transition) {
  1544   switch (transition) {
  2500     case GST_STATE_CHANGE_READY_TO_PAUSED:
  1545     case GST_STATE_CHANGE_READY_TO_PAUSED:
  2501       /* we want to go async to PAUSED until we managed to configure and add the
       
  2502        * sinks */
       
  2503       do_async_start (playsink);
       
  2504       ret = GST_STATE_CHANGE_ASYNC;
       
  2505       break;
       
  2506     case GST_STATE_CHANGE_PAUSED_TO_READY:
       
  2507     case GST_STATE_CHANGE_READY_TO_NULL:
       
  2508       if (playsink->audiochain && playsink->audiochain->sink_volume) {
       
  2509         /* remove our links to the mute and volume elements when they were
       
  2510          * provided by a sink */
       
  2511         playsink->audiochain->volume = NULL;
       
  2512         playsink->audiochain->mute = NULL;
       
  2513       }
       
  2514       ret = GST_STATE_CHANGE_SUCCESS;
       
  2515       break;
  1546       break;
  2516     default:
  1547     default:
  2517       /* all other state changes return SUCCESS by default, this value can be
  1548       break;
  2518        * overridden by the result of the children */
  1549   }
  2519       ret = GST_STATE_CHANGE_SUCCESS;
  1550 
  2520       break;
  1551   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
  2521   }
  1552   if (ret == GST_STATE_CHANGE_FAILURE)
  2522 
  1553     return ret;
  2523   /* do the state change of the children */
       
  2524   bret =
       
  2525       GST_ELEMENT_CLASS (gst_play_sink_parent_class)->change_state (element,
       
  2526       transition);
       
  2527   /* now look at the result of our children and adjust the return value */
       
  2528   switch (bret) {
       
  2529     case GST_STATE_CHANGE_FAILURE:
       
  2530       /* failure, we stop */
       
  2531       goto activate_failed;
       
  2532     case GST_STATE_CHANGE_NO_PREROLL:
       
  2533       /* some child returned NO_PREROLL. This is strange but we never know. We
       
  2534        * commit our async state change (if any) and return the NO_PREROLL */
       
  2535       do_async_done (playsink);
       
  2536       ret = bret;
       
  2537       break;
       
  2538     case GST_STATE_CHANGE_ASYNC:
       
  2539       /* some child was async, return this */
       
  2540       ret = bret;
       
  2541       break;
       
  2542     default:
       
  2543       /* return our previously configured return value */
       
  2544       break;
       
  2545   }
       
  2546 
  1554 
  2547   switch (transition) {
  1555   switch (transition) {
  2548     case GST_STATE_CHANGE_READY_TO_PAUSED:
  1556     case GST_STATE_CHANGE_READY_TO_PAUSED:
  2549       break;
  1557       break;
  2550     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
  1558     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
  2551       /* FIXME Release audio device when we implement that */
  1559       /* FIXME Release audio device when we implement that */
  2552       playsink->need_async_start = TRUE;
       
  2553       break;
  1560       break;
  2554     case GST_STATE_CHANGE_PAUSED_TO_READY:
  1561     case GST_STATE_CHANGE_PAUSED_TO_READY:
  2555     case GST_STATE_CHANGE_READY_TO_NULL:
       
  2556       /* remove sinks we added */
  1562       /* remove sinks we added */
  2557       if (playsink->videochain) {
  1563       if (playsink->videochain) {
  2558         activate_chain (GST_PLAY_CHAIN (playsink->videochain), FALSE);
  1564         activate_chain (playsink->videochain, FALSE);
  2559         add_chain (GST_PLAY_CHAIN (playsink->videochain), FALSE);
  1565         add_chain (playsink->videochain, FALSE);
  2560       }
  1566       }
  2561       if (playsink->audiochain) {
  1567       if (playsink->audiochain) {
  2562         activate_chain (GST_PLAY_CHAIN (playsink->audiochain), FALSE);
  1568         activate_chain (playsink->audiochain, FALSE);
  2563         add_chain (GST_PLAY_CHAIN (playsink->audiochain), FALSE);
  1569         add_chain (playsink->audiochain, FALSE);
  2564       }
  1570       }
  2565       if (playsink->vischain) {
       
  2566         activate_chain (GST_PLAY_CHAIN (playsink->vischain), FALSE);
       
  2567         add_chain (GST_PLAY_CHAIN (playsink->vischain), FALSE);
       
  2568       }
       
  2569       if (playsink->textchain) {
       
  2570         activate_chain (GST_PLAY_CHAIN (playsink->textchain), FALSE);
       
  2571         add_chain (GST_PLAY_CHAIN (playsink->textchain), FALSE);
       
  2572       }
       
  2573       if (playsink->subpchain) {
       
  2574         activate_chain (GST_PLAY_CHAIN (playsink->subpchain), FALSE);
       
  2575         add_chain (GST_PLAY_CHAIN (playsink->subpchain), FALSE);
       
  2576       }
       
  2577       do_async_done (playsink);
       
  2578       break;
  1571       break;
  2579     default:
  1572     default:
  2580       break;
  1573       break;
  2581   }
  1574   }
       
  1575 
  2582   return ret;
  1576   return ret;
  2583 
  1577 }
  2584   /* ERRORS */
       
  2585 activate_failed:
       
  2586   {
       
  2587     GST_DEBUG_OBJECT (element,
       
  2588         "element failed to change states -- activation problem?");
       
  2589     return GST_STATE_CHANGE_FAILURE;
       
  2590   }
       
  2591 }