gstreamer_core/libs/gst/base/gstbasesink.c
branchRCL_3
changeset 30 7e817e7e631c
parent 29 567bb019e3e3
equal deleted inserted replaced
29:567bb019e3e3 30:7e817e7e631c
   161 #endif
   161 #endif
   162 
   162 
   163 #define GST_BASE_SINK_GET_PRIVATE(obj)  \
   163 #define GST_BASE_SINK_GET_PRIVATE(obj)  \
   164    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_SINK, GstBaseSinkPrivate))
   164    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_SINK, GstBaseSinkPrivate))
   165 
   165 
   166 #define GST_FLOW_STEP GST_FLOW_CUSTOM_ERROR
       
   167 
       
   168 typedef struct
       
   169 {
       
   170   gboolean valid;               /* if this info is valid */
       
   171   guint32 seqnum;               /* the seqnum of the STEP event */
       
   172   GstFormat format;             /* the format of the amount */
       
   173   guint64 amount;               /* the total amount of data to skip */
       
   174   guint64 position;             /* the position in the stepped data */
       
   175   guint64 duration;             /* the duration in time of the skipped data */
       
   176   guint64 start;                /* running_time of the start */
       
   177   gdouble rate;                 /* rate of skipping */
       
   178   gdouble start_rate;           /* rate before skipping */
       
   179   guint64 start_start;          /* start position skipping */
       
   180   guint64 start_stop;           /* stop position skipping */
       
   181   gboolean flush;               /* if this was a flushing step */
       
   182   gboolean intermediate;        /* if this is an intermediate step */
       
   183   gboolean need_preroll;        /* if we need preroll after this step */
       
   184 } GstStepInfo;
       
   185 
       
   186 /* FIXME, some stuff in ABI.data and other in Private...
   166 /* FIXME, some stuff in ABI.data and other in Private...
   187  * Make up your mind please.
   167  * Make up your mind please.
   188  */
   168  */
   189 struct _GstBaseSinkPrivate
   169 struct _GstBaseSinkPrivate
   190 {
   170 {
   191   gint qos_enabled;             /* ATOMIC */
   171   gint qos_enabled;             /* ATOMIC */
   192   gboolean async_enabled;
   172   gboolean async_enabled;
   193   GstClockTimeDiff ts_offset;
   173   GstClockTimeDiff ts_offset;
   194   GstClockTime render_delay;
       
   195 
   174 
   196   /* start, stop of current buffer, stream time, used to report position */
   175   /* start, stop of current buffer, stream time, used to report position */
   197   GstClockTime current_sstart;
   176   GstClockTime current_sstart;
   198   GstClockTime current_sstop;
   177   GstClockTime current_sstop;
   199 
   178 
   240   /* when we are prerolled and able to report latency */
   219   /* when we are prerolled and able to report latency */
   241   gboolean have_latency;
   220   gboolean have_latency;
   242 
   221 
   243   /* the last buffer we prerolled or rendered. Useful for making snapshots */
   222   /* the last buffer we prerolled or rendered. Useful for making snapshots */
   244   GstBuffer *last_buffer;
   223   GstBuffer *last_buffer;
   245 
       
   246   /* caps for pull based scheduling */
       
   247   GstCaps *pull_caps;
       
   248 
       
   249   /* blocksize for pulling */
       
   250   guint blocksize;
       
   251 
       
   252   gboolean discont;
       
   253 
       
   254   /* seqnum of the stream */
       
   255   guint32 seqnum;
       
   256 
       
   257   gboolean call_preroll;
       
   258   gboolean step_unlock;
       
   259 
       
   260   /* we have a pending and a current step operation */
       
   261   GstStepInfo current_step;
       
   262   GstStepInfo pending_step;
       
   263 };
   224 };
   264 
   225 
   265 #define DO_RUNNING_AVG(avg,val,size) (((val) + ((size)-1) * (avg)) / (size))
   226 #define DO_RUNNING_AVG(avg,val,size) (((val) + ((size)-1) * (avg)) / (size))
   266 
   227 
   267 /* generic running average, this has a neutral window size */
   228 /* generic running average, this has a neutral window size */
   273 #define UPDATE_RUNNING_AVG_P(avg,val) DO_RUNNING_AVG(avg,val,16)
   234 #define UPDATE_RUNNING_AVG_P(avg,val) DO_RUNNING_AVG(avg,val,16)
   274 #define UPDATE_RUNNING_AVG_N(avg,val) DO_RUNNING_AVG(avg,val,4)
   235 #define UPDATE_RUNNING_AVG_N(avg,val) DO_RUNNING_AVG(avg,val,4)
   275 
   236 
   276 /* BaseSink properties */
   237 /* BaseSink properties */
   277 
   238 
       
   239 #define DEFAULT_SIZE 1024
   278 #define DEFAULT_CAN_ACTIVATE_PULL FALSE /* fixme: enable me */
   240 #define DEFAULT_CAN_ACTIVATE_PULL FALSE /* fixme: enable me */
   279 #define DEFAULT_CAN_ACTIVATE_PUSH TRUE
   241 #define DEFAULT_CAN_ACTIVATE_PUSH TRUE
   280 
   242 
   281 #define DEFAULT_PREROLL_QUEUE_LEN	0
   243 #define DEFAULT_PREROLL_QUEUE_LEN	0
   282 #define DEFAULT_SYNC			TRUE
   244 #define DEFAULT_SYNC			TRUE
   283 #define DEFAULT_MAX_LATENESS		-1
   245 #define DEFAULT_MAX_LATENESS		-1
   284 #define DEFAULT_QOS			FALSE
   246 #define DEFAULT_QOS			FALSE
   285 #define DEFAULT_ASYNC			TRUE
   247 #define DEFAULT_ASYNC			TRUE
   286 #define DEFAULT_TS_OFFSET		0
   248 #define DEFAULT_TS_OFFSET		0
   287 #define DEFAULT_BLOCKSIZE 		4096
       
   288 #define DEFAULT_RENDER_DELAY 		0
       
   289 
   249 
   290 enum
   250 enum
   291 {
   251 {
   292   PROP_0,
   252   PROP_0,
   293   PROP_PREROLL_QUEUE_LEN,
   253   PROP_PREROLL_QUEUE_LEN,
   295   PROP_MAX_LATENESS,
   255   PROP_MAX_LATENESS,
   296   PROP_QOS,
   256   PROP_QOS,
   297   PROP_ASYNC,
   257   PROP_ASYNC,
   298   PROP_TS_OFFSET,
   258   PROP_TS_OFFSET,
   299   PROP_LAST_BUFFER,
   259   PROP_LAST_BUFFER,
   300   PROP_BLOCKSIZE,
       
   301   PROP_RENDER_DELAY,
       
   302   PROP_LAST
   260   PROP_LAST
   303 };
   261 };
   304 
   262 
   305 static GstElementClass *parent_class = NULL;
   263 static GstElementClass *parent_class = NULL;
   306 
   264 
   313 
   271 
   314 
   272 
   315 GType
   273 GType
   316 gst_base_sink_get_type (void)
   274 gst_base_sink_get_type (void)
   317 {
   275 {
   318   static volatile gsize base_sink_type = 0;
   276   static GType base_sink_type = 0;
   319 
   277 
   320   if (g_once_init_enter (&base_sink_type)) {
   278   if (G_UNLIKELY (base_sink_type == 0)) {
   321     GType _type;
       
   322     static const GTypeInfo base_sink_info = {
   279     static const GTypeInfo base_sink_info = {
   323       sizeof (GstBaseSinkClass),
   280       sizeof (GstBaseSinkClass),
   324       NULL,
   281       NULL,
   325       NULL,
   282       NULL,
   326       (GClassInitFunc) gst_base_sink_class_init,
   283       (GClassInitFunc) gst_base_sink_class_init,
   329       sizeof (GstBaseSink),
   286       sizeof (GstBaseSink),
   330       0,
   287       0,
   331       (GInstanceInitFunc) gst_base_sink_init,
   288       (GInstanceInitFunc) gst_base_sink_init,
   332     };
   289     };
   333 
   290 
   334     _type = g_type_register_static (GST_TYPE_ELEMENT,
   291     base_sink_type = g_type_register_static (GST_TYPE_ELEMENT,
   335         "GstBaseSink", &base_sink_info, G_TYPE_FLAG_ABSTRACT);
   292         "GstBaseSink", &base_sink_info, G_TYPE_FLAG_ABSTRACT);
   336     g_once_init_leave (&base_sink_type, _type);
       
   337   }
   293   }
   338   return base_sink_type;
   294   return base_sink_type;
   339 }
   295 }
   340 
   296 
   341 static void gst_base_sink_set_property (GObject * object, guint prop_id,
   297 static void gst_base_sink_set_property (GObject * object, guint prop_id,
   355     GstClockTime * start, GstClockTime * end);
   311     GstClockTime * start, GstClockTime * end);
   356 static gboolean gst_base_sink_set_flushing (GstBaseSink * basesink,
   312 static gboolean gst_base_sink_set_flushing (GstBaseSink * basesink,
   357     GstPad * pad, gboolean flushing);
   313     GstPad * pad, gboolean flushing);
   358 static gboolean gst_base_sink_default_activate_pull (GstBaseSink * basesink,
   314 static gboolean gst_base_sink_default_activate_pull (GstBaseSink * basesink,
   359     gboolean active);
   315     gboolean active);
   360 static gboolean gst_base_sink_default_do_seek (GstBaseSink * sink,
       
   361     GstSegment * segment);
       
   362 static gboolean gst_base_sink_default_prepare_seek_segment (GstBaseSink * sink,
       
   363     GstEvent * event, GstSegment * segment);
       
   364 
   316 
   365 static GstStateChangeReturn gst_base_sink_change_state (GstElement * element,
   317 static GstStateChangeReturn gst_base_sink_change_state (GstElement * element,
   366     GstStateChange transition);
   318     GstStateChange transition);
   367 
   319 
   368 static GstFlowReturn gst_base_sink_chain (GstPad * pad, GstBuffer * buffer);
   320 static GstFlowReturn gst_base_sink_chain (GstPad * pad, GstBuffer * buffer);
   369 static GstFlowReturn gst_base_sink_chain_list (GstPad * pad,
       
   370     GstBufferList * list);
       
   371 
       
   372 static void gst_base_sink_loop (GstPad * pad);
   321 static void gst_base_sink_loop (GstPad * pad);
   373 static gboolean gst_base_sink_pad_activate (GstPad * pad);
   322 static gboolean gst_base_sink_pad_activate (GstPad * pad);
   374 static gboolean gst_base_sink_pad_activate_push (GstPad * pad, gboolean active);
   323 static gboolean gst_base_sink_pad_activate_push (GstPad * pad, gboolean active);
   375 static gboolean gst_base_sink_pad_activate_pull (GstPad * pad, gboolean active);
   324 static gboolean gst_base_sink_pad_activate_pull (GstPad * pad, gboolean active);
   376 static gboolean gst_base_sink_event (GstPad * pad, GstEvent * event);
   325 static gboolean gst_base_sink_event (GstPad * pad, GstEvent * event);
   377 static gboolean gst_base_sink_peer_query (GstBaseSink * sink, GstQuery * query);
   326 static gboolean gst_base_sink_peer_query (GstBaseSink * sink, GstQuery * query);
   378 
   327 
   379 static gboolean gst_base_sink_negotiate_pull (GstBaseSink * basesink);
       
   380 
       
   381 /* check if an object was too late */
   328 /* check if an object was too late */
   382 static gboolean gst_base_sink_is_too_late (GstBaseSink * basesink,
   329 static gboolean gst_base_sink_is_too_late (GstBaseSink * basesink,
   383     GstMiniObject * obj, GstClockTime start, GstClockTime stop,
   330     GstMiniObject * obj, GstClockTime start, GstClockTime stop,
   384     GstClockReturn status, GstClockTimeDiff jitter);
   331     GstClockReturn status, GstClockTimeDiff jitter);
   385 static GstFlowReturn gst_base_sink_preroll_object (GstBaseSink * basesink,
       
   386     gboolean is_list, GstMiniObject * obj);
       
   387 
   332 
   388 static void
   333 static void
   389 gst_base_sink_class_init (GstBaseSinkClass * klass)
   334 gst_base_sink_class_init (GstBaseSinkClass * klass)
   390 {
   335 {
   391   GObjectClass *gobject_class;
   336   GObjectClass *gobject_class;
   408   /* FIXME, this next value should be configured using an event from the
   353   /* FIXME, this next value should be configured using an event from the
   409    * upstream element, ie, the BUFFER_SIZE event. */
   354    * upstream element, ie, the BUFFER_SIZE event. */
   410   g_object_class_install_property (gobject_class, PROP_PREROLL_QUEUE_LEN,
   355   g_object_class_install_property (gobject_class, PROP_PREROLL_QUEUE_LEN,
   411       g_param_spec_uint ("preroll-queue-len", "Preroll queue length",
   356       g_param_spec_uint ("preroll-queue-len", "Preroll queue length",
   412           "Number of buffers to queue during preroll", 0, G_MAXUINT,
   357           "Number of buffers to queue during preroll", 0, G_MAXUINT,
   413           DEFAULT_PREROLL_QUEUE_LEN,
   358           DEFAULT_PREROLL_QUEUE_LEN, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
   414           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
       
   415 
   359 
   416   g_object_class_install_property (gobject_class, PROP_SYNC,
   360   g_object_class_install_property (gobject_class, PROP_SYNC,
   417       g_param_spec_boolean ("sync", "Sync", "Sync on the clock", DEFAULT_SYNC,
   361       g_param_spec_boolean ("sync", "Sync", "Sync on the clock", DEFAULT_SYNC,
   418           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
   362           G_PARAM_READWRITE));
   419 
   363 
   420   g_object_class_install_property (gobject_class, PROP_MAX_LATENESS,
   364   g_object_class_install_property (gobject_class, PROP_MAX_LATENESS,
   421       g_param_spec_int64 ("max-lateness", "Max Lateness",
   365       g_param_spec_int64 ("max-lateness", "Max Lateness",
   422           "Maximum number of nanoseconds that a buffer can be late before it "
   366           "Maximum number of nanoseconds that a buffer can be late before it "
   423           "is dropped (-1 unlimited)", -1, G_MAXINT64, DEFAULT_MAX_LATENESS,
   367           "is dropped (-1 unlimited)", -1, G_MAXINT64, DEFAULT_MAX_LATENESS,
   424           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
   368           G_PARAM_READWRITE));
   425 
   369 
   426   g_object_class_install_property (gobject_class, PROP_QOS,
   370   g_object_class_install_property (gobject_class, PROP_QOS,
   427       g_param_spec_boolean ("qos", "Qos",
   371       g_param_spec_boolean ("qos", "Qos",
   428           "Generate Quality-of-Service events upstream", DEFAULT_QOS,
   372           "Generate Quality-of-Service events upstream", DEFAULT_QOS,
   429           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
   373           G_PARAM_READWRITE));
   430   /**
   374   /**
   431    * GstBaseSink:async
   375    * GstBaseSink:async
   432    *
   376    *
   433    * If set to #TRUE, the basesink will perform asynchronous state changes.
   377    * If set to #TRUE, the basesink will perform asynchronous state changes.
   434    * When set to #FALSE, the sink will not signal the parent when it prerolls.
   378    * When set to #FALSE, the sink will not signal the parent when it prerolls.
   437    *
   381    *
   438    * Since: 0.10.15
   382    * Since: 0.10.15
   439    */
   383    */
   440   g_object_class_install_property (gobject_class, PROP_ASYNC,
   384   g_object_class_install_property (gobject_class, PROP_ASYNC,
   441       g_param_spec_boolean ("async", "Async",
   385       g_param_spec_boolean ("async", "Async",
   442           "Go asynchronously to PAUSED", DEFAULT_ASYNC,
   386           "Go asynchronously to PAUSED", DEFAULT_ASYNC, G_PARAM_READWRITE));
   443           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
       
   444   /**
   387   /**
   445    * GstBaseSink:ts-offset
   388    * GstBaseSink:ts-offset
   446    *
   389    *
   447    * Controls the final synchronisation, a negative value will render the buffer
   390    * Controls the final synchronisation, a negative value will render the buffer
   448    * earlier while a positive value delays playback. This property can be 
   391    * earlier while a positive value delays playback. This property can be 
   451    * Since: 0.10.15
   394    * Since: 0.10.15
   452    */
   395    */
   453   g_object_class_install_property (gobject_class, PROP_TS_OFFSET,
   396   g_object_class_install_property (gobject_class, PROP_TS_OFFSET,
   454       g_param_spec_int64 ("ts-offset", "TS Offset",
   397       g_param_spec_int64 ("ts-offset", "TS Offset",
   455           "Timestamp offset in nanoseconds", G_MININT64, G_MAXINT64,
   398           "Timestamp offset in nanoseconds", G_MININT64, G_MAXINT64,
   456           DEFAULT_TS_OFFSET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
   399           DEFAULT_TS_OFFSET, G_PARAM_READWRITE));
       
   400 
   457   /**
   401   /**
   458    * GstBaseSink:last-buffer
   402    * GstBaseSink:last-buffer
   459    *
   403    *
   460    * The last buffer that arrived in the sink and was used for preroll or for
   404    * The last buffer that arrived in the sink and was used for preroll or for
   461    * rendering. This property can be used to generate thumbnails. This property
   405    * rendering. This property can be used to generate thumbnails. This property
   464    * Since: 0.10.15
   408    * Since: 0.10.15
   465    */
   409    */
   466   g_object_class_install_property (gobject_class, PROP_LAST_BUFFER,
   410   g_object_class_install_property (gobject_class, PROP_LAST_BUFFER,
   467       gst_param_spec_mini_object ("last-buffer", "Last Buffer",
   411       gst_param_spec_mini_object ("last-buffer", "Last Buffer",
   468           "The last buffer received in the sink", GST_TYPE_BUFFER,
   412           "The last buffer received in the sink", GST_TYPE_BUFFER,
   469           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
   413           G_PARAM_READABLE));
   470   /**
       
   471    * GstBaseSink:blocksize
       
   472    *
       
   473    * The amount of bytes to pull when operating in pull mode.
       
   474    *
       
   475    * Since: 0.10.22
       
   476    */
       
   477   g_object_class_install_property (gobject_class, PROP_BLOCKSIZE,
       
   478       g_param_spec_uint ("blocksize", "Block size",
       
   479           "Size in bytes to pull per buffer (0 = default)", 0, G_MAXUINT,
       
   480           DEFAULT_BLOCKSIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
       
   481   /**
       
   482    * GstBaseSink:render-delay
       
   483    *
       
   484    * The additional delay between synchronisation and actual rendering of the
       
   485    * media. This property will add additional latency to the device in order to
       
   486    * make other sinks compensate for the delay.
       
   487    *
       
   488    * Since: 0.10.22
       
   489    */
       
   490   g_object_class_install_property (gobject_class, PROP_RENDER_DELAY,
       
   491       g_param_spec_uint64 ("render-delay", "Render Delay",
       
   492           "Additional render delay of the sink in nanoseconds", 0, G_MAXUINT64,
       
   493           DEFAULT_RENDER_DELAY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
       
   494 
   414 
   495   gstelement_class->change_state =
   415   gstelement_class->change_state =
   496       GST_DEBUG_FUNCPTR (gst_base_sink_change_state);
   416       GST_DEBUG_FUNCPTR (gst_base_sink_change_state);
   497   gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_base_sink_send_event);
   417   gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_base_sink_send_event);
   498   gstelement_class->query = GST_DEBUG_FUNCPTR (gst_base_sink_query);
   418   gstelement_class->query = GST_DEBUG_FUNCPTR (gst_base_sink_query);
   512   GstBaseSink *bsink;
   432   GstBaseSink *bsink;
   513   GstCaps *caps = NULL;
   433   GstCaps *caps = NULL;
   514 
   434 
   515   bsink = GST_BASE_SINK (gst_pad_get_parent (pad));
   435   bsink = GST_BASE_SINK (gst_pad_get_parent (pad));
   516   bclass = GST_BASE_SINK_GET_CLASS (bsink);
   436   bclass = GST_BASE_SINK_GET_CLASS (bsink);
   517 
   437   if (bclass->get_caps)
   518   if (bsink->pad_mode == GST_ACTIVATE_PULL) {
   438     caps = bclass->get_caps (bsink);
   519     /* if we are operating in pull mode we only accept the negotiated caps */
   439 
   520     GST_OBJECT_LOCK (pad);
       
   521     if ((caps = GST_PAD_CAPS (pad)))
       
   522       gst_caps_ref (caps);
       
   523     GST_OBJECT_UNLOCK (pad);
       
   524   }
       
   525   if (caps == NULL) {
   440   if (caps == NULL) {
   526     if (bclass->get_caps)
   441     GstPadTemplate *pad_template;
   527       caps = bclass->get_caps (bsink);
   442 
   528 
   443     pad_template =
   529     if (caps == NULL) {
   444         gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink");
   530       GstPadTemplate *pad_template;
   445     if (pad_template != NULL) {
   531 
   446       caps = gst_caps_ref (gst_pad_template_get_caps (pad_template));
   532       pad_template =
       
   533           gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass),
       
   534           "sink");
       
   535       if (pad_template != NULL) {
       
   536         caps = gst_caps_ref (gst_pad_template_get_caps (pad_template));
       
   537       }
       
   538     }
   447     }
   539   }
   448   }
   540   gst_object_unref (bsink);
   449   gst_object_unref (bsink);
   541 
   450 
   542   return caps;
   451   return caps;
   549   GstBaseSink *bsink;
   458   GstBaseSink *bsink;
   550   gboolean res = TRUE;
   459   gboolean res = TRUE;
   551 
   460 
   552   bsink = GST_BASE_SINK (gst_pad_get_parent (pad));
   461   bsink = GST_BASE_SINK (gst_pad_get_parent (pad));
   553   bclass = GST_BASE_SINK_GET_CLASS (bsink);
   462   bclass = GST_BASE_SINK_GET_CLASS (bsink);
       
   463 
       
   464   if (bsink->pad_mode == GST_ACTIVATE_PULL) {
       
   465     GstPad *peer = gst_pad_get_peer (pad);
       
   466 
       
   467     if (peer)
       
   468       res = gst_pad_set_caps (peer, caps);
       
   469     else
       
   470       res = FALSE;
       
   471 
       
   472     if (!res)
       
   473       GST_DEBUG_OBJECT (bsink, "peer setcaps() failed");
       
   474   }
   554 
   475 
   555   if (res && bclass->set_caps)
   476   if (res && bclass->set_caps)
   556     res = bclass->set_caps (bsink, caps);
   477     res = bclass->set_caps (bsink, caps);
   557 
   478 
   558   gst_object_unref (bsink);
   479   gst_object_unref (bsink);
   626       GST_DEBUG_FUNCPTR (gst_base_sink_pad_activate_pull));
   547       GST_DEBUG_FUNCPTR (gst_base_sink_pad_activate_pull));
   627   gst_pad_set_event_function (basesink->sinkpad,
   548   gst_pad_set_event_function (basesink->sinkpad,
   628       GST_DEBUG_FUNCPTR (gst_base_sink_event));
   549       GST_DEBUG_FUNCPTR (gst_base_sink_event));
   629   gst_pad_set_chain_function (basesink->sinkpad,
   550   gst_pad_set_chain_function (basesink->sinkpad,
   630       GST_DEBUG_FUNCPTR (gst_base_sink_chain));
   551       GST_DEBUG_FUNCPTR (gst_base_sink_chain));
   631   gst_pad_set_chain_list_function (basesink->sinkpad,
       
   632       GST_DEBUG_FUNCPTR (gst_base_sink_chain_list));
       
   633   gst_element_add_pad (GST_ELEMENT_CAST (basesink), basesink->sinkpad);
   552   gst_element_add_pad (GST_ELEMENT_CAST (basesink), basesink->sinkpad);
   634 
   553 
   635   basesink->pad_mode = GST_ACTIVATE_NONE;
   554   basesink->pad_mode = GST_ACTIVATE_NONE;
   636   basesink->preroll_queue = g_queue_new ();
   555   basesink->preroll_queue = g_queue_new ();
   637   basesink->abidata.ABI.clip_segment = gst_segment_new ();
   556   basesink->abidata.ABI.clip_segment = gst_segment_new ();
   640   basesink->can_activate_push = DEFAULT_CAN_ACTIVATE_PUSH;
   559   basesink->can_activate_push = DEFAULT_CAN_ACTIVATE_PUSH;
   641   basesink->can_activate_pull = DEFAULT_CAN_ACTIVATE_PULL;
   560   basesink->can_activate_pull = DEFAULT_CAN_ACTIVATE_PULL;
   642 
   561 
   643   basesink->sync = DEFAULT_SYNC;
   562   basesink->sync = DEFAULT_SYNC;
   644   basesink->abidata.ABI.max_lateness = DEFAULT_MAX_LATENESS;
   563   basesink->abidata.ABI.max_lateness = DEFAULT_MAX_LATENESS;
   645   g_atomic_int_set (&priv->qos_enabled, DEFAULT_QOS);
   564   gst_atomic_int_set (&priv->qos_enabled, DEFAULT_QOS);
   646   priv->async_enabled = DEFAULT_ASYNC;
   565   priv->async_enabled = DEFAULT_ASYNC;
   647   priv->ts_offset = DEFAULT_TS_OFFSET;
   566   priv->ts_offset = DEFAULT_TS_OFFSET;
   648   priv->render_delay = DEFAULT_RENDER_DELAY;
       
   649   priv->blocksize = DEFAULT_BLOCKSIZE;
       
   650 
   567 
   651   GST_OBJECT_FLAG_SET (basesink, GST_ELEMENT_IS_SINK);
   568   GST_OBJECT_FLAG_SET (basesink, GST_ELEMENT_IS_SINK);
   652 }
   569 }
   653 
   570 
   654 static void
   571 static void
   793 void
   710 void
   794 gst_base_sink_set_qos_enabled (GstBaseSink * sink, gboolean enabled)
   711 gst_base_sink_set_qos_enabled (GstBaseSink * sink, gboolean enabled)
   795 {
   712 {
   796   g_return_if_fail (GST_IS_BASE_SINK (sink));
   713   g_return_if_fail (GST_IS_BASE_SINK (sink));
   797 
   714 
   798   g_atomic_int_set (&sink->priv->qos_enabled, enabled);
   715   gst_atomic_int_set (&sink->priv->qos_enabled, enabled);
   799 }
   716 }
   800 
   717 
   801 /**
   718 /**
   802  * gst_base_sink_is_qos_enabled:
   719  * gst_base_sink_is_qos_enabled:
   803  * @sink: the sink
   720  * @sink: the sink
   846 {
   763 {
   847   g_return_if_fail (GST_IS_BASE_SINK (sink));
   764   g_return_if_fail (GST_IS_BASE_SINK (sink));
   848 
   765 
   849   GST_PAD_PREROLL_LOCK (sink->sinkpad);
   766   GST_PAD_PREROLL_LOCK (sink->sinkpad);
   850   sink->priv->async_enabled = enabled;
   767   sink->priv->async_enabled = enabled;
   851   GST_LOG_OBJECT (sink, "set async enabled to %d", enabled);
       
   852   GST_PAD_PREROLL_UNLOCK (sink->sinkpad);
   768   GST_PAD_PREROLL_UNLOCK (sink->sinkpad);
   853 }
   769 }
   854 
   770 
   855 /**
   771 /**
   856  * gst_base_sink_is_async_enabled:
   772  * gst_base_sink_is_async_enabled:
   903 {
   819 {
   904   g_return_if_fail (GST_IS_BASE_SINK (sink));
   820   g_return_if_fail (GST_IS_BASE_SINK (sink));
   905 
   821 
   906   GST_OBJECT_LOCK (sink);
   822   GST_OBJECT_LOCK (sink);
   907   sink->priv->ts_offset = offset;
   823   sink->priv->ts_offset = offset;
   908   GST_LOG_OBJECT (sink, "set time offset to %" G_GINT64_FORMAT, offset);
       
   909   GST_OBJECT_UNLOCK (sink);
   824   GST_OBJECT_UNLOCK (sink);
   910 }
   825 }
   911 
   826 
   912 /**
   827 /**
   913  * gst_base_sink_get_ts_offset:
   828  * gst_base_sink_get_ts_offset:
   974 static void
   889 static void
   975 gst_base_sink_set_last_buffer (GstBaseSink * sink, GstBuffer * buffer)
   890 gst_base_sink_set_last_buffer (GstBaseSink * sink, GstBuffer * buffer)
   976 {
   891 {
   977   GstBuffer *old;
   892   GstBuffer *old;
   978 
   893 
       
   894   if (buffer)
       
   895     gst_buffer_ref (buffer);
       
   896 
   979   GST_OBJECT_LOCK (sink);
   897   GST_OBJECT_LOCK (sink);
   980   old = sink->priv->last_buffer;
   898   old = sink->priv->last_buffer;
   981   if (G_LIKELY (old != buffer)) {
   899   sink->priv->last_buffer = buffer;
   982     GST_DEBUG_OBJECT (sink, "setting last buffer to %p", buffer);
       
   983     if (G_LIKELY (buffer))
       
   984       gst_buffer_ref (buffer);
       
   985     sink->priv->last_buffer = buffer;
       
   986   } else {
       
   987     old = NULL;
       
   988   }
       
   989   GST_OBJECT_UNLOCK (sink);
   900   GST_OBJECT_UNLOCK (sink);
   990 
   901 
   991   /* avoid unreffing with the lock because cleanup code might want to take the
   902   if (old)
   992    * lock too */
       
   993   if (G_LIKELY (old))
       
   994     gst_buffer_unref (old);
   903     gst_buffer_unref (old);
   995 }
   904 }
   996 
   905 
   997 /**
   906 /**
   998  * gst_base_sink_get_latency:
   907  * gst_base_sink_get_latency:
  1051 gst_base_sink_query_latency (GstBaseSink * sink, gboolean * live,
   960 gst_base_sink_query_latency (GstBaseSink * sink, gboolean * live,
  1052     gboolean * upstream_live, GstClockTime * min_latency,
   961     gboolean * upstream_live, GstClockTime * min_latency,
  1053     GstClockTime * max_latency)
   962     GstClockTime * max_latency)
  1054 {
   963 {
  1055   gboolean l, us_live, res, have_latency;
   964   gboolean l, us_live, res, have_latency;
  1056   GstClockTime min, max, render_delay;
   965   GstClockTime min, max;
  1057   GstQuery *query;
   966   GstQuery *query;
  1058   GstClockTime us_min, us_max;
   967   GstClockTime us_min, us_max;
  1059 
   968 
  1060   /* we are live when we sync to the clock */
   969   /* we are live when we sync to the clock */
  1061   GST_OBJECT_LOCK (sink);
   970   GST_OBJECT_LOCK (sink);
  1062   l = sink->sync;
   971   l = sink->sync;
  1063   have_latency = sink->priv->have_latency;
   972   have_latency = sink->priv->have_latency;
  1064   render_delay = sink->priv->render_delay;
       
  1065   GST_OBJECT_UNLOCK (sink);
   973   GST_OBJECT_UNLOCK (sink);
  1066 
   974 
  1067   /* assume no latency */
   975   /* assume no latency */
  1068   min = 0;
   976   min = 0;
  1069   max = -1;
   977   max = -1;
  1070   us_live = FALSE;
   978   us_live = FALSE;
  1071 
   979 
  1072   if (have_latency) {
   980   /* we are live */
  1073     GST_DEBUG_OBJECT (sink, "we are ready for LATENCY query");
   981   if (l) {
  1074     /* we are ready for a latency query this is when we preroll or when we are
   982     if (have_latency) {
  1075      * not async. */
   983       /* we are live and ready for a latency query */
  1076     query = gst_query_new_latency ();
   984       query = gst_query_new_latency ();
  1077 
   985 
  1078     /* ask the peer for the latency */
   986       /* ask the peer for the latency */
  1079     if ((res = gst_base_sink_peer_query (sink, query))) {
   987       if (!(res = gst_base_sink_peer_query (sink, query)))
       
   988         goto query_failed;
       
   989 
  1080       /* get upstream min and max latency */
   990       /* get upstream min and max latency */
  1081       gst_query_parse_latency (query, &us_live, &us_min, &us_max);
   991       gst_query_parse_latency (query, &us_live, &us_min, &us_max);
       
   992       gst_query_unref (query);
  1082 
   993 
  1083       if (us_live) {
   994       if (us_live) {
  1084         /* upstream live, use its latency, subclasses should use these
   995         /* upstream live, use its latency, subclasses should use these
  1085          * values to create the complete latency. */
   996          * values to create the complete latency. */
  1086         min = us_min;
   997         min = us_min;
  1087         max = us_max;
   998         max = us_max;
  1088       }
   999       }
  1089       if (l) {
  1000     } else {
  1090         /* we need to add the render delay if we are live */
  1001       /* we are live but are not yet ready for a latency query */
  1091         if (min != -1)
  1002       res = FALSE;
  1092           min += render_delay;
       
  1093         if (max != -1)
       
  1094           max += render_delay;
       
  1095       }
       
  1096     }
  1003     }
       
  1004   } else {
       
  1005     /* not live, result is always TRUE */
       
  1006     res = TRUE;
       
  1007   }
       
  1008 
       
  1009   GST_DEBUG_OBJECT (sink, "latency query: live: %d, have_latency %d,"
       
  1010       " upstream: %d, min %" GST_TIME_FORMAT ", max %" GST_TIME_FORMAT, l,
       
  1011       have_latency, us_live, GST_TIME_ARGS (min), GST_TIME_ARGS (max));
       
  1012 
       
  1013   if (live)
       
  1014     *live = l;
       
  1015   if (upstream_live)
       
  1016     *upstream_live = us_live;
       
  1017   if (min_latency)
       
  1018     *min_latency = min;
       
  1019   if (max_latency)
       
  1020     *max_latency = max;
       
  1021 
       
  1022   return res;
       
  1023 
       
  1024   /* ERRORS */
       
  1025 query_failed:
       
  1026   {
       
  1027     GST_DEBUG_OBJECT (sink, "latency query failed");
  1097     gst_query_unref (query);
  1028     gst_query_unref (query);
  1098   } else {
  1029     return FALSE;
  1099     GST_DEBUG_OBJECT (sink, "we are not yet ready for LATENCY query");
  1030   }
  1100     res = FALSE;
       
  1101   }
       
  1102 
       
  1103   /* not live, we tried to do the query, if it failed we return TRUE anyway */
       
  1104   if (!res) {
       
  1105     if (!l) {
       
  1106       res = TRUE;
       
  1107       GST_DEBUG_OBJECT (sink, "latency query failed but we are not live");
       
  1108     } else {
       
  1109       GST_DEBUG_OBJECT (sink, "latency query failed and we are live");
       
  1110     }
       
  1111   }
       
  1112 
       
  1113   if (res) {
       
  1114     GST_DEBUG_OBJECT (sink, "latency query: live: %d, have_latency %d,"
       
  1115         " upstream: %d, min %" GST_TIME_FORMAT ", max %" GST_TIME_FORMAT, l,
       
  1116         have_latency, us_live, GST_TIME_ARGS (min), GST_TIME_ARGS (max));
       
  1117 
       
  1118     if (live)
       
  1119       *live = l;
       
  1120     if (upstream_live)
       
  1121       *upstream_live = us_live;
       
  1122     if (min_latency)
       
  1123       *min_latency = min;
       
  1124     if (max_latency)
       
  1125       *max_latency = max;
       
  1126   }
       
  1127   return res;
       
  1128 }
       
  1129 
       
  1130 /**
       
  1131  * gst_base_sink_set_render_delay:
       
  1132  * @sink: a #GstBaseSink
       
  1133  * @delay: the new delay
       
  1134  *
       
  1135  * Set the render delay in @sink to @delay. The render delay is the time 
       
  1136  * between actual rendering of a buffer and its synchronisation time. Some
       
  1137  * devices might delay media rendering which can be compensated for with this
       
  1138  * function. 
       
  1139  *
       
  1140  * After calling this function, this sink will report additional latency and
       
  1141  * other sinks will adjust their latency to delay the rendering of their media.
       
  1142  *
       
  1143  * This function is usually called by subclasses.
       
  1144  *
       
  1145  * Since: 0.10.21
       
  1146  */
       
  1147 #ifdef __SYMBIAN32__
       
  1148 EXPORT_C
       
  1149 #endif
       
  1150 
       
  1151 void
       
  1152 gst_base_sink_set_render_delay (GstBaseSink * sink, GstClockTime delay)
       
  1153 {
       
  1154   GstClockTime old_render_delay;
       
  1155 
       
  1156   g_return_if_fail (GST_IS_BASE_SINK (sink));
       
  1157 
       
  1158   GST_OBJECT_LOCK (sink);
       
  1159   old_render_delay = sink->priv->render_delay;
       
  1160   sink->priv->render_delay = delay;
       
  1161   GST_LOG_OBJECT (sink, "set render delay to %" GST_TIME_FORMAT,
       
  1162       GST_TIME_ARGS (delay));
       
  1163   GST_OBJECT_UNLOCK (sink);
       
  1164 
       
  1165   if (delay != old_render_delay) {
       
  1166     GST_DEBUG_OBJECT (sink, "posting latency changed");
       
  1167     gst_element_post_message (GST_ELEMENT_CAST (sink),
       
  1168         gst_message_new_latency (GST_OBJECT_CAST (sink)));
       
  1169   }
       
  1170 }
       
  1171 
       
  1172 /**
       
  1173  * gst_base_sink_get_render_delay:
       
  1174  * @sink: a #GstBaseSink
       
  1175  *
       
  1176  * Get the render delay of @sink. see gst_base_sink_set_render_delay() for more
       
  1177  * information about the render delay.
       
  1178  *
       
  1179  * Returns: the render delay of @sink.
       
  1180  *
       
  1181  * Since: 0.10.21
       
  1182  */
       
  1183 #ifdef __SYMBIAN32__
       
  1184 EXPORT_C
       
  1185 #endif
       
  1186 
       
  1187 GstClockTime
       
  1188 gst_base_sink_get_render_delay (GstBaseSink * sink)
       
  1189 {
       
  1190   GstClockTimeDiff res;
       
  1191 
       
  1192   g_return_val_if_fail (GST_IS_BASE_SINK (sink), 0);
       
  1193 
       
  1194   GST_OBJECT_LOCK (sink);
       
  1195   res = sink->priv->render_delay;
       
  1196   GST_OBJECT_UNLOCK (sink);
       
  1197 
       
  1198   return res;
       
  1199 }
       
  1200 
       
  1201 /**
       
  1202  * gst_base_sink_set_blocksize:
       
  1203  * @sink: a #GstBaseSink
       
  1204  * @blocksize: the blocksize in bytes
       
  1205  *
       
  1206  * Set the number of bytes that the sink will pull when it is operating in pull
       
  1207  * mode.
       
  1208  *
       
  1209  * Since: 0.10.22
       
  1210  */
       
  1211 #ifdef __SYMBIAN32__
       
  1212 EXPORT_C
       
  1213 #endif
       
  1214 
       
  1215 void
       
  1216 gst_base_sink_set_blocksize (GstBaseSink * sink, guint blocksize)
       
  1217 {
       
  1218   g_return_if_fail (GST_IS_BASE_SINK (sink));
       
  1219 
       
  1220   GST_OBJECT_LOCK (sink);
       
  1221   sink->priv->blocksize = blocksize;
       
  1222   GST_LOG_OBJECT (sink, "set blocksize to %u", blocksize);
       
  1223   GST_OBJECT_UNLOCK (sink);
       
  1224 }
       
  1225 
       
  1226 /**
       
  1227  * gst_base_sink_get_blocksize:
       
  1228  * @sink: a #GstBaseSink
       
  1229  *
       
  1230  * Get the number of bytes that the sink will pull when it is operating in pull
       
  1231  * mode.
       
  1232  *
       
  1233  * Returns: the number of bytes @sink will pull in pull mode.
       
  1234  *
       
  1235  * Since: 0.10.22
       
  1236  */
       
  1237 #ifdef __SYMBIAN32__
       
  1238 EXPORT_C
       
  1239 #endif
       
  1240 
       
  1241 guint
       
  1242 gst_base_sink_get_blocksize (GstBaseSink * sink)
       
  1243 {
       
  1244   guint res;
       
  1245 
       
  1246   g_return_val_if_fail (GST_IS_BASE_SINK (sink), 0);
       
  1247 
       
  1248   GST_OBJECT_LOCK (sink);
       
  1249   res = sink->priv->blocksize;
       
  1250   GST_OBJECT_UNLOCK (sink);
       
  1251 
       
  1252   return res;
       
  1253 }
  1031 }
  1254 
  1032 
  1255 static void
  1033 static void
  1256 gst_base_sink_set_property (GObject * object, guint prop_id,
  1034 gst_base_sink_set_property (GObject * object, guint prop_id,
  1257     const GValue * value, GParamSpec * pspec)
  1035     const GValue * value, GParamSpec * pspec)
  1278       gst_base_sink_set_async_enabled (sink, g_value_get_boolean (value));
  1056       gst_base_sink_set_async_enabled (sink, g_value_get_boolean (value));
  1279       break;
  1057       break;
  1280     case PROP_TS_OFFSET:
  1058     case PROP_TS_OFFSET:
  1281       gst_base_sink_set_ts_offset (sink, g_value_get_int64 (value));
  1059       gst_base_sink_set_ts_offset (sink, g_value_get_int64 (value));
  1282       break;
  1060       break;
  1283     case PROP_BLOCKSIZE:
       
  1284       gst_base_sink_set_blocksize (sink, g_value_get_uint (value));
       
  1285       break;
       
  1286     case PROP_RENDER_DELAY:
       
  1287       gst_base_sink_set_render_delay (sink, g_value_get_uint64 (value));
       
  1288       break;
       
  1289     default:
  1061     default:
  1290       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  1062       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  1291       break;
  1063       break;
  1292   }
  1064   }
  1293 }
  1065 }
  1320       g_value_set_int64 (value, gst_base_sink_get_ts_offset (sink));
  1092       g_value_set_int64 (value, gst_base_sink_get_ts_offset (sink));
  1321       break;
  1093       break;
  1322     case PROP_LAST_BUFFER:
  1094     case PROP_LAST_BUFFER:
  1323       gst_value_take_buffer (value, gst_base_sink_get_last_buffer (sink));
  1095       gst_value_take_buffer (value, gst_base_sink_get_last_buffer (sink));
  1324       break;
  1096       break;
  1325     case PROP_BLOCKSIZE:
       
  1326       g_value_set_uint (value, gst_base_sink_get_blocksize (sink));
       
  1327       break;
       
  1328     case PROP_RENDER_DELAY:
       
  1329       g_value_set_uint64 (value, gst_base_sink_get_render_delay (sink));
       
  1330       break;
       
  1331     default:
  1097     default:
  1332       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  1098       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  1333       break;
  1099       break;
  1334   }
  1100   }
  1335 }
  1101 }
  1368   }
  1134   }
  1369   /* we can't have EOS anymore now */
  1135   /* we can't have EOS anymore now */
  1370   basesink->eos = FALSE;
  1136   basesink->eos = FALSE;
  1371   basesink->priv->received_eos = FALSE;
  1137   basesink->priv->received_eos = FALSE;
  1372   basesink->have_preroll = FALSE;
  1138   basesink->have_preroll = FALSE;
  1373   basesink->priv->step_unlock = FALSE;
       
  1374   basesink->eos_queued = FALSE;
  1139   basesink->eos_queued = FALSE;
  1375   basesink->preroll_queued = 0;
  1140   basesink->preroll_queued = 0;
  1376   basesink->buffers_queued = 0;
  1141   basesink->buffers_queued = 0;
  1377   basesink->events_queued = 0;
  1142   basesink->events_queued = 0;
  1378   /* can't report latency anymore until we preroll again */
  1143   /* can't report latency anymore until we preroll again */
  1437   /* commit state and proceed to next pending state */
  1202   /* commit state and proceed to next pending state */
  1438   GstState current, next, pending, post_pending;
  1203   GstState current, next, pending, post_pending;
  1439   gboolean post_paused = FALSE;
  1204   gboolean post_paused = FALSE;
  1440   gboolean post_async_done = FALSE;
  1205   gboolean post_async_done = FALSE;
  1441   gboolean post_playing = FALSE;
  1206   gboolean post_playing = FALSE;
       
  1207   gboolean sync;
  1442 
  1208 
  1443   /* we are certainly not playing async anymore now */
  1209   /* we are certainly not playing async anymore now */
  1444   basesink->playing_async = FALSE;
  1210   basesink->playing_async = FALSE;
  1445 
  1211 
  1446   GST_OBJECT_LOCK (basesink);
  1212   GST_OBJECT_LOCK (basesink);
  1447   current = GST_STATE (basesink);
  1213   current = GST_STATE (basesink);
  1448   next = GST_STATE_NEXT (basesink);
  1214   next = GST_STATE_NEXT (basesink);
  1449   pending = GST_STATE_PENDING (basesink);
  1215   pending = GST_STATE_PENDING (basesink);
  1450   post_pending = pending;
  1216   post_pending = pending;
       
  1217   sync = basesink->sync;
  1451 
  1218 
  1452   switch (pending) {
  1219   switch (pending) {
  1453     case GST_STATE_PLAYING:
  1220     case GST_STATE_PLAYING:
  1454     {
  1221     {
  1455       GstBaseSinkClass *bclass;
  1222       GstBaseSinkClass *bclass;
  1468         post_paused = TRUE;
  1235         post_paused = TRUE;
  1469       }
  1236       }
  1470 
  1237 
  1471       /* make sure we notify the subclass of async playing */
  1238       /* make sure we notify the subclass of async playing */
  1472       if (bclass->async_play) {
  1239       if (bclass->async_play) {
  1473         GST_WARNING_OBJECT (basesink, "deprecated async_play");
       
  1474         ret = bclass->async_play (basesink);
  1240         ret = bclass->async_play (basesink);
  1475         if (ret == GST_STATE_CHANGE_FAILURE)
  1241         if (ret == GST_STATE_CHANGE_FAILURE)
  1476           goto async_failed;
  1242           goto async_failed;
  1477       }
  1243       }
  1478       break;
  1244       break;
  1566     GST_OBJECT_UNLOCK (basesink);
  1332     GST_OBJECT_UNLOCK (basesink);
  1567     return FALSE;
  1333     return FALSE;
  1568   }
  1334   }
  1569 }
  1335 }
  1570 
  1336 
  1571 static void
       
  1572 start_stepping (GstBaseSink * sink, GstSegment * segment,
       
  1573     GstStepInfo * pending, GstStepInfo * current)
       
  1574 {
       
  1575   gint64 end;
       
  1576   GstMessage *message;
       
  1577 
       
  1578   GST_DEBUG_OBJECT (sink, "update pending step");
       
  1579 
       
  1580   GST_OBJECT_LOCK (sink);
       
  1581   memcpy (current, pending, sizeof (GstStepInfo));
       
  1582   pending->valid = FALSE;
       
  1583   GST_OBJECT_UNLOCK (sink);
       
  1584 
       
  1585   /* post message first */
       
  1586   message =
       
  1587       gst_message_new_step_start (GST_OBJECT (sink), TRUE, current->format,
       
  1588       current->amount, current->rate, current->flush, current->intermediate);
       
  1589   gst_message_set_seqnum (message, current->seqnum);
       
  1590   gst_element_post_message (GST_ELEMENT (sink), message);
       
  1591 
       
  1592   /* get the running time of where we paused and remember it */
       
  1593   current->start = gst_element_get_start_time (GST_ELEMENT_CAST (sink));
       
  1594   gst_segment_set_running_time (segment, GST_FORMAT_TIME, current->start);
       
  1595 
       
  1596   /* set the new rate for the remainder of the segment */
       
  1597   current->start_rate = segment->rate;
       
  1598   segment->rate *= current->rate;
       
  1599   segment->abs_rate = ABS (segment->rate);
       
  1600 
       
  1601   /* save values */
       
  1602   if (segment->rate > 0.0)
       
  1603     current->start_stop = segment->stop;
       
  1604   else
       
  1605     current->start_start = segment->start;
       
  1606 
       
  1607   if (current->format == GST_FORMAT_TIME) {
       
  1608     end = current->start + current->amount;
       
  1609     if (!current->flush) {
       
  1610       /* update the segment clipping regions for non-flushing seeks */
       
  1611       if (segment->rate > 0.0) {
       
  1612         segment->stop = gst_segment_to_position (segment, GST_FORMAT_TIME, end);
       
  1613         segment->last_stop = segment->stop;
       
  1614       } else {
       
  1615         gint64 position;
       
  1616 
       
  1617         position = gst_segment_to_position (segment, GST_FORMAT_TIME, end);
       
  1618         segment->time = position;
       
  1619         segment->start = position;
       
  1620         segment->last_stop = position;
       
  1621       }
       
  1622     }
       
  1623   }
       
  1624 
       
  1625   GST_DEBUG_OBJECT (sink,
       
  1626       "segment now rate %lf, applied rate %lf, "
       
  1627       "format GST_FORMAT_TIME, "
       
  1628       "%" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT
       
  1629       ", time %" GST_TIME_FORMAT ", accum %" GST_TIME_FORMAT,
       
  1630       segment->rate, segment->applied_rate, GST_TIME_ARGS (segment->start),
       
  1631       GST_TIME_ARGS (segment->stop), GST_TIME_ARGS (segment->time),
       
  1632       GST_TIME_ARGS (segment->accum));
       
  1633 
       
  1634   GST_DEBUG_OBJECT (sink, "step started at running_time %" GST_TIME_FORMAT,
       
  1635       GST_TIME_ARGS (current->start));
       
  1636 
       
  1637   if (current->amount == -1) {
       
  1638     GST_DEBUG_OBJECT (sink, "step amount == -1, stop stepping");
       
  1639     current->valid = FALSE;
       
  1640   } else {
       
  1641     GST_DEBUG_OBJECT (sink, "step amount: %" G_GUINT64_FORMAT ", format: %s, "
       
  1642         "rate: %f", current->amount, gst_format_get_name (current->format),
       
  1643         current->rate);
       
  1644   }
       
  1645 }
       
  1646 
       
  1647 static void
       
  1648 stop_stepping (GstBaseSink * sink, GstSegment * segment,
       
  1649     GstStepInfo * current, gint64 rstart, gint64 rstop, gboolean eos)
       
  1650 {
       
  1651   gint64 stop, position;
       
  1652   GstMessage *message;
       
  1653 
       
  1654   GST_DEBUG_OBJECT (sink, "step complete");
       
  1655 
       
  1656   if (segment->rate > 0.0)
       
  1657     stop = rstart;
       
  1658   else
       
  1659     stop = rstop;
       
  1660 
       
  1661   GST_DEBUG_OBJECT (sink,
       
  1662       "step stop at running_time %" GST_TIME_FORMAT, GST_TIME_ARGS (stop));
       
  1663 
       
  1664   if (stop == -1)
       
  1665     current->duration = current->position;
       
  1666   else
       
  1667     current->duration = stop - current->start;
       
  1668 
       
  1669   GST_DEBUG_OBJECT (sink, "step elapsed running_time %" GST_TIME_FORMAT,
       
  1670       GST_TIME_ARGS (current->duration));
       
  1671 
       
  1672   position = current->start + current->duration;
       
  1673 
       
  1674   /* now move the segment to the new running time */
       
  1675   gst_segment_set_running_time (segment, GST_FORMAT_TIME, position);
       
  1676 
       
  1677   if (current->flush) {
       
  1678     /* and remove the accumulated time we flushed, start time did not change */
       
  1679     segment->accum = current->start;
       
  1680   } else {
       
  1681     /* start time is now the stepped position */
       
  1682     gst_element_set_start_time (GST_ELEMENT_CAST (sink), position);
       
  1683   }
       
  1684 
       
  1685   /* restore the previous rate */
       
  1686   segment->rate = current->start_rate;
       
  1687   segment->abs_rate = ABS (segment->rate);
       
  1688 
       
  1689   if (segment->rate > 0.0)
       
  1690     segment->stop = current->start_stop;
       
  1691   else
       
  1692     segment->start = current->start_start;
       
  1693 
       
  1694   /* the clip segment is used for position report in paused... */
       
  1695   memcpy (sink->abidata.ABI.clip_segment, segment, sizeof (GstSegment));
       
  1696 
       
  1697   /* post the step done when we know the stepped duration in TIME */
       
  1698   message =
       
  1699       gst_message_new_step_done (GST_OBJECT_CAST (sink), current->format,
       
  1700       current->amount, current->rate, current->flush, current->intermediate,
       
  1701       current->duration, eos);
       
  1702   gst_message_set_seqnum (message, current->seqnum);
       
  1703   gst_element_post_message (GST_ELEMENT_CAST (sink), message);
       
  1704 
       
  1705   if (!current->intermediate)
       
  1706     sink->need_preroll = current->need_preroll;
       
  1707 
       
  1708   /* and the current step info finished and becomes invalid */
       
  1709   current->valid = FALSE;
       
  1710 }
       
  1711 
       
  1712 static gboolean
       
  1713 handle_stepping (GstBaseSink * sink, GstSegment * segment,
       
  1714     GstStepInfo * current, gint64 * cstart, gint64 * cstop, gint64 * rstart,
       
  1715     gint64 * rstop)
       
  1716 {
       
  1717   GstBaseSinkPrivate *priv;
       
  1718   gboolean step_end = FALSE;
       
  1719 
       
  1720   priv = sink->priv;
       
  1721 
       
  1722   /* see if we need to skip this buffer because of stepping */
       
  1723   switch (current->format) {
       
  1724     case GST_FORMAT_TIME:
       
  1725     {
       
  1726       guint64 end;
       
  1727       gint64 first, last;
       
  1728 
       
  1729       if (segment->rate > 0.0) {
       
  1730         first = *rstart;
       
  1731         last = *rstop;
       
  1732       } else {
       
  1733         first = *rstop;
       
  1734         last = *rstart;
       
  1735       }
       
  1736 
       
  1737       end = current->start + current->amount;
       
  1738       current->position = first - current->start;
       
  1739 
       
  1740       if (G_UNLIKELY (segment->abs_rate != 1.0))
       
  1741         current->position /= segment->abs_rate;
       
  1742 
       
  1743       GST_DEBUG_OBJECT (sink,
       
  1744           "buffer: %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
       
  1745           GST_TIME_ARGS (first), GST_TIME_ARGS (last));
       
  1746       GST_DEBUG_OBJECT (sink,
       
  1747           "got time step %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT "/%"
       
  1748           GST_TIME_FORMAT, GST_TIME_ARGS (current->position),
       
  1749           GST_TIME_ARGS (last - current->start),
       
  1750           GST_TIME_ARGS (current->amount));
       
  1751 
       
  1752       if ((current->flush && current->position >= current->amount)
       
  1753           || last >= end) {
       
  1754         GST_DEBUG_OBJECT (sink, "step ended, we need clipping");
       
  1755         step_end = TRUE;
       
  1756         if (segment->rate > 0.0) {
       
  1757           *rstart = end;
       
  1758           *cstart = gst_segment_to_position (segment, GST_FORMAT_TIME, end);
       
  1759         } else {
       
  1760           *rstop = end;
       
  1761           *cstop = gst_segment_to_position (segment, GST_FORMAT_TIME, end);
       
  1762         }
       
  1763       }
       
  1764       GST_DEBUG_OBJECT (sink,
       
  1765           "cstart %" GST_TIME_FORMAT ", rstart %" GST_TIME_FORMAT,
       
  1766           GST_TIME_ARGS (*cstart), GST_TIME_ARGS (*rstart));
       
  1767       GST_DEBUG_OBJECT (sink,
       
  1768           "cstop %" GST_TIME_FORMAT ", rstop %" GST_TIME_FORMAT,
       
  1769           GST_TIME_ARGS (*cstop), GST_TIME_ARGS (*rstop));
       
  1770       break;
       
  1771     }
       
  1772     case GST_FORMAT_BUFFERS:
       
  1773       GST_DEBUG_OBJECT (sink,
       
  1774           "got default step %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT,
       
  1775           current->position, current->amount);
       
  1776 
       
  1777       if (current->position < current->amount) {
       
  1778         current->position++;
       
  1779       } else {
       
  1780         step_end = TRUE;
       
  1781       }
       
  1782       break;
       
  1783     case GST_FORMAT_DEFAULT:
       
  1784     default:
       
  1785       GST_DEBUG_OBJECT (sink,
       
  1786           "got unknown step %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT,
       
  1787           current->position, current->amount);
       
  1788       break;
       
  1789   }
       
  1790   return step_end;
       
  1791 }
       
  1792 
  1337 
  1793 /* with STREAM_LOCK, PREROLL_LOCK
  1338 /* with STREAM_LOCK, PREROLL_LOCK
  1794  *
  1339  *
  1795  * Returns TRUE if the object needs synchronisation and takes therefore
  1340  * Returns TRUE if the object needs synchronisation and takes therefore
  1796  * part in prerolling.
  1341  * part in prerolling.
  1800  */
  1345  */
  1801 static gboolean
  1346 static gboolean
  1802 gst_base_sink_get_sync_times (GstBaseSink * basesink, GstMiniObject * obj,
  1347 gst_base_sink_get_sync_times (GstBaseSink * basesink, GstMiniObject * obj,
  1803     GstClockTime * rsstart, GstClockTime * rsstop,
  1348     GstClockTime * rsstart, GstClockTime * rsstop,
  1804     GstClockTime * rrstart, GstClockTime * rrstop, gboolean * do_sync,
  1349     GstClockTime * rrstart, GstClockTime * rrstop, gboolean * do_sync,
  1805     gboolean * stepped, GstSegment * segment, GstStepInfo * step,
  1350     GstSegment * segment)
  1806     gboolean * step_end)
       
  1807 {
  1351 {
  1808   GstBaseSinkClass *bclass;
  1352   GstBaseSinkClass *bclass;
  1809   GstBuffer *buffer;
  1353   GstBuffer *buffer;
  1810   GstClockTime start, stop;     /* raw start/stop timestamps */
  1354   GstClockTime start, stop;     /* raw start/stop timestamps */
  1811   gint64 cstart, cstop;         /* clipped raw timestamps */
  1355   gint64 cstart, cstop;         /* clipped raw timestamps */
  1812   gint64 rstart, rstop;         /* clipped timestamps converted to running time */
  1356   gint64 rstart, rstop;         /* clipped timestamps converted to running time */
  1813   GstClockTime sstart, sstop;   /* clipped timestamps converted to stream time */
  1357   GstClockTime sstart, sstop;   /* clipped timestamps converted to stream time */
  1814   GstFormat format;
  1358   GstFormat format;
  1815   GstBaseSinkPrivate *priv;
  1359   GstBaseSinkPrivate *priv;
  1816   gboolean eos;
       
  1817 
  1360 
  1818   priv = basesink->priv;
  1361   priv = basesink->priv;
  1819 
  1362 
  1820   /* start with nothing */
  1363   /* start with nothing */
  1821   start = stop = -1;
  1364   start = stop = sstart = sstop = rstart = rstop = -1;
  1822 
  1365 
  1823   if (G_UNLIKELY (GST_IS_EVENT (obj))) {
  1366   if (G_UNLIKELY (GST_IS_EVENT (obj))) {
  1824     GstEvent *event = GST_EVENT_CAST (obj);
  1367     GstEvent *event = GST_EVENT_CAST (obj);
  1825 
  1368 
  1826     switch (GST_EVENT_TYPE (event)) {
  1369     switch (GST_EVENT_TYPE (event)) {
  1827         /* EOS event needs syncing */
  1370         /* EOS event needs syncing */
  1828       case GST_EVENT_EOS:
  1371       case GST_EVENT_EOS:
  1829       {
  1372         sstart = sstop = priv->current_sstop;
  1830         if (basesink->segment.rate >= 0.0) {
       
  1831           sstart = sstop = priv->current_sstop;
       
  1832           if (sstart == -1) {
       
  1833             /* we have not seen a buffer yet, use the segment values */
       
  1834             sstart = sstop = gst_segment_to_stream_time (&basesink->segment,
       
  1835                 basesink->segment.format, basesink->segment.stop);
       
  1836           }
       
  1837         } else {
       
  1838           sstart = sstop = priv->current_sstart;
       
  1839           if (sstart == -1) {
       
  1840             /* we have not seen a buffer yet, use the segment values */
       
  1841             sstart = sstop = gst_segment_to_stream_time (&basesink->segment,
       
  1842                 basesink->segment.format, basesink->segment.start);
       
  1843           }
       
  1844         }
       
  1845 
       
  1846         rstart = rstop = priv->eos_rtime;
  1373         rstart = rstop = priv->eos_rtime;
  1847         *do_sync = rstart != -1;
  1374         *do_sync = rstart != -1;
  1848         GST_DEBUG_OBJECT (basesink, "sync times for EOS %" GST_TIME_FORMAT,
  1375         GST_DEBUG_OBJECT (basesink, "sync times for EOS %" GST_TIME_FORMAT,
  1849             GST_TIME_ARGS (rstart));
  1376             GST_TIME_ARGS (rstart));
  1850         /* if we are stepping, we end now */
  1377         goto done;
  1851         *step_end = step->valid;
       
  1852         eos = TRUE;
       
  1853         goto eos_done;
       
  1854       }
       
  1855       default:
       
  1856         /* other events do not need syncing */
  1378         /* other events do not need syncing */
  1857         /* FIXME, maybe NEWSEGMENT might need synchronisation
  1379         /* FIXME, maybe NEWSEGMENT might need synchronisation
  1858          * since the POSITION query depends on accumulated times and
  1380          * since the POSITION query depends on accumulated times and
  1859          * we cannot accumulate the current segment before the previous
  1381          * we cannot accumulate the current segment before the previous
  1860          * one completed.
  1382          * one completed.
  1861          */
  1383          */
       
  1384       default:
  1862         return FALSE;
  1385         return FALSE;
  1863     }
  1386     }
  1864   }
  1387   }
  1865 
  1388 
  1866   eos = FALSE;
       
  1867 
       
  1868   /* else do buffer sync code */
  1389   /* else do buffer sync code */
  1869   buffer = GST_BUFFER_CAST (obj);
  1390   buffer = GST_BUFFER_CAST (obj);
  1870 
  1391 
  1871   bclass = GST_BASE_SINK_GET_CLASS (basesink);
  1392   bclass = GST_BASE_SINK_GET_CLASS (basesink);
  1872 
  1393 
  1873   /* just get the times to see if we need syncing, if the start returns -1 we
  1394   /* just get the times to see if we need syncing */
  1874    * don't sync. */
       
  1875   if (bclass->get_times)
  1395   if (bclass->get_times)
  1876     bclass->get_times (basesink, buffer, &start, &stop);
  1396     bclass->get_times (basesink, buffer, &start, &stop);
  1877 
  1397 
  1878   if (start == -1) {
  1398   if (start == -1) {
  1879     /* we don't need to sync but we still want to get the timestamps for
       
  1880      * tracking the position */
       
  1881     gst_base_sink_get_times (basesink, buffer, &start, &stop);
  1399     gst_base_sink_get_times (basesink, buffer, &start, &stop);
  1882     *do_sync = FALSE;
  1400     *do_sync = FALSE;
  1883   } else {
  1401   } else {
  1884     *do_sync = TRUE;
  1402     *do_sync = TRUE;
  1885   }
  1403   }
  1889       GST_TIME_ARGS (stop), *do_sync);
  1407       GST_TIME_ARGS (stop), *do_sync);
  1890 
  1408 
  1891   /* collect segment and format for code clarity */
  1409   /* collect segment and format for code clarity */
  1892   format = segment->format;
  1410   format = segment->format;
  1893 
  1411 
  1894   /* no timestamp clipping if we did not get a TIME segment format */
  1412   /* no timestamp clipping if we did not * get a TIME segment format */
  1895   if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
  1413   if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
  1896     cstart = start;
  1414     cstart = start;
  1897     cstop = stop;
  1415     cstop = stop;
  1898     /* do running and stream time in TIME format */
  1416     /* do running and stream time in TIME format */
  1899     format = GST_FORMAT_TIME;
  1417     format = GST_FORMAT_TIME;
  1900     GST_LOG_OBJECT (basesink, "not time format, don't clip");
       
  1901     goto do_times;
  1418     goto do_times;
  1902   }
  1419   }
  1903 
  1420 
  1904   /* clip, only when we know about time */
  1421   /* clip */
  1905   if (G_UNLIKELY (!gst_segment_clip (segment, GST_FORMAT_TIME,
  1422   if (G_UNLIKELY (!gst_segment_clip (segment, GST_FORMAT_TIME,
  1906               (gint64) start, (gint64) stop, &cstart, &cstop))) {
  1423               (gint64) start, (gint64) stop, &cstart, &cstop)))
  1907     if (step->valid) {
       
  1908       GST_DEBUG_OBJECT (basesink, "step out of segment");
       
  1909       /* when we are stepping, pretend we're at the end of the segment */
       
  1910       if (segment->rate > 0.0) {
       
  1911         cstart = segment->stop;
       
  1912         cstop = segment->stop;
       
  1913       } else {
       
  1914         cstart = segment->start;
       
  1915         cstop = segment->start;
       
  1916       }
       
  1917       goto do_times;
       
  1918     }
       
  1919     goto out_of_segment;
  1424     goto out_of_segment;
  1920   }
       
  1921 
  1425 
  1922   if (G_UNLIKELY (start != cstart || stop != cstop)) {
  1426   if (G_UNLIKELY (start != cstart || stop != cstop)) {
  1923     GST_DEBUG_OBJECT (basesink, "clipped to: start %" GST_TIME_FORMAT
  1427     GST_DEBUG_OBJECT (basesink, "clipped to: start %" GST_TIME_FORMAT
  1924         ", stop: %" GST_TIME_FORMAT, GST_TIME_ARGS (cstart),
  1428         ", stop: %" GST_TIME_FORMAT, GST_TIME_ARGS (cstart),
  1925         GST_TIME_ARGS (cstop));
  1429         GST_TIME_ARGS (cstop));
  1926   }
  1430   }
  1927 
  1431 
  1928   /* set last stop position */
  1432   /* set last stop position */
  1929   if (G_LIKELY (cstop != GST_CLOCK_TIME_NONE))
  1433   gst_segment_set_last_stop (segment, GST_FORMAT_TIME, cstop);
  1930     gst_segment_set_last_stop (segment, GST_FORMAT_TIME, cstop);
       
  1931   else
       
  1932     gst_segment_set_last_stop (segment, GST_FORMAT_TIME, cstart);
       
  1933 
  1434 
  1934 do_times:
  1435 do_times:
  1935   rstart = gst_segment_to_running_time (segment, format, cstart);
       
  1936   rstop = gst_segment_to_running_time (segment, format, cstop);
       
  1937 
       
  1938   if (G_UNLIKELY (step->valid)) {
       
  1939     if (!(*step_end = handle_stepping (basesink, segment, step, &cstart, &cstop,
       
  1940                 &rstart, &rstop))) {
       
  1941       /* step is still busy, we discard data when we are flushing */
       
  1942       *stepped = step->flush;
       
  1943     }
       
  1944   }
       
  1945   /* this can produce wrong values if we accumulated non-TIME segments. If this happens,
  1436   /* this can produce wrong values if we accumulated non-TIME segments. If this happens,
  1946    * upstream is behaving very badly */
  1437    * upstream is behaving very badly */
  1947   sstart = gst_segment_to_stream_time (segment, format, cstart);
  1438   sstart = gst_segment_to_stream_time (segment, format, cstart);
  1948   sstop = gst_segment_to_stream_time (segment, format, cstop);
  1439   sstop = gst_segment_to_stream_time (segment, format, cstop);
  1949 
  1440   rstart = gst_segment_to_running_time (segment, format, cstart);
  1950 eos_done:
  1441   rstop = gst_segment_to_running_time (segment, format, cstop);
  1951   /* eos_done label only called when doing EOS, we also stop stepping then */
  1442 
  1952   if (*step_end && step->flush) {
  1443 done:
  1953     GST_DEBUG_OBJECT (basesink, "flushing step ended");
       
  1954     stop_stepping (basesink, segment, step, rstart, rstop, eos);
       
  1955     *step_end = FALSE;
       
  1956   }
       
  1957 
       
  1958   /* save times */
  1444   /* save times */
  1959   *rsstart = sstart;
  1445   *rsstart = sstart;
  1960   *rsstop = sstop;
  1446   *rsstop = sstop;
  1961   *rrstart = rstart;
  1447   *rrstart = rstart;
  1962   *rrstop = rstop;
  1448   *rrstop = rstop;
  1965   return TRUE;
  1451   return TRUE;
  1966 
  1452 
  1967   /* special cases */
  1453   /* special cases */
  1968 out_of_segment:
  1454 out_of_segment:
  1969   {
  1455   {
  1970     /* we usually clip in the chain function already but stepping could cause
  1456     /* should not happen since we clip them in the chain function already, 
  1971      * the segment to be updated later. we return FALSE so that we don't try
  1457      * we return FALSE so that we don't try to sync on it. */
  1972      * to sync on it. */
  1458     GST_ELEMENT_WARNING (basesink, STREAM, FAILED,
       
  1459         (NULL), ("unexpected buffer out of segment found."));
  1973     GST_LOG_OBJECT (basesink, "buffer skipped, not in segment");
  1460     GST_LOG_OBJECT (basesink, "buffer skipped, not in segment");
  1974     return FALSE;
  1461     return FALSE;
  1975   }
  1462   }
  1976 }
  1463 }
  1977 
  1464 
  1978 /* with STREAM_LOCK, PREROLL_LOCK, LOCK
  1465 /* with STREAM_LOCK, PREROLL_LOCK
  1979  * adjust a timestamp with the latency and timestamp offset */
  1466  *
  1980 static GstClockTime
  1467  * Waits for the clock to reach @time. If @time is not valid, no
  1981 gst_base_sink_adjust_time (GstBaseSink * basesink, GstClockTime time)
  1468  * synchronisation is done and BADTIME is returned. 
  1982 {
  1469  * If synchronisation is disabled in the element or there is no
       
  1470  * clock, no synchronisation is done and BADTIME is returned.
       
  1471  *
       
  1472  * Else a blocking wait is performed on the clock. We save the ClockID
       
  1473  * so we can unlock the entry at any time. While we are blocking, we 
       
  1474  * release the PREROLL_LOCK so that other threads can interrupt the entry.
       
  1475  *
       
  1476  * @time is expressed in running time.
       
  1477  */
       
  1478 static GstClockReturn
       
  1479 gst_base_sink_wait_clock (GstBaseSink * basesink, GstClockTime time,
       
  1480     GstClockTimeDiff * jitter)
       
  1481 {
       
  1482   GstClockID id;
       
  1483   GstClockReturn ret;
       
  1484   GstClock *clock;
  1983   GstClockTimeDiff ts_offset;
  1485   GstClockTimeDiff ts_offset;
  1984 
  1486 
  1985   /* don't do anything funny with invalid timestamps */
       
  1986   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time)))
  1487   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time)))
  1987     return time;
  1488     goto invalid_time;
  1988 
  1489 
       
  1490   GST_OBJECT_LOCK (basesink);
       
  1491   if (G_UNLIKELY (!basesink->sync))
       
  1492     goto no_sync;
       
  1493 
       
  1494   if (G_UNLIKELY ((clock = GST_ELEMENT_CLOCK (basesink)) == NULL))
       
  1495     goto no_clock;
       
  1496 
       
  1497   /* add base time and latency */
       
  1498   time += GST_ELEMENT_CAST (basesink)->base_time;
  1989   time += basesink->priv->latency;
  1499   time += basesink->priv->latency;
  1990 
  1500 
  1991   /* apply offset, be carefull for underflows */
  1501   /* apply offset, be carefull for underflows */
  1992   ts_offset = basesink->priv->ts_offset;
  1502   ts_offset = basesink->priv->ts_offset;
  1993   if (ts_offset < 0) {
  1503   if (ts_offset < 0) {
  1997     else
  1507     else
  1998       time = 0;
  1508       time = 0;
  1999   } else
  1509   } else
  2000     time += ts_offset;
  1510     time += ts_offset;
  2001 
  1511 
  2002   return time;
       
  2003 }
       
  2004 
       
  2005 /**
       
  2006  * gst_base_sink_wait_clock:
       
  2007  * @sink: the sink
       
  2008  * @time: the running_time to be reached
       
  2009  * @jitter: the jitter to be filled with time diff (can be NULL)
       
  2010  *
       
  2011  * This function will block until @time is reached. It is usually called by
       
  2012  * subclasses that use their own internal synchronisation.
       
  2013  *
       
  2014  * If @time is not valid, no sycnhronisation is done and #GST_CLOCK_BADTIME is
       
  2015  * returned. Likewise, if synchronisation is disabled in the element or there
       
  2016  * is no clock, no synchronisation is done and #GST_CLOCK_BADTIME is returned.
       
  2017  *
       
  2018  * This function should only be called with the PREROLL_LOCK held, like when
       
  2019  * receiving an EOS event in the ::event vmethod or when receiving a buffer in
       
  2020  * the ::render vmethod.
       
  2021  *
       
  2022  * The @time argument should be the running_time of when this method should
       
  2023  * return and is not adjusted with any latency or offset configured in the
       
  2024  * sink.
       
  2025  *
       
  2026  * Since 0.10.20
       
  2027  *
       
  2028  * Returns: #GstClockReturn
       
  2029  */
       
  2030 #ifdef __SYMBIAN32__
       
  2031 EXPORT_C
       
  2032 #endif
       
  2033 
       
  2034 GstClockReturn
       
  2035 gst_base_sink_wait_clock (GstBaseSink * sink, GstClockTime time,
       
  2036     GstClockTimeDiff * jitter)
       
  2037 {
       
  2038   GstClockID id;
       
  2039   GstClockReturn ret;
       
  2040   GstClock *clock;
       
  2041 
       
  2042   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time)))
       
  2043     goto invalid_time;
       
  2044 
       
  2045   GST_OBJECT_LOCK (sink);
       
  2046   if (G_UNLIKELY (!sink->sync))
       
  2047     goto no_sync;
       
  2048 
       
  2049   if (G_UNLIKELY ((clock = GST_ELEMENT_CLOCK (sink)) == NULL))
       
  2050     goto no_clock;
       
  2051 
       
  2052   /* add base_time to running_time to get the time against the clock */
       
  2053   time += GST_ELEMENT_CAST (sink)->base_time;
       
  2054 
       
  2055   id = gst_clock_new_single_shot_id (clock, time);
  1512   id = gst_clock_new_single_shot_id (clock, time);
  2056   GST_OBJECT_UNLOCK (sink);
  1513   GST_OBJECT_UNLOCK (basesink);
  2057 
  1514 
  2058   /* A blocking wait is performed on the clock. We save the ClockID
  1515   basesink->clock_id = id;
  2059    * so we can unlock the entry at any time. While we are blocking, we 
       
  2060    * release the PREROLL_LOCK so that other threads can interrupt the
       
  2061    * entry. */
       
  2062   sink->clock_id = id;
       
  2063   /* release the preroll lock while waiting */
  1516   /* release the preroll lock while waiting */
  2064   GST_PAD_PREROLL_UNLOCK (sink->sinkpad);
  1517   GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
  2065 
  1518 
  2066   ret = gst_clock_id_wait (id, jitter);
  1519   ret = gst_clock_id_wait (id, jitter);
  2067 
  1520 
  2068   GST_PAD_PREROLL_LOCK (sink->sinkpad);
  1521   GST_PAD_PREROLL_LOCK (basesink->sinkpad);
  2069   gst_clock_id_unref (id);
  1522   gst_clock_id_unref (id);
  2070   sink->clock_id = NULL;
  1523   basesink->clock_id = NULL;
  2071 
  1524 
  2072   return ret;
  1525   return ret;
  2073 
  1526 
  2074   /* no syncing needed */
  1527   /* no syncing needed */
  2075 invalid_time:
  1528 invalid_time:
  2076   {
  1529   {
  2077     GST_DEBUG_OBJECT (sink, "time not valid, no sync needed");
  1530     GST_DEBUG_OBJECT (basesink, "time not valid, no sync needed");
  2078     return GST_CLOCK_BADTIME;
  1531     return GST_CLOCK_BADTIME;
  2079   }
  1532   }
  2080 no_sync:
  1533 no_sync:
  2081   {
  1534   {
  2082     GST_DEBUG_OBJECT (sink, "sync disabled");
  1535     GST_DEBUG_OBJECT (basesink, "sync disabled");
  2083     GST_OBJECT_UNLOCK (sink);
  1536     GST_OBJECT_UNLOCK (basesink);
  2084     return GST_CLOCK_BADTIME;
  1537     return GST_CLOCK_BADTIME;
  2085   }
  1538   }
  2086 no_clock:
  1539 no_clock:
  2087   {
  1540   {
  2088     GST_DEBUG_OBJECT (sink, "no clock, can't sync");
  1541     GST_DEBUG_OBJECT (basesink, "no clock, can't sync");
  2089     GST_OBJECT_UNLOCK (sink);
  1542     GST_OBJECT_UNLOCK (basesink);
  2090     return GST_CLOCK_BADTIME;
  1543     return GST_CLOCK_BADTIME;
  2091   }
  1544   }
  2092 }
  1545 }
  2093 
  1546 
  2094 /**
  1547 /**
  2101  *
  1554  *
  2102  * This function will block until a state change to PLAYING happens (in which
  1555  * This function will block until a state change to PLAYING happens (in which
  2103  * case this function returns #GST_FLOW_OK) or the processing must be stopped due
  1556  * case this function returns #GST_FLOW_OK) or the processing must be stopped due
  2104  * to a state change to READY or a FLUSH event (in which case this function
  1557  * to a state change to READY or a FLUSH event (in which case this function
  2105  * returns #GST_FLOW_WRONG_STATE).
  1558  * returns #GST_FLOW_WRONG_STATE).
  2106  *
       
  2107  * This function should only be called with the PREROLL_LOCK held, like in the
       
  2108  * render function.
       
  2109  *
  1559  *
  2110  * Since: 0.10.11
  1560  * Since: 0.10.11
  2111  *
  1561  *
  2112  * Returns: #GST_FLOW_OK if the preroll completed and processing can
  1562  * Returns: #GST_FLOW_OK if the preroll completed and processing can
  2113  * continue. Any other return value should be returned from the render vmethod.
  1563  * continue. Any other return value should be returned from the render vmethod.
  2124   /* block until the state changes, or we get a flush, or something */
  1574   /* block until the state changes, or we get a flush, or something */
  2125   GST_PAD_PREROLL_WAIT (sink->sinkpad);
  1575   GST_PAD_PREROLL_WAIT (sink->sinkpad);
  2126   sink->have_preroll = FALSE;
  1576   sink->have_preroll = FALSE;
  2127   if (G_UNLIKELY (sink->flushing))
  1577   if (G_UNLIKELY (sink->flushing))
  2128     goto stopping;
  1578     goto stopping;
  2129   if (G_UNLIKELY (sink->priv->step_unlock))
       
  2130     goto step_unlocked;
       
  2131   GST_DEBUG_OBJECT (sink, "continue after preroll");
  1579   GST_DEBUG_OBJECT (sink, "continue after preroll");
  2132 
  1580 
  2133   return GST_FLOW_OK;
  1581   return GST_FLOW_OK;
  2134 
  1582 
  2135   /* ERRORS */
  1583   /* ERRORS */
  2136 stopping:
  1584 stopping:
  2137   {
  1585   {
  2138     GST_DEBUG_OBJECT (sink, "preroll interrupted because of flush");
  1586     GST_DEBUG_OBJECT (sink, "preroll interrupted");
  2139     return GST_FLOW_WRONG_STATE;
  1587     return GST_FLOW_WRONG_STATE;
  2140   }
       
  2141 step_unlocked:
       
  2142   {
       
  2143     sink->priv->step_unlock = FALSE;
       
  2144     GST_DEBUG_OBJECT (sink, "preroll interrupted because of step");
       
  2145     return GST_FLOW_STEP;
       
  2146   }
       
  2147 }
       
  2148 
       
  2149 /**
       
  2150  * gst_base_sink_do_preroll:
       
  2151  * @sink: the sink
       
  2152  * @obj: the object that caused the preroll
       
  2153  *
       
  2154  * If the @sink spawns its own thread for pulling buffers from upstream it
       
  2155  * should call this method after it has pulled a buffer. If the element needed
       
  2156  * to preroll, this function will perform the preroll and will then block
       
  2157  * until the element state is changed.
       
  2158  *
       
  2159  * This function should be called with the PREROLL_LOCK held.
       
  2160  *
       
  2161  * Since 0.10.22
       
  2162  *
       
  2163  * Returns: #GST_FLOW_OK if the preroll completed and processing can
       
  2164  * continue. Any other return value should be returned from the render vmethod.
       
  2165  */
       
  2166 #ifdef __SYMBIAN32__
       
  2167 EXPORT_C
       
  2168 #endif
       
  2169 
       
  2170 GstFlowReturn
       
  2171 gst_base_sink_do_preroll (GstBaseSink * sink, GstMiniObject * obj)
       
  2172 {
       
  2173   GstFlowReturn ret;
       
  2174 
       
  2175   while (G_UNLIKELY (sink->need_preroll)) {
       
  2176     GST_DEBUG_OBJECT (sink, "prerolling object %p", obj);
       
  2177 
       
  2178     ret = gst_base_sink_preroll_object (sink, FALSE, obj);
       
  2179     if (ret != GST_FLOW_OK)
       
  2180       goto preroll_failed;
       
  2181 
       
  2182     /* need to recheck here because the commit state could have
       
  2183      * made us not need the preroll anymore */
       
  2184     if (G_LIKELY (sink->need_preroll)) {
       
  2185       /* block until the state changes, or we get a flush, or something */
       
  2186       ret = gst_base_sink_wait_preroll (sink);
       
  2187       if (ret != GST_FLOW_OK) {
       
  2188         if (ret == GST_FLOW_STEP)
       
  2189           ret = GST_FLOW_OK;
       
  2190         else
       
  2191           goto preroll_failed;
       
  2192       }
       
  2193     }
       
  2194   }
       
  2195   return GST_FLOW_OK;
       
  2196 
       
  2197   /* ERRORS */
       
  2198 preroll_failed:
       
  2199   {
       
  2200     GST_DEBUG_OBJECT (sink, "preroll failed %d", ret);
       
  2201     return ret;
       
  2202   }
  1588   }
  2203 }
  1589 }
  2204 
  1590 
  2205 /**
  1591 /**
  2206  * gst_base_sink_wait_eos:
  1592  * gst_base_sink_wait_eos:
  2213  * EOS be handled by the base class.
  1599  * EOS be handled by the base class.
  2214  *
  1600  *
  2215  * This function should only be called with the PREROLL_LOCK held, like when
  1601  * This function should only be called with the PREROLL_LOCK held, like when
  2216  * receiving an EOS event in the ::event vmethod.
  1602  * receiving an EOS event in the ::event vmethod.
  2217  *
  1603  *
  2218  * The @time argument should be the running_time of when the EOS should happen
       
  2219  * and will be adjusted with any latency and offset configured in the sink.
       
  2220  *
       
  2221  * Since 0.10.15
  1604  * Since 0.10.15
  2222  *
  1605  *
  2223  * Returns: #GstFlowReturn
  1606  * Returns: #GstFlowReturn
  2224  */
  1607  */
  2225 #ifdef __SYMBIAN32__
  1608 #ifdef __SYMBIAN32__
  2232 {
  1615 {
  2233   GstClockReturn status;
  1616   GstClockReturn status;
  2234   GstFlowReturn ret;
  1617   GstFlowReturn ret;
  2235 
  1618 
  2236   do {
  1619   do {
  2237     GstClockTime stime;
       
  2238 
       
  2239     GST_DEBUG_OBJECT (sink, "checking preroll");
  1620     GST_DEBUG_OBJECT (sink, "checking preroll");
  2240 
  1621 
  2241     /* first wait for the playing state before we can continue */
  1622     /* first wait for the playing state before we can continue */
  2242     if (G_UNLIKELY (sink->need_preroll)) {
  1623     if (G_UNLIKELY (sink->need_preroll)) {
  2243       ret = gst_base_sink_wait_preroll (sink);
  1624       ret = gst_base_sink_wait_preroll (sink);
  2244       if (ret != GST_FLOW_OK) {
  1625       if (ret != GST_FLOW_OK)
  2245         if (ret == GST_FLOW_STEP)
  1626         goto flushing;
  2246           ret = GST_FLOW_OK;
       
  2247         else
       
  2248           goto flushing;
       
  2249       }
       
  2250     }
  1627     }
  2251 
  1628 
  2252     /* preroll done, we can sync since we are in PLAYING now. */
  1629     /* preroll done, we can sync since we are in PLAYING now. */
  2253     GST_DEBUG_OBJECT (sink, "possibly waiting for clock to reach %"
  1630     GST_DEBUG_OBJECT (sink, "possibly waiting for clock to reach %"
  2254         GST_TIME_FORMAT, GST_TIME_ARGS (time));
  1631         GST_TIME_FORMAT, GST_TIME_ARGS (time));
  2255 
  1632 
  2256     /* compensate for latency and ts_offset. We don't adjust for render delay
       
  2257      * because we don't interact with the device on EOS normally. */
       
  2258     stime = gst_base_sink_adjust_time (sink, time);
       
  2259 
       
  2260     /* wait for the clock, this can be interrupted because we got shut down or 
  1633     /* wait for the clock, this can be interrupted because we got shut down or 
  2261      * we PAUSED. */
  1634      * we PAUSED. */
  2262     status = gst_base_sink_wait_clock (sink, stime, jitter);
  1635     status = gst_base_sink_wait_clock (sink, time, jitter);
  2263 
  1636 
  2264     GST_DEBUG_OBJECT (sink, "clock returned %d", status);
  1637     GST_DEBUG_OBJECT (sink, "clock returned %d", status);
  2265 
  1638 
  2266     /* invalid time, no clock or sync disabled, just continue then */
  1639     /* invalid time, no clock or sync disabled, just continue then */
  2267     if (status == GST_CLOCK_BADTIME)
  1640     if (status == GST_CLOCK_BADTIME)
  2309  *
  1682  *
  2310  * does not take ownership of obj.
  1683  * does not take ownership of obj.
  2311  */
  1684  */
  2312 static GstFlowReturn
  1685 static GstFlowReturn
  2313 gst_base_sink_do_sync (GstBaseSink * basesink, GstPad * pad,
  1686 gst_base_sink_do_sync (GstBaseSink * basesink, GstPad * pad,
  2314     GstMiniObject * obj, gboolean * late, gboolean * step_end)
  1687     GstMiniObject * obj, gboolean * late)
  2315 {
  1688 {
  2316   GstClockTimeDiff jitter;
  1689   GstClockTimeDiff jitter;
  2317   gboolean syncable;
  1690   gboolean syncable;
  2318   GstClockReturn status = GST_CLOCK_OK;
  1691   GstClockReturn status = GST_CLOCK_OK;
  2319   GstClockTime rstart, rstop, sstart, sstop, stime;
  1692   GstClockTime rstart, rstop, sstart, sstop;
  2320   gboolean do_sync;
  1693   gboolean do_sync;
  2321   GstBaseSinkPrivate *priv;
  1694   GstBaseSinkPrivate *priv;
  2322   GstFlowReturn ret;
       
  2323   GstStepInfo *current, *pending;
       
  2324   gboolean stepped;
       
  2325 
  1695 
  2326   priv = basesink->priv;
  1696   priv = basesink->priv;
  2327 
  1697 
  2328 do_step:
       
  2329   sstart = sstop = rstart = rstop = -1;
  1698   sstart = sstop = rstart = rstop = -1;
  2330   do_sync = TRUE;
  1699   do_sync = TRUE;
  2331   stepped = FALSE;
       
  2332 
  1700 
  2333   priv->current_rstart = -1;
  1701   priv->current_rstart = -1;
  2334 
       
  2335   /* get stepping info */
       
  2336   current = &priv->current_step;
       
  2337   pending = &priv->pending_step;
       
  2338 
  1702 
  2339   /* get timing information for this object against the render segment */
  1703   /* get timing information for this object against the render segment */
  2340   syncable = gst_base_sink_get_sync_times (basesink, obj,
  1704   syncable = gst_base_sink_get_sync_times (basesink, obj,
  2341       &sstart, &sstop, &rstart, &rstop, &do_sync, &stepped, &basesink->segment,
  1705       &sstart, &sstop, &rstart, &rstop, &do_sync, &basesink->segment);
  2342       current, step_end);
       
  2343 
       
  2344   if (G_UNLIKELY (stepped))
       
  2345     goto step_skipped;
       
  2346 
  1706 
  2347   /* a syncable object needs to participate in preroll and
  1707   /* a syncable object needs to participate in preroll and
  2348    * clocking. All buffers and EOS are syncable. */
  1708    * clocking. All buffers and EOS are syncable. */
  2349   if (G_UNLIKELY (!syncable))
  1709   if (G_UNLIKELY (!syncable))
  2350     goto not_syncable;
  1710     goto not_syncable;
  2351 
  1711 
  2352   /* store timing info for current object */
  1712   /* store timing info for current object */
  2353   priv->current_rstart = rstart;
  1713   priv->current_rstart = rstart;
  2354   priv->current_rstop = (rstop != -1 ? rstop : rstart);
  1714   priv->current_rstop = (rstop != -1 ? rstop : rstart);
  2355 
       
  2356   /* save sync time for eos when the previous object needed sync */
  1715   /* save sync time for eos when the previous object needed sync */
  2357   priv->eos_rtime = (do_sync ? priv->current_rstop : -1);
  1716   priv->eos_rtime = (do_sync ? priv->current_rstop : -1);
  2358 
  1717 
  2359 again:
  1718 again:
  2360   /* first do preroll, this makes sure we commit our state
  1719   /* first do preroll, this makes sure we commit our state
  2361    * to PAUSED and can continue to PLAYING. We cannot perform
  1720    * to PAUSED and can continue to PLAYING. We cannot perform
  2362    * any clock sync in PAUSED because there is no clock. */
  1721    * any clock sync in PAUSED because there is no clock. 
  2363   ret = gst_base_sink_do_preroll (basesink, obj);
  1722    */
  2364   if (G_UNLIKELY (ret != GST_FLOW_OK))
  1723   while (G_UNLIKELY (basesink->need_preroll)) {
  2365     goto preroll_failed;
  1724     GST_DEBUG_OBJECT (basesink, "prerolling object %p", obj);
       
  1725 
       
  1726     if (G_LIKELY (basesink->playing_async)) {
       
  1727       /* commit state */
       
  1728       if (G_UNLIKELY (!gst_base_sink_commit_state (basesink)))
       
  1729         goto stopping;
       
  1730     }
       
  1731 
       
  1732     /* need to recheck here because the commit state could have
       
  1733      * made us not need the preroll anymore */
       
  1734     if (G_LIKELY (basesink->need_preroll)) {
       
  1735       /* block until the state changes, or we get a flush, or something */
       
  1736       if (gst_base_sink_wait_preroll (basesink) != GST_FLOW_OK)
       
  1737         goto flushing;
       
  1738     }
       
  1739   }
  2366 
  1740 
  2367   /* After rendering we store the position of the last buffer so that we can use
  1741   /* After rendering we store the position of the last buffer so that we can use
  2368    * it to report the position. We need to take the lock here. */
  1742    * it to report the position. We need to take the lock here. */
  2369   GST_OBJECT_LOCK (basesink);
  1743   GST_OBJECT_LOCK (basesink);
  2370   priv->current_sstart = sstart;
  1744   priv->current_sstart = sstart;
  2371   priv->current_sstop = (sstop != -1 ? sstop : sstart);
  1745   priv->current_sstop = (sstop != -1 ? sstop : sstart);
  2372   GST_OBJECT_UNLOCK (basesink);
  1746   GST_OBJECT_UNLOCK (basesink);
  2373 
  1747 
  2374   /* update the segment with a pending step if the current one is invalid and we
       
  2375    * have a new pending one. We only accept new step updates after a preroll */
       
  2376   if (G_UNLIKELY (pending->valid && !current->valid)) {
       
  2377     start_stepping (basesink, &basesink->segment, pending, current);
       
  2378     goto do_step;
       
  2379   }
       
  2380 
       
  2381   if (!do_sync)
  1748   if (!do_sync)
  2382     goto done;
  1749     goto done;
  2383 
  1750 
  2384   /* adjust for latency */
       
  2385   stime = gst_base_sink_adjust_time (basesink, rstart);
       
  2386 
       
  2387   /* adjust for render-delay, avoid underflows */
       
  2388   if (stime != -1) {
       
  2389     if (stime > priv->render_delay)
       
  2390       stime -= priv->render_delay;
       
  2391     else
       
  2392       stime = 0;
       
  2393   }
       
  2394 
       
  2395   /* preroll done, we can sync since we are in PLAYING now. */
  1751   /* preroll done, we can sync since we are in PLAYING now. */
  2396   GST_DEBUG_OBJECT (basesink, "possibly waiting for clock to reach %"
  1752   GST_DEBUG_OBJECT (basesink, "possibly waiting for clock to reach %"
  2397       GST_TIME_FORMAT ", adjusted %" GST_TIME_FORMAT,
  1753       GST_TIME_FORMAT, GST_TIME_ARGS (rstart));
  2398       GST_TIME_ARGS (rstart), GST_TIME_ARGS (stime));
  1754 
  2399 
  1755   /* this function will return immediatly if start == -1, no clock
  2400   /* This function will return immediatly if start == -1, no clock
       
  2401    * or sync is disabled with GST_CLOCK_BADTIME. */
  1756    * or sync is disabled with GST_CLOCK_BADTIME. */
  2402   status = gst_base_sink_wait_clock (basesink, stime, &jitter);
  1757   status = gst_base_sink_wait_clock (basesink, rstart, &jitter);
  2403 
  1758 
  2404   GST_DEBUG_OBJECT (basesink, "clock returned %d", status);
  1759   GST_DEBUG_OBJECT (basesink, "clock returned %d", status);
  2405 
  1760 
  2406   /* invalid time, no clock or sync disabled, just render */
  1761   /* invalid time, no clock or sync disabled, just render */
  2407   if (status == GST_CLOCK_BADTIME)
  1762   if (status == GST_CLOCK_BADTIME)
  2413 
  1768 
  2414   /* check for unlocked by a state change, we are not flushing so
  1769   /* check for unlocked by a state change, we are not flushing so
  2415    * we can try to preroll on the current buffer. */
  1770    * we can try to preroll on the current buffer. */
  2416   if (G_UNLIKELY (status == GST_CLOCK_UNSCHEDULED)) {
  1771   if (G_UNLIKELY (status == GST_CLOCK_UNSCHEDULED)) {
  2417     GST_DEBUG_OBJECT (basesink, "unscheduled, waiting some more");
  1772     GST_DEBUG_OBJECT (basesink, "unscheduled, waiting some more");
  2418     priv->call_preroll = TRUE;
       
  2419     goto again;
  1773     goto again;
  2420   }
  1774   }
  2421 
  1775 
  2422   /* successful syncing done, record observation */
  1776   /* successful syncing done, record observation */
  2423   priv->current_jitter = jitter;
  1777   priv->current_jitter = jitter;
  2428 
  1782 
  2429 done:
  1783 done:
  2430   return GST_FLOW_OK;
  1784   return GST_FLOW_OK;
  2431 
  1785 
  2432   /* ERRORS */
  1786   /* ERRORS */
  2433 step_skipped:
       
  2434   {
       
  2435     GST_DEBUG_OBJECT (basesink, "skipped stepped object %p", obj);
       
  2436     *late = TRUE;
       
  2437     return GST_FLOW_OK;
       
  2438   }
       
  2439 not_syncable:
  1787 not_syncable:
  2440   {
  1788   {
  2441     GST_DEBUG_OBJECT (basesink, "non syncable object %p", obj);
  1789     GST_DEBUG_OBJECT (basesink, "non syncable object %p", obj);
  2442     return GST_FLOW_OK;
  1790     return GST_FLOW_OK;
  2443   }
  1791   }
  2444 flushing:
  1792 flushing:
  2445   {
  1793   {
  2446     GST_DEBUG_OBJECT (basesink, "we are flushing");
  1794     GST_DEBUG_OBJECT (basesink, "we are flushing");
  2447     return GST_FLOW_WRONG_STATE;
  1795     return GST_FLOW_WRONG_STATE;
  2448   }
  1796   }
  2449 preroll_failed:
  1797 stopping:
  2450   {
  1798   {
  2451     GST_DEBUG_OBJECT (basesink, "preroll failed");
  1799     GST_DEBUG_OBJECT (basesink, "stopping while commiting state");
  2452     *step_end = FALSE;
  1800     return GST_FLOW_WRONG_STATE;
  2453     return ret;
       
  2454   }
  1801   }
  2455 }
  1802 }
  2456 
  1803 
  2457 static gboolean
  1804 static gboolean
  2458 gst_base_sink_send_qos (GstBaseSink * basesink,
  1805 gst_base_sink_send_qos (GstBaseSink * basesink,
  2486 
  1833 
  2487   priv = sink->priv;
  1834   priv = sink->priv;
  2488 
  1835 
  2489   start = priv->current_rstart;
  1836   start = priv->current_rstart;
  2490 
  1837 
  2491   if (priv->current_step.valid)
       
  2492     return;
       
  2493 
       
  2494   /* if Quality-of-Service disabled, do nothing */
  1838   /* if Quality-of-Service disabled, do nothing */
  2495   if (!g_atomic_int_get (&priv->qos_enabled) || start == -1)
  1839   if (!g_atomic_int_get (&priv->qos_enabled) || start == -1)
  2496     return;
  1840     return;
  2497 
  1841 
  2498   stop = priv->current_rstop;
  1842   stop = priv->current_rstop;
  2499   jitter = priv->current_jitter;
  1843   jitter = priv->current_jitter;
  2500 
  1844 
  2501   if (jitter < 0) {
  1845   /* this is the time the buffer entered the sink */
  2502     /* this is the time the buffer entered the sink */
  1846   entered = start + jitter;
  2503     if (start < -jitter)
  1847   /* this is the time the buffer left the sink */
  2504       entered = 0;
  1848   left = start + (jitter < 0 ? 0 : jitter);
  2505     else
       
  2506       entered = start + jitter;
       
  2507     left = start;
       
  2508   } else {
       
  2509     /* this is the time the buffer entered the sink */
       
  2510     entered = start + jitter;
       
  2511     /* this is the time the buffer left the sink */
       
  2512     left = start + jitter;
       
  2513   }
       
  2514 
  1849 
  2515   /* calculate duration of the buffer */
  1850   /* calculate duration of the buffer */
  2516   if (stop != -1)
  1851   if (stop != -1)
  2517     duration = stop - start;
  1852     duration = stop - start;
  2518   else
  1853   else
  2576       "updated: avg_duration: %" GST_TIME_FORMAT ", avg_pt: %" GST_TIME_FORMAT
  1911       "updated: avg_duration: %" GST_TIME_FORMAT ", avg_pt: %" GST_TIME_FORMAT
  2577       ", avg_rate: %g", GST_TIME_ARGS (priv->avg_duration),
  1912       ", avg_rate: %g", GST_TIME_ARGS (priv->avg_duration),
  2578       GST_TIME_ARGS (priv->avg_pt), priv->avg_rate);
  1913       GST_TIME_ARGS (priv->avg_pt), priv->avg_rate);
  2579 
  1914 
  2580 
  1915 
       
  1916   /* if we have a valid rate, start sending QoS messages */
  2581   if (priv->avg_rate >= 0.0) {
  1917   if (priv->avg_rate >= 0.0) {
  2582     /* if we have a valid rate, start sending QoS messages */
       
  2583     if (priv->current_jitter < 0) {
       
  2584       /* make sure we never go below 0 when adding the jitter to the
       
  2585        * timestamp. */
       
  2586       if (priv->current_rstart < -priv->current_jitter)
       
  2587         priv->current_jitter = -priv->current_rstart;
       
  2588     }
       
  2589     gst_base_sink_send_qos (sink, priv->avg_rate, priv->current_rstart,
  1918     gst_base_sink_send_qos (sink, priv->avg_rate, priv->current_rstart,
  2590         priv->current_jitter);
  1919         priv->current_jitter);
  2591   }
  1920   }
  2592 
  1921 
  2593   /* record when this buffer will leave us */
  1922   /* record when this buffer will leave us */
  2659   else
  1988   else
  2660     max_lateness += start;
  1989     max_lateness += start;
  2661 
  1990 
  2662   /* if the jitter bigger than duration and lateness we are too late */
  1991   /* if the jitter bigger than duration and lateness we are too late */
  2663   if ((late = start + jitter > max_lateness)) {
  1992   if ((late = start + jitter > max_lateness)) {
  2664     GST_CAT_DEBUG_OBJECT (GST_CAT_PERFORMANCE, basesink,
  1993     GST_DEBUG_OBJECT (basesink, "buffer is too late %" GST_TIME_FORMAT
  2665         "buffer is too late %" GST_TIME_FORMAT
       
  2666         " > %" GST_TIME_FORMAT, GST_TIME_ARGS (start + jitter),
  1994         " > %" GST_TIME_FORMAT, GST_TIME_ARGS (start + jitter),
  2667         GST_TIME_ARGS (max_lateness));
  1995         GST_TIME_ARGS (max_lateness));
  2668     /* !!emergency!!, if we did not receive anything valid for more than a 
  1996     /* !!emergency!!, if we did not receive anything valid for more than a 
  2669      * second, render it anyway so the user sees something */
  1997      * second, render it anyway so the user sees something */
  2670     if (priv->last_in_time != -1 && start - priv->last_in_time > GST_SECOND) {
  1998     if (priv->last_in_time && start - priv->last_in_time > GST_SECOND) {
  2671       late = FALSE;
  1999       late = FALSE;
  2672       GST_ELEMENT_WARNING (basesink, CORE, CLOCK,
  2000       GST_DEBUG_OBJECT (basesink,
  2673           (_("A lot of buffers are being dropped.")),
       
  2674           ("There may be a timestamping problem, or this computer is too slow."));
       
  2675       GST_CAT_DEBUG_OBJECT (GST_CAT_PERFORMANCE, basesink,
       
  2676           "**emergency** last buffer at %" GST_TIME_FORMAT " > GST_SECOND",
  2001           "**emergency** last buffer at %" GST_TIME_FORMAT " > GST_SECOND",
  2677           GST_TIME_ARGS (priv->last_in_time));
  2002           GST_TIME_ARGS (priv->last_in_time));
  2678     }
  2003     }
  2679   }
  2004   }
  2680 
  2005 
  2705     GST_DEBUG_OBJECT (basesink, "buffer has no timestamp");
  2030     GST_DEBUG_OBJECT (basesink, "buffer has no timestamp");
  2706     return FALSE;
  2031     return FALSE;
  2707   }
  2032   }
  2708 }
  2033 }
  2709 
  2034 
  2710 /* called before and after calling the render vmethod. It keeps track of how
       
  2711  * much time was spent in the render method and is used to check if we are
       
  2712  * flooded */
       
  2713 static void
  2035 static void
  2714 gst_base_sink_do_render_stats (GstBaseSink * basesink, gboolean start)
  2036 gst_base_sink_do_render_stats (GstBaseSink * basesink, gboolean start)
  2715 {
  2037 {
  2716   GstBaseSinkPrivate *priv;
  2038   GstBaseSinkPrivate *priv;
  2717 
  2039 
  2742  *
  2064  *
  2743  * takes ownership of obj.
  2065  * takes ownership of obj.
  2744  */
  2066  */
  2745 static GstFlowReturn
  2067 static GstFlowReturn
  2746 gst_base_sink_render_object (GstBaseSink * basesink, GstPad * pad,
  2068 gst_base_sink_render_object (GstBaseSink * basesink, GstPad * pad,
  2747     gboolean is_list, gpointer obj)
  2069     GstMiniObject * obj)
  2748 {
  2070 {
  2749   GstFlowReturn ret;
  2071   GstFlowReturn ret = GST_FLOW_OK;
  2750   GstBaseSinkClass *bclass;
  2072   GstBaseSinkClass *bclass;
  2751   gboolean late, step_end;
  2073   gboolean late = FALSE;
  2752   gpointer sync_obj;
       
  2753 
       
  2754   GstBaseSinkPrivate *priv;
  2074   GstBaseSinkPrivate *priv;
  2755 
  2075 
  2756   priv = basesink->priv;
  2076   priv = basesink->priv;
  2757 
       
  2758   if (is_list) {
       
  2759     /*
       
  2760      * If buffer list, use the first group buffer within the list
       
  2761      * for syncing
       
  2762      */
       
  2763     sync_obj = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0, 0);
       
  2764     g_assert (NULL != sync_obj);
       
  2765   } else {
       
  2766     sync_obj = obj;
       
  2767   }
       
  2768 
       
  2769 again:
       
  2770   late = FALSE;
       
  2771   step_end = FALSE;
       
  2772   ret = GST_FLOW_OK;
       
  2773 
  2077 
  2774   /* synchronize this object, non syncable objects return OK
  2078   /* synchronize this object, non syncable objects return OK
  2775    * immediatly. */
  2079    * immediatly. */
  2776   ret = gst_base_sink_do_sync (basesink, pad, sync_obj, &late, &step_end);
  2080   ret = gst_base_sink_do_sync (basesink, pad, obj, &late);
  2777   if (G_UNLIKELY (ret != GST_FLOW_OK))
  2081   if (G_UNLIKELY (ret != GST_FLOW_OK))
  2778     goto sync_failed;
  2082     goto sync_failed;
  2779 
  2083 
  2780   /* and now render, event or buffer/buffer list. */
  2084   /* and now render, event or buffer. */
  2781   if (G_LIKELY (is_list || GST_IS_BUFFER (obj))) {
  2085   if (G_LIKELY (GST_IS_BUFFER (obj))) {
       
  2086     GstBuffer *buf;
       
  2087 
  2782     /* drop late buffers unconditionally, let's hope it's unlikely */
  2088     /* drop late buffers unconditionally, let's hope it's unlikely */
  2783     if (G_UNLIKELY (late))
  2089     if (G_UNLIKELY (late))
  2784       goto dropped;
  2090       goto dropped;
  2785 
  2091 
       
  2092     buf = GST_BUFFER_CAST (obj);
       
  2093 
       
  2094     gst_base_sink_set_last_buffer (basesink, buf);
       
  2095 
  2786     bclass = GST_BASE_SINK_GET_CLASS (basesink);
  2096     bclass = GST_BASE_SINK_GET_CLASS (basesink);
  2787 
  2097 
  2788     if (G_LIKELY ((is_list && bclass->render_list) ||
  2098     if (G_LIKELY (bclass->render)) {
  2789             (!is_list && bclass->render))) {
       
  2790       gint do_qos;
  2099       gint do_qos;
  2791 
  2100 
  2792       /* read once, to get same value before and after */
  2101       /* read once, to get same value before and after */
  2793       do_qos = g_atomic_int_get (&priv->qos_enabled);
  2102       do_qos = g_atomic_int_get (&priv->qos_enabled);
  2794 
  2103 
  2795       GST_DEBUG_OBJECT (basesink, "rendering object %p", obj);
  2104       GST_DEBUG_OBJECT (basesink, "rendering buffer %p", obj);
  2796 
  2105 
  2797       /* record rendering time for QoS and stats */
  2106       /* record rendering time for QoS and stats */
  2798       if (do_qos)
  2107       if (do_qos)
  2799         gst_base_sink_do_render_stats (basesink, TRUE);
  2108         gst_base_sink_do_render_stats (basesink, TRUE);
  2800 
  2109 
  2801       if (!is_list) {
  2110       ret = bclass->render (basesink, buf);
  2802         GstBuffer *buf;
  2111 
  2803 
  2112       priv->rendered++;
  2804         /* For buffer lists do not set last buffer. Creating buffer
       
  2805          * with meaningful data can be done only with memcpy which will
       
  2806          * significantly affect performance */
       
  2807         buf = GST_BUFFER_CAST (obj);
       
  2808         gst_base_sink_set_last_buffer (basesink, buf);
       
  2809 
       
  2810         ret = bclass->render (basesink, buf);
       
  2811       } else {
       
  2812         GstBufferList *buflist;
       
  2813 
       
  2814         buflist = GST_BUFFER_LIST_CAST (obj);
       
  2815 
       
  2816         ret = bclass->render_list (basesink, buflist);
       
  2817       }
       
  2818 
  2113 
  2819       if (do_qos)
  2114       if (do_qos)
  2820         gst_base_sink_do_render_stats (basesink, FALSE);
  2115         gst_base_sink_do_render_stats (basesink, FALSE);
  2821 
       
  2822       if (ret == GST_FLOW_STEP)
       
  2823         goto again;
       
  2824 
       
  2825       if (G_UNLIKELY (basesink->flushing))
       
  2826         goto flushing;
       
  2827 
       
  2828       priv->rendered++;
       
  2829     }
  2116     }
  2830   } else {
  2117   } else {
  2831     GstEvent *event = GST_EVENT_CAST (obj);
  2118     GstEvent *event = GST_EVENT_CAST (obj);
  2832     gboolean event_res = TRUE;
  2119     gboolean event_res = TRUE;
  2833     GstEventType type;
  2120     GstEventType type;
  2840         gst_event_type_get_name (type));
  2127         gst_event_type_get_name (type));
  2841 
  2128 
  2842     if (bclass->event)
  2129     if (bclass->event)
  2843       event_res = bclass->event (basesink, event);
  2130       event_res = bclass->event (basesink, event);
  2844 
  2131 
  2845     /* when we get here we could be flushing again when the event handler calls
       
  2846      * _wait_eos(). We have to ignore this object in that case. */
       
  2847     if (G_UNLIKELY (basesink->flushing))
       
  2848       goto flushing;
       
  2849 
       
  2850     if (G_LIKELY (event_res)) {
  2132     if (G_LIKELY (event_res)) {
  2851       guint32 seqnum;
       
  2852 
       
  2853       seqnum = basesink->priv->seqnum = gst_event_get_seqnum (event);
       
  2854       GST_DEBUG_OBJECT (basesink, "Got seqnum #%" G_GUINT32_FORMAT, seqnum);
       
  2855 
       
  2856       switch (type) {
  2133       switch (type) {
  2857         case GST_EVENT_EOS:
  2134         case GST_EVENT_EOS:
  2858         {
       
  2859           GstMessage *message;
       
  2860 
       
  2861           /* the EOS event is completely handled so we mark
  2135           /* the EOS event is completely handled so we mark
  2862            * ourselves as being in the EOS state. eos is also 
  2136            * ourselves as being in the EOS state. eos is also 
  2863            * protected by the object lock so we can read it when 
  2137            * protected by the object lock so we can read it when 
  2864            * answering the POSITION query. */
  2138            * answering the POSITION query. */
  2865           GST_OBJECT_LOCK (basesink);
  2139           GST_OBJECT_LOCK (basesink);
  2866           basesink->eos = TRUE;
  2140           basesink->eos = TRUE;
  2867           GST_OBJECT_UNLOCK (basesink);
  2141           GST_OBJECT_UNLOCK (basesink);
  2868 
       
  2869           /* ok, now we can post the message */
  2142           /* ok, now we can post the message */
  2870           GST_DEBUG_OBJECT (basesink, "Now posting EOS");
  2143           GST_DEBUG_OBJECT (basesink, "Now posting EOS");
  2871 
  2144           gst_element_post_message (GST_ELEMENT_CAST (basesink),
  2872           message = gst_message_new_eos (GST_OBJECT_CAST (basesink));
  2145               gst_message_new_eos (GST_OBJECT_CAST (basesink)));
  2873           gst_message_set_seqnum (message, seqnum);
       
  2874           gst_element_post_message (GST_ELEMENT_CAST (basesink), message);
       
  2875           break;
  2146           break;
  2876         }
       
  2877         case GST_EVENT_NEWSEGMENT:
  2147         case GST_EVENT_NEWSEGMENT:
  2878           /* configure the segment */
  2148           /* configure the segment */
  2879           gst_base_sink_configure_segment (basesink, pad, event,
  2149           gst_base_sink_configure_segment (basesink, pad, event,
  2880               &basesink->segment);
  2150               &basesink->segment);
  2881           break;
  2151           break;
  2884       }
  2154       }
  2885     }
  2155     }
  2886   }
  2156   }
  2887 
  2157 
  2888 done:
  2158 done:
  2889   if (step_end) {
       
  2890     /* the step ended, check if we need to activate a new step */
       
  2891     GST_DEBUG_OBJECT (basesink, "step ended");
       
  2892     stop_stepping (basesink, &basesink->segment, &priv->current_step,
       
  2893         priv->current_rstart, priv->current_rstop, basesink->eos);
       
  2894     goto again;
       
  2895   }
       
  2896 
       
  2897   gst_base_sink_perform_qos (basesink, late);
  2159   gst_base_sink_perform_qos (basesink, late);
  2898 
  2160 
  2899   GST_DEBUG_OBJECT (basesink, "object unref after render %p", obj);
  2161   GST_DEBUG_OBJECT (basesink, "object unref after render %p", obj);
  2900   gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
  2162   gst_mini_object_unref (obj);
       
  2163 
  2901   return ret;
  2164   return ret;
  2902 
  2165 
  2903   /* ERRORS */
  2166   /* ERRORS */
  2904 sync_failed:
  2167 sync_failed:
  2905   {
  2168   {
  2910   {
  2173   {
  2911     priv->dropped++;
  2174     priv->dropped++;
  2912     GST_DEBUG_OBJECT (basesink, "buffer late, dropping");
  2175     GST_DEBUG_OBJECT (basesink, "buffer late, dropping");
  2913     goto done;
  2176     goto done;
  2914   }
  2177   }
  2915 flushing:
       
  2916   {
       
  2917     GST_DEBUG_OBJECT (basesink, "we are flushing, ignore object");
       
  2918     gst_mini_object_unref (obj);
       
  2919     return GST_FLOW_WRONG_STATE;
       
  2920   }
       
  2921 }
  2178 }
  2922 
  2179 
  2923 /* with STREAM_LOCK, PREROLL_LOCK
  2180 /* with STREAM_LOCK, PREROLL_LOCK
  2924  *
  2181  *
  2925  * Perform preroll on the given object. For buffers this means 
  2182  * Perform preroll on the given object. For buffers this means 
  2927  * If that succeeds, the state will be commited.
  2184  * If that succeeds, the state will be commited.
  2928  *
  2185  *
  2929  * function does not take ownership of obj.
  2186  * function does not take ownership of obj.
  2930  */
  2187  */
  2931 static GstFlowReturn
  2188 static GstFlowReturn
  2932 gst_base_sink_preroll_object (GstBaseSink * basesink, gboolean is_list,
  2189 gst_base_sink_preroll_object (GstBaseSink * basesink, GstPad * pad,
  2933     GstMiniObject * obj)
  2190     GstMiniObject * obj)
  2934 {
  2191 {
  2935   GstFlowReturn ret;
  2192   GstFlowReturn ret;
  2936 
  2193 
  2937   GST_DEBUG_OBJECT (basesink, "prerolling object %p", obj);
  2194   GST_DEBUG_OBJECT (basesink, "do preroll %p", obj);
  2938 
  2195 
  2939   /* if it's a buffer, we need to call the preroll method */
  2196   /* if it's a buffer, we need to call the preroll method */
  2940   if (G_LIKELY (is_list || GST_IS_BUFFER (obj)) && basesink->priv->call_preroll) {
  2197   if (G_LIKELY (GST_IS_BUFFER (obj))) {
  2941     GstBaseSinkClass *bclass;
  2198     GstBaseSinkClass *bclass;
  2942     GstBuffer *buf;
  2199     GstBuffer *buf;
  2943     GstClockTime timestamp;
  2200     GstClockTime timestamp;
  2944 
  2201 
  2945     if (is_list) {
  2202     buf = GST_BUFFER_CAST (obj);
  2946       buf = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0, 0);
       
  2947       g_assert (NULL != buf);
       
  2948     } else {
       
  2949       buf = GST_BUFFER_CAST (obj);
       
  2950     }
       
  2951 
       
  2952     timestamp = GST_BUFFER_TIMESTAMP (buf);
  2203     timestamp = GST_BUFFER_TIMESTAMP (buf);
  2953 
  2204 
  2954     GST_DEBUG_OBJECT (basesink, "preroll buffer %" GST_TIME_FORMAT,
  2205     GST_DEBUG_OBJECT (basesink, "preroll buffer %" GST_TIME_FORMAT,
  2955         GST_TIME_ARGS (timestamp));
  2206         GST_TIME_ARGS (timestamp));
  2956 
  2207 
  2957     /*
  2208     gst_base_sink_set_last_buffer (basesink, buf);
  2958      * For buffer lists do not set last buffer. Creating buffer
       
  2959      * with meaningful data can be done only with memcpy which will
       
  2960      * significantly affect performance
       
  2961      */
       
  2962     if (!is_list) {
       
  2963       gst_base_sink_set_last_buffer (basesink, buf);
       
  2964     }
       
  2965 
  2209 
  2966     bclass = GST_BASE_SINK_GET_CLASS (basesink);
  2210     bclass = GST_BASE_SINK_GET_CLASS (basesink);
  2967     if (bclass->preroll)
  2211     if (bclass->preroll)
  2968       if ((ret = bclass->preroll (basesink, buf)) != GST_FLOW_OK)
  2212       if ((ret = bclass->preroll (basesink, buf)) != GST_FLOW_OK)
  2969         goto preroll_failed;
  2213         goto preroll_failed;
  2970 
       
  2971     basesink->priv->call_preroll = FALSE;
       
  2972   }
  2214   }
  2973 
  2215 
  2974   /* commit state */
  2216   /* commit state */
  2975   if (G_LIKELY (basesink->playing_async)) {
  2217   if (G_LIKELY (basesink->playing_async)) {
  2976     if (G_UNLIKELY (!gst_base_sink_commit_state (basesink)))
  2218     if (G_UNLIKELY (!gst_base_sink_commit_state (basesink)))
  3001  *
  2243  *
  3002  * This function takes ownership of the object.
  2244  * This function takes ownership of the object.
  3003  */
  2245  */
  3004 static GstFlowReturn
  2246 static GstFlowReturn
  3005 gst_base_sink_queue_object_unlocked (GstBaseSink * basesink, GstPad * pad,
  2247 gst_base_sink_queue_object_unlocked (GstBaseSink * basesink, GstPad * pad,
  3006     gboolean is_list, gpointer obj, gboolean prerollable)
  2248     GstMiniObject * obj, gboolean prerollable)
  3007 {
  2249 {
  3008   GstFlowReturn ret = GST_FLOW_OK;
  2250   GstFlowReturn ret = GST_FLOW_OK;
  3009   gint length;
  2251   gint length;
  3010   GQueue *q;
  2252   GQueue *q;
  3011 
  2253 
  3017 
  2259 
  3018     GST_DEBUG_OBJECT (basesink, "now %d prerolled items", length);
  2260     GST_DEBUG_OBJECT (basesink, "now %d prerolled items", length);
  3019 
  2261 
  3020     /* first prerollable item needs to finish the preroll */
  2262     /* first prerollable item needs to finish the preroll */
  3021     if (length == 1) {
  2263     if (length == 1) {
  3022       ret = gst_base_sink_preroll_object (basesink, is_list, obj);
  2264       ret = gst_base_sink_preroll_object (basesink, pad, obj);
  3023       if (G_UNLIKELY (ret != GST_FLOW_OK))
  2265       if (G_UNLIKELY (ret != GST_FLOW_OK))
  3024         goto preroll_failed;
  2266         goto preroll_failed;
  3025     }
  2267     }
  3026     /* need to recheck if we need preroll, commmit state during preroll 
  2268     /* need to recheck if we need preroll, commmit state during preroll 
  3027      * could have made us not need more preroll. */
  2269      * could have made us not need more preroll. */
  3030        * queue. */
  2272        * queue. */
  3031       if (G_UNLIKELY (length <= basesink->preroll_queue_max_len))
  2273       if (G_UNLIKELY (length <= basesink->preroll_queue_max_len))
  3032         goto more_preroll;
  2274         goto more_preroll;
  3033     }
  2275     }
  3034   }
  2276   }
       
  2277 
  3035   /* we can start rendering (or blocking) the queued object
  2278   /* we can start rendering (or blocking) the queued object
  3036    * if any. */
  2279    * if any. */
  3037   q = basesink->preroll_queue;
  2280   q = basesink->preroll_queue;
  3038   while (G_UNLIKELY (!g_queue_is_empty (q))) {
  2281   while (G_UNLIKELY (!g_queue_is_empty (q))) {
  3039     GstMiniObject *o;
  2282     GstMiniObject *o;
  3040 
  2283 
  3041     o = g_queue_pop_head (q);
  2284     o = g_queue_pop_head (q);
  3042     GST_DEBUG_OBJECT (basesink, "rendering queued object %p", o);
  2285     GST_DEBUG_OBJECT (basesink, "rendering queued object %p", o);
  3043 
  2286 
  3044     /* do something with the return value */
  2287     /* do something with the return value */
  3045     ret = gst_base_sink_render_object (basesink, pad, FALSE, o);
  2288     ret = gst_base_sink_render_object (basesink, pad, o);
  3046     if (ret != GST_FLOW_OK)
  2289     if (ret != GST_FLOW_OK)
  3047       goto dequeue_failed;
  2290       goto dequeue_failed;
  3048   }
  2291   }
  3049 
  2292 
  3050   /* now render the object */
  2293   /* now render the object */
  3051   ret = gst_base_sink_render_object (basesink, pad, is_list, obj);
  2294   ret = gst_base_sink_render_object (basesink, pad, obj);
  3052   basesink->preroll_queued = 0;
  2295   basesink->preroll_queued = 0;
  3053 
  2296 
  3054   return ret;
  2297   return ret;
  3055 
  2298 
  3056   /* special cases */
  2299   /* special cases */
  3057 preroll_failed:
  2300 preroll_failed:
  3058   {
  2301   {
  3059     GST_DEBUG_OBJECT (basesink, "preroll failed, reason %s",
  2302     GST_DEBUG_OBJECT (basesink, "preroll failed, reason %s",
  3060         gst_flow_get_name (ret));
  2303         gst_flow_get_name (ret));
  3061     gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
  2304     gst_mini_object_unref (obj);
  3062     return ret;
  2305     return ret;
  3063   }
  2306   }
  3064 more_preroll:
  2307 more_preroll:
  3065   {
  2308   {
  3066     /* add object to the queue and return */
  2309     /* add object to the queue and return */
  3071   }
  2314   }
  3072 dequeue_failed:
  2315 dequeue_failed:
  3073   {
  2316   {
  3074     GST_DEBUG_OBJECT (basesink, "rendering queued objects failed, reason %s",
  2317     GST_DEBUG_OBJECT (basesink, "rendering queued objects failed, reason %s",
  3075         gst_flow_get_name (ret));
  2318         gst_flow_get_name (ret));
  3076     gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
  2319     gst_mini_object_unref (obj);
  3077     return ret;
  2320     return ret;
  3078   }
  2321   }
  3079 }
  2322 }
  3080 
  2323 
  3081 /* with STREAM_LOCK
  2324 /* with STREAM_LOCK
  3096     goto flushing;
  2339     goto flushing;
  3097 
  2340 
  3098   if (G_UNLIKELY (basesink->priv->received_eos))
  2341   if (G_UNLIKELY (basesink->priv->received_eos))
  3099     goto was_eos;
  2342     goto was_eos;
  3100 
  2343 
  3101   ret =
  2344   ret = gst_base_sink_queue_object_unlocked (basesink, pad, obj, prerollable);
  3102       gst_base_sink_queue_object_unlocked (basesink, pad, FALSE, obj,
       
  3103       prerollable);
       
  3104   GST_PAD_PREROLL_UNLOCK (pad);
  2345   GST_PAD_PREROLL_UNLOCK (pad);
  3105 
  2346 
  3106   return ret;
  2347   return ret;
  3107 
  2348 
  3108   /* ERRORS */
  2349   /* ERRORS */
  3119         "we are EOS, dropping object, return UNEXPECTED");
  2360         "we are EOS, dropping object, return UNEXPECTED");
  3120     GST_PAD_PREROLL_UNLOCK (pad);
  2361     GST_PAD_PREROLL_UNLOCK (pad);
  3121     gst_mini_object_unref (obj);
  2362     gst_mini_object_unref (obj);
  3122     return GST_FLOW_UNEXPECTED;
  2363     return GST_FLOW_UNEXPECTED;
  3123   }
  2364   }
  3124 }
       
  3125 
       
  3126 static void
       
  3127 gst_base_sink_flush_start (GstBaseSink * basesink, GstPad * pad)
       
  3128 {
       
  3129   /* make sure we are not blocked on the clock also clear any pending
       
  3130    * eos state. */
       
  3131   gst_base_sink_set_flushing (basesink, pad, TRUE);
       
  3132 
       
  3133   /* we grab the stream lock but that is not needed since setting the
       
  3134    * sink to flushing would make sure no state commit is being done
       
  3135    * anymore */
       
  3136   GST_PAD_STREAM_LOCK (pad);
       
  3137   gst_base_sink_reset_qos (basesink);
       
  3138   if (basesink->priv->async_enabled) {
       
  3139     /* and we need to commit our state again on the next
       
  3140      * prerolled buffer */
       
  3141     basesink->playing_async = TRUE;
       
  3142     gst_element_lost_state (GST_ELEMENT_CAST (basesink));
       
  3143   } else {
       
  3144     basesink->priv->have_latency = TRUE;
       
  3145     basesink->need_preroll = FALSE;
       
  3146   }
       
  3147   gst_base_sink_set_last_buffer (basesink, NULL);
       
  3148   GST_PAD_STREAM_UNLOCK (pad);
       
  3149 }
       
  3150 
       
  3151 static void
       
  3152 gst_base_sink_flush_stop (GstBaseSink * basesink, GstPad * pad)
       
  3153 {
       
  3154   /* unset flushing so we can accept new data, this also flushes out any EOS
       
  3155    * event. */
       
  3156   gst_base_sink_set_flushing (basesink, pad, FALSE);
       
  3157 
       
  3158   /* for position reporting */
       
  3159   GST_OBJECT_LOCK (basesink);
       
  3160   basesink->priv->current_sstart = -1;
       
  3161   basesink->priv->current_sstop = -1;
       
  3162   basesink->priv->eos_rtime = -1;
       
  3163   basesink->priv->call_preroll = TRUE;
       
  3164   basesink->priv->current_step.valid = FALSE;
       
  3165   basesink->priv->pending_step.valid = FALSE;
       
  3166   if (basesink->pad_mode == GST_ACTIVATE_PUSH) {
       
  3167     /* we need new segment info after the flush. */
       
  3168     basesink->have_newsegment = FALSE;
       
  3169     gst_segment_init (&basesink->segment, GST_FORMAT_UNDEFINED);
       
  3170     gst_segment_init (basesink->abidata.ABI.clip_segment, GST_FORMAT_UNDEFINED);
       
  3171   }
       
  3172   GST_OBJECT_UNLOCK (basesink);
       
  3173 }
  2365 }
  3174 
  2366 
  3175 static gboolean
  2367 static gboolean
  3176 gst_base_sink_event (GstPad * pad, GstEvent * event)
  2368 gst_base_sink_event (GstPad * pad, GstEvent * event)
  3177 {
  2369 {
  3199         /* we can't accept anything when we are EOS */
  2391         /* we can't accept anything when we are EOS */
  3200         result = FALSE;
  2392         result = FALSE;
  3201         gst_event_unref (event);
  2393         gst_event_unref (event);
  3202       } else {
  2394       } else {
  3203         /* we set the received EOS flag here so that we can use it when testing if
  2395         /* we set the received EOS flag here so that we can use it when testing if
  3204          * we are prerolled and to refuse more buffers. */
  2396          * we are prerolled and to refure more buffers. */
  3205         basesink->priv->received_eos = TRUE;
  2397         basesink->priv->received_eos = TRUE;
  3206 
  2398 
  3207         /* EOS is a prerollable object, we call the unlocked version because it
  2399         /* EOS is a prerollable object, we call the unlocked version because it
  3208          * does not check the received_eos flag. */
  2400          * does not check the received_eos flag. */
  3209         ret = gst_base_sink_queue_object_unlocked (basesink, pad,
  2401         ret = gst_base_sink_queue_object_unlocked (basesink, pad,
  3210             FALSE, GST_MINI_OBJECT_CAST (event), TRUE);
  2402             GST_MINI_OBJECT_CAST (event), TRUE);
  3211         if (G_UNLIKELY (ret != GST_FLOW_OK))
  2403         if (G_UNLIKELY (ret != GST_FLOW_OK))
  3212           result = FALSE;
  2404           result = FALSE;
  3213       }
  2405       }
  3214       GST_PAD_PREROLL_UNLOCK (pad);
  2406       GST_PAD_PREROLL_UNLOCK (pad);
  3215       break;
  2407       break;
  3235         gst_base_sink_configure_segment (basesink, pad, event,
  2427         gst_base_sink_configure_segment (basesink, pad, event,
  3236             basesink->abidata.ABI.clip_segment);
  2428             basesink->abidata.ABI.clip_segment);
  3237 
  2429 
  3238         ret =
  2430         ret =
  3239             gst_base_sink_queue_object_unlocked (basesink, pad,
  2431             gst_base_sink_queue_object_unlocked (basesink, pad,
  3240             FALSE, GST_MINI_OBJECT_CAST (event), FALSE);
  2432             GST_MINI_OBJECT_CAST (event), FALSE);
  3241         if (G_UNLIKELY (ret != GST_FLOW_OK))
  2433         if (G_UNLIKELY (ret != GST_FLOW_OK))
  3242           result = FALSE;
  2434           result = FALSE;
  3243         else {
  2435         else
  3244           GST_OBJECT_LOCK (basesink);
       
  3245           basesink->have_newsegment = TRUE;
  2436           basesink->have_newsegment = TRUE;
  3246           GST_OBJECT_UNLOCK (basesink);
       
  3247         }
       
  3248       }
  2437       }
  3249       GST_PAD_PREROLL_UNLOCK (pad);
  2438       GST_PAD_PREROLL_UNLOCK (pad);
  3250       break;
  2439       break;
  3251     }
  2440     }
  3252     case GST_EVENT_FLUSH_START:
  2441     case GST_EVENT_FLUSH_START:
  3253       if (bclass->event)
  2442       if (bclass->event)
  3254         bclass->event (basesink, event);
  2443         bclass->event (basesink, event);
  3255 
  2444 
  3256       GST_DEBUG_OBJECT (basesink, "flush-start %p", event);
  2445       GST_DEBUG_OBJECT (basesink, "flush-start %p", event);
  3257 
  2446 
  3258       gst_base_sink_flush_start (basesink, pad);
  2447       /* make sure we are not blocked on the clock also clear any pending
       
  2448        * eos state. */
       
  2449       gst_base_sink_set_flushing (basesink, pad, TRUE);
       
  2450 
       
  2451       /* we grab the stream lock but that is not needed since setting the
       
  2452        * sink to flushing would make sure no state commit is being done
       
  2453        * anymore */
       
  2454       GST_PAD_STREAM_LOCK (pad);
       
  2455       gst_base_sink_reset_qos (basesink);
       
  2456       if (basesink->priv->async_enabled) {
       
  2457         /* and we need to commit our state again on the next
       
  2458          * prerolled buffer */
       
  2459         basesink->playing_async = TRUE;
       
  2460         gst_element_lost_state (GST_ELEMENT_CAST (basesink));
       
  2461       } else {
       
  2462         basesink->priv->have_latency = TRUE;
       
  2463         basesink->need_preroll = FALSE;
       
  2464       }
       
  2465       gst_base_sink_set_last_buffer (basesink, NULL);
       
  2466       GST_PAD_STREAM_UNLOCK (pad);
  3259 
  2467 
  3260       gst_event_unref (event);
  2468       gst_event_unref (event);
  3261       break;
  2469       break;
  3262     case GST_EVENT_FLUSH_STOP:
  2470     case GST_EVENT_FLUSH_STOP:
  3263       if (bclass->event)
  2471       if (bclass->event)
  3264         bclass->event (basesink, event);
  2472         bclass->event (basesink, event);
  3265 
  2473 
  3266       GST_DEBUG_OBJECT (basesink, "flush-stop %p", event);
  2474       GST_DEBUG_OBJECT (basesink, "flush-stop %p", event);
  3267 
  2475 
  3268       gst_base_sink_flush_stop (basesink, pad);
  2476       /* unset flushing so we can accept new data, this also flushes out any EOS
       
  2477        * event. */
       
  2478       gst_base_sink_set_flushing (basesink, pad, FALSE);
       
  2479 
       
  2480       /* we need new segment info after the flush. */
       
  2481       gst_segment_init (&basesink->segment, GST_FORMAT_UNDEFINED);
       
  2482       gst_segment_init (basesink->abidata.ABI.clip_segment,
       
  2483           GST_FORMAT_UNDEFINED);
       
  2484       basesink->have_newsegment = FALSE;
       
  2485 
       
  2486       /* for position reporting */
       
  2487       GST_OBJECT_LOCK (basesink);
       
  2488       basesink->priv->current_sstart = -1;
       
  2489       basesink->priv->current_sstop = -1;
       
  2490       GST_OBJECT_UNLOCK (basesink);
  3269 
  2491 
  3270       gst_event_unref (event);
  2492       gst_event_unref (event);
  3271       break;
  2493       break;
  3272     default:
  2494     default:
  3273       /* other events are sent to queue or subclass depending on if they
  2495       /* other events are sent to queue or subclass depending on if they
  3328   /* we have 2 cases where the PREROLL_LOCK is released:
  2550   /* we have 2 cases where the PREROLL_LOCK is released:
  3329    *  1) we are blocking in the PREROLL_LOCK and thus are prerolled.
  2551    *  1) we are blocking in the PREROLL_LOCK and thus are prerolled.
  3330    *  2) we are syncing on the clock
  2552    *  2) we are syncing on the clock
  3331    */
  2553    */
  3332   is_prerolled = basesink->have_preroll || basesink->priv->received_eos;
  2554   is_prerolled = basesink->have_preroll || basesink->priv->received_eos;
  3333   res = !is_prerolled;
  2555   res = !is_prerolled && basesink->pad_mode != GST_ACTIVATE_PULL;
  3334 
       
  3335   GST_DEBUG_OBJECT (basesink, "have_preroll: %d, EOS: %d => needs preroll: %d",
  2556   GST_DEBUG_OBJECT (basesink, "have_preroll: %d, EOS: %d => needs preroll: %d",
  3336       basesink->have_preroll, basesink->priv->received_eos, res);
  2557       basesink->have_preroll, basesink->priv->received_eos, res);
  3337 
  2558 
  3338   return res;
  2559   return res;
  3339 }
  2560 }
  3346  *
  2567  *
  3347  * This function takes ownership of the buffer.
  2568  * This function takes ownership of the buffer.
  3348  */
  2569  */
  3349 static GstFlowReturn
  2570 static GstFlowReturn
  3350 gst_base_sink_chain_unlocked (GstBaseSink * basesink, GstPad * pad,
  2571 gst_base_sink_chain_unlocked (GstBaseSink * basesink, GstPad * pad,
  3351     gboolean is_list, gpointer obj)
  2572     GstBuffer * buf)
  3352 {
  2573 {
  3353   GstBaseSinkClass *bclass;
       
  3354   GstFlowReturn result;
  2574   GstFlowReturn result;
  3355   GstClockTime start = GST_CLOCK_TIME_NONE, end = GST_CLOCK_TIME_NONE;
  2575   GstClockTime start = GST_CLOCK_TIME_NONE, end = GST_CLOCK_TIME_NONE;
  3356   GstSegment *clip_segment;
  2576   GstSegment *clip_segment;
  3357   GstBuffer *time_buf;
       
  3358 
  2577 
  3359   if (G_UNLIKELY (basesink->flushing))
  2578   if (G_UNLIKELY (basesink->flushing))
  3360     goto flushing;
  2579     goto flushing;
  3361 
  2580 
  3362   if (G_UNLIKELY (basesink->priv->received_eos))
  2581   if (G_UNLIKELY (basesink->priv->received_eos))
  3363     goto was_eos;
  2582     goto was_eos;
  3364 
       
  3365   if (is_list) {
       
  3366     time_buf = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0, 0);
       
  3367     g_assert (NULL != time_buf);
       
  3368   } else {
       
  3369     time_buf = GST_BUFFER_CAST (obj);
       
  3370   }
       
  3371 
  2583 
  3372   /* for code clarity */
  2584   /* for code clarity */
  3373   clip_segment = basesink->abidata.ABI.clip_segment;
  2585   clip_segment = basesink->abidata.ABI.clip_segment;
  3374 
  2586 
  3375   if (G_UNLIKELY (!basesink->have_newsegment)) {
  2587   if (G_UNLIKELY (!basesink->have_newsegment)) {
  3380       GST_ELEMENT_WARNING (basesink, STREAM, FAILED,
  2592       GST_ELEMENT_WARNING (basesink, STREAM, FAILED,
  3381           (_("Internal data flow problem.")),
  2593           (_("Internal data flow problem.")),
  3382           ("Received buffer without a new-segment. Assuming timestamps start from 0."));
  2594           ("Received buffer without a new-segment. Assuming timestamps start from 0."));
  3383     }
  2595     }
  3384 
  2596 
       
  2597     basesink->have_newsegment = TRUE;
  3385     /* this means this sink will assume timestamps start from 0 */
  2598     /* this means this sink will assume timestamps start from 0 */
  3386     GST_OBJECT_LOCK (basesink);
       
  3387     clip_segment->start = 0;
  2599     clip_segment->start = 0;
  3388     clip_segment->stop = -1;
  2600     clip_segment->stop = -1;
  3389     basesink->segment.start = 0;
  2601     basesink->segment.start = 0;
  3390     basesink->segment.stop = -1;
  2602     basesink->segment.stop = -1;
  3391     basesink->have_newsegment = TRUE;
  2603   }
  3392     GST_OBJECT_UNLOCK (basesink);
  2604 
  3393   }
  2605   /* check if the buffer needs to be dropped */
  3394 
  2606   /* we don't use the subclassed method as it may not return
  3395   bclass = GST_BASE_SINK_GET_CLASS (basesink);
  2607    * valid values for our purpose here */
  3396 
  2608   gst_base_sink_get_times (basesink, buf, &start, &end);
  3397   /* check if the buffer needs to be dropped, we first ask the subclass for the
       
  3398    * start and end */
       
  3399   if (bclass->get_times)
       
  3400     bclass->get_times (basesink, time_buf, &start, &end);
       
  3401 
       
  3402   if (start == -1) {
       
  3403     /* if the subclass does not want sync, we use our own values so that we at
       
  3404      * least clip the buffer to the segment */
       
  3405     gst_base_sink_get_times (basesink, time_buf, &start, &end);
       
  3406   }
       
  3407 
  2609 
  3408   GST_DEBUG_OBJECT (basesink, "got times start: %" GST_TIME_FORMAT
  2610   GST_DEBUG_OBJECT (basesink, "got times start: %" GST_TIME_FORMAT
  3409       ", end: %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (end));
  2611       ", end: %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (end));
  3410 
  2612 
  3411   /* a dropped buffer does not participate in anything */
  2613   /* a dropped buffer does not participate in anything */
  3417   }
  2619   }
  3418 
  2620 
  3419   /* now we can process the buffer in the queue, this function takes ownership
  2621   /* now we can process the buffer in the queue, this function takes ownership
  3420    * of the buffer */
  2622    * of the buffer */
  3421   result = gst_base_sink_queue_object_unlocked (basesink, pad,
  2623   result = gst_base_sink_queue_object_unlocked (basesink, pad,
  3422       is_list, obj, TRUE);
  2624       GST_MINI_OBJECT_CAST (buf), TRUE);
       
  2625 
  3423   return result;
  2626   return result;
  3424 
  2627 
  3425   /* ERRORS */
  2628   /* ERRORS */
  3426 flushing:
  2629 flushing:
  3427   {
  2630   {
  3428     GST_DEBUG_OBJECT (basesink, "sink is flushing");
  2631     GST_DEBUG_OBJECT (basesink, "sink is flushing");
  3429     gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
  2632     gst_buffer_unref (buf);
  3430     return GST_FLOW_WRONG_STATE;
  2633     return GST_FLOW_WRONG_STATE;
  3431   }
  2634   }
  3432 was_eos:
  2635 was_eos:
  3433   {
  2636   {
  3434     GST_DEBUG_OBJECT (basesink,
  2637     GST_DEBUG_OBJECT (basesink,
  3435         "we are EOS, dropping object, return UNEXPECTED");
  2638         "we are EOS, dropping object, return UNEXPECTED");
  3436     gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
  2639     gst_buffer_unref (buf);
  3437     return GST_FLOW_UNEXPECTED;
  2640     return GST_FLOW_UNEXPECTED;
  3438   }
  2641   }
  3439 out_of_segment:
  2642 out_of_segment:
  3440   {
  2643   {
  3441     GST_DEBUG_OBJECT (basesink, "dropping buffer, out of clipping segment");
  2644     GST_DEBUG_OBJECT (basesink, "dropping buffer, out of clipping segment");
  3442     gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
  2645     gst_buffer_unref (buf);
  3443     return GST_FLOW_OK;
  2646     return GST_FLOW_OK;
  3444   }
  2647   }
  3445 }
  2648 }
  3446 
  2649 
  3447 /* with STREAM_LOCK
  2650 /* with STREAM_LOCK
  3448  */
  2651  */
  3449 static GstFlowReturn
  2652 static GstFlowReturn
  3450 gst_base_sink_chain_main (GstBaseSink * basesink, GstPad * pad,
  2653 gst_base_sink_chain (GstPad * pad, GstBuffer * buf)
  3451     gboolean is_list, gpointer obj)
  2654 {
  3452 {
  2655   GstBaseSink *basesink;
  3453   GstFlowReturn result;
  2656   GstFlowReturn result;
       
  2657 
       
  2658   basesink = GST_BASE_SINK (GST_OBJECT_PARENT (pad));
  3454 
  2659 
  3455   if (G_UNLIKELY (basesink->pad_mode != GST_ACTIVATE_PUSH))
  2660   if (G_UNLIKELY (basesink->pad_mode != GST_ACTIVATE_PUSH))
  3456     goto wrong_mode;
  2661     goto wrong_mode;
  3457 
  2662 
  3458   GST_PAD_PREROLL_LOCK (pad);
  2663   GST_PAD_PREROLL_LOCK (pad);
  3459   result = gst_base_sink_chain_unlocked (basesink, pad, is_list, obj);
  2664   result = gst_base_sink_chain_unlocked (basesink, pad, buf);
  3460   GST_PAD_PREROLL_UNLOCK (pad);
  2665   GST_PAD_PREROLL_UNLOCK (pad);
  3461 
  2666 
  3462 done:
  2667 done:
  3463   return result;
  2668   return result;
  3464 
  2669 
  3468     GST_OBJECT_LOCK (pad);
  2673     GST_OBJECT_LOCK (pad);
  3469     GST_WARNING_OBJECT (basesink,
  2674     GST_WARNING_OBJECT (basesink,
  3470         "Push on pad %s:%s, but it was not activated in push mode",
  2675         "Push on pad %s:%s, but it was not activated in push mode",
  3471         GST_DEBUG_PAD_NAME (pad));
  2676         GST_DEBUG_PAD_NAME (pad));
  3472     GST_OBJECT_UNLOCK (pad);
  2677     GST_OBJECT_UNLOCK (pad);
  3473     gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
  2678     gst_buffer_unref (buf);
  3474     /* we don't post an error message this will signal to the peer
  2679     /* we don't post an error message this will signal to the peer
  3475      * pushing that EOS is reached. */
  2680      * pushing that EOS is reached. */
  3476     result = GST_FLOW_UNEXPECTED;
  2681     result = GST_FLOW_UNEXPECTED;
  3477     goto done;
  2682     goto done;
  3478   }
  2683   }
  3479 }
  2684 }
  3480 
  2685 
  3481 static GstFlowReturn
       
  3482 gst_base_sink_chain (GstPad * pad, GstBuffer * buf)
       
  3483 {
       
  3484   GstBaseSink *basesink;
       
  3485 
       
  3486   basesink = GST_BASE_SINK (GST_OBJECT_PARENT (pad));
       
  3487 
       
  3488   return gst_base_sink_chain_main (basesink, pad, FALSE, buf);
       
  3489 }
       
  3490 
       
  3491 static GstFlowReturn
       
  3492 gst_base_sink_chain_list (GstPad * pad, GstBufferList * list)
       
  3493 {
       
  3494   GstBaseSink *basesink;
       
  3495   GstBaseSinkClass *bclass;
       
  3496   GstFlowReturn result;
       
  3497 
       
  3498   basesink = GST_BASE_SINK (GST_OBJECT_PARENT (pad));
       
  3499   bclass = GST_BASE_SINK_GET_CLASS (basesink);
       
  3500 
       
  3501   if (G_LIKELY (bclass->render_list)) {
       
  3502     result = gst_base_sink_chain_main (basesink, pad, TRUE, list);
       
  3503   } else {
       
  3504     GstBufferListIterator *it;
       
  3505     GstBuffer *group;
       
  3506 
       
  3507     GST_INFO_OBJECT (pad, "chaining each group in list as a merged buffer");
       
  3508 
       
  3509     it = gst_buffer_list_iterate (list);
       
  3510 
       
  3511     result = GST_FLOW_OK;
       
  3512     if (gst_buffer_list_iterator_next_group (it)) {
       
  3513       do {
       
  3514         group = gst_buffer_list_iterator_merge_group (it);
       
  3515         if (group == NULL) {
       
  3516           group = gst_buffer_new ();
       
  3517           GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining empty group");
       
  3518         } else {
       
  3519           GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining group");
       
  3520         }
       
  3521         result = gst_base_sink_chain_main (basesink, pad, FALSE, group);
       
  3522       } while (result == GST_FLOW_OK
       
  3523           && gst_buffer_list_iterator_next_group (it));
       
  3524     } else {
       
  3525       GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining empty group");
       
  3526       result =
       
  3527           gst_base_sink_chain_main (basesink, pad, FALSE, gst_buffer_new ());
       
  3528     }
       
  3529     gst_buffer_list_iterator_free (it);
       
  3530     gst_buffer_list_unref (list);
       
  3531   }
       
  3532   return result;
       
  3533 }
       
  3534 
       
  3535 
       
  3536 static gboolean
       
  3537 gst_base_sink_default_do_seek (GstBaseSink * sink, GstSegment * segment)
       
  3538 {
       
  3539   gboolean res = TRUE;
       
  3540 
       
  3541   /* update our offset if the start/stop position was updated */
       
  3542   if (segment->format == GST_FORMAT_BYTES) {
       
  3543     segment->time = segment->start;
       
  3544   } else if (segment->start == 0) {
       
  3545     /* seek to start, we can implement a default for this. */
       
  3546     segment->time = 0;
       
  3547   } else {
       
  3548     res = FALSE;
       
  3549     GST_INFO_OBJECT (sink, "Can't do a default seek");
       
  3550   }
       
  3551 
       
  3552   return res;
       
  3553 }
       
  3554 
       
  3555 #define SEEK_TYPE_IS_RELATIVE(t) (((t) != GST_SEEK_TYPE_NONE) && ((t) != GST_SEEK_TYPE_SET))
       
  3556 
       
  3557 static gboolean
       
  3558 gst_base_sink_default_prepare_seek_segment (GstBaseSink * sink,
       
  3559     GstEvent * event, GstSegment * segment)
       
  3560 {
       
  3561   /* By default, we try one of 2 things:
       
  3562    *   - For absolute seek positions, convert the requested position to our 
       
  3563    *     configured processing format and place it in the output segment \
       
  3564    *   - For relative seek positions, convert our current (input) values to the
       
  3565    *     seek format, adjust by the relative seek offset and then convert back to
       
  3566    *     the processing format
       
  3567    */
       
  3568   GstSeekType cur_type, stop_type;
       
  3569   gint64 cur, stop;
       
  3570   GstSeekFlags flags;
       
  3571   GstFormat seek_format, dest_format;
       
  3572   gdouble rate;
       
  3573   gboolean update;
       
  3574   gboolean res = TRUE;
       
  3575 
       
  3576   gst_event_parse_seek (event, &rate, &seek_format, &flags,
       
  3577       &cur_type, &cur, &stop_type, &stop);
       
  3578   dest_format = segment->format;
       
  3579 
       
  3580   if (seek_format == dest_format) {
       
  3581     gst_segment_set_seek (segment, rate, seek_format, flags,
       
  3582         cur_type, cur, stop_type, stop, &update);
       
  3583     return TRUE;
       
  3584   }
       
  3585 
       
  3586   if (cur_type != GST_SEEK_TYPE_NONE) {
       
  3587     /* FIXME: Handle seek_cur & seek_end by converting the input segment vals */
       
  3588     res =
       
  3589         gst_pad_query_convert (sink->sinkpad, seek_format, cur, &dest_format,
       
  3590         &cur);
       
  3591     cur_type = GST_SEEK_TYPE_SET;
       
  3592   }
       
  3593 
       
  3594   if (res && stop_type != GST_SEEK_TYPE_NONE) {
       
  3595     /* FIXME: Handle seek_cur & seek_end by converting the input segment vals */
       
  3596     res =
       
  3597         gst_pad_query_convert (sink->sinkpad, seek_format, stop, &dest_format,
       
  3598         &stop);
       
  3599     stop_type = GST_SEEK_TYPE_SET;
       
  3600   }
       
  3601 
       
  3602   /* And finally, configure our output segment in the desired format */
       
  3603   gst_segment_set_seek (segment, rate, dest_format, flags, cur_type, cur,
       
  3604       stop_type, stop, &update);
       
  3605 
       
  3606   if (!res)
       
  3607     goto no_format;
       
  3608 
       
  3609   return res;
       
  3610 
       
  3611 no_format:
       
  3612   {
       
  3613     GST_DEBUG_OBJECT (sink, "undefined format given, seek aborted.");
       
  3614     return FALSE;
       
  3615   }
       
  3616 }
       
  3617 
       
  3618 /* perform a seek, only executed in pull mode */
       
  3619 static gboolean
       
  3620 gst_base_sink_perform_seek (GstBaseSink * sink, GstPad * pad, GstEvent * event)
       
  3621 {
       
  3622   gboolean flush;
       
  3623   gdouble rate;
       
  3624   GstFormat seek_format, dest_format;
       
  3625   GstSeekFlags flags;
       
  3626   GstSeekType cur_type, stop_type;
       
  3627   gboolean seekseg_configured = FALSE;
       
  3628   gint64 cur, stop;
       
  3629   gboolean update, res = TRUE;
       
  3630   GstSegment seeksegment;
       
  3631 
       
  3632   dest_format = sink->segment.format;
       
  3633 
       
  3634   if (event) {
       
  3635     GST_DEBUG_OBJECT (sink, "performing seek with event %p", event);
       
  3636     gst_event_parse_seek (event, &rate, &seek_format, &flags,
       
  3637         &cur_type, &cur, &stop_type, &stop);
       
  3638 
       
  3639     flush = flags & GST_SEEK_FLAG_FLUSH;
       
  3640   } else {
       
  3641     GST_DEBUG_OBJECT (sink, "performing seek without event");
       
  3642     flush = FALSE;
       
  3643   }
       
  3644 
       
  3645   if (flush) {
       
  3646     GST_DEBUG_OBJECT (sink, "flushing upstream");
       
  3647     gst_pad_push_event (pad, gst_event_new_flush_start ());
       
  3648     gst_base_sink_flush_start (sink, pad);
       
  3649   } else {
       
  3650     GST_DEBUG_OBJECT (sink, "pausing pulling thread");
       
  3651   }
       
  3652 
       
  3653   GST_PAD_STREAM_LOCK (pad);
       
  3654 
       
  3655   /* If we configured the seeksegment above, don't overwrite it now. Otherwise
       
  3656    * copy the current segment info into the temp segment that we can actually
       
  3657    * attempt the seek with. We only update the real segment if the seek suceeds. */
       
  3658   if (!seekseg_configured) {
       
  3659     memcpy (&seeksegment, &sink->segment, sizeof (GstSegment));
       
  3660 
       
  3661     /* now configure the final seek segment */
       
  3662     if (event) {
       
  3663       if (sink->segment.format != seek_format) {
       
  3664         /* OK, here's where we give the subclass a chance to convert the relative
       
  3665          * seek into an absolute one in the processing format. We set up any
       
  3666          * absolute seek above, before taking the stream lock. */
       
  3667         if (!gst_base_sink_default_prepare_seek_segment (sink, event,
       
  3668                 &seeksegment)) {
       
  3669           GST_DEBUG_OBJECT (sink,
       
  3670               "Preparing the seek failed after flushing. " "Aborting seek");
       
  3671           res = FALSE;
       
  3672         }
       
  3673       } else {
       
  3674         /* The seek format matches our processing format, no need to ask the
       
  3675          * the subclass to configure the segment. */
       
  3676         gst_segment_set_seek (&seeksegment, rate, seek_format, flags,
       
  3677             cur_type, cur, stop_type, stop, &update);
       
  3678       }
       
  3679     }
       
  3680     /* Else, no seek event passed, so we're just (re)starting the 
       
  3681        current segment. */
       
  3682   }
       
  3683 
       
  3684   if (res) {
       
  3685     GST_DEBUG_OBJECT (sink, "segment configured from %" G_GINT64_FORMAT
       
  3686         " to %" G_GINT64_FORMAT ", position %" G_GINT64_FORMAT,
       
  3687         seeksegment.start, seeksegment.stop, seeksegment.last_stop);
       
  3688 
       
  3689     /* do the seek, segment.last_stop contains the new position. */
       
  3690     res = gst_base_sink_default_do_seek (sink, &seeksegment);
       
  3691   }
       
  3692 
       
  3693 
       
  3694   if (flush) {
       
  3695     GST_DEBUG_OBJECT (sink, "stop flushing upstream");
       
  3696     gst_pad_push_event (pad, gst_event_new_flush_stop ());
       
  3697     gst_base_sink_flush_stop (sink, pad);
       
  3698   } else if (res && sink->abidata.ABI.running) {
       
  3699     /* we are running the current segment and doing a non-flushing seek, 
       
  3700      * close the segment first based on the last_stop. */
       
  3701     GST_DEBUG_OBJECT (sink, "closing running segment %" G_GINT64_FORMAT
       
  3702         " to %" G_GINT64_FORMAT, sink->segment.start, sink->segment.last_stop);
       
  3703   }
       
  3704 
       
  3705   /* The subclass must have converted the segment to the processing format 
       
  3706    * by now */
       
  3707   if (res && seeksegment.format != dest_format) {
       
  3708     GST_DEBUG_OBJECT (sink, "Subclass failed to prepare a seek segment "
       
  3709         "in the correct format. Aborting seek.");
       
  3710     res = FALSE;
       
  3711   }
       
  3712 
       
  3713   /* if successfull seek, we update our real segment and push
       
  3714    * out the new segment. */
       
  3715   if (res) {
       
  3716     memcpy (&sink->segment, &seeksegment, sizeof (GstSegment));
       
  3717 
       
  3718     if (sink->segment.flags & GST_SEEK_FLAG_SEGMENT) {
       
  3719       gst_element_post_message (GST_ELEMENT (sink),
       
  3720           gst_message_new_segment_start (GST_OBJECT (sink),
       
  3721               sink->segment.format, sink->segment.last_stop));
       
  3722     }
       
  3723   }
       
  3724 
       
  3725   sink->priv->discont = TRUE;
       
  3726   sink->abidata.ABI.running = TRUE;
       
  3727 
       
  3728   GST_PAD_STREAM_UNLOCK (pad);
       
  3729 
       
  3730   return res;
       
  3731 }
       
  3732 
       
  3733 static void
       
  3734 set_step_info (GstBaseSink * sink, GstStepInfo * current, GstStepInfo * pending,
       
  3735     guint seqnum, GstFormat format, guint64 amount, gdouble rate,
       
  3736     gboolean flush, gboolean intermediate)
       
  3737 {
       
  3738   GST_OBJECT_LOCK (sink);
       
  3739   pending->seqnum = seqnum;
       
  3740   pending->format = format;
       
  3741   pending->amount = amount;
       
  3742   pending->position = 0;
       
  3743   pending->rate = rate;
       
  3744   pending->flush = flush;
       
  3745   pending->intermediate = intermediate;
       
  3746   pending->valid = TRUE;
       
  3747   /* flush invalidates the current stepping segment */
       
  3748   if (flush)
       
  3749     current->valid = FALSE;
       
  3750   GST_OBJECT_UNLOCK (sink);
       
  3751 }
       
  3752 
       
  3753 static gboolean
       
  3754 gst_base_sink_perform_step (GstBaseSink * sink, GstPad * pad, GstEvent * event)
       
  3755 {
       
  3756   GstBaseSinkPrivate *priv;
       
  3757   GstBaseSinkClass *bclass;
       
  3758   gboolean flush, intermediate;
       
  3759   gdouble rate;
       
  3760   GstFormat format;
       
  3761   guint64 amount;
       
  3762   guint seqnum;
       
  3763   GstStepInfo *pending, *current;
       
  3764   GstMessage *message;
       
  3765 
       
  3766   bclass = GST_BASE_SINK_GET_CLASS (sink);
       
  3767   priv = sink->priv;
       
  3768 
       
  3769   GST_DEBUG_OBJECT (sink, "performing step with event %p", event);
       
  3770 
       
  3771   gst_event_parse_step (event, &format, &amount, &rate, &flush, &intermediate);
       
  3772   seqnum = gst_event_get_seqnum (event);
       
  3773 
       
  3774   pending = &priv->pending_step;
       
  3775   current = &priv->current_step;
       
  3776 
       
  3777   /* post message first */
       
  3778   message = gst_message_new_step_start (GST_OBJECT (sink), FALSE, format,
       
  3779       amount, rate, flush, intermediate);
       
  3780   gst_message_set_seqnum (message, seqnum);
       
  3781   gst_element_post_message (GST_ELEMENT (sink), message);
       
  3782 
       
  3783   if (flush) {
       
  3784     /* we need to call ::unlock before locking PREROLL_LOCK
       
  3785      * since we lock it before going into ::render */
       
  3786     if (bclass->unlock)
       
  3787       bclass->unlock (sink);
       
  3788 
       
  3789     GST_PAD_PREROLL_LOCK (sink->sinkpad);
       
  3790     /* now that we have the PREROLL lock, clear our unlock request */
       
  3791     if (bclass->unlock_stop)
       
  3792       bclass->unlock_stop (sink);
       
  3793 
       
  3794     /* update the stepinfo and make it valid */
       
  3795     set_step_info (sink, current, pending, seqnum, format, amount, rate, flush,
       
  3796         intermediate);
       
  3797 
       
  3798     if (sink->priv->async_enabled) {
       
  3799       /* and we need to commit our state again on the next
       
  3800        * prerolled buffer */
       
  3801       sink->playing_async = TRUE;
       
  3802       priv->pending_step.need_preroll = TRUE;
       
  3803       sink->need_preroll = FALSE;
       
  3804       gst_element_lost_state_full (GST_ELEMENT_CAST (sink), FALSE);
       
  3805     } else {
       
  3806       sink->priv->have_latency = TRUE;
       
  3807       sink->need_preroll = FALSE;
       
  3808     }
       
  3809     priv->current_sstart = -1;
       
  3810     priv->current_sstop = -1;
       
  3811     priv->eos_rtime = -1;
       
  3812     priv->call_preroll = TRUE;
       
  3813     gst_base_sink_set_last_buffer (sink, NULL);
       
  3814     gst_base_sink_reset_qos (sink);
       
  3815 
       
  3816     if (sink->clock_id) {
       
  3817       gst_clock_id_unschedule (sink->clock_id);
       
  3818     }
       
  3819 
       
  3820     if (sink->have_preroll) {
       
  3821       GST_DEBUG_OBJECT (sink, "signal waiter");
       
  3822       priv->step_unlock = TRUE;
       
  3823       GST_PAD_PREROLL_SIGNAL (sink->sinkpad);
       
  3824     }
       
  3825     GST_PAD_PREROLL_UNLOCK (sink->sinkpad);
       
  3826   } else {
       
  3827     /* update the stepinfo and make it valid */
       
  3828     set_step_info (sink, current, pending, seqnum, format, amount, rate, flush,
       
  3829         intermediate);
       
  3830   }
       
  3831 
       
  3832   return TRUE;
       
  3833 }
       
  3834 
       
  3835 /* with STREAM_LOCK
  2686 /* with STREAM_LOCK
  3836  */
  2687  */
  3837 static void
  2688 static void
  3838 gst_base_sink_loop (GstPad * pad)
  2689 gst_base_sink_loop (GstPad * pad)
  3839 {
  2690 {
  3840   GstBaseSink *basesink;
  2691   GstBaseSink *basesink;
  3841   GstBuffer *buf = NULL;
  2692   GstBuffer *buf = NULL;
  3842   GstFlowReturn result;
  2693   GstFlowReturn result;
  3843   guint blocksize;
       
  3844   guint64 offset;
       
  3845 
  2694 
  3846   basesink = GST_BASE_SINK (GST_OBJECT_PARENT (pad));
  2695   basesink = GST_BASE_SINK (GST_OBJECT_PARENT (pad));
  3847 
  2696 
  3848   g_assert (basesink->pad_mode == GST_ACTIVATE_PULL);
  2697   g_assert (basesink->pad_mode == GST_ACTIVATE_PULL);
  3849 
  2698 
  3850   if ((blocksize = basesink->priv->blocksize) == 0)
       
  3851     blocksize = -1;
       
  3852 
       
  3853   offset = basesink->segment.last_stop;
       
  3854 
       
  3855   GST_DEBUG_OBJECT (basesink, "pulling %" G_GUINT64_FORMAT ", %u",
  2699   GST_DEBUG_OBJECT (basesink, "pulling %" G_GUINT64_FORMAT ", %u",
  3856       offset, blocksize);
  2700       basesink->offset, (guint) DEFAULT_SIZE);
  3857 
  2701 
  3858   result = gst_pad_pull_range (pad, offset, blocksize, &buf);
  2702   result = gst_pad_pull_range (pad, basesink->offset, DEFAULT_SIZE, &buf);
  3859   if (G_UNLIKELY (result != GST_FLOW_OK))
  2703   if (G_UNLIKELY (result != GST_FLOW_OK))
  3860     goto paused;
  2704     goto paused;
  3861 
  2705 
  3862   if (G_UNLIKELY (buf == NULL))
  2706   if (G_UNLIKELY (buf == NULL))
  3863     goto no_buffer;
  2707     goto no_buffer;
  3864 
  2708 
  3865   offset += GST_BUFFER_SIZE (buf);
  2709   basesink->offset += GST_BUFFER_SIZE (buf);
  3866 
       
  3867   gst_segment_set_last_stop (&basesink->segment, GST_FORMAT_BYTES, offset);
       
  3868 
  2710 
  3869   GST_PAD_PREROLL_LOCK (pad);
  2711   GST_PAD_PREROLL_LOCK (pad);
  3870   result = gst_base_sink_chain_unlocked (basesink, pad, FALSE, buf);
  2712   result = gst_base_sink_chain_unlocked (basesink, pad, buf);
  3871   GST_PAD_PREROLL_UNLOCK (pad);
  2713   GST_PAD_PREROLL_UNLOCK (pad);
  3872   if (G_UNLIKELY (result != GST_FLOW_OK))
  2714   if (G_UNLIKELY (result != GST_FLOW_OK))
  3873     goto paused;
  2715     goto paused;
  3874 
  2716 
  3875   return;
  2717   return;
  3880     GST_LOG_OBJECT (basesink, "pausing task, reason %s",
  2722     GST_LOG_OBJECT (basesink, "pausing task, reason %s",
  3881         gst_flow_get_name (result));
  2723         gst_flow_get_name (result));
  3882     gst_pad_pause_task (pad);
  2724     gst_pad_pause_task (pad);
  3883     /* fatal errors and NOT_LINKED cause EOS */
  2725     /* fatal errors and NOT_LINKED cause EOS */
  3884     if (GST_FLOW_IS_FATAL (result) || result == GST_FLOW_NOT_LINKED) {
  2726     if (GST_FLOW_IS_FATAL (result) || result == GST_FLOW_NOT_LINKED) {
  3885       if (result == GST_FLOW_UNEXPECTED) {
  2727       /* FIXME, we shouldn't post EOS when we are operating in segment mode */
  3886         /* perform EOS logic */
  2728       gst_base_sink_event (pad, gst_event_new_eos ());
  3887         if (basesink->segment.flags & GST_SEEK_FLAG_SEGMENT) {
  2729       /* EOS does not cause an ERROR message */
  3888           gst_element_post_message (GST_ELEMENT_CAST (basesink),
  2730       if (result != GST_FLOW_UNEXPECTED) {
  3889               gst_message_new_segment_done (GST_OBJECT_CAST (basesink),
       
  3890                   basesink->segment.format, basesink->segment.last_stop));
       
  3891         } else {
       
  3892           gst_base_sink_event (pad, gst_event_new_eos ());
       
  3893         }
       
  3894       } else {
       
  3895         /* for fatal errors we post an error message, post the error
       
  3896          * first so the app knows about the error first. */
       
  3897         GST_ELEMENT_ERROR (basesink, STREAM, FAILED,
  2731         GST_ELEMENT_ERROR (basesink, STREAM, FAILED,
  3898             (_("Internal data stream error.")),
  2732             (_("Internal data stream error.")),
  3899             ("stream stopped, reason %s", gst_flow_get_name (result)));
  2733             ("stream stopped, reason %s", gst_flow_get_name (result)));
  3900         gst_base_sink_event (pad, gst_event_new_eos ());
       
  3901       }
  2734       }
  3902     }
  2735     }
  3903     return;
  2736     return;
  3904   }
  2737   }
  3905 no_buffer:
  2738 no_buffer:
  3906   {
  2739   {
  3907     GST_LOG_OBJECT (basesink, "no buffer, pausing");
  2740     GST_LOG_OBJECT (basesink, "no buffer, pausing");
  3908     GST_ELEMENT_ERROR (basesink, STREAM, FAILED,
       
  3909         (_("Internal data flow error.")), ("element returned NULL buffer"));
       
  3910     result = GST_FLOW_ERROR;
  2741     result = GST_FLOW_ERROR;
  3911     goto paused;
  2742     goto paused;
  3912   }
  2743   }
  3913 }
  2744 }
  3914 
  2745 
  3941     /* step 2, unblock clock sync (if any) or any other blocking thing */
  2772     /* step 2, unblock clock sync (if any) or any other blocking thing */
  3942     if (basesink->clock_id) {
  2773     if (basesink->clock_id) {
  3943       gst_clock_id_unschedule (basesink->clock_id);
  2774       gst_clock_id_unschedule (basesink->clock_id);
  3944     }
  2775     }
  3945 
  2776 
  3946     /* flush out the data thread if it's locked in finish_preroll, this will
  2777     /* flush out the data thread if it's locked in finish_preroll */
  3947      * also flush out the EOS state */
       
  3948     GST_DEBUG_OBJECT (basesink,
  2778     GST_DEBUG_OBJECT (basesink,
  3949         "flushing out data thread, need preroll to TRUE");
  2779         "flushing out data thread, need preroll to TRUE");
  3950     gst_base_sink_preroll_queue_flush (basesink, pad);
  2780     gst_base_sink_preroll_queue_flush (basesink, pad);
  3951   }
  2781   }
  3952   GST_PAD_PREROLL_UNLOCK (pad);
  2782   GST_PAD_PREROLL_UNLOCK (pad);
  3981 
  2811 
  3982   GST_DEBUG_OBJECT (basesink, "Trying pull mode first");
  2812   GST_DEBUG_OBJECT (basesink, "Trying pull mode first");
  3983 
  2813 
  3984   gst_base_sink_set_flushing (basesink, pad, FALSE);
  2814   gst_base_sink_set_flushing (basesink, pad, FALSE);
  3985 
  2815 
  3986   /* we need to have the pull mode enabled */
  2816   if (basesink->can_activate_pull && gst_pad_check_pull_range (pad)
  3987   if (!basesink->can_activate_pull) {
  2817       && gst_pad_activate_pull (pad, TRUE)) {
  3988     GST_DEBUG_OBJECT (basesink, "pull mode disabled");
  2818     GST_DEBUG_OBJECT (basesink, "Success activating pull mode");
  3989     goto fallback;
  2819     result = TRUE;
  3990   }
  2820   } else {
  3991 
  2821     GST_DEBUG_OBJECT (basesink, "Falling back to push mode");
  3992   /* check if downstreams supports pull mode at all */
  2822     if (gst_pad_activate_push (pad, TRUE)) {
  3993   if (!gst_pad_check_pull_range (pad)) {
  2823       GST_DEBUG_OBJECT (basesink, "Success activating push mode");
  3994     GST_DEBUG_OBJECT (basesink, "pull mode not supported");
  2824       result = TRUE;
  3995     goto fallback;
  2825     }
  3996   }
  2826   }
  3997 
  2827 
  3998   /* set the pad mode before starting the task so that it's in the
       
  3999    * correct state for the new thread. also the sink set_caps and get_caps
       
  4000    * function checks this */
       
  4001   basesink->pad_mode = GST_ACTIVATE_PULL;
       
  4002 
       
  4003   /* we first try to negotiate a format so that when we try to activate
       
  4004    * downstream, it knows about our format */
       
  4005   if (!gst_base_sink_negotiate_pull (basesink)) {
       
  4006     GST_DEBUG_OBJECT (basesink, "failed to negotiate in pull mode");
       
  4007     goto fallback;
       
  4008   }
       
  4009 
       
  4010   /* ok activate now */
       
  4011   if (!gst_pad_activate_pull (pad, TRUE)) {
       
  4012     /* clear any pending caps */
       
  4013     GST_OBJECT_LOCK (basesink);
       
  4014     gst_caps_replace (&basesink->priv->pull_caps, NULL);
       
  4015     GST_OBJECT_UNLOCK (basesink);
       
  4016     GST_DEBUG_OBJECT (basesink, "failed to activate in pull mode");
       
  4017     goto fallback;
       
  4018   }
       
  4019 
       
  4020   GST_DEBUG_OBJECT (basesink, "Success activating pull mode");
       
  4021   result = TRUE;
       
  4022   goto done;
       
  4023 
       
  4024   /* push mode fallback */
       
  4025 fallback:
       
  4026   GST_DEBUG_OBJECT (basesink, "Falling back to push mode");
       
  4027   if ((result = gst_pad_activate_push (pad, TRUE))) {
       
  4028     GST_DEBUG_OBJECT (basesink, "Success activating push mode");
       
  4029   }
       
  4030 
       
  4031 done:
       
  4032   if (!result) {
  2828   if (!result) {
  4033     GST_WARNING_OBJECT (basesink, "Could not activate pad in either mode");
  2829     GST_WARNING_OBJECT (basesink, "Could not activate pad in either mode");
  4034     gst_base_sink_set_flushing (basesink, pad, TRUE);
  2830     gst_base_sink_set_flushing (basesink, pad, TRUE);
  4035   }
  2831   }
  4036 
  2832 
  4073 
  2869 
  4074 static gboolean
  2870 static gboolean
  4075 gst_base_sink_negotiate_pull (GstBaseSink * basesink)
  2871 gst_base_sink_negotiate_pull (GstBaseSink * basesink)
  4076 {
  2872 {
  4077   GstCaps *caps;
  2873   GstCaps *caps;
  4078   gboolean result;
  2874   GstPad *pad;
  4079 
  2875 
  4080   result = FALSE;
  2876   GST_OBJECT_LOCK (basesink);
  4081 
  2877   pad = basesink->sinkpad;
  4082   /* this returns the intersection between our caps and the peer caps. If there
  2878   gst_object_ref (pad);
  4083    * is no peer, it returns NULL and we can't operate in pull mode so we can
  2879   GST_OBJECT_UNLOCK (basesink);
  4084    * fail the negotiation. */
  2880 
  4085   caps = gst_pad_get_allowed_caps (GST_BASE_SINK_PAD (basesink));
  2881   caps = gst_pad_get_allowed_caps (pad);
  4086   if (caps == NULL || gst_caps_is_empty (caps))
  2882   if (gst_caps_is_empty (caps))
  4087     goto no_caps_possible;
  2883     goto no_caps_possible;
  4088 
  2884 
  4089   GST_DEBUG_OBJECT (basesink, "allowed caps: %" GST_PTR_FORMAT, caps);
       
  4090 
       
  4091   caps = gst_caps_make_writable (caps);
  2885   caps = gst_caps_make_writable (caps);
  4092   /* get the first (prefered) format */
       
  4093   gst_caps_truncate (caps);
  2886   gst_caps_truncate (caps);
  4094   /* try to fixate */
  2887   gst_pad_fixate_caps (pad, caps);
  4095   gst_pad_fixate_caps (GST_BASE_SINK_PAD (basesink), caps);
       
  4096 
       
  4097   GST_DEBUG_OBJECT (basesink, "fixated to: %" GST_PTR_FORMAT, caps);
       
  4098 
  2888 
  4099   if (gst_caps_is_any (caps)) {
  2889   if (gst_caps_is_any (caps)) {
  4100     GST_DEBUG_OBJECT (basesink, "caps were ANY after fixating, "
  2890     GST_DEBUG_OBJECT (basesink, "caps were ANY after fixating, "
  4101         "allowing pull()");
  2891         "allowing pull()");
  4102     /* neither side has template caps in this case, so they are prepared for
  2892     /* neither side has template caps in this case, so they are prepared for
  4103        pull() without setcaps() */
  2893        pull() without setcaps() */
  4104     result = TRUE;
  2894   } else {
  4105   } else if (gst_caps_is_fixed (caps)) {
  2895     if (!gst_pad_set_caps (pad, caps))
  4106     if (!gst_pad_set_caps (GST_BASE_SINK_PAD (basesink), caps))
       
  4107       goto could_not_set_caps;
  2896       goto could_not_set_caps;
  4108 
       
  4109     GST_OBJECT_LOCK (basesink);
       
  4110     gst_caps_replace (&basesink->priv->pull_caps, caps);
       
  4111     GST_OBJECT_UNLOCK (basesink);
       
  4112 
       
  4113     result = TRUE;
       
  4114   }
  2897   }
  4115 
  2898 
  4116   gst_caps_unref (caps);
  2899   gst_caps_unref (caps);
  4117 
  2900   gst_object_unref (pad);
  4118   return result;
  2901 
       
  2902   return TRUE;
  4119 
  2903 
  4120 no_caps_possible:
  2904 no_caps_possible:
  4121   {
  2905   {
  4122     GST_INFO_OBJECT (basesink, "Pipeline could not agree on caps");
  2906     GST_INFO_OBJECT (basesink, "Pipeline could not agree on caps");
  4123     GST_DEBUG_OBJECT (basesink, "get_allowed_caps() returned EMPTY");
  2907     GST_DEBUG_OBJECT (basesink, "get_allowed_caps() returned EMPTY");
  4124     if (caps)
  2908     gst_object_unref (pad);
  4125       gst_caps_unref (caps);
       
  4126     return FALSE;
  2909     return FALSE;
  4127   }
  2910   }
  4128 could_not_set_caps:
  2911 could_not_set_caps:
  4129   {
  2912   {
  4130     GST_INFO_OBJECT (basesink, "Could not set caps: %" GST_PTR_FORMAT, caps);
  2913     GST_INFO_OBJECT (basesink, "Could not set caps: %" GST_PTR_FORMAT, caps);
  4131     gst_caps_unref (caps);
  2914     gst_caps_unref (caps);
       
  2915     gst_object_unref (pad);
  4132     return FALSE;
  2916     return FALSE;
  4133   }
  2917   }
  4134 }
  2918 }
  4135 
  2919 
  4136 /* this won't get called until we implement an activate function */
  2920 /* this won't get called until we implement an activate function */
  4143 
  2927 
  4144   basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
  2928   basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
  4145   bclass = GST_BASE_SINK_GET_CLASS (basesink);
  2929   bclass = GST_BASE_SINK_GET_CLASS (basesink);
  4146 
  2930 
  4147   if (active) {
  2931   if (active) {
  4148     GstFormat format;
  2932     if (!basesink->can_activate_pull) {
  4149     gint64 duration;
  2933       result = FALSE;
  4150 
  2934       basesink->pad_mode = GST_ACTIVATE_NONE;
  4151     /* we mark we have a newsegment here because pull based
       
  4152      * mode works just fine without having a newsegment before the
       
  4153      * first buffer */
       
  4154     format = GST_FORMAT_BYTES;
       
  4155 
       
  4156     gst_segment_init (&basesink->segment, format);
       
  4157     gst_segment_init (basesink->abidata.ABI.clip_segment, format);
       
  4158     GST_OBJECT_LOCK (basesink);
       
  4159     basesink->have_newsegment = TRUE;
       
  4160     GST_OBJECT_UNLOCK (basesink);
       
  4161 
       
  4162     /* get the peer duration in bytes */
       
  4163     result = gst_pad_query_peer_duration (pad, &format, &duration);
       
  4164     if (result) {
       
  4165       GST_DEBUG_OBJECT (basesink,
       
  4166           "setting duration in bytes to %" G_GINT64_FORMAT, duration);
       
  4167       gst_segment_set_duration (basesink->abidata.ABI.clip_segment, format,
       
  4168           duration);
       
  4169       gst_segment_set_duration (&basesink->segment, format, duration);
       
  4170     } else {
  2935     } else {
  4171       GST_DEBUG_OBJECT (basesink, "unknown duration");
  2936       GstPad *peer = gst_pad_get_peer (pad);
       
  2937 
       
  2938       if (G_UNLIKELY (peer == NULL)) {
       
  2939         g_warning ("Trying to activate pad in pull mode, but no peer");
       
  2940         result = FALSE;
       
  2941         basesink->pad_mode = GST_ACTIVATE_NONE;
       
  2942       } else {
       
  2943         if (gst_pad_activate_pull (peer, TRUE)) {
       
  2944           /* we mark we have a newsegment here because pull based
       
  2945            * mode works just fine without having a newsegment before the
       
  2946            * first buffer */
       
  2947           gst_segment_init (&basesink->segment, GST_FORMAT_UNDEFINED);
       
  2948           gst_segment_init (basesink->abidata.ABI.clip_segment,
       
  2949               GST_FORMAT_UNDEFINED);
       
  2950           basesink->have_newsegment = TRUE;
       
  2951 
       
  2952           /* set the pad mode before starting the task so that it's in the
       
  2953              correct state for the new thread. also the sink set_caps function
       
  2954              checks this */
       
  2955           basesink->pad_mode = GST_ACTIVATE_PULL;
       
  2956           if ((result = gst_base_sink_negotiate_pull (basesink))) {
       
  2957             if (bclass->activate_pull)
       
  2958               result = bclass->activate_pull (basesink, TRUE);
       
  2959             else
       
  2960               result = FALSE;
       
  2961           }
       
  2962           /* but if starting the thread fails, set it back */
       
  2963           if (!result)
       
  2964             basesink->pad_mode = GST_ACTIVATE_NONE;
       
  2965         } else {
       
  2966           GST_DEBUG_OBJECT (pad, "Failed to activate peer in pull mode");
       
  2967           result = FALSE;
       
  2968           basesink->pad_mode = GST_ACTIVATE_NONE;
       
  2969         }
       
  2970         gst_object_unref (peer);
       
  2971       }
  4172     }
  2972     }
  4173 
       
  4174     if (bclass->activate_pull)
       
  4175       result = bclass->activate_pull (basesink, TRUE);
       
  4176     else
       
  4177       result = FALSE;
       
  4178 
       
  4179     if (!result)
       
  4180       goto activate_failed;
       
  4181 
       
  4182   } else {
  2973   } else {
  4183     if (G_UNLIKELY (basesink->pad_mode != GST_ACTIVATE_PULL)) {
  2974     if (G_UNLIKELY (basesink->pad_mode != GST_ACTIVATE_PULL)) {
  4184       g_warning ("Internal GStreamer activation error!!!");
  2975       g_warning ("Internal GStreamer activation error!!!");
  4185       result = FALSE;
  2976       result = FALSE;
  4186     } else {
  2977     } else {
  4187       result = gst_base_sink_set_flushing (basesink, pad, TRUE);
  2978       result = gst_base_sink_set_flushing (basesink, pad, TRUE);
  4188       if (bclass->activate_pull)
  2979       if (bclass->activate_pull)
  4189         result &= bclass->activate_pull (basesink, FALSE);
  2980         result &= bclass->activate_pull (basesink, FALSE);
  4190       basesink->pad_mode = GST_ACTIVATE_NONE;
  2981       basesink->pad_mode = GST_ACTIVATE_NONE;
  4191       /* clear any pending caps */
       
  4192       GST_OBJECT_LOCK (basesink);
       
  4193       gst_caps_replace (&basesink->priv->pull_caps, NULL);
       
  4194       GST_OBJECT_UNLOCK (basesink);
       
  4195     }
  2982     }
  4196   }
  2983   }
       
  2984 
  4197   gst_object_unref (basesink);
  2985   gst_object_unref (basesink);
  4198 
  2986 
  4199   return result;
  2987   return result;
  4200 
       
  4201   /* ERRORS */
       
  4202 activate_failed:
       
  4203   {
       
  4204     /* reset, as starting the thread failed */
       
  4205     basesink->pad_mode = GST_ACTIVATE_NONE;
       
  4206 
       
  4207     GST_ERROR_OBJECT (basesink, "subclass failed to activate in pull mode");
       
  4208     return FALSE;
       
  4209   }
       
  4210 }
  2988 }
  4211 
  2989 
  4212 /* send an event to our sinkpad peer. */
  2990 /* send an event to our sinkpad peer. */
  4213 static gboolean
  2991 static gboolean
  4214 gst_base_sink_send_event (GstElement * element, GstEvent * event)
  2992 gst_base_sink_send_event (GstElement * element, GstEvent * event)
  4215 {
  2993 {
  4216   GstPad *pad;
  2994   GstPad *pad;
  4217   GstBaseSink *basesink = GST_BASE_SINK (element);
  2995   GstBaseSink *basesink = GST_BASE_SINK (element);
  4218   gboolean forward, result = TRUE;
  2996   gboolean forward, result = TRUE;
  4219   GstActivateMode mode;
       
  4220 
       
  4221   GST_OBJECT_LOCK (element);
       
  4222   /* get the pad and the scheduling mode */
       
  4223   pad = gst_object_ref (basesink->sinkpad);
       
  4224   mode = basesink->pad_mode;
       
  4225   GST_OBJECT_UNLOCK (element);
       
  4226 
  2997 
  4227   /* only push UPSTREAM events upstream */
  2998   /* only push UPSTREAM events upstream */
  4228   forward = GST_EVENT_IS_UPSTREAM (event);
  2999   forward = GST_EVENT_IS_UPSTREAM (event);
  4229 
  3000 
  4230   switch (GST_EVENT_TYPE (event)) {
  3001   switch (GST_EVENT_TYPE (event)) {
  4232     {
  3003     {
  4233       GstClockTime latency;
  3004       GstClockTime latency;
  4234 
  3005 
  4235       gst_event_parse_latency (event, &latency);
  3006       gst_event_parse_latency (event, &latency);
  4236 
  3007 
  4237       /* store the latency. We use this to adjust the running_time before syncing
       
  4238        * it to the clock. */
       
  4239       GST_OBJECT_LOCK (element);
  3008       GST_OBJECT_LOCK (element);
  4240       basesink->priv->latency = latency;
  3009       basesink->priv->latency = latency;
  4241       if (!basesink->priv->have_latency)
       
  4242         forward = FALSE;
       
  4243       GST_OBJECT_UNLOCK (element);
  3010       GST_OBJECT_UNLOCK (element);
  4244       GST_DEBUG_OBJECT (basesink, "latency set to %" GST_TIME_FORMAT,
  3011       GST_DEBUG_OBJECT (basesink, "latency set to %" GST_TIME_FORMAT,
  4245           GST_TIME_ARGS (latency));
  3012           GST_TIME_ARGS (latency));
  4246 
  3013 
  4247       /* We forward this event so that all elements know about the global pipeline
  3014       /* don't forward, yet */
  4248        * latency. This is interesting for an element when it wants to figure out
  3015       forward = FALSE;
  4249        * when a particular piece of data will be rendered. */
       
  4250       break;
  3016       break;
  4251     }
  3017     }
  4252     case GST_EVENT_SEEK:
       
  4253       /* in pull mode we will execute the seek */
       
  4254       if (mode == GST_ACTIVATE_PULL)
       
  4255         result = gst_base_sink_perform_seek (basesink, pad, event);
       
  4256       break;
       
  4257     case GST_EVENT_STEP:
       
  4258       result = gst_base_sink_perform_step (basesink, pad, event);
       
  4259       forward = FALSE;
       
  4260       break;
       
  4261     default:
  3018     default:
  4262       break;
  3019       break;
  4263   }
  3020   }
  4264 
  3021 
  4265   if (forward) {
  3022   if (forward) {
       
  3023     GST_OBJECT_LOCK (element);
       
  3024     pad = gst_object_ref (basesink->sinkpad);
       
  3025     GST_OBJECT_UNLOCK (element);
       
  3026 
  4266     result = gst_pad_push_event (pad, event);
  3027     result = gst_pad_push_event (pad, event);
       
  3028 
       
  3029     gst_object_unref (pad);
  4267   } else {
  3030   } else {
  4268     /* not forwarded, unref the event */
  3031     /* not forwarded, unref the event */
  4269     gst_event_unref (event);
  3032     gst_event_unref (event);
  4270   }
  3033   }
  4271 
       
  4272   gst_object_unref (pad);
       
  4273   return result;
  3034   return result;
  4274 }
  3035 }
  4275 
  3036 
  4276 static gboolean
  3037 static gboolean
  4277 gst_base_sink_peer_query (GstBaseSink * sink, GstQuery * query)
  3038 gst_base_sink_peer_query (GstBaseSink * sink, GstQuery * query)
  4286   return res;
  3047   return res;
  4287 }
  3048 }
  4288 
  3049 
  4289 /* get the end position of the last seen object, this is used
  3050 /* get the end position of the last seen object, this is used
  4290  * for EOS and for making sure that we don't report a position we
  3051  * for EOS and for making sure that we don't report a position we
  4291  * have not reached yet. With LOCK. */
  3052  * have not reached yet. */
  4292 static gboolean
  3053 static gboolean
  4293 gst_base_sink_get_position_last (GstBaseSink * basesink, GstFormat format,
  3054 gst_base_sink_get_position_last (GstBaseSink * basesink, gint64 * cur)
  4294     gint64 * cur)
  3055 {
  4295 {
  3056   /* return last observed stream time */
  4296   GstFormat oformat;
  3057   *cur = basesink->priv->current_sstop;
  4297   GstSegment *segment;
       
  4298   gboolean ret = TRUE;
       
  4299 
       
  4300   segment = &basesink->segment;
       
  4301   oformat = segment->format;
       
  4302 
       
  4303   if (oformat == GST_FORMAT_TIME) {
       
  4304     /* return last observed stream time, we keep the stream time around in the
       
  4305      * time format. */
       
  4306     *cur = basesink->priv->current_sstop;
       
  4307   } else {
       
  4308     /* convert last stop to stream time */
       
  4309     *cur = gst_segment_to_stream_time (segment, oformat, segment->last_stop);
       
  4310   }
       
  4311 
       
  4312   if (*cur != -1 && oformat != format) {
       
  4313     GST_OBJECT_UNLOCK (basesink);
       
  4314     /* convert to the target format if we need to, release lock first */
       
  4315     ret =
       
  4316         gst_pad_query_convert (basesink->sinkpad, oformat, *cur, &format, cur);
       
  4317     if (!ret)
       
  4318       *cur = -1;
       
  4319     GST_OBJECT_LOCK (basesink);
       
  4320   }
       
  4321 
       
  4322   GST_DEBUG_OBJECT (basesink, "POSITION: %" GST_TIME_FORMAT,
  3058   GST_DEBUG_OBJECT (basesink, "POSITION: %" GST_TIME_FORMAT,
  4323       GST_TIME_ARGS (*cur));
  3059       GST_TIME_ARGS (*cur));
  4324 
  3060   return TRUE;
  4325   return ret;
       
  4326 }
  3061 }
  4327 
  3062 
  4328 /* get the position when we are PAUSED, this is the stream time of the buffer
  3063 /* get the position when we are PAUSED, this is the stream time of the buffer
  4329  * that prerolled. If no buffer is prerolled (we are still flushing), this
  3064  * that prerolled. If no buffer is prerolled (we are still flushing), this
  4330  * value will be -1. With LOCK. */
  3065  * value will be -1. */
  4331 static gboolean
  3066 static gboolean
  4332 gst_base_sink_get_position_paused (GstBaseSink * basesink, GstFormat format,
  3067 gst_base_sink_get_position_paused (GstBaseSink * basesink, gint64 * cur)
  4333     gint64 * cur)
       
  4334 {
  3068 {
  4335   gboolean res;
  3069   gboolean res;
  4336   gint64 time;
  3070   gint64 time;
  4337   GstSegment *segment;
  3071   GstSegment *segment;
  4338   GstFormat oformat;
  3072 
  4339 
  3073   *cur = basesink->priv->current_sstart;
  4340   /* we don't use the clip segment in pull mode, when seeking we update the
  3074   segment = basesink->abidata.ABI.clip_segment;
  4341    * main segment directly with the new segment values without it having to be
       
  4342    * activated by the rendering after preroll */
       
  4343   if (basesink->pad_mode == GST_ACTIVATE_PUSH)
       
  4344     segment = basesink->abidata.ABI.clip_segment;
       
  4345   else
       
  4346     segment = &basesink->segment;
       
  4347   oformat = segment->format;
       
  4348 
       
  4349   if (oformat == GST_FORMAT_TIME) {
       
  4350     *cur = basesink->priv->current_sstart;
       
  4351     if (segment->rate < 0.0 && basesink->priv->current_sstop != -1) {
       
  4352       /* for reverse playback we prefer the stream time stop position if we have
       
  4353        * one */
       
  4354       *cur = basesink->priv->current_sstop;
       
  4355     }
       
  4356   } else {
       
  4357     *cur = gst_segment_to_stream_time (segment, oformat, segment->last_stop);
       
  4358   }
       
  4359 
  3075 
  4360   time = segment->time;
  3076   time = segment->time;
  4361 
  3077 
  4362   if (*cur != -1) {
  3078   if (*cur != -1) {
  4363     *cur = MAX (*cur, time);
  3079     *cur = MAX (*cur, time);
  4371       GST_DEBUG_OBJECT (basesink, "POSITION as time: %" GST_TIME_FORMAT,
  3087       GST_DEBUG_OBJECT (basesink, "POSITION as time: %" GST_TIME_FORMAT,
  4372           GST_TIME_ARGS (*cur));
  3088           GST_TIME_ARGS (*cur));
  4373     } else {
  3089     } else {
  4374       /* reverse, next expected timestamp is segment->stop. We use the function
  3090       /* reverse, next expected timestamp is segment->stop. We use the function
  4375        * to get things right for negative applied_rates. */
  3091        * to get things right for negative applied_rates. */
  4376       *cur = gst_segment_to_stream_time (segment, oformat, segment->stop);
  3092       *cur =
       
  3093           gst_segment_to_stream_time (segment, GST_FORMAT_TIME, segment->stop);
  4377       GST_DEBUG_OBJECT (basesink, "reverse POSITION: %" GST_TIME_FORMAT,
  3094       GST_DEBUG_OBJECT (basesink, "reverse POSITION: %" GST_TIME_FORMAT,
  4378           GST_TIME_ARGS (*cur));
  3095           GST_TIME_ARGS (*cur));
  4379     }
  3096     }
  4380   }
  3097   }
  4381 
       
  4382   res = (*cur != -1);
  3098   res = (*cur != -1);
  4383   if (res && oformat != format) {
       
  4384     GST_OBJECT_UNLOCK (basesink);
       
  4385     res =
       
  4386         gst_pad_query_convert (basesink->sinkpad, oformat, *cur, &format, cur);
       
  4387     if (!res)
       
  4388       *cur = -1;
       
  4389     GST_OBJECT_LOCK (basesink);
       
  4390   }
       
  4391 
  3099 
  4392   return res;
  3100   return res;
  4393 }
  3101 }
  4394 
  3102 
  4395 static gboolean
  3103 static gboolean
  4396 gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format,
  3104 gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format,
  4397     gint64 * cur, gboolean * upstream)
  3105     gint64 * cur)
  4398 {
  3106 {
  4399   GstClock *clock;
  3107   GstClock *clock;
  4400   gboolean res = FALSE;
  3108   gboolean res = FALSE;
  4401   GstFormat oformat, tformat;
  3109 
  4402   GstClockTime now, base, latency;
  3110   switch (format) {
  4403   gint64 time, accum, duration;
  3111       /* we can answer time format */
  4404   gdouble rate;
  3112     case GST_FORMAT_TIME:
  4405   gint64 last;
  3113     {
  4406 
  3114       GstClockTime now, base, latency;
  4407   GST_OBJECT_LOCK (basesink);
  3115       gint64 time, accum, duration;
  4408   /* our intermediate time format */
  3116       gdouble rate;
  4409   tformat = GST_FORMAT_TIME;
  3117       gint64 last;
  4410   /* get the format in the segment */
  3118 
  4411   oformat = basesink->segment.format;
  3119       GST_OBJECT_LOCK (basesink);
  4412 
  3120 
  4413   /* can only give answer based on the clock if not EOS */
  3121       /* can only give answer based on the clock if not EOS */
  4414   if (G_UNLIKELY (basesink->eos))
  3122       if (G_UNLIKELY (basesink->eos))
  4415     goto in_eos;
  3123         goto in_eos;
  4416 
  3124 
  4417   /* we can only get the segment when we are not NULL or READY */
  3125       /* in PAUSE we cannot read from the clock so we
  4418   if (!basesink->have_newsegment)
  3126        * report time based on the last seen timestamp. */
  4419     goto wrong_state;
  3127       if (GST_STATE (basesink) == GST_STATE_PAUSED)
  4420 
  3128         goto in_pause;
  4421   /* when not in PLAYING or when we're busy with a state change, we
  3129 
  4422    * cannot read from the clock so we report time based on the
  3130       /* We get position from clock only in PLAYING, we checked
  4423    * last seen timestamp. */
  3131        * the PAUSED case above, so this is check is to test 
  4424   if (GST_STATE (basesink) != GST_STATE_PLAYING ||
  3132        * READY and NULL, where the position is always 0 */
  4425       GST_STATE_PENDING (basesink) != GST_STATE_VOID_PENDING)
  3133       if (GST_STATE (basesink) != GST_STATE_PLAYING)
  4426     goto in_pause;
  3134         goto wrong_state;
  4427 
  3135 
  4428   /* we need to sync on the clock. */
  3136       /* we need to sync on the clock. */
  4429   if (basesink->sync == FALSE)
  3137       if (basesink->sync == FALSE)
  4430     goto no_sync;
  3138         goto no_sync;
  4431 
  3139 
  4432   /* and we need a clock */
  3140       /* and we need a clock */
  4433   if (G_UNLIKELY ((clock = GST_ELEMENT_CLOCK (basesink)) == NULL))
  3141       if (G_UNLIKELY ((clock = GST_ELEMENT_CLOCK (basesink)) == NULL))
  4434     goto no_sync;
  3142         goto no_sync;
  4435 
  3143 
  4436   /* collect all data we need holding the lock */
  3144       /* collect all data we need holding the lock */
  4437   if (GST_CLOCK_TIME_IS_VALID (basesink->segment.time))
  3145       if (GST_CLOCK_TIME_IS_VALID (basesink->segment.time))
  4438     time = basesink->segment.time;
  3146         time = basesink->segment.time;
  4439   else
  3147       else
  4440     time = 0;
  3148         time = 0;
  4441 
  3149 
  4442   if (GST_CLOCK_TIME_IS_VALID (basesink->segment.stop))
  3150       if (GST_CLOCK_TIME_IS_VALID (basesink->segment.stop))
  4443     duration = basesink->segment.stop - basesink->segment.start;
  3151         duration = basesink->segment.stop - basesink->segment.start;
  4444   else
  3152       else
  4445     duration = 0;
  3153         duration = 0;
  4446 
  3154 
  4447   base = GST_ELEMENT_CAST (basesink)->base_time;
  3155       base = GST_ELEMENT_CAST (basesink)->base_time;
  4448   accum = basesink->segment.accum;
  3156       accum = basesink->segment.accum;
  4449   rate = basesink->segment.rate * basesink->segment.applied_rate;
  3157       rate = basesink->segment.rate * basesink->segment.applied_rate;
  4450   latency = basesink->priv->latency;
  3158       gst_base_sink_get_position_last (basesink, &last);
  4451 
  3159       latency = basesink->priv->latency;
  4452   gst_object_ref (clock);
  3160 
  4453 
  3161       gst_object_ref (clock);
  4454   /* this function might release the LOCK */
  3162       /* need to release the object lock before we can get the time, 
  4455   gst_base_sink_get_position_last (basesink, format, &last);
  3163        * a clock might take the LOCK of the provider, which could be
  4456 
  3164        * a basesink subclass. */
  4457   /* need to release the object lock before we can get the time, 
  3165       GST_OBJECT_UNLOCK (basesink);
  4458    * a clock might take the LOCK of the provider, which could be
  3166 
  4459    * a basesink subclass. */
  3167       now = gst_clock_get_time (clock);
  4460   GST_OBJECT_UNLOCK (basesink);
  3168 
  4461 
  3169       /* subtract base time and accumulated time from the clock time. 
  4462   now = gst_clock_get_time (clock);
  3170        * Make sure we don't go negative. This is the current time in
  4463 
  3171        * the segment which we need to scale with the combined 
  4464   if (oformat != tformat) {
  3172        * rate and applied rate. */
  4465     /* convert accum, time and duration to time */
  3173       base += accum;
  4466     if (!gst_pad_query_convert (basesink->sinkpad, oformat, accum, &tformat,
  3174       base += latency;
  4467             &accum))
  3175       base = MIN (now, base);
  4468       goto convert_failed;
  3176 
  4469     if (!gst_pad_query_convert (basesink->sinkpad, oformat, duration, &tformat,
  3177       /* for negative rates we need to count back from from the segment
  4470             &duration))
  3178        * duration. */
  4471       goto convert_failed;
  3179       if (rate < 0.0)
  4472     if (!gst_pad_query_convert (basesink->sinkpad, oformat, time, &tformat,
  3180         time += duration;
  4473             &time))
  3181       *cur = time + gst_guint64_to_gdouble (now - base) * rate;
  4474       goto convert_failed;
  3182 
  4475   }
  3183       /* never report more than last seen position */
  4476 
  3184       if (last != -1)
  4477   /* subtract base time and accumulated time from the clock time. 
  3185         *cur = MIN (last, *cur);
  4478    * Make sure we don't go negative. This is the current time in
  3186 
  4479    * the segment which we need to scale with the combined 
  3187       gst_object_unref (clock);
  4480    * rate and applied rate. */
  3188 
  4481   base += accum;
  3189       res = TRUE;
  4482   base += latency;
  3190 
  4483   base = MIN (now, base);
  3191       GST_DEBUG_OBJECT (basesink,
  4484 
  3192           "now %" GST_TIME_FORMAT " - base %" GST_TIME_FORMAT " - accum %"
  4485   /* for negative rates we need to count back from from the segment
  3193           GST_TIME_FORMAT " + time %" GST_TIME_FORMAT,
  4486    * duration. */
  3194           GST_TIME_ARGS (now), GST_TIME_ARGS (base),
  4487   if (rate < 0.0)
  3195           GST_TIME_ARGS (accum), GST_TIME_ARGS (time));
  4488     time += duration;
  3196       break;
  4489 
  3197     }
  4490   *cur = time + gst_guint64_to_gdouble (now - base) * rate;
  3198     default:
  4491 
  3199       /* cannot answer other than TIME, we return FALSE, which will
  4492   /* never report more than last seen position */
  3200        * send the query upstream. */
  4493   if (last != -1)
  3201       break;
  4494     *cur = MIN (last, *cur);
  3202   }
  4495 
       
  4496   gst_object_unref (clock);
       
  4497 
       
  4498   GST_DEBUG_OBJECT (basesink,
       
  4499       "now %" GST_TIME_FORMAT " - base %" GST_TIME_FORMAT " - accum %"
       
  4500       GST_TIME_FORMAT " + time %" GST_TIME_FORMAT,
       
  4501       GST_TIME_ARGS (now), GST_TIME_ARGS (base),
       
  4502       GST_TIME_ARGS (accum), GST_TIME_ARGS (time));
       
  4503 
       
  4504   if (oformat != format) {
       
  4505     /* convert time to final format */
       
  4506     if (!gst_pad_query_convert (basesink->sinkpad, tformat, *cur, &format, cur))
       
  4507       goto convert_failed;
       
  4508   }
       
  4509 
       
  4510   res = TRUE;
       
  4511 
  3203 
  4512 done:
  3204 done:
  4513   GST_DEBUG_OBJECT (basesink, "res: %d, POSITION: %" GST_TIME_FORMAT,
  3205   GST_DEBUG_OBJECT (basesink, "res: %d, POSITION: %" GST_TIME_FORMAT,
  4514       res, GST_TIME_ARGS (*cur));
  3206       res, GST_TIME_ARGS (*cur));
  4515   return res;
  3207   return res;
  4516 
  3208 
  4517   /* special cases */
  3209   /* special cases */
  4518 in_eos:
  3210 in_eos:
  4519   {
  3211   {
  4520     GST_DEBUG_OBJECT (basesink, "position in EOS");
  3212     GST_DEBUG_OBJECT (basesink, "position in EOS");
  4521     res = gst_base_sink_get_position_last (basesink, format, cur);
  3213     res = gst_base_sink_get_position_last (basesink, cur);
  4522     GST_OBJECT_UNLOCK (basesink);
  3214     GST_OBJECT_UNLOCK (basesink);
  4523     goto done;
  3215     goto done;
  4524   }
  3216   }
  4525 in_pause:
  3217 in_pause:
  4526   {
  3218   {
  4527     GST_DEBUG_OBJECT (basesink, "position in PAUSED");
  3219     GST_DEBUG_OBJECT (basesink, "position in PAUSED");
  4528     res = gst_base_sink_get_position_paused (basesink, format, cur);
  3220     res = gst_base_sink_get_position_paused (basesink, cur);
  4529     GST_OBJECT_UNLOCK (basesink);
  3221     GST_OBJECT_UNLOCK (basesink);
  4530     goto done;
  3222     goto done;
  4531   }
  3223   }
  4532 wrong_state:
  3224 wrong_state:
  4533   {
  3225   {
  4534     /* in NULL or READY we always return FALSE and -1 */
  3226     /* in NULL or READY we always return 0 */
  4535     GST_DEBUG_OBJECT (basesink, "position in wrong state, return -1");
  3227     GST_DEBUG_OBJECT (basesink, "position in wrong state, return -1");
  4536     res = FALSE;
  3228     res = FALSE;
  4537     *cur = -1;
  3229     *cur = -1;
  4538     GST_OBJECT_UNLOCK (basesink);
  3230     GST_OBJECT_UNLOCK (basesink);
  4539     goto done;
  3231     goto done;
  4540   }
  3232   }
  4541 no_sync:
  3233 no_sync:
  4542   {
  3234   {
  4543     /* report last seen timestamp if any, else ask upstream to answer */
  3235     /* report last seen timestamp if any, else return FALSE so
       
  3236      * that upstream can answer */
  4544     if ((*cur = basesink->priv->current_sstart) != -1)
  3237     if ((*cur = basesink->priv->current_sstart) != -1)
  4545       res = TRUE;
  3238       res = TRUE;
  4546     else
       
  4547       *upstream = TRUE;
       
  4548 
       
  4549     GST_DEBUG_OBJECT (basesink, "no sync, res %d, POSITION %" GST_TIME_FORMAT,
  3239     GST_DEBUG_OBJECT (basesink, "no sync, res %d, POSITION %" GST_TIME_FORMAT,
  4550         res, GST_TIME_ARGS (*cur));
  3240         res, GST_TIME_ARGS (*cur));
  4551     GST_OBJECT_UNLOCK (basesink);
  3241     GST_OBJECT_UNLOCK (basesink);
  4552     return res;
  3242     return res;
  4553   }
       
  4554 convert_failed:
       
  4555   {
       
  4556     GST_DEBUG_OBJECT (basesink, "convert failed, try upstream");
       
  4557     *upstream = TRUE;
       
  4558     return FALSE;
       
  4559   }
  3243   }
  4560 }
  3244 }
  4561 
  3245 
  4562 static gboolean
  3246 static gboolean
  4563 gst_base_sink_query (GstElement * element, GstQuery * query)
  3247 gst_base_sink_query (GstElement * element, GstQuery * query)
  4569   switch (GST_QUERY_TYPE (query)) {
  3253   switch (GST_QUERY_TYPE (query)) {
  4570     case GST_QUERY_POSITION:
  3254     case GST_QUERY_POSITION:
  4571     {
  3255     {
  4572       gint64 cur = 0;
  3256       gint64 cur = 0;
  4573       GstFormat format;
  3257       GstFormat format;
  4574       gboolean upstream = FALSE;
       
  4575 
  3258 
  4576       gst_query_parse_position (query, &format, NULL);
  3259       gst_query_parse_position (query, &format, NULL);
  4577 
  3260 
  4578       GST_DEBUG_OBJECT (basesink, "position format %d", format);
  3261       GST_DEBUG_OBJECT (basesink, "position format %d", format);
  4579 
  3262 
  4580       /* first try to get the position based on the clock */
  3263       /* first try to get the position based on the clock */
  4581       if ((res =
  3264       if ((res = gst_base_sink_get_position (basesink, format, &cur))) {
  4582               gst_base_sink_get_position (basesink, format, &cur, &upstream))) {
       
  4583         gst_query_set_position (query, format, cur);
  3265         gst_query_set_position (query, format, cur);
  4584       } else if (upstream) {
  3266       } else {
  4585         /* fallback to peer query */
  3267         /* fallback to peer query */
  4586         res = gst_base_sink_peer_query (basesink, query);
  3268         res = gst_base_sink_peer_query (basesink, query);
  4587       }
  3269       }
  4588       break;
  3270       break;
  4589     }
  3271     }
  4590     case GST_QUERY_DURATION:
  3272     case GST_QUERY_DURATION:
  4591     {
  3273       GST_DEBUG_OBJECT (basesink, "duration query");
  4592       GstFormat format, uformat;
  3274       res = gst_base_sink_peer_query (basesink, query);
  4593       gint64 duration, uduration;
  3275       break;
  4594 
       
  4595       gst_query_parse_duration (query, &format, NULL);
       
  4596 
       
  4597       GST_DEBUG_OBJECT (basesink, "duration query in format %s",
       
  4598           gst_format_get_name (format));
       
  4599 
       
  4600       if (basesink->pad_mode == GST_ACTIVATE_PULL) {
       
  4601         uformat = GST_FORMAT_BYTES;
       
  4602 
       
  4603         /* get the duration in bytes, in pull mode that's all we are sure to
       
  4604          * know. We have to explicitly get this value from upstream instead of
       
  4605          * using our cached value because it might change. Duration caching
       
  4606          * should be done at a higher level. */
       
  4607         res = gst_pad_query_peer_duration (basesink->sinkpad, &uformat,
       
  4608             &uduration);
       
  4609         if (res) {
       
  4610           gst_segment_set_duration (&basesink->segment, uformat, uduration);
       
  4611           if (format != uformat) {
       
  4612             /* convert to the requested format */
       
  4613             res = gst_pad_query_convert (basesink->sinkpad, uformat, uduration,
       
  4614                 &format, &duration);
       
  4615           } else {
       
  4616             duration = uduration;
       
  4617           }
       
  4618           if (res) {
       
  4619             /* set the result */
       
  4620             gst_query_set_duration (query, format, duration);
       
  4621           }
       
  4622         }
       
  4623       } else {
       
  4624         /* in push mode we simply forward upstream */
       
  4625         res = gst_base_sink_peer_query (basesink, query);
       
  4626       }
       
  4627       break;
       
  4628     }
       
  4629     case GST_QUERY_LATENCY:
  3276     case GST_QUERY_LATENCY:
  4630     {
  3277     {
  4631       gboolean live, us_live;
  3278       gboolean live, us_live;
  4632       GstClockTime min, max;
  3279       GstClockTime min, max;
  4633 
  3280 
  4681     case GST_STATE_CHANGE_READY_TO_PAUSED:
  3328     case GST_STATE_CHANGE_READY_TO_PAUSED:
  4682       /* need to complete preroll before this state change completes, there
  3329       /* need to complete preroll before this state change completes, there
  4683        * is no data flow in READY so we can safely assume we need to preroll. */
  3330        * is no data flow in READY so we can safely assume we need to preroll. */
  4684       GST_PAD_PREROLL_LOCK (basesink->sinkpad);
  3331       GST_PAD_PREROLL_LOCK (basesink->sinkpad);
  4685       GST_DEBUG_OBJECT (basesink, "READY to PAUSED");
  3332       GST_DEBUG_OBJECT (basesink, "READY to PAUSED");
  4686       basesink->have_newsegment = FALSE;
       
  4687       gst_segment_init (&basesink->segment, GST_FORMAT_UNDEFINED);
  3333       gst_segment_init (&basesink->segment, GST_FORMAT_UNDEFINED);
  4688       gst_segment_init (basesink->abidata.ABI.clip_segment,
  3334       gst_segment_init (basesink->abidata.ABI.clip_segment,
  4689           GST_FORMAT_UNDEFINED);
  3335           GST_FORMAT_UNDEFINED);
       
  3336       basesink->have_newsegment = FALSE;
  4690       basesink->offset = 0;
  3337       basesink->offset = 0;
  4691       basesink->have_preroll = FALSE;
  3338       basesink->have_preroll = FALSE;
  4692       priv->step_unlock = FALSE;
       
  4693       basesink->need_preroll = TRUE;
  3339       basesink->need_preroll = TRUE;
  4694       basesink->playing_async = TRUE;
  3340       basesink->playing_async = TRUE;
  4695       priv->current_sstart = -1;
  3341       priv->current_sstart = -1;
  4696       priv->current_sstop = -1;
  3342       priv->current_sstop = -1;
  4697       priv->eos_rtime = -1;
  3343       priv->eos_rtime = -1;
  4698       priv->latency = 0;
  3344       priv->latency = 0;
  4699       basesink->eos = FALSE;
  3345       basesink->eos = FALSE;
  4700       priv->received_eos = FALSE;
  3346       priv->received_eos = FALSE;
  4701       gst_base_sink_reset_qos (basesink);
  3347       gst_base_sink_reset_qos (basesink);
  4702       priv->commited = FALSE;
  3348       priv->commited = FALSE;
  4703       priv->call_preroll = TRUE;
       
  4704       priv->current_step.valid = FALSE;
       
  4705       priv->pending_step.valid = FALSE;
       
  4706       if (priv->async_enabled) {
  3349       if (priv->async_enabled) {
  4707         GST_DEBUG_OBJECT (basesink, "doing async state change");
  3350         GST_DEBUG_OBJECT (basesink, "doing async state change");
  4708         /* when async enabled, post async-start message and return ASYNC from
  3351         /* when async enabled, post async-start message and return ASYNC from
  4709          * the state change function */
  3352          * the state change function */
  4710         ret = GST_STATE_CHANGE_ASYNC;
  3353         ret = GST_STATE_CHANGE_ASYNC;
  4721         GST_DEBUG_OBJECT (basesink, "PAUSED to PLAYING, don't need preroll");
  3364         GST_DEBUG_OBJECT (basesink, "PAUSED to PLAYING, don't need preroll");
  4722         /* no preroll needed anymore now. */
  3365         /* no preroll needed anymore now. */
  4723         basesink->playing_async = FALSE;
  3366         basesink->playing_async = FALSE;
  4724         basesink->need_preroll = FALSE;
  3367         basesink->need_preroll = FALSE;
  4725         if (basesink->eos) {
  3368         if (basesink->eos) {
  4726           GstMessage *message;
       
  4727 
       
  4728           /* need to post EOS message here */
  3369           /* need to post EOS message here */
  4729           GST_DEBUG_OBJECT (basesink, "Now posting EOS");
  3370           GST_DEBUG_OBJECT (basesink, "Now posting EOS");
  4730           message = gst_message_new_eos (GST_OBJECT_CAST (basesink));
  3371           gst_element_post_message (GST_ELEMENT_CAST (basesink),
  4731           gst_message_set_seqnum (message, basesink->priv->seqnum);
  3372               gst_message_new_eos (GST_OBJECT_CAST (basesink)));
  4732           gst_element_post_message (GST_ELEMENT_CAST (basesink), message);
       
  4733         } else {
  3373         } else {
  4734           GST_DEBUG_OBJECT (basesink, "signal preroll");
  3374           GST_DEBUG_OBJECT (basesink, "signal preroll");
  4735           GST_PAD_PREROLL_SIGNAL (basesink->sinkpad);
  3375           GST_PAD_PREROLL_SIGNAL (basesink->sinkpad);
  4736         }
  3376         }
  4737       } else {
  3377       } else {
  4738         GST_DEBUG_OBJECT (basesink, "PAUSED to PLAYING, we are not prerolled");
  3378         GST_DEBUG_OBJECT (basesink, "PAUSED to PLAYING, we are not prerolled");
  4739         basesink->need_preroll = TRUE;
  3379         basesink->need_preroll = TRUE;
  4740         basesink->playing_async = TRUE;
  3380         basesink->playing_async = TRUE;
  4741         priv->call_preroll = TRUE;
       
  4742         priv->commited = FALSE;
  3381         priv->commited = FALSE;
  4743         if (priv->async_enabled) {
  3382         if (priv->async_enabled) {
  4744           GST_DEBUG_OBJECT (basesink, "doing async state change");
  3383           GST_DEBUG_OBJECT (basesink, "doing async state change");
  4745           ret = GST_STATE_CHANGE_ASYNC;
  3384           ret = GST_STATE_CHANGE_ASYNC;
  4746           gst_element_post_message (GST_ELEMENT_CAST (basesink),
  3385           gst_element_post_message (GST_ELEMENT_CAST (basesink),
  4760     if (G_UNLIKELY (bret == GST_STATE_CHANGE_FAILURE))
  3399     if (G_UNLIKELY (bret == GST_STATE_CHANGE_FAILURE))
  4761       goto activate_failed;
  3400       goto activate_failed;
  4762   }
  3401   }
  4763 
  3402 
  4764   switch (transition) {
  3403   switch (transition) {
       
  3404     case GST_STATE_CHANGE_READY_TO_PAUSED:
       
  3405       /* note that this is the upward case, which doesn't follow most
       
  3406          patterns */
       
  3407       if (basesink->pad_mode == GST_ACTIVATE_PULL) {
       
  3408         GST_DEBUG_OBJECT (basesink, "basesink activated in pull mode, "
       
  3409             "returning SUCCESS directly");
       
  3410         GST_PAD_PREROLL_LOCK (basesink->sinkpad);
       
  3411         gst_element_post_message (GST_ELEMENT_CAST (basesink),
       
  3412             gst_message_new_async_done (GST_OBJECT_CAST (basesink)));
       
  3413         GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
       
  3414         ret = GST_STATE_CHANGE_SUCCESS;
       
  3415       }
       
  3416       break;
  4765     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
  3417     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
  4766       GST_DEBUG_OBJECT (basesink, "PLAYING to PAUSED");
  3418       GST_DEBUG_OBJECT (basesink, "PLAYING to PAUSED");
  4767       /* FIXME, make sure we cannot enter _render first */
  3419       /* FIXME, make sure we cannot enter _render first */
  4768 
  3420 
  4769       /* we need to call ::unlock before locking PREROLL_LOCK
  3421       /* we need to call ::unlock before locking PREROLL_LOCK
  4796         } else {
  3448         } else {
  4797           GST_DEBUG_OBJECT (basesink,
  3449           GST_DEBUG_OBJECT (basesink,
  4798               "PLAYING to PAUSED, we are not prerolled");
  3450               "PLAYING to PAUSED, we are not prerolled");
  4799           basesink->playing_async = TRUE;
  3451           basesink->playing_async = TRUE;
  4800           priv->commited = FALSE;
  3452           priv->commited = FALSE;
  4801           priv->call_preroll = TRUE;
       
  4802           if (priv->async_enabled) {
  3453           if (priv->async_enabled) {
  4803             GST_DEBUG_OBJECT (basesink, "doing async state change");
  3454             GST_DEBUG_OBJECT (basesink, "doing async state change");
  4804             ret = GST_STATE_CHANGE_ASYNC;
  3455             ret = GST_STATE_CHANGE_ASYNC;
  4805             gst_element_post_message (GST_ELEMENT_CAST (basesink),
  3456             gst_element_post_message (GST_ELEMENT_CAST (basesink),
  4806                 gst_message_new_async_start (GST_OBJECT_CAST (basesink),
  3457                 gst_message_new_async_start (GST_OBJECT_CAST (basesink),
  4814       gst_base_sink_reset_qos (basesink);
  3465       gst_base_sink_reset_qos (basesink);
  4815       GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
  3466       GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
  4816       break;
  3467       break;
  4817     case GST_STATE_CHANGE_PAUSED_TO_READY:
  3468     case GST_STATE_CHANGE_PAUSED_TO_READY:
  4818       GST_PAD_PREROLL_LOCK (basesink->sinkpad);
  3469       GST_PAD_PREROLL_LOCK (basesink->sinkpad);
  4819       /* start by reseting our position state with the object lock so that the
       
  4820        * position query gets the right idea. We do this before we post the
       
  4821        * messages so that the message handlers pick this up. */
       
  4822       GST_OBJECT_LOCK (basesink);
       
  4823       basesink->have_newsegment = FALSE;
       
  4824       priv->current_sstart = -1;
       
  4825       priv->current_sstop = -1;
       
  4826       priv->have_latency = FALSE;
       
  4827       GST_OBJECT_UNLOCK (basesink);
       
  4828 
       
  4829       gst_base_sink_set_last_buffer (basesink, NULL);
       
  4830       priv->call_preroll = FALSE;
       
  4831 
       
  4832       if (!priv->commited) {
  3470       if (!priv->commited) {
  4833         if (priv->async_enabled) {
  3471         if (priv->async_enabled) {
  4834           GST_DEBUG_OBJECT (basesink, "PAUSED to READY, posting async-done");
  3472           GST_DEBUG_OBJECT (basesink, "PAUSED to READY, posting async-done");
  4835 
  3473 
  4836           gst_element_post_message (GST_ELEMENT_CAST (basesink),
  3474           gst_element_post_message (GST_ELEMENT_CAST (basesink),
  4842         }
  3480         }
  4843         priv->commited = TRUE;
  3481         priv->commited = TRUE;
  4844       } else {
  3482       } else {
  4845         GST_DEBUG_OBJECT (basesink, "PAUSED to READY, don't need_preroll");
  3483         GST_DEBUG_OBJECT (basesink, "PAUSED to READY, don't need_preroll");
  4846       }
  3484       }
       
  3485       priv->current_sstart = -1;
       
  3486       priv->current_sstop = -1;
       
  3487       priv->have_latency = FALSE;
       
  3488       gst_base_sink_set_last_buffer (basesink, NULL);
  4847       GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
  3489       GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
  4848       break;
  3490       break;
  4849     case GST_STATE_CHANGE_READY_TO_NULL:
  3491     case GST_STATE_CHANGE_READY_TO_NULL:
  4850       if (bclass->stop) {
  3492       if (bclass->stop) {
  4851         if (!bclass->stop (basesink)) {
  3493         if (!bclass->stop (basesink)) {
  4852           GST_WARNING_OBJECT (basesink, "failed to stop");
  3494           GST_WARNING_OBJECT (basesink, "failed to stop");
  4853         }
  3495         }
  4854       }
  3496       }
  4855       gst_base_sink_set_last_buffer (basesink, NULL);
  3497       gst_base_sink_set_last_buffer (basesink, NULL);
  4856       priv->call_preroll = FALSE;
       
  4857       break;
  3498       break;
  4858     default:
  3499     default:
  4859       break;
  3500       break;
  4860   }
  3501   }
  4861 
  3502