basesink: Switch enable_last_buffer to an atomic int
[platform/upstream/gstreamer.git] / libs / gst / base / gstbasesink.c
1 /* GStreamer
2  * Copyright (C) 2005-2007 Wim Taymans <wim.taymans@gmail.com>
3  *
4  * gstbasesink.c: Base class for sink elements
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 /**
23  * SECTION:gstbasesink
24  * @short_description: Base class for sink elements
25  * @see_also: #GstBaseTransform, #GstBaseSrc
26  *
27  * #GstBaseSink is the base class for sink elements in GStreamer, such as
28  * xvimagesink or filesink. It is a layer on top of #GstElement that provides a
29  * simplified interface to plugin writers. #GstBaseSink handles many details
30  * for you, for example: preroll, clock synchronization, state changes,
31  * activation in push or pull mode, and queries.
32  *
33  * In most cases, when writing sink elements, there is no need to implement
34  * class methods from #GstElement or to set functions on pads, because the
35  * #GstBaseSink infrastructure should be sufficient.
36  *
37  * #GstBaseSink provides support for exactly one sink pad, which should be
38  * named "sink". A sink implementation (subclass of #GstBaseSink) should
39  * install a pad template in its base_init function, like so:
40  * |[
41  * static void
42  * my_element_base_init (gpointer g_class)
43  * {
44  *   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
45  *
46  *   // sinktemplate should be a #GstStaticPadTemplate with direction
47  *   // #GST_PAD_SINK and name "sink"
48  *   gst_element_class_add_pad_template (gstelement_class,
49  *       gst_static_pad_template_get (&amp;sinktemplate));
50  *   // see #GstElementDetails
51  *   gst_element_class_set_details (gstelement_class, &amp;details);
52  * }
53  * ]|
54  *
55  * #GstBaseSink will handle the prerolling correctly. This means that it will
56  * return #GST_STATE_CHANGE_ASYNC from a state change to PAUSED until the first
57  * buffer arrives in this element. The base class will call the
58  * #GstBaseSinkClass.preroll() vmethod with this preroll buffer and will then
59  * commit the state change to the next asynchronously pending state.
60  *
61  * When the element is set to PLAYING, #GstBaseSink will synchronise on the
62  * clock using the times returned from #GstBaseSinkClass.get_times(). If this
63  * function returns #GST_CLOCK_TIME_NONE for the start time, no synchronisation
64  * will be done. Synchronisation can be disabled entirely by setting the object
65  * #GstBaseSink:sync property to %FALSE.
66  *
67  * After synchronisation the virtual method #GstBaseSinkClass.render() will be
68  * called. Subclasses should minimally implement this method.
69  *
70  * Since 0.10.3 subclasses that synchronise on the clock in the
71  * #GstBaseSinkClass.render() method are supported as well. These classes
72  * typically receive a buffer in the render method and can then potentially
73  * block on the clock while rendering. A typical example is an audiosink.
74  * Since 0.10.11 these subclasses can use gst_base_sink_wait_preroll() to
75  * perform the blocking wait.
76  *
77  * Upon receiving the EOS event in the PLAYING state, #GstBaseSink will wait
78  * for the clock to reach the time indicated by the stop time of the last
79  * #GstBaseSinkClass.get_times() call before posting an EOS message. When the
80  * element receives EOS in PAUSED, preroll completes, the event is queued and an
81  * EOS message is posted when going to PLAYING.
82  *
83  * #GstBaseSink will internally use the #GST_EVENT_NEWSEGMENT events to schedule
84  * synchronisation and clipping of buffers. Buffers that fall completely outside
85  * of the current segment are dropped. Buffers that fall partially in the
86  * segment are rendered (and prerolled). Subclasses should do any subbuffer
87  * clipping themselves when needed.
88  *
89  * #GstBaseSink will by default report the current playback position in
90  * #GST_FORMAT_TIME based on the current clock time and segment information.
91  * If no clock has been set on the element, the query will be forwarded
92  * upstream.
93  *
94  * The #GstBaseSinkClass.set_caps() function will be called when the subclass
95  * should configure itself to process a specific media type.
96  *
97  * The #GstBaseSinkClass.start() and #GstBaseSinkClass.stop() virtual methods
98  * will be called when resources should be allocated. Any 
99  * #GstBaseSinkClass.preroll(), #GstBaseSinkClass.render() and
100  * #GstBaseSinkClass.set_caps() function will be called between the
101  * #GstBaseSinkClass.start() and #GstBaseSinkClass.stop() calls.
102  *
103  * The #GstBaseSinkClass.event() virtual method will be called when an event is
104  * received by #GstBaseSink. Normally this method should only be overriden by
105  * very specific elements (such as file sinks) which need to handle the
106  * newsegment event specially.
107  *
108  * #GstBaseSink provides an overridable #GstBaseSinkClass.buffer_alloc()
109  * function that can be used by sinks that want to do reverse negotiation or to
110  * provide custom buffers (hardware buffers for example) to upstream elements.
111  *
112  * The #GstBaseSinkClass.unlock() method is called when the elements should
113  * unblock any blocking operations they perform in the
114  * #GstBaseSinkClass.render() method. This is mostly useful when the
115  * #GstBaseSinkClass.render() method performs a blocking write on a file
116  * descriptor, for example.
117  *
118  * The #GstBaseSink:max-lateness property affects how the sink deals with
119  * buffers that arrive too late in the sink. A buffer arrives too late in the
120  * sink when the presentation time (as a combination of the last segment, buffer
121  * timestamp and element base_time) plus the duration is before the current
122  * time of the clock.
123  * If the frame is later than max-lateness, the sink will drop the buffer
124  * without calling the render method.
125  * This feature is disabled if sync is disabled, the
126  * #GstBaseSinkClass.get_times() method does not return a valid start time or
127  * max-lateness is set to -1 (the default).
128  * Subclasses can use gst_base_sink_set_max_lateness() to configure the
129  * max-lateness value.
130  *
131  * The #GstBaseSink:qos property will enable the quality-of-service features of
132  * the basesink which gather statistics about the real-time performance of the
133  * clock synchronisation. For each buffer received in the sink, statistics are
134  * gathered and a QOS event is sent upstream with these numbers. This
135  * information can then be used by upstream elements to reduce their processing
136  * rate, for example.
137  *
138  * Since 0.10.15 the #GstBaseSink:async property can be used to instruct the
139  * sink to never perform an ASYNC state change. This feature is mostly usable
140  * when dealing with non-synchronized streams or sparse streams.
141  *
142  * Last reviewed on 2007-08-29 (0.10.15)
143  */
144
145 #ifdef HAVE_CONFIG_H
146 #  include "config.h"
147 #endif
148
149 #include <gst/gst_private.h>
150
151 #include "gstbasesink.h"
152 #include <gst/gstmarshal.h>
153 #include <gst/gst-i18n-lib.h>
154
155 GST_DEBUG_CATEGORY_STATIC (gst_base_sink_debug);
156 #define GST_CAT_DEFAULT gst_base_sink_debug
157
158 #define GST_BASE_SINK_GET_PRIVATE(obj)  \
159    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_SINK, GstBaseSinkPrivate))
160
161 #define GST_FLOW_STEP GST_FLOW_CUSTOM_ERROR
162
163 typedef struct
164 {
165   gboolean valid;               /* if this info is valid */
166   guint32 seqnum;               /* the seqnum of the STEP event */
167   GstFormat format;             /* the format of the amount */
168   guint64 amount;               /* the total amount of data to skip */
169   guint64 position;             /* the position in the stepped data */
170   guint64 duration;             /* the duration in time of the skipped data */
171   guint64 start;                /* running_time of the start */
172   gdouble rate;                 /* rate of skipping */
173   gdouble start_rate;           /* rate before skipping */
174   guint64 start_start;          /* start position skipping */
175   guint64 start_stop;           /* stop position skipping */
176   gboolean flush;               /* if this was a flushing step */
177   gboolean intermediate;        /* if this is an intermediate step */
178   gboolean need_preroll;        /* if we need preroll after this step */
179 } GstStepInfo;
180
181 /* FIXME, some stuff in ABI.data and other in Private...
182  * Make up your mind please.
183  */
184 struct _GstBaseSinkPrivate
185 {
186   gint qos_enabled;             /* ATOMIC */
187   gboolean async_enabled;
188   GstClockTimeDiff ts_offset;
189   GstClockTime render_delay;
190
191   /* start, stop of current buffer, stream time, used to report position */
192   GstClockTime current_sstart;
193   GstClockTime current_sstop;
194
195   /* start, stop and jitter of current buffer, running time */
196   GstClockTime current_rstart;
197   GstClockTime current_rstop;
198   GstClockTimeDiff current_jitter;
199
200   /* EOS sync time in running time */
201   GstClockTime eos_rtime;
202
203   /* last buffer that arrived in time, running time */
204   GstClockTime last_in_time;
205   /* when the last buffer left the sink, running time */
206   GstClockTime last_left;
207
208   /* running averages go here these are done on running time */
209   GstClockTime avg_pt;
210   GstClockTime avg_duration;
211   gdouble avg_rate;
212
213   /* these are done on system time. avg_jitter and avg_render are
214    * compared to eachother to see if the rendering time takes a
215    * huge amount of the processing, If so we are flooded with
216    * buffers. */
217   GstClockTime last_left_systime;
218   GstClockTime avg_jitter;
219   GstClockTime start, stop;
220   GstClockTime avg_render;
221
222   /* number of rendered and dropped frames */
223   guint64 rendered;
224   guint64 dropped;
225
226   /* latency stuff */
227   GstClockTime latency;
228
229   /* if we already commited the state */
230   gboolean commited;
231
232   /* when we received EOS */
233   gboolean received_eos;
234
235   /* when we are prerolled and able to report latency */
236   gboolean have_latency;
237
238   /* the last buffer we prerolled or rendered. Useful for making snapshots */
239   gint enable_last_buffer;      /* atomic */
240   GstBuffer *last_buffer;
241
242   /* caps for pull based scheduling */
243   GstCaps *pull_caps;
244
245   /* blocksize for pulling */
246   guint blocksize;
247
248   gboolean discont;
249
250   /* seqnum of the stream */
251   guint32 seqnum;
252
253   gboolean call_preroll;
254   gboolean step_unlock;
255
256   /* we have a pending and a current step operation */
257   GstStepInfo current_step;
258   GstStepInfo pending_step;
259 };
260
261 #define DO_RUNNING_AVG(avg,val,size) (((val) + ((size)-1) * (avg)) / (size))
262
263 /* generic running average, this has a neutral window size */
264 #define UPDATE_RUNNING_AVG(avg,val)   DO_RUNNING_AVG(avg,val,8)
265
266 /* the windows for these running averages are experimentally obtained.
267  * possitive values get averaged more while negative values use a small
268  * window so we can react faster to badness. */
269 #define UPDATE_RUNNING_AVG_P(avg,val) DO_RUNNING_AVG(avg,val,16)
270 #define UPDATE_RUNNING_AVG_N(avg,val) DO_RUNNING_AVG(avg,val,4)
271
272 /* BaseSink properties */
273
274 #define DEFAULT_CAN_ACTIVATE_PULL FALSE /* fixme: enable me */
275 #define DEFAULT_CAN_ACTIVATE_PUSH TRUE
276
277 #define DEFAULT_PREROLL_QUEUE_LEN   0
278 #define DEFAULT_SYNC                TRUE
279 #define DEFAULT_MAX_LATENESS        -1
280 #define DEFAULT_QOS                 FALSE
281 #define DEFAULT_ASYNC               TRUE
282 #define DEFAULT_TS_OFFSET           0
283 #define DEFAULT_BLOCKSIZE           4096
284 #define DEFAULT_RENDER_DELAY        0
285 #define DEFAULT_ENABLE_LAST_BUFFER  TRUE
286
287 enum
288 {
289   PROP_0,
290   PROP_PREROLL_QUEUE_LEN,
291   PROP_SYNC,
292   PROP_MAX_LATENESS,
293   PROP_QOS,
294   PROP_ASYNC,
295   PROP_TS_OFFSET,
296   PROP_ENABLE_LAST_BUFFER,
297   PROP_LAST_BUFFER,
298   PROP_BLOCKSIZE,
299   PROP_RENDER_DELAY,
300   PROP_LAST
301 };
302
303 static GstElementClass *parent_class = NULL;
304
305 static void gst_base_sink_class_init (GstBaseSinkClass * klass);
306 static void gst_base_sink_init (GstBaseSink * trans, gpointer g_class);
307 static void gst_base_sink_finalize (GObject * object);
308
309 GType
310 gst_base_sink_get_type (void)
311 {
312   static volatile gsize base_sink_type = 0;
313
314   if (g_once_init_enter (&base_sink_type)) {
315     GType _type;
316     static const GTypeInfo base_sink_info = {
317       sizeof (GstBaseSinkClass),
318       NULL,
319       NULL,
320       (GClassInitFunc) gst_base_sink_class_init,
321       NULL,
322       NULL,
323       sizeof (GstBaseSink),
324       0,
325       (GInstanceInitFunc) gst_base_sink_init,
326     };
327
328     _type = g_type_register_static (GST_TYPE_ELEMENT,
329         "GstBaseSink", &base_sink_info, G_TYPE_FLAG_ABSTRACT);
330     g_once_init_leave (&base_sink_type, _type);
331   }
332   return base_sink_type;
333 }
334
335 static void gst_base_sink_set_property (GObject * object, guint prop_id,
336     const GValue * value, GParamSpec * pspec);
337 static void gst_base_sink_get_property (GObject * object, guint prop_id,
338     GValue * value, GParamSpec * pspec);
339
340 static gboolean gst_base_sink_send_event (GstElement * element,
341     GstEvent * event);
342 static gboolean gst_base_sink_query (GstElement * element, GstQuery * query);
343 static const GstQueryType *gst_base_sink_get_query_types (GstElement * element);
344
345 static GstCaps *gst_base_sink_get_caps (GstBaseSink * sink);
346 static gboolean gst_base_sink_set_caps (GstBaseSink * sink, GstCaps * caps);
347 static GstFlowReturn gst_base_sink_buffer_alloc (GstBaseSink * sink,
348     guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
349 static void gst_base_sink_get_times (GstBaseSink * basesink, GstBuffer * buffer,
350     GstClockTime * start, GstClockTime * end);
351 static gboolean gst_base_sink_set_flushing (GstBaseSink * basesink,
352     GstPad * pad, gboolean flushing);
353 static gboolean gst_base_sink_default_activate_pull (GstBaseSink * basesink,
354     gboolean active);
355 static gboolean gst_base_sink_default_do_seek (GstBaseSink * sink,
356     GstSegment * segment);
357 static gboolean gst_base_sink_default_prepare_seek_segment (GstBaseSink * sink,
358     GstEvent * event, GstSegment * segment);
359
360 static GstStateChangeReturn gst_base_sink_change_state (GstElement * element,
361     GstStateChange transition);
362
363 static GstFlowReturn gst_base_sink_chain (GstPad * pad, GstBuffer * buffer);
364 static GstFlowReturn gst_base_sink_chain_list (GstPad * pad,
365     GstBufferList * list);
366
367 static void gst_base_sink_loop (GstPad * pad);
368 static gboolean gst_base_sink_pad_activate (GstPad * pad);
369 static gboolean gst_base_sink_pad_activate_push (GstPad * pad, gboolean active);
370 static gboolean gst_base_sink_pad_activate_pull (GstPad * pad, gboolean active);
371 static gboolean gst_base_sink_event (GstPad * pad, GstEvent * event);
372
373 static gboolean gst_base_sink_negotiate_pull (GstBaseSink * basesink);
374 static GstCaps *gst_base_sink_pad_getcaps (GstPad * pad);
375 static gboolean gst_base_sink_pad_setcaps (GstPad * pad, GstCaps * caps);
376 static void gst_base_sink_pad_fixate (GstPad * pad, GstCaps * caps);
377 static GstFlowReturn gst_base_sink_pad_buffer_alloc (GstPad * pad,
378     guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
379
380
381 /* check if an object was too late */
382 static gboolean gst_base_sink_is_too_late (GstBaseSink * basesink,
383     GstMiniObject * obj, GstClockTime start, GstClockTime stop,
384     GstClockReturn status, GstClockTimeDiff jitter);
385 static GstFlowReturn gst_base_sink_preroll_object (GstBaseSink * basesink,
386     gboolean is_list, GstMiniObject * obj);
387
388 static void
389 gst_base_sink_class_init (GstBaseSinkClass * klass)
390 {
391   GObjectClass *gobject_class;
392   GstElementClass *gstelement_class;
393
394   gobject_class = G_OBJECT_CLASS (klass);
395   gstelement_class = GST_ELEMENT_CLASS (klass);
396
397   GST_DEBUG_CATEGORY_INIT (gst_base_sink_debug, "basesink", 0,
398       "basesink element");
399
400   g_type_class_add_private (klass, sizeof (GstBaseSinkPrivate));
401
402   parent_class = g_type_class_peek_parent (klass);
403
404   gobject_class->finalize = gst_base_sink_finalize;
405   gobject_class->set_property = gst_base_sink_set_property;
406   gobject_class->get_property = gst_base_sink_get_property;
407
408   /* FIXME, this next value should be configured using an event from the
409    * upstream element, ie, the BUFFER_SIZE event. */
410   g_object_class_install_property (gobject_class, PROP_PREROLL_QUEUE_LEN,
411       g_param_spec_uint ("preroll-queue-len", "Preroll queue length",
412           "Number of buffers to queue during preroll", 0, G_MAXUINT,
413           DEFAULT_PREROLL_QUEUE_LEN,
414           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
415
416   g_object_class_install_property (gobject_class, PROP_SYNC,
417       g_param_spec_boolean ("sync", "Sync", "Sync on the clock", DEFAULT_SYNC,
418           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
419
420   g_object_class_install_property (gobject_class, PROP_MAX_LATENESS,
421       g_param_spec_int64 ("max-lateness", "Max Lateness",
422           "Maximum number of nanoseconds that a buffer can be late before it "
423           "is dropped (-1 unlimited)", -1, G_MAXINT64, DEFAULT_MAX_LATENESS,
424           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
425
426   g_object_class_install_property (gobject_class, PROP_QOS,
427       g_param_spec_boolean ("qos", "Qos",
428           "Generate Quality-of-Service events upstream", DEFAULT_QOS,
429           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
430   /**
431    * GstBaseSink:async
432    *
433    * 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.
435    * Use this option when dealing with sparse streams or when synchronisation is
436    * not required.
437    *
438    * Since: 0.10.15
439    */
440   g_object_class_install_property (gobject_class, PROP_ASYNC,
441       g_param_spec_boolean ("async", "Async",
442           "Go asynchronously to PAUSED", DEFAULT_ASYNC,
443           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
444   /**
445    * GstBaseSink:ts-offset
446    *
447    * Controls the final synchronisation, a negative value will render the buffer
448    * earlier while a positive value delays playback. This property can be
449    * used to fix synchronisation in bad files.
450    *
451    * Since: 0.10.15
452    */
453   g_object_class_install_property (gobject_class, PROP_TS_OFFSET,
454       g_param_spec_int64 ("ts-offset", "TS Offset",
455           "Timestamp offset in nanoseconds", G_MININT64, G_MAXINT64,
456           DEFAULT_TS_OFFSET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
457
458   /**
459    * GstBaseSink:enable-last-buffer
460    *
461    * Enable the last-buffer property. If FALSE, basesink doesn't keep a
462    * reference to the last buffer arrived and the last-buffer property is always
463    * set to NULL. This can be useful if you need buffers to be released as soon
464    * as possible, eg. if you're using a buffer pool.
465    *
466    * Since: 0.10.30
467    */
468   g_object_class_install_property (gobject_class, PROP_ENABLE_LAST_BUFFER,
469       g_param_spec_boolean ("enable-last-buffer", "Enable Last Buffer",
470           "Enable the last-buffer property", DEFAULT_ENABLE_LAST_BUFFER,
471           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
472
473   /**
474    * GstBaseSink:last-buffer
475    *
476    * The last buffer that arrived in the sink and was used for preroll or for
477    * rendering. This property can be used to generate thumbnails. This property
478    * can be NULL when the sink has not yet received a bufer.
479    *
480    * Since: 0.10.15
481    */
482   g_object_class_install_property (gobject_class, PROP_LAST_BUFFER,
483       gst_param_spec_mini_object ("last-buffer", "Last Buffer",
484           "The last buffer received in the sink", GST_TYPE_BUFFER,
485           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
486   /**
487    * GstBaseSink:blocksize
488    *
489    * The amount of bytes to pull when operating in pull mode.
490    *
491    * Since: 0.10.22
492    */
493   g_object_class_install_property (gobject_class, PROP_BLOCKSIZE,
494       g_param_spec_uint ("blocksize", "Block size",
495           "Size in bytes to pull per buffer (0 = default)", 0, G_MAXUINT,
496           DEFAULT_BLOCKSIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
497   /**
498    * GstBaseSink:render-delay
499    *
500    * The additional delay between synchronisation and actual rendering of the
501    * media. This property will add additional latency to the device in order to
502    * make other sinks compensate for the delay.
503    *
504    * Since: 0.10.22
505    */
506   g_object_class_install_property (gobject_class, PROP_RENDER_DELAY,
507       g_param_spec_uint64 ("render-delay", "Render Delay",
508           "Additional render delay of the sink in nanoseconds", 0, G_MAXUINT64,
509           DEFAULT_RENDER_DELAY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
510
511   gstelement_class->change_state =
512       GST_DEBUG_FUNCPTR (gst_base_sink_change_state);
513   gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_base_sink_send_event);
514   gstelement_class->query = GST_DEBUG_FUNCPTR (gst_base_sink_query);
515   gstelement_class->get_query_types =
516       GST_DEBUG_FUNCPTR (gst_base_sink_get_query_types);
517
518   klass->get_caps = GST_DEBUG_FUNCPTR (gst_base_sink_get_caps);
519   klass->set_caps = GST_DEBUG_FUNCPTR (gst_base_sink_set_caps);
520   klass->buffer_alloc = GST_DEBUG_FUNCPTR (gst_base_sink_buffer_alloc);
521   klass->get_times = GST_DEBUG_FUNCPTR (gst_base_sink_get_times);
522   klass->activate_pull =
523       GST_DEBUG_FUNCPTR (gst_base_sink_default_activate_pull);
524
525   /* Registering debug symbols for function pointers */
526   GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_getcaps);
527   GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_setcaps);
528   GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_fixate);
529   GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_buffer_alloc);
530   GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_activate);
531   GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_activate_push);
532   GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_activate_pull);
533   GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_event);
534   GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_chain);
535   GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_chain_list);
536 }
537
538 static GstCaps *
539 gst_base_sink_pad_getcaps (GstPad * pad)
540 {
541   GstBaseSinkClass *bclass;
542   GstBaseSink *bsink;
543   GstCaps *caps = NULL;
544
545   bsink = GST_BASE_SINK (gst_pad_get_parent (pad));
546   bclass = GST_BASE_SINK_GET_CLASS (bsink);
547
548   if (bsink->pad_mode == GST_ACTIVATE_PULL) {
549     /* if we are operating in pull mode we only accept the negotiated caps */
550     GST_OBJECT_LOCK (pad);
551     if ((caps = GST_PAD_CAPS (pad)))
552       gst_caps_ref (caps);
553     GST_OBJECT_UNLOCK (pad);
554   }
555   if (caps == NULL) {
556     if (bclass->get_caps)
557       caps = bclass->get_caps (bsink);
558
559     if (caps == NULL) {
560       GstPadTemplate *pad_template;
561
562       pad_template =
563           gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass),
564           "sink");
565       if (pad_template != NULL) {
566         caps = gst_caps_ref (gst_pad_template_get_caps (pad_template));
567       }
568     }
569   }
570   gst_object_unref (bsink);
571
572   return caps;
573 }
574
575 static gboolean
576 gst_base_sink_pad_setcaps (GstPad * pad, GstCaps * caps)
577 {
578   GstBaseSinkClass *bclass;
579   GstBaseSink *bsink;
580   gboolean res = TRUE;
581
582   bsink = GST_BASE_SINK (gst_pad_get_parent (pad));
583   bclass = GST_BASE_SINK_GET_CLASS (bsink);
584
585   if (res && bclass->set_caps)
586     res = bclass->set_caps (bsink, caps);
587
588   gst_object_unref (bsink);
589
590   return res;
591 }
592
593 static void
594 gst_base_sink_pad_fixate (GstPad * pad, GstCaps * caps)
595 {
596   GstBaseSinkClass *bclass;
597   GstBaseSink *bsink;
598
599   bsink = GST_BASE_SINK (gst_pad_get_parent (pad));
600   bclass = GST_BASE_SINK_GET_CLASS (bsink);
601
602   if (bclass->fixate)
603     bclass->fixate (bsink, caps);
604
605   gst_object_unref (bsink);
606 }
607
608 static GstFlowReturn
609 gst_base_sink_pad_buffer_alloc (GstPad * pad, guint64 offset, guint size,
610     GstCaps * caps, GstBuffer ** buf)
611 {
612   GstBaseSinkClass *bclass;
613   GstBaseSink *bsink;
614   GstFlowReturn result = GST_FLOW_OK;
615
616   bsink = GST_BASE_SINK (gst_pad_get_parent (pad));
617   bclass = GST_BASE_SINK_GET_CLASS (bsink);
618
619   if (bclass->buffer_alloc)
620     result = bclass->buffer_alloc (bsink, offset, size, caps, buf);
621   else
622     *buf = NULL;                /* fallback in gstpad.c will allocate generic buffer */
623
624   gst_object_unref (bsink);
625
626   return result;
627 }
628
629 static void
630 gst_base_sink_init (GstBaseSink * basesink, gpointer g_class)
631 {
632   GstPadTemplate *pad_template;
633   GstBaseSinkPrivate *priv;
634
635   basesink->priv = priv = GST_BASE_SINK_GET_PRIVATE (basesink);
636
637   pad_template =
638       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "sink");
639   g_return_if_fail (pad_template != NULL);
640
641   basesink->sinkpad = gst_pad_new_from_template (pad_template, "sink");
642
643   gst_pad_set_getcaps_function (basesink->sinkpad, gst_base_sink_pad_getcaps);
644   gst_pad_set_setcaps_function (basesink->sinkpad, gst_base_sink_pad_setcaps);
645   gst_pad_set_fixatecaps_function (basesink->sinkpad, gst_base_sink_pad_fixate);
646   gst_pad_set_bufferalloc_function (basesink->sinkpad,
647       gst_base_sink_pad_buffer_alloc);
648   gst_pad_set_activate_function (basesink->sinkpad, gst_base_sink_pad_activate);
649   gst_pad_set_activatepush_function (basesink->sinkpad,
650       gst_base_sink_pad_activate_push);
651   gst_pad_set_activatepull_function (basesink->sinkpad,
652       gst_base_sink_pad_activate_pull);
653   gst_pad_set_event_function (basesink->sinkpad, gst_base_sink_event);
654   gst_pad_set_chain_function (basesink->sinkpad, gst_base_sink_chain);
655   gst_pad_set_chain_list_function (basesink->sinkpad, gst_base_sink_chain_list);
656   gst_element_add_pad (GST_ELEMENT_CAST (basesink), basesink->sinkpad);
657
658   basesink->pad_mode = GST_ACTIVATE_NONE;
659   basesink->preroll_queue = g_queue_new ();
660   basesink->abidata.ABI.clip_segment = gst_segment_new ();
661   priv->have_latency = FALSE;
662
663   basesink->can_activate_push = DEFAULT_CAN_ACTIVATE_PUSH;
664   basesink->can_activate_pull = DEFAULT_CAN_ACTIVATE_PULL;
665
666   basesink->sync = DEFAULT_SYNC;
667   basesink->abidata.ABI.max_lateness = DEFAULT_MAX_LATENESS;
668   g_atomic_int_set (&priv->qos_enabled, DEFAULT_QOS);
669   priv->async_enabled = DEFAULT_ASYNC;
670   priv->ts_offset = DEFAULT_TS_OFFSET;
671   priv->render_delay = DEFAULT_RENDER_DELAY;
672   priv->blocksize = DEFAULT_BLOCKSIZE;
673   g_atomic_int_set (&priv->enable_last_buffer, DEFAULT_ENABLE_LAST_BUFFER);
674
675   GST_OBJECT_FLAG_SET (basesink, GST_ELEMENT_IS_SINK);
676 }
677
678 static void
679 gst_base_sink_finalize (GObject * object)
680 {
681   GstBaseSink *basesink;
682
683   basesink = GST_BASE_SINK (object);
684
685   g_queue_free (basesink->preroll_queue);
686   gst_segment_free (basesink->abidata.ABI.clip_segment);
687
688   G_OBJECT_CLASS (parent_class)->finalize (object);
689 }
690
691 /**
692  * gst_base_sink_set_sync:
693  * @sink: the sink
694  * @sync: the new sync value.
695  *
696  * Configures @sink to synchronize on the clock or not. When
697  * @sync is FALSE, incomming samples will be played as fast as
698  * possible. If @sync is TRUE, the timestamps of the incomming
699  * buffers will be used to schedule the exact render time of its
700  * contents.
701  *
702  * Since: 0.10.4
703  */
704 void
705 gst_base_sink_set_sync (GstBaseSink * sink, gboolean sync)
706 {
707   g_return_if_fail (GST_IS_BASE_SINK (sink));
708
709   GST_OBJECT_LOCK (sink);
710   sink->sync = sync;
711   GST_OBJECT_UNLOCK (sink);
712 }
713
714 /**
715  * gst_base_sink_get_sync:
716  * @sink: the sink
717  *
718  * Checks if @sink is currently configured to synchronize against the
719  * clock.
720  *
721  * Returns: TRUE if the sink is configured to synchronize against the clock.
722  *
723  * Since: 0.10.4
724  */
725 gboolean
726 gst_base_sink_get_sync (GstBaseSink * sink)
727 {
728   gboolean res;
729
730   g_return_val_if_fail (GST_IS_BASE_SINK (sink), FALSE);
731
732   GST_OBJECT_LOCK (sink);
733   res = sink->sync;
734   GST_OBJECT_UNLOCK (sink);
735
736   return res;
737 }
738
739 /**
740  * gst_base_sink_set_max_lateness:
741  * @sink: the sink
742  * @max_lateness: the new max lateness value.
743  *
744  * Sets the new max lateness value to @max_lateness. This value is
745  * used to decide if a buffer should be dropped or not based on the
746  * buffer timestamp and the current clock time. A value of -1 means
747  * an unlimited time.
748  *
749  * Since: 0.10.4
750  */
751 void
752 gst_base_sink_set_max_lateness (GstBaseSink * sink, gint64 max_lateness)
753 {
754   g_return_if_fail (GST_IS_BASE_SINK (sink));
755
756   GST_OBJECT_LOCK (sink);
757   sink->abidata.ABI.max_lateness = max_lateness;
758   GST_OBJECT_UNLOCK (sink);
759 }
760
761 /**
762  * gst_base_sink_get_max_lateness:
763  * @sink: the sink
764  *
765  * Gets the max lateness value. See gst_base_sink_set_max_lateness for
766  * more details.
767  *
768  * Returns: The maximum time in nanoseconds that a buffer can be late
769  * before it is dropped and not rendered. A value of -1 means an
770  * unlimited time.
771  *
772  * Since: 0.10.4
773  */
774 gint64
775 gst_base_sink_get_max_lateness (GstBaseSink * sink)
776 {
777   gint64 res;
778
779   g_return_val_if_fail (GST_IS_BASE_SINK (sink), -1);
780
781   GST_OBJECT_LOCK (sink);
782   res = sink->abidata.ABI.max_lateness;
783   GST_OBJECT_UNLOCK (sink);
784
785   return res;
786 }
787
788 /**
789  * gst_base_sink_set_qos_enabled:
790  * @sink: the sink
791  * @enabled: the new qos value.
792  *
793  * Configures @sink to send Quality-of-Service events upstream.
794  *
795  * Since: 0.10.5
796  */
797 void
798 gst_base_sink_set_qos_enabled (GstBaseSink * sink, gboolean enabled)
799 {
800   g_return_if_fail (GST_IS_BASE_SINK (sink));
801
802   g_atomic_int_set (&sink->priv->qos_enabled, enabled);
803 }
804
805 /**
806  * gst_base_sink_is_qos_enabled:
807  * @sink: the sink
808  *
809  * Checks if @sink is currently configured to send Quality-of-Service events
810  * upstream.
811  *
812  * Returns: TRUE if the sink is configured to perform Quality-of-Service.
813  *
814  * Since: 0.10.5
815  */
816 gboolean
817 gst_base_sink_is_qos_enabled (GstBaseSink * sink)
818 {
819   gboolean res;
820
821   g_return_val_if_fail (GST_IS_BASE_SINK (sink), FALSE);
822
823   res = g_atomic_int_get (&sink->priv->qos_enabled);
824
825   return res;
826 }
827
828 /**
829  * gst_base_sink_set_async_enabled:
830  * @sink: the sink
831  * @enabled: the new async value.
832  *
833  * Configures @sink to perform all state changes asynchronusly. When async is
834  * disabled, the sink will immediatly go to PAUSED instead of waiting for a
835  * preroll buffer. This feature is usefull if the sink does not synchronize
836  * against the clock or when it is dealing with sparse streams.
837  *
838  * Since: 0.10.15
839  */
840 void
841 gst_base_sink_set_async_enabled (GstBaseSink * sink, gboolean enabled)
842 {
843   g_return_if_fail (GST_IS_BASE_SINK (sink));
844
845   GST_PAD_PREROLL_LOCK (sink->sinkpad);
846   g_atomic_int_set (&sink->priv->async_enabled, enabled);
847   GST_LOG_OBJECT (sink, "set async enabled to %d", enabled);
848   GST_PAD_PREROLL_UNLOCK (sink->sinkpad);
849 }
850
851 /**
852  * gst_base_sink_is_async_enabled:
853  * @sink: the sink
854  *
855  * Checks if @sink is currently configured to perform asynchronous state
856  * changes to PAUSED.
857  *
858  * Returns: TRUE if the sink is configured to perform asynchronous state
859  * changes.
860  *
861  * Since: 0.10.15
862  */
863 gboolean
864 gst_base_sink_is_async_enabled (GstBaseSink * sink)
865 {
866   gboolean res;
867
868   g_return_val_if_fail (GST_IS_BASE_SINK (sink), FALSE);
869
870   res = g_atomic_int_get (&sink->priv->async_enabled);
871
872   return res;
873 }
874
875 /**
876  * gst_base_sink_set_ts_offset:
877  * @sink: the sink
878  * @offset: the new offset
879  *
880  * Adjust the synchronisation of @sink with @offset. A negative value will
881  * render buffers earlier than their timestamp. A positive value will delay
882  * rendering. This function can be used to fix playback of badly timestamped
883  * buffers.
884  *
885  * Since: 0.10.15
886  */
887 void
888 gst_base_sink_set_ts_offset (GstBaseSink * sink, GstClockTimeDiff offset)
889 {
890   g_return_if_fail (GST_IS_BASE_SINK (sink));
891
892   GST_OBJECT_LOCK (sink);
893   sink->priv->ts_offset = offset;
894   GST_LOG_OBJECT (sink, "set time offset to %" G_GINT64_FORMAT, offset);
895   GST_OBJECT_UNLOCK (sink);
896 }
897
898 /**
899  * gst_base_sink_get_ts_offset:
900  * @sink: the sink
901  *
902  * Get the synchronisation offset of @sink.
903  *
904  * Returns: The synchronisation offset.
905  *
906  * Since: 0.10.15
907  */
908 GstClockTimeDiff
909 gst_base_sink_get_ts_offset (GstBaseSink * sink)
910 {
911   GstClockTimeDiff res;
912
913   g_return_val_if_fail (GST_IS_BASE_SINK (sink), 0);
914
915   GST_OBJECT_LOCK (sink);
916   res = sink->priv->ts_offset;
917   GST_OBJECT_UNLOCK (sink);
918
919   return res;
920 }
921
922 /**
923  * gst_base_sink_get_last_buffer:
924  * @sink: the sink
925  *
926  * Get the last buffer that arrived in the sink and was used for preroll or for
927  * rendering. This property can be used to generate thumbnails.
928  *
929  * The #GstCaps on the buffer can be used to determine the type of the buffer.
930  *
931  * Returns: a #GstBuffer. gst_buffer_unref() after usage. This function returns
932  * NULL when no buffer has arrived in the sink yet or when the sink is not in
933  * PAUSED or PLAYING.
934  *
935  * Since: 0.10.15
936  */
937 GstBuffer *
938 gst_base_sink_get_last_buffer (GstBaseSink * sink)
939 {
940   GstBuffer *res;
941
942   g_return_val_if_fail (GST_IS_BASE_SINK (sink), NULL);
943
944   GST_OBJECT_LOCK (sink);
945   if ((res = sink->priv->last_buffer))
946     gst_buffer_ref (res);
947   GST_OBJECT_UNLOCK (sink);
948
949   return res;
950 }
951
952 /* with OBJECT_LOCK */
953 static void
954 gst_base_sink_set_last_buffer_unlocked (GstBaseSink * sink, GstBuffer * buffer)
955 {
956   GstBuffer *old;
957
958   old = sink->priv->last_buffer;
959   if (G_LIKELY (old != buffer)) {
960     GST_DEBUG_OBJECT (sink, "setting last buffer to %p", buffer);
961     if (G_LIKELY (buffer))
962       gst_buffer_ref (buffer);
963     sink->priv->last_buffer = buffer;
964   } else {
965     old = NULL;
966   }
967   /* avoid unreffing with the lock because cleanup code might want to take the
968    * lock too */
969   if (G_LIKELY (old)) {
970     GST_OBJECT_UNLOCK (sink);
971     gst_buffer_unref (old);
972     GST_OBJECT_LOCK (sink);
973   }
974 }
975
976 static void
977 gst_base_sink_set_last_buffer (GstBaseSink * sink, GstBuffer * buffer)
978 {
979   if (!g_atomic_int_get (&sink->priv->enable_last_buffer))
980     return;
981
982   GST_OBJECT_LOCK (sink);
983   gst_base_sink_set_last_buffer_unlocked (sink, buffer);
984   GST_OBJECT_UNLOCK (sink);
985 }
986
987 /**
988  * gst_base_sink_set_last_buffer_enabled:
989  * @sink: the sink
990  * @enabled: the new enable-last-buffer value.
991  *
992  * Configures @sink to store the last received buffer in the last-buffer
993  * property.
994  *
995  * Since: 0.10.30
996  */
997 void
998 gst_base_sink_set_last_buffer_enabled (GstBaseSink * sink, gboolean enabled)
999 {
1000   g_return_if_fail (GST_IS_BASE_SINK (sink));
1001
1002   /* Only take lock if we change the value */
1003   if (g_atomic_int_compare_and_exchange (&sink->priv->enable_last_buffer,
1004           !enabled, enabled) && !enabled) {
1005     GST_OBJECT_LOCK (sink);
1006     gst_base_sink_set_last_buffer_unlocked (sink, NULL);
1007     GST_OBJECT_UNLOCK (sink);
1008   }
1009 }
1010
1011 /**
1012  * gst_base_sink_is_last_buffer_enabled:
1013  * @sink: the sink
1014  *
1015  * Checks if @sink is currently configured to store the last received buffer in
1016  * the last-buffer property.
1017  *
1018  * Returns: TRUE if the sink is configured to store the last received buffer.
1019  *
1020  * Since: 0.10.30
1021  */
1022 gboolean
1023 gst_base_sink_is_last_buffer_enabled (GstBaseSink * sink)
1024 {
1025   g_return_val_if_fail (GST_IS_BASE_SINK (sink), FALSE);
1026
1027   return g_atomic_int_get (&sink->priv->enable_last_buffer);
1028 }
1029
1030 /**
1031  * gst_base_sink_get_latency:
1032  * @sink: the sink
1033  *
1034  * Get the currently configured latency.
1035  *
1036  * Returns: The configured latency.
1037  *
1038  * Since: 0.10.12
1039  */
1040 GstClockTime
1041 gst_base_sink_get_latency (GstBaseSink * sink)
1042 {
1043   GstClockTime res;
1044
1045   GST_OBJECT_LOCK (sink);
1046   res = sink->priv->latency;
1047   GST_OBJECT_UNLOCK (sink);
1048
1049   return res;
1050 }
1051
1052 /**
1053  * gst_base_sink_query_latency:
1054  * @sink: the sink
1055  * @live: if the sink is live
1056  * @upstream_live: if an upstream element is live
1057  * @min_latency: the min latency of the upstream elements
1058  * @max_latency: the max latency of the upstream elements
1059  *
1060  * Query the sink for the latency parameters. The latency will be queried from
1061  * the upstream elements. @live will be TRUE if @sink is configured to
1062  * synchronize against the clock. @upstream_live will be TRUE if an upstream
1063  * element is live.
1064  *
1065  * If both @live and @upstream_live are TRUE, the sink will want to compensate
1066  * for the latency introduced by the upstream elements by setting the
1067  * @min_latency to a strictly possitive value.
1068  *
1069  * This function is mostly used by subclasses.
1070  *
1071  * Returns: TRUE if the query succeeded.
1072  *
1073  * Since: 0.10.12
1074  */
1075 gboolean
1076 gst_base_sink_query_latency (GstBaseSink * sink, gboolean * live,
1077     gboolean * upstream_live, GstClockTime * min_latency,
1078     GstClockTime * max_latency)
1079 {
1080   gboolean l, us_live, res, have_latency;
1081   GstClockTime min, max, render_delay;
1082   GstQuery *query;
1083   GstClockTime us_min, us_max;
1084
1085   /* we are live when we sync to the clock */
1086   GST_OBJECT_LOCK (sink);
1087   l = sink->sync;
1088   have_latency = sink->priv->have_latency;
1089   render_delay = sink->priv->render_delay;
1090   GST_OBJECT_UNLOCK (sink);
1091
1092   /* assume no latency */
1093   min = 0;
1094   max = -1;
1095   us_live = FALSE;
1096
1097   if (have_latency) {
1098     GST_DEBUG_OBJECT (sink, "we are ready for LATENCY query");
1099     /* we are ready for a latency query this is when we preroll or when we are
1100      * not async. */
1101     query = gst_query_new_latency ();
1102
1103     /* ask the peer for the latency */
1104     if ((res = gst_pad_peer_query (sink->sinkpad, query))) {
1105       /* get upstream min and max latency */
1106       gst_query_parse_latency (query, &us_live, &us_min, &us_max);
1107
1108       if (us_live) {
1109         /* upstream live, use its latency, subclasses should use these
1110          * values to create the complete latency. */
1111         min = us_min;
1112         max = us_max;
1113       }
1114       if (l) {
1115         /* we need to add the render delay if we are live */
1116         if (min != -1)
1117           min += render_delay;
1118         if (max != -1)
1119           max += render_delay;
1120       }
1121     }
1122     gst_query_unref (query);
1123   } else {
1124     GST_DEBUG_OBJECT (sink, "we are not yet ready for LATENCY query");
1125     res = FALSE;
1126   }
1127
1128   /* not live, we tried to do the query, if it failed we return TRUE anyway */
1129   if (!res) {
1130     if (!l) {
1131       res = TRUE;
1132       GST_DEBUG_OBJECT (sink, "latency query failed but we are not live");
1133     } else {
1134       GST_DEBUG_OBJECT (sink, "latency query failed and we are live");
1135     }
1136   }
1137
1138   if (res) {
1139     GST_DEBUG_OBJECT (sink, "latency query: live: %d, have_latency %d,"
1140         " upstream: %d, min %" GST_TIME_FORMAT ", max %" GST_TIME_FORMAT, l,
1141         have_latency, us_live, GST_TIME_ARGS (min), GST_TIME_ARGS (max));
1142
1143     if (live)
1144       *live = l;
1145     if (upstream_live)
1146       *upstream_live = us_live;
1147     if (min_latency)
1148       *min_latency = min;
1149     if (max_latency)
1150       *max_latency = max;
1151   }
1152   return res;
1153 }
1154
1155 /**
1156  * gst_base_sink_set_render_delay:
1157  * @sink: a #GstBaseSink
1158  * @delay: the new delay
1159  *
1160  * Set the render delay in @sink to @delay. The render delay is the time
1161  * between actual rendering of a buffer and its synchronisation time. Some
1162  * devices might delay media rendering which can be compensated for with this
1163  * function.
1164  *
1165  * After calling this function, this sink will report additional latency and
1166  * other sinks will adjust their latency to delay the rendering of their media.
1167  *
1168  * This function is usually called by subclasses.
1169  *
1170  * Since: 0.10.21
1171  */
1172 void
1173 gst_base_sink_set_render_delay (GstBaseSink * sink, GstClockTime delay)
1174 {
1175   GstClockTime old_render_delay;
1176
1177   g_return_if_fail (GST_IS_BASE_SINK (sink));
1178
1179   GST_OBJECT_LOCK (sink);
1180   old_render_delay = sink->priv->render_delay;
1181   sink->priv->render_delay = delay;
1182   GST_LOG_OBJECT (sink, "set render delay to %" GST_TIME_FORMAT,
1183       GST_TIME_ARGS (delay));
1184   GST_OBJECT_UNLOCK (sink);
1185
1186   if (delay != old_render_delay) {
1187     GST_DEBUG_OBJECT (sink, "posting latency changed");
1188     gst_element_post_message (GST_ELEMENT_CAST (sink),
1189         gst_message_new_latency (GST_OBJECT_CAST (sink)));
1190   }
1191 }
1192
1193 /**
1194  * gst_base_sink_get_render_delay:
1195  * @sink: a #GstBaseSink
1196  *
1197  * Get the render delay of @sink. see gst_base_sink_set_render_delay() for more
1198  * information about the render delay.
1199  *
1200  * Returns: the render delay of @sink.
1201  *
1202  * Since: 0.10.21
1203  */
1204 GstClockTime
1205 gst_base_sink_get_render_delay (GstBaseSink * sink)
1206 {
1207   GstClockTimeDiff res;
1208
1209   g_return_val_if_fail (GST_IS_BASE_SINK (sink), 0);
1210
1211   GST_OBJECT_LOCK (sink);
1212   res = sink->priv->render_delay;
1213   GST_OBJECT_UNLOCK (sink);
1214
1215   return res;
1216 }
1217
1218 /**
1219  * gst_base_sink_set_blocksize:
1220  * @sink: a #GstBaseSink
1221  * @blocksize: the blocksize in bytes
1222  *
1223  * Set the number of bytes that the sink will pull when it is operating in pull
1224  * mode.
1225  *
1226  * Since: 0.10.22
1227  */
1228 void
1229 gst_base_sink_set_blocksize (GstBaseSink * sink, guint blocksize)
1230 {
1231   g_return_if_fail (GST_IS_BASE_SINK (sink));
1232
1233   GST_OBJECT_LOCK (sink);
1234   sink->priv->blocksize = blocksize;
1235   GST_LOG_OBJECT (sink, "set blocksize to %u", blocksize);
1236   GST_OBJECT_UNLOCK (sink);
1237 }
1238
1239 /**
1240  * gst_base_sink_get_blocksize:
1241  * @sink: a #GstBaseSink
1242  *
1243  * Get the number of bytes that the sink will pull when it is operating in pull
1244  * mode.
1245  *
1246  * Returns: the number of bytes @sink will pull in pull mode.
1247  *
1248  * Since: 0.10.22
1249  */
1250 guint
1251 gst_base_sink_get_blocksize (GstBaseSink * sink)
1252 {
1253   guint res;
1254
1255   g_return_val_if_fail (GST_IS_BASE_SINK (sink), 0);
1256
1257   GST_OBJECT_LOCK (sink);
1258   res = sink->priv->blocksize;
1259   GST_OBJECT_UNLOCK (sink);
1260
1261   return res;
1262 }
1263
1264 static void
1265 gst_base_sink_set_property (GObject * object, guint prop_id,
1266     const GValue * value, GParamSpec * pspec)
1267 {
1268   GstBaseSink *sink = GST_BASE_SINK (object);
1269
1270   switch (prop_id) {
1271     case PROP_PREROLL_QUEUE_LEN:
1272       /* preroll lock necessary to serialize with finish_preroll */
1273       GST_PAD_PREROLL_LOCK (sink->sinkpad);
1274       g_atomic_int_set (&sink->preroll_queue_max_len, g_value_get_uint (value));
1275       GST_PAD_PREROLL_UNLOCK (sink->sinkpad);
1276       break;
1277     case PROP_SYNC:
1278       gst_base_sink_set_sync (sink, g_value_get_boolean (value));
1279       break;
1280     case PROP_MAX_LATENESS:
1281       gst_base_sink_set_max_lateness (sink, g_value_get_int64 (value));
1282       break;
1283     case PROP_QOS:
1284       gst_base_sink_set_qos_enabled (sink, g_value_get_boolean (value));
1285       break;
1286     case PROP_ASYNC:
1287       gst_base_sink_set_async_enabled (sink, g_value_get_boolean (value));
1288       break;
1289     case PROP_TS_OFFSET:
1290       gst_base_sink_set_ts_offset (sink, g_value_get_int64 (value));
1291       break;
1292     case PROP_BLOCKSIZE:
1293       gst_base_sink_set_blocksize (sink, g_value_get_uint (value));
1294       break;
1295     case PROP_RENDER_DELAY:
1296       gst_base_sink_set_render_delay (sink, g_value_get_uint64 (value));
1297       break;
1298     case PROP_ENABLE_LAST_BUFFER:
1299       gst_base_sink_set_last_buffer_enabled (sink, g_value_get_boolean (value));
1300       break;
1301     default:
1302       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1303       break;
1304   }
1305 }
1306
1307 static void
1308 gst_base_sink_get_property (GObject * object, guint prop_id, GValue * value,
1309     GParamSpec * pspec)
1310 {
1311   GstBaseSink *sink = GST_BASE_SINK (object);
1312
1313   switch (prop_id) {
1314     case PROP_PREROLL_QUEUE_LEN:
1315       g_value_set_uint (value, g_atomic_int_get (&sink->preroll_queue_max_len));
1316       break;
1317     case PROP_SYNC:
1318       g_value_set_boolean (value, gst_base_sink_get_sync (sink));
1319       break;
1320     case PROP_MAX_LATENESS:
1321       g_value_set_int64 (value, gst_base_sink_get_max_lateness (sink));
1322       break;
1323     case PROP_QOS:
1324       g_value_set_boolean (value, gst_base_sink_is_qos_enabled (sink));
1325       break;
1326     case PROP_ASYNC:
1327       g_value_set_boolean (value, gst_base_sink_is_async_enabled (sink));
1328       break;
1329     case PROP_TS_OFFSET:
1330       g_value_set_int64 (value, gst_base_sink_get_ts_offset (sink));
1331       break;
1332     case PROP_LAST_BUFFER:
1333       gst_value_take_buffer (value, gst_base_sink_get_last_buffer (sink));
1334       break;
1335     case PROP_ENABLE_LAST_BUFFER:
1336       g_value_set_boolean (value, gst_base_sink_is_last_buffer_enabled (sink));
1337       break;
1338     case PROP_BLOCKSIZE:
1339       g_value_set_uint (value, gst_base_sink_get_blocksize (sink));
1340       break;
1341     case PROP_RENDER_DELAY:
1342       g_value_set_uint64 (value, gst_base_sink_get_render_delay (sink));
1343       break;
1344     default:
1345       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1346       break;
1347   }
1348 }
1349
1350
1351 static GstCaps *
1352 gst_base_sink_get_caps (GstBaseSink * sink)
1353 {
1354   return NULL;
1355 }
1356
1357 static gboolean
1358 gst_base_sink_set_caps (GstBaseSink * sink, GstCaps * caps)
1359 {
1360   return TRUE;
1361 }
1362
1363 static GstFlowReturn
1364 gst_base_sink_buffer_alloc (GstBaseSink * sink, guint64 offset, guint size,
1365     GstCaps * caps, GstBuffer ** buf)
1366 {
1367   *buf = NULL;
1368   return GST_FLOW_OK;
1369 }
1370
1371 /* with PREROLL_LOCK, STREAM_LOCK */
1372 static void
1373 gst_base_sink_preroll_queue_flush (GstBaseSink * basesink, GstPad * pad)
1374 {
1375   GstMiniObject *obj;
1376
1377   GST_DEBUG_OBJECT (basesink, "flushing queue %p", basesink);
1378   while ((obj = g_queue_pop_head (basesink->preroll_queue))) {
1379     GST_DEBUG_OBJECT (basesink, "popped %p", obj);
1380     gst_mini_object_unref (obj);
1381   }
1382   /* we can't have EOS anymore now */
1383   basesink->eos = FALSE;
1384   basesink->priv->received_eos = FALSE;
1385   basesink->have_preroll = FALSE;
1386   basesink->priv->step_unlock = FALSE;
1387   basesink->eos_queued = FALSE;
1388   basesink->preroll_queued = 0;
1389   basesink->buffers_queued = 0;
1390   basesink->events_queued = 0;
1391   /* can't report latency anymore until we preroll again */
1392   if (basesink->priv->async_enabled) {
1393     GST_OBJECT_LOCK (basesink);
1394     basesink->priv->have_latency = FALSE;
1395     GST_OBJECT_UNLOCK (basesink);
1396   }
1397   /* and signal any waiters now */
1398   GST_PAD_PREROLL_SIGNAL (pad);
1399 }
1400
1401 /* with STREAM_LOCK, configures given segment with the event information. */
1402 static void
1403 gst_base_sink_configure_segment (GstBaseSink * basesink, GstPad * pad,
1404     GstEvent * event, GstSegment * segment)
1405 {
1406   gboolean update;
1407   gdouble rate, arate;
1408   GstFormat format;
1409   gint64 start;
1410   gint64 stop;
1411   gint64 time;
1412
1413   /* the newsegment event is needed to bring the buffer timestamps to the
1414    * stream time and to drop samples outside of the playback segment. */
1415   gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
1416       &start, &stop, &time);
1417
1418   /* The segment is protected with both the STREAM_LOCK and the OBJECT_LOCK.
1419    * We protect with the OBJECT_LOCK so that we can use the values to
1420    * safely answer a POSITION query. */
1421   GST_OBJECT_LOCK (basesink);
1422   gst_segment_set_newsegment_full (segment, update, rate, arate, format, start,
1423       stop, time);
1424
1425   if (format == GST_FORMAT_TIME) {
1426     GST_DEBUG_OBJECT (basesink,
1427         "configured NEWSEGMENT update %d, rate %lf, applied rate %lf, "
1428         "format GST_FORMAT_TIME, "
1429         "%" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT
1430         ", time %" GST_TIME_FORMAT ", accum %" GST_TIME_FORMAT,
1431         update, rate, arate, GST_TIME_ARGS (segment->start),
1432         GST_TIME_ARGS (segment->stop), GST_TIME_ARGS (segment->time),
1433         GST_TIME_ARGS (segment->accum));
1434   } else {
1435     GST_DEBUG_OBJECT (basesink,
1436         "configured NEWSEGMENT update %d, rate %lf, applied rate %lf, "
1437         "format %d, "
1438         "%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %"
1439         G_GINT64_FORMAT ", accum %" G_GINT64_FORMAT, update, rate, arate,
1440         segment->format, segment->start, segment->stop, segment->time,
1441         segment->accum);
1442   }
1443   GST_OBJECT_UNLOCK (basesink);
1444 }
1445
1446 /* with PREROLL_LOCK, STREAM_LOCK */
1447 static gboolean
1448 gst_base_sink_commit_state (GstBaseSink * basesink)
1449 {
1450   /* commit state and proceed to next pending state */
1451   GstState current, next, pending, post_pending;
1452   gboolean post_paused = FALSE;
1453   gboolean post_async_done = FALSE;
1454   gboolean post_playing = FALSE;
1455
1456   /* we are certainly not playing async anymore now */
1457   basesink->playing_async = FALSE;
1458
1459   GST_OBJECT_LOCK (basesink);
1460   current = GST_STATE (basesink);
1461   next = GST_STATE_NEXT (basesink);
1462   pending = GST_STATE_PENDING (basesink);
1463   post_pending = pending;
1464
1465   switch (pending) {
1466     case GST_STATE_PLAYING:
1467     {
1468       GstBaseSinkClass *bclass;
1469       GstStateChangeReturn ret;
1470
1471       bclass = GST_BASE_SINK_GET_CLASS (basesink);
1472
1473       GST_DEBUG_OBJECT (basesink, "commiting state to PLAYING");
1474
1475       basesink->need_preroll = FALSE;
1476       post_async_done = TRUE;
1477       basesink->priv->commited = TRUE;
1478       post_playing = TRUE;
1479       /* post PAUSED too when we were READY */
1480       if (current == GST_STATE_READY) {
1481         post_paused = TRUE;
1482       }
1483
1484       /* make sure we notify the subclass of async playing */
1485       if (bclass->async_play) {
1486         GST_WARNING_OBJECT (basesink, "deprecated async_play");
1487         ret = bclass->async_play (basesink);
1488         if (ret == GST_STATE_CHANGE_FAILURE)
1489           goto async_failed;
1490       }
1491       break;
1492     }
1493     case GST_STATE_PAUSED:
1494       GST_DEBUG_OBJECT (basesink, "commiting state to PAUSED");
1495       post_paused = TRUE;
1496       post_async_done = TRUE;
1497       basesink->priv->commited = TRUE;
1498       post_pending = GST_STATE_VOID_PENDING;
1499       break;
1500     case GST_STATE_READY:
1501     case GST_STATE_NULL:
1502       goto stopping;
1503     case GST_STATE_VOID_PENDING:
1504       goto nothing_pending;
1505     default:
1506       break;
1507   }
1508
1509   /* we can report latency queries now */
1510   basesink->priv->have_latency = TRUE;
1511
1512   GST_STATE (basesink) = pending;
1513   GST_STATE_NEXT (basesink) = GST_STATE_VOID_PENDING;
1514   GST_STATE_PENDING (basesink) = GST_STATE_VOID_PENDING;
1515   GST_STATE_RETURN (basesink) = GST_STATE_CHANGE_SUCCESS;
1516   GST_OBJECT_UNLOCK (basesink);
1517
1518   if (post_paused) {
1519     GST_DEBUG_OBJECT (basesink, "posting PAUSED state change message");
1520     gst_element_post_message (GST_ELEMENT_CAST (basesink),
1521         gst_message_new_state_changed (GST_OBJECT_CAST (basesink),
1522             current, next, post_pending));
1523   }
1524   if (post_async_done) {
1525     GST_DEBUG_OBJECT (basesink, "posting async-done message");
1526     gst_element_post_message (GST_ELEMENT_CAST (basesink),
1527         gst_message_new_async_done (GST_OBJECT_CAST (basesink)));
1528   }
1529   if (post_playing) {
1530     GST_DEBUG_OBJECT (basesink, "posting PLAYING state change message");
1531     gst_element_post_message (GST_ELEMENT_CAST (basesink),
1532         gst_message_new_state_changed (GST_OBJECT_CAST (basesink),
1533             next, pending, GST_STATE_VOID_PENDING));
1534   }
1535
1536   GST_STATE_BROADCAST (basesink);
1537
1538   return TRUE;
1539
1540 nothing_pending:
1541   {
1542     /* Depending on the state, set our vars. We get in this situation when the
1543      * state change function got a change to update the state vars before the
1544      * streaming thread did. This is fine but we need to make sure that we
1545      * update the need_preroll var since it was TRUE when we got here and might
1546      * become FALSE if we got to PLAYING. */
1547     GST_DEBUG_OBJECT (basesink, "nothing to commit, now in %s",
1548         gst_element_state_get_name (current));
1549     switch (current) {
1550       case GST_STATE_PLAYING:
1551         basesink->need_preroll = FALSE;
1552         break;
1553       case GST_STATE_PAUSED:
1554         basesink->need_preroll = TRUE;
1555         break;
1556       default:
1557         basesink->need_preroll = FALSE;
1558         basesink->flushing = TRUE;
1559         break;
1560     }
1561     /* we can report latency queries now */
1562     basesink->priv->have_latency = TRUE;
1563     GST_OBJECT_UNLOCK (basesink);
1564     return TRUE;
1565   }
1566 stopping:
1567   {
1568     /* app is going to READY */
1569     GST_DEBUG_OBJECT (basesink, "stopping");
1570     basesink->need_preroll = FALSE;
1571     basesink->flushing = TRUE;
1572     GST_OBJECT_UNLOCK (basesink);
1573     return FALSE;
1574   }
1575 async_failed:
1576   {
1577     GST_DEBUG_OBJECT (basesink, "async commit failed");
1578     GST_STATE_RETURN (basesink) = GST_STATE_CHANGE_FAILURE;
1579     GST_OBJECT_UNLOCK (basesink);
1580     return FALSE;
1581   }
1582 }
1583
1584 static void
1585 start_stepping (GstBaseSink * sink, GstSegment * segment,
1586     GstStepInfo * pending, GstStepInfo * current)
1587 {
1588   gint64 end;
1589   GstMessage *message;
1590
1591   GST_DEBUG_OBJECT (sink, "update pending step");
1592
1593   GST_OBJECT_LOCK (sink);
1594   memcpy (current, pending, sizeof (GstStepInfo));
1595   pending->valid = FALSE;
1596   GST_OBJECT_UNLOCK (sink);
1597
1598   /* post message first */
1599   message =
1600       gst_message_new_step_start (GST_OBJECT (sink), TRUE, current->format,
1601       current->amount, current->rate, current->flush, current->intermediate);
1602   gst_message_set_seqnum (message, current->seqnum);
1603   gst_element_post_message (GST_ELEMENT (sink), message);
1604
1605   /* get the running time of where we paused and remember it */
1606   current->start = gst_element_get_start_time (GST_ELEMENT_CAST (sink));
1607   gst_segment_set_running_time (segment, GST_FORMAT_TIME, current->start);
1608
1609   /* set the new rate for the remainder of the segment */
1610   current->start_rate = segment->rate;
1611   segment->rate *= current->rate;
1612   segment->abs_rate = ABS (segment->rate);
1613
1614   /* save values */
1615   if (segment->rate > 0.0)
1616     current->start_stop = segment->stop;
1617   else
1618     current->start_start = segment->start;
1619
1620   if (current->format == GST_FORMAT_TIME) {
1621     end = current->start + current->amount;
1622     if (!current->flush) {
1623       /* update the segment clipping regions for non-flushing seeks */
1624       if (segment->rate > 0.0) {
1625         segment->stop = gst_segment_to_position (segment, GST_FORMAT_TIME, end);
1626         segment->last_stop = segment->stop;
1627       } else {
1628         gint64 position;
1629
1630         position = gst_segment_to_position (segment, GST_FORMAT_TIME, end);
1631         segment->time = position;
1632         segment->start = position;
1633         segment->last_stop = position;
1634       }
1635     }
1636   }
1637
1638   GST_DEBUG_OBJECT (sink,
1639       "segment now rate %lf, applied rate %lf, "
1640       "format GST_FORMAT_TIME, "
1641       "%" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT
1642       ", time %" GST_TIME_FORMAT ", accum %" GST_TIME_FORMAT,
1643       segment->rate, segment->applied_rate, GST_TIME_ARGS (segment->start),
1644       GST_TIME_ARGS (segment->stop), GST_TIME_ARGS (segment->time),
1645       GST_TIME_ARGS (segment->accum));
1646
1647   GST_DEBUG_OBJECT (sink, "step started at running_time %" GST_TIME_FORMAT,
1648       GST_TIME_ARGS (current->start));
1649
1650   if (current->amount == -1) {
1651     GST_DEBUG_OBJECT (sink, "step amount == -1, stop stepping");
1652     current->valid = FALSE;
1653   } else {
1654     GST_DEBUG_OBJECT (sink, "step amount: %" G_GUINT64_FORMAT ", format: %s, "
1655         "rate: %f", current->amount, gst_format_get_name (current->format),
1656         current->rate);
1657   }
1658 }
1659
1660 static void
1661 stop_stepping (GstBaseSink * sink, GstSegment * segment,
1662     GstStepInfo * current, gint64 rstart, gint64 rstop, gboolean eos)
1663 {
1664   gint64 stop, position;
1665   GstMessage *message;
1666
1667   GST_DEBUG_OBJECT (sink, "step complete");
1668
1669   if (segment->rate > 0.0)
1670     stop = rstart;
1671   else
1672     stop = rstop;
1673
1674   GST_DEBUG_OBJECT (sink,
1675       "step stop at running_time %" GST_TIME_FORMAT, GST_TIME_ARGS (stop));
1676
1677   if (stop == -1)
1678     current->duration = current->position;
1679   else
1680     current->duration = stop - current->start;
1681
1682   GST_DEBUG_OBJECT (sink, "step elapsed running_time %" GST_TIME_FORMAT,
1683       GST_TIME_ARGS (current->duration));
1684
1685   position = current->start + current->duration;
1686
1687   /* now move the segment to the new running time */
1688   gst_segment_set_running_time (segment, GST_FORMAT_TIME, position);
1689
1690   if (current->flush) {
1691     /* and remove the accumulated time we flushed, start time did not change */
1692     segment->accum = current->start;
1693   } else {
1694     /* start time is now the stepped position */
1695     gst_element_set_start_time (GST_ELEMENT_CAST (sink), position);
1696   }
1697
1698   /* restore the previous rate */
1699   segment->rate = current->start_rate;
1700   segment->abs_rate = ABS (segment->rate);
1701
1702   if (segment->rate > 0.0)
1703     segment->stop = current->start_stop;
1704   else
1705     segment->start = current->start_start;
1706
1707   /* the clip segment is used for position report in paused... */
1708   memcpy (sink->abidata.ABI.clip_segment, segment, sizeof (GstSegment));
1709
1710   /* post the step done when we know the stepped duration in TIME */
1711   message =
1712       gst_message_new_step_done (GST_OBJECT_CAST (sink), current->format,
1713       current->amount, current->rate, current->flush, current->intermediate,
1714       current->duration, eos);
1715   gst_message_set_seqnum (message, current->seqnum);
1716   gst_element_post_message (GST_ELEMENT_CAST (sink), message);
1717
1718   if (!current->intermediate)
1719     sink->need_preroll = current->need_preroll;
1720
1721   /* and the current step info finished and becomes invalid */
1722   current->valid = FALSE;
1723 }
1724
1725 static gboolean
1726 handle_stepping (GstBaseSink * sink, GstSegment * segment,
1727     GstStepInfo * current, gint64 * cstart, gint64 * cstop, gint64 * rstart,
1728     gint64 * rstop)
1729 {
1730   gboolean step_end = FALSE;
1731
1732   /* see if we need to skip this buffer because of stepping */
1733   switch (current->format) {
1734     case GST_FORMAT_TIME:
1735     {
1736       guint64 end;
1737       gint64 first, last;
1738
1739       if (segment->rate > 0.0) {
1740         if (segment->stop == *cstop)
1741           *rstop = *rstart + current->amount;
1742
1743         first = *rstart;
1744         last = *rstop;
1745       } else {
1746         if (segment->start == *cstart)
1747           *rstart = *rstop + current->amount;
1748
1749         first = *rstop;
1750         last = *rstart;
1751       }
1752
1753       end = current->start + current->amount;
1754       current->position = first - current->start;
1755
1756       if (G_UNLIKELY (segment->abs_rate != 1.0))
1757         current->position /= segment->abs_rate;
1758
1759       GST_DEBUG_OBJECT (sink,
1760           "buffer: %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1761           GST_TIME_ARGS (first), GST_TIME_ARGS (last));
1762       GST_DEBUG_OBJECT (sink,
1763           "got time step %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT "/%"
1764           GST_TIME_FORMAT, GST_TIME_ARGS (current->position),
1765           GST_TIME_ARGS (last - current->start),
1766           GST_TIME_ARGS (current->amount));
1767
1768       if ((current->flush && current->position >= current->amount)
1769           || last >= end) {
1770         GST_DEBUG_OBJECT (sink, "step ended, we need clipping");
1771         step_end = TRUE;
1772         if (segment->rate > 0.0) {
1773           *rstart = end;
1774           *cstart = gst_segment_to_position (segment, GST_FORMAT_TIME, end);
1775         } else {
1776           *rstop = end;
1777           *cstop = gst_segment_to_position (segment, GST_FORMAT_TIME, end);
1778         }
1779       }
1780       GST_DEBUG_OBJECT (sink,
1781           "cstart %" GST_TIME_FORMAT ", rstart %" GST_TIME_FORMAT,
1782           GST_TIME_ARGS (*cstart), GST_TIME_ARGS (*rstart));
1783       GST_DEBUG_OBJECT (sink,
1784           "cstop %" GST_TIME_FORMAT ", rstop %" GST_TIME_FORMAT,
1785           GST_TIME_ARGS (*cstop), GST_TIME_ARGS (*rstop));
1786       break;
1787     }
1788     case GST_FORMAT_BUFFERS:
1789       GST_DEBUG_OBJECT (sink,
1790           "got default step %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT,
1791           current->position, current->amount);
1792
1793       if (current->position < current->amount) {
1794         current->position++;
1795       } else {
1796         step_end = TRUE;
1797       }
1798       break;
1799     case GST_FORMAT_DEFAULT:
1800     default:
1801       GST_DEBUG_OBJECT (sink,
1802           "got unknown step %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT,
1803           current->position, current->amount);
1804       break;
1805   }
1806   return step_end;
1807 }
1808
1809 /* with STREAM_LOCK, PREROLL_LOCK
1810  *
1811  * Returns TRUE if the object needs synchronisation and takes therefore
1812  * part in prerolling.
1813  *
1814  * rsstart/rsstop contain the start/stop in stream time.
1815  * rrstart/rrstop contain the start/stop in running time.
1816  */
1817 static gboolean
1818 gst_base_sink_get_sync_times (GstBaseSink * basesink, GstMiniObject * obj,
1819     GstClockTime * rsstart, GstClockTime * rsstop,
1820     GstClockTime * rrstart, GstClockTime * rrstop, gboolean * do_sync,
1821     gboolean * stepped, GstSegment * segment, GstStepInfo * step,
1822     gboolean * step_end)
1823 {
1824   GstBaseSinkClass *bclass;
1825   GstBuffer *buffer;
1826   GstClockTime start, stop;     /* raw start/stop timestamps */
1827   gint64 cstart, cstop;         /* clipped raw timestamps */
1828   gint64 rstart, rstop;         /* clipped timestamps converted to running time */
1829   GstClockTime sstart, sstop;   /* clipped timestamps converted to stream time */
1830   GstFormat format;
1831   GstBaseSinkPrivate *priv;
1832   gboolean eos;
1833
1834   priv = basesink->priv;
1835
1836   /* start with nothing */
1837   start = stop = GST_CLOCK_TIME_NONE;
1838
1839   if (G_UNLIKELY (GST_IS_EVENT (obj))) {
1840     GstEvent *event = GST_EVENT_CAST (obj);
1841
1842     switch (GST_EVENT_TYPE (event)) {
1843         /* EOS event needs syncing */
1844       case GST_EVENT_EOS:
1845       {
1846         if (basesink->segment.rate >= 0.0) {
1847           sstart = sstop = priv->current_sstop;
1848           if (!GST_CLOCK_TIME_IS_VALID (sstart)) {
1849             /* we have not seen a buffer yet, use the segment values */
1850             sstart = sstop = gst_segment_to_stream_time (&basesink->segment,
1851                 basesink->segment.format, basesink->segment.stop);
1852           }
1853         } else {
1854           sstart = sstop = priv->current_sstart;
1855           if (!GST_CLOCK_TIME_IS_VALID (sstart)) {
1856             /* we have not seen a buffer yet, use the segment values */
1857             sstart = sstop = gst_segment_to_stream_time (&basesink->segment,
1858                 basesink->segment.format, basesink->segment.start);
1859           }
1860         }
1861
1862         rstart = rstop = priv->eos_rtime;
1863         *do_sync = rstart != -1;
1864         GST_DEBUG_OBJECT (basesink, "sync times for EOS %" GST_TIME_FORMAT,
1865             GST_TIME_ARGS (rstart));
1866         /* if we are stepping, we end now */
1867         *step_end = step->valid;
1868         eos = TRUE;
1869         goto eos_done;
1870       }
1871       default:
1872         /* other events do not need syncing */
1873         /* FIXME, maybe NEWSEGMENT might need synchronisation
1874          * since the POSITION query depends on accumulated times and
1875          * we cannot accumulate the current segment before the previous
1876          * one completed.
1877          */
1878         return FALSE;
1879     }
1880   }
1881
1882   eos = FALSE;
1883
1884 again:
1885   /* else do buffer sync code */
1886   buffer = GST_BUFFER_CAST (obj);
1887
1888   bclass = GST_BASE_SINK_GET_CLASS (basesink);
1889
1890   /* just get the times to see if we need syncing, if the start returns -1 we
1891    * don't sync. */
1892   if (bclass->get_times)
1893     bclass->get_times (basesink, buffer, &start, &stop);
1894
1895   if (!GST_CLOCK_TIME_IS_VALID (start)) {
1896     /* we don't need to sync but we still want to get the timestamps for
1897      * tracking the position */
1898     gst_base_sink_get_times (basesink, buffer, &start, &stop);
1899     *do_sync = FALSE;
1900   } else {
1901     *do_sync = TRUE;
1902   }
1903
1904   GST_DEBUG_OBJECT (basesink, "got times start: %" GST_TIME_FORMAT
1905       ", stop: %" GST_TIME_FORMAT ", do_sync %d", GST_TIME_ARGS (start),
1906       GST_TIME_ARGS (stop), *do_sync);
1907
1908   /* collect segment and format for code clarity */
1909   format = segment->format;
1910
1911   /* no timestamp clipping if we did not get a TIME segment format */
1912   if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
1913     cstart = start;
1914     cstop = stop;
1915     /* do running and stream time in TIME format */
1916     format = GST_FORMAT_TIME;
1917     GST_LOG_OBJECT (basesink, "not time format, don't clip");
1918     goto do_times;
1919   }
1920
1921   /* clip, only when we know about time */
1922   if (G_UNLIKELY (!gst_segment_clip (segment, GST_FORMAT_TIME,
1923               (gint64) start, (gint64) stop, &cstart, &cstop))) {
1924     if (step->valid) {
1925       GST_DEBUG_OBJECT (basesink, "step out of segment");
1926       /* when we are stepping, pretend we're at the end of the segment */
1927       if (segment->rate > 0.0) {
1928         cstart = segment->stop;
1929         cstop = segment->stop;
1930       } else {
1931         cstart = segment->start;
1932         cstop = segment->start;
1933       }
1934       goto do_times;
1935     }
1936     goto out_of_segment;
1937   }
1938
1939   if (G_UNLIKELY (start != cstart || stop != cstop)) {
1940     GST_DEBUG_OBJECT (basesink, "clipped to: start %" GST_TIME_FORMAT
1941         ", stop: %" GST_TIME_FORMAT, GST_TIME_ARGS (cstart),
1942         GST_TIME_ARGS (cstop));
1943   }
1944
1945   /* set last stop position */
1946   if (G_LIKELY (cstop != GST_CLOCK_TIME_NONE))
1947     gst_segment_set_last_stop (segment, GST_FORMAT_TIME, cstop);
1948   else
1949     gst_segment_set_last_stop (segment, GST_FORMAT_TIME, cstart);
1950
1951 do_times:
1952   rstart = gst_segment_to_running_time (segment, format, cstart);
1953   rstop = gst_segment_to_running_time (segment, format, cstop);
1954
1955   if (G_UNLIKELY (step->valid)) {
1956     if (!(*step_end = handle_stepping (basesink, segment, step, &cstart, &cstop,
1957                 &rstart, &rstop))) {
1958       /* step is still busy, we discard data when we are flushing */
1959       *stepped = step->flush;
1960       GST_DEBUG_OBJECT (basesink, "stepping busy");
1961     }
1962   }
1963   /* this can produce wrong values if we accumulated non-TIME segments. If this happens,
1964    * upstream is behaving very badly */
1965   sstart = gst_segment_to_stream_time (segment, format, cstart);
1966   sstop = gst_segment_to_stream_time (segment, format, cstop);
1967
1968 eos_done:
1969   /* eos_done label only called when doing EOS, we also stop stepping then */
1970   if (*step_end && step->flush) {
1971     GST_DEBUG_OBJECT (basesink, "flushing step ended");
1972     stop_stepping (basesink, segment, step, rstart, rstop, eos);
1973     *step_end = FALSE;
1974     /* re-determine running start times for adjusted segment
1975      * (which has a flushed amount of running/accumulated time removed) */
1976     if (!GST_IS_EVENT (obj)) {
1977       GST_DEBUG_OBJECT (basesink, "refresh sync times");
1978       goto again;
1979     }
1980   }
1981
1982   /* save times */
1983   *rsstart = sstart;
1984   *rsstop = sstop;
1985   *rrstart = rstart;
1986   *rrstop = rstop;
1987
1988   /* buffers and EOS always need syncing and preroll */
1989   return TRUE;
1990
1991   /* special cases */
1992 out_of_segment:
1993   {
1994     /* we usually clip in the chain function already but stepping could cause
1995      * the segment to be updated later. we return FALSE so that we don't try
1996      * to sync on it. */
1997     GST_LOG_OBJECT (basesink, "buffer skipped, not in segment");
1998     return FALSE;
1999   }
2000 }
2001
2002 /* with STREAM_LOCK, PREROLL_LOCK, LOCK
2003  * adjust a timestamp with the latency and timestamp offset. This function does
2004  * not adjust for the render delay. */
2005 static GstClockTime
2006 gst_base_sink_adjust_time (GstBaseSink * basesink, GstClockTime time)
2007 {
2008   GstClockTimeDiff ts_offset;
2009
2010   /* don't do anything funny with invalid timestamps */
2011   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time)))
2012     return time;
2013
2014   time += basesink->priv->latency;
2015
2016   /* apply offset, be carefull for underflows */
2017   ts_offset = basesink->priv->ts_offset;
2018   if (ts_offset < 0) {
2019     ts_offset = -ts_offset;
2020     if (ts_offset < time)
2021       time -= ts_offset;
2022     else
2023       time = 0;
2024   } else
2025     time += ts_offset;
2026
2027   /* subtract the render delay again, which was included in the latency */
2028   if (time > basesink->priv->render_delay)
2029     time -= basesink->priv->render_delay;
2030   else
2031     time = 0;
2032
2033   return time;
2034 }
2035
2036 /**
2037  * gst_base_sink_wait_clock:
2038  * @sink: the sink
2039  * @time: the running_time to be reached
2040  * @jitter: the jitter to be filled with time diff (can be NULL)
2041  *
2042  * This function will block until @time is reached. It is usually called by
2043  * subclasses that use their own internal synchronisation.
2044  *
2045  * If @time is not valid, no sycnhronisation is done and #GST_CLOCK_BADTIME is
2046  * returned. Likewise, if synchronisation is disabled in the element or there
2047  * is no clock, no synchronisation is done and #GST_CLOCK_BADTIME is returned.
2048  *
2049  * This function should only be called with the PREROLL_LOCK held, like when
2050  * receiving an EOS event in the #GstBaseSinkClass.event() vmethod or when
2051  * receiving a buffer in
2052  * the #GstBaseSinkClass.render() vmethod.
2053  *
2054  * The @time argument should be the running_time of when this method should
2055  * return and is not adjusted with any latency or offset configured in the
2056  * sink.
2057  *
2058  * Since 0.10.20
2059  *
2060  * Returns: #GstClockReturn
2061  */
2062 GstClockReturn
2063 gst_base_sink_wait_clock (GstBaseSink * sink, GstClockTime time,
2064     GstClockTimeDiff * jitter)
2065 {
2066   GstClockID id;
2067   GstClockReturn ret;
2068   GstClock *clock;
2069   GstClockTime base_time;
2070
2071   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time)))
2072     goto invalid_time;
2073
2074   GST_OBJECT_LOCK (sink);
2075   if (G_UNLIKELY (!sink->sync))
2076     goto no_sync;
2077
2078   if (G_UNLIKELY ((clock = GST_ELEMENT_CLOCK (sink)) == NULL))
2079     goto no_clock;
2080
2081   base_time = GST_ELEMENT_CAST (sink)->base_time;
2082   GST_LOG_OBJECT (sink,
2083       "time %" GST_TIME_FORMAT ", base_time %" GST_TIME_FORMAT,
2084       GST_TIME_ARGS (time), GST_TIME_ARGS (base_time));
2085
2086   /* add base_time to running_time to get the time against the clock */
2087   time += base_time;
2088
2089   id = gst_clock_new_single_shot_id (clock, time);
2090   GST_OBJECT_UNLOCK (sink);
2091
2092   /* A blocking wait is performed on the clock. We save the ClockID
2093    * so we can unlock the entry at any time. While we are blocking, we
2094    * release the PREROLL_LOCK so that other threads can interrupt the
2095    * entry. */
2096   sink->clock_id = id;
2097   /* release the preroll lock while waiting */
2098   GST_PAD_PREROLL_UNLOCK (sink->sinkpad);
2099
2100   ret = gst_clock_id_wait (id, jitter);
2101
2102   GST_PAD_PREROLL_LOCK (sink->sinkpad);
2103   gst_clock_id_unref (id);
2104   sink->clock_id = NULL;
2105
2106   return ret;
2107
2108   /* no syncing needed */
2109 invalid_time:
2110   {
2111     GST_DEBUG_OBJECT (sink, "time not valid, no sync needed");
2112     return GST_CLOCK_BADTIME;
2113   }
2114 no_sync:
2115   {
2116     GST_DEBUG_OBJECT (sink, "sync disabled");
2117     GST_OBJECT_UNLOCK (sink);
2118     return GST_CLOCK_BADTIME;
2119   }
2120 no_clock:
2121   {
2122     GST_DEBUG_OBJECT (sink, "no clock, can't sync");
2123     GST_OBJECT_UNLOCK (sink);
2124     return GST_CLOCK_BADTIME;
2125   }
2126 }
2127
2128 /**
2129  * gst_base_sink_wait_preroll:
2130  * @sink: the sink
2131  *
2132  * If the #GstBaseSinkClass.render() method performs its own synchronisation
2133  * against the clock it must unblock when going from PLAYING to the PAUSED state
2134  * and call this method before continuing to render the remaining data.
2135  *
2136  * This function will block until a state change to PLAYING happens (in which
2137  * case this function returns #GST_FLOW_OK) or the processing must be stopped due
2138  * to a state change to READY or a FLUSH event (in which case this function
2139  * returns #GST_FLOW_WRONG_STATE).
2140  *
2141  * This function should only be called with the PREROLL_LOCK held, like in the
2142  * render function.
2143  *
2144  * Since: 0.10.11
2145  *
2146  * Returns: #GST_FLOW_OK if the preroll completed and processing can
2147  * continue. Any other return value should be returned from the render vmethod.
2148  */
2149 GstFlowReturn
2150 gst_base_sink_wait_preroll (GstBaseSink * sink)
2151 {
2152   sink->have_preroll = TRUE;
2153   GST_DEBUG_OBJECT (sink, "waiting in preroll for flush or PLAYING");
2154   /* block until the state changes, or we get a flush, or something */
2155   GST_PAD_PREROLL_WAIT (sink->sinkpad);
2156   sink->have_preroll = FALSE;
2157   if (G_UNLIKELY (sink->flushing))
2158     goto stopping;
2159   if (G_UNLIKELY (sink->priv->step_unlock))
2160     goto step_unlocked;
2161   GST_DEBUG_OBJECT (sink, "continue after preroll");
2162
2163   return GST_FLOW_OK;
2164
2165   /* ERRORS */
2166 stopping:
2167   {
2168     GST_DEBUG_OBJECT (sink, "preroll interrupted because of flush");
2169     return GST_FLOW_WRONG_STATE;
2170   }
2171 step_unlocked:
2172   {
2173     sink->priv->step_unlock = FALSE;
2174     GST_DEBUG_OBJECT (sink, "preroll interrupted because of step");
2175     return GST_FLOW_STEP;
2176   }
2177 }
2178
2179 /**
2180  * gst_base_sink_do_preroll:
2181  * @sink: the sink
2182  * @obj: the object that caused the preroll
2183  *
2184  * If the @sink spawns its own thread for pulling buffers from upstream it
2185  * should call this method after it has pulled a buffer. If the element needed
2186  * to preroll, this function will perform the preroll and will then block
2187  * until the element state is changed.
2188  *
2189  * This function should be called with the PREROLL_LOCK held.
2190  *
2191  * Since 0.10.22
2192  *
2193  * Returns: #GST_FLOW_OK if the preroll completed and processing can
2194  * continue. Any other return value should be returned from the render vmethod.
2195  */
2196 GstFlowReturn
2197 gst_base_sink_do_preroll (GstBaseSink * sink, GstMiniObject * obj)
2198 {
2199   GstFlowReturn ret;
2200
2201   while (G_UNLIKELY (sink->need_preroll)) {
2202     GST_DEBUG_OBJECT (sink, "prerolling object %p", obj);
2203
2204     ret = gst_base_sink_preroll_object (sink, FALSE, obj);
2205     if (ret != GST_FLOW_OK)
2206       goto preroll_failed;
2207
2208     /* need to recheck here because the commit state could have
2209      * made us not need the preroll anymore */
2210     if (G_LIKELY (sink->need_preroll)) {
2211       /* block until the state changes, or we get a flush, or something */
2212       ret = gst_base_sink_wait_preroll (sink);
2213       if ((ret != GST_FLOW_OK) && (ret != GST_FLOW_STEP))
2214         goto preroll_failed;
2215     }
2216   }
2217   return GST_FLOW_OK;
2218
2219   /* ERRORS */
2220 preroll_failed:
2221   {
2222     GST_DEBUG_OBJECT (sink, "preroll failed %d", ret);
2223     return ret;
2224   }
2225 }
2226
2227 /**
2228  * gst_base_sink_wait_eos:
2229  * @sink: the sink
2230  * @time: the running_time to be reached
2231  * @jitter: the jitter to be filled with time diff (can be NULL)
2232  *
2233  * This function will block until @time is reached. It is usually called by
2234  * subclasses that use their own internal synchronisation but want to let the
2235  * EOS be handled by the base class.
2236  *
2237  * This function should only be called with the PREROLL_LOCK held, like when
2238  * receiving an EOS event in the ::event vmethod.
2239  *
2240  * The @time argument should be the running_time of when the EOS should happen
2241  * and will be adjusted with any latency and offset configured in the sink.
2242  *
2243  * Since 0.10.15
2244  *
2245  * Returns: #GstFlowReturn
2246  */
2247 GstFlowReturn
2248 gst_base_sink_wait_eos (GstBaseSink * sink, GstClockTime time,
2249     GstClockTimeDiff * jitter)
2250 {
2251   GstClockReturn status;
2252   GstFlowReturn ret;
2253
2254   do {
2255     GstClockTime stime;
2256
2257     GST_DEBUG_OBJECT (sink, "checking preroll");
2258
2259     /* first wait for the playing state before we can continue */
2260     if (G_UNLIKELY (sink->need_preroll)) {
2261       ret = gst_base_sink_wait_preroll (sink);
2262       if ((ret != GST_FLOW_OK) && (ret != GST_FLOW_STEP))
2263         goto flushing;
2264     }
2265
2266     /* preroll done, we can sync since we are in PLAYING now. */
2267     GST_DEBUG_OBJECT (sink, "possibly waiting for clock to reach %"
2268         GST_TIME_FORMAT, GST_TIME_ARGS (time));
2269
2270     /* compensate for latency and ts_offset. We don't adjust for render delay
2271      * because we don't interact with the device on EOS normally. */
2272     stime = gst_base_sink_adjust_time (sink, time);
2273
2274     /* wait for the clock, this can be interrupted because we got shut down or
2275      * we PAUSED. */
2276     status = gst_base_sink_wait_clock (sink, stime, jitter);
2277
2278     GST_DEBUG_OBJECT (sink, "clock returned %d", status);
2279
2280     /* invalid time, no clock or sync disabled, just continue then */
2281     if (status == GST_CLOCK_BADTIME)
2282       break;
2283
2284     /* waiting could have been interrupted and we can be flushing now */
2285     if (G_UNLIKELY (sink->flushing))
2286       goto flushing;
2287
2288     /* retry if we got unscheduled, which means we did not reach the timeout
2289      * yet. if some other error occures, we continue. */
2290   } while (status == GST_CLOCK_UNSCHEDULED);
2291
2292   GST_DEBUG_OBJECT (sink, "end of stream");
2293
2294   return GST_FLOW_OK;
2295
2296   /* ERRORS */
2297 flushing:
2298   {
2299     GST_DEBUG_OBJECT (sink, "we are flushing");
2300     return GST_FLOW_WRONG_STATE;
2301   }
2302 }
2303
2304 /* with STREAM_LOCK, PREROLL_LOCK
2305  *
2306  * Make sure we are in PLAYING and synchronize an object to the clock.
2307  *
2308  * If we need preroll, we are not in PLAYING. We try to commit the state
2309  * if needed and then block if we still are not PLAYING.
2310  *
2311  * We start waiting on the clock in PLAYING. If we got interrupted, we
2312  * immediatly try to re-preroll.
2313  *
2314  * Some objects do not need synchronisation (most events) and so this function
2315  * immediatly returns GST_FLOW_OK.
2316  *
2317  * for objects that arrive later than max-lateness to be synchronized to the
2318  * clock have the @late boolean set to TRUE.
2319  *
2320  * This function keeps a running average of the jitter (the diff between the
2321  * clock time and the requested sync time). The jitter is negative for
2322  * objects that arrive in time and positive for late buffers.
2323  *
2324  * does not take ownership of obj.
2325  */
2326 static GstFlowReturn
2327 gst_base_sink_do_sync (GstBaseSink * basesink, GstPad * pad,
2328     GstMiniObject * obj, gboolean * late, gboolean * step_end)
2329 {
2330   GstClockTimeDiff jitter = 0;
2331   gboolean syncable;
2332   GstClockReturn status = GST_CLOCK_OK;
2333   GstClockTime rstart, rstop, sstart, sstop, stime;
2334   gboolean do_sync;
2335   GstBaseSinkPrivate *priv;
2336   GstFlowReturn ret;
2337   GstStepInfo *current, *pending;
2338   gboolean stepped;
2339
2340   priv = basesink->priv;
2341
2342 do_step:
2343   sstart = sstop = rstart = rstop = GST_CLOCK_TIME_NONE;
2344   do_sync = TRUE;
2345   stepped = FALSE;
2346
2347   priv->current_rstart = GST_CLOCK_TIME_NONE;
2348
2349   /* get stepping info */
2350   current = &priv->current_step;
2351   pending = &priv->pending_step;
2352
2353   /* get timing information for this object against the render segment */
2354   syncable = gst_base_sink_get_sync_times (basesink, obj,
2355       &sstart, &sstop, &rstart, &rstop, &do_sync, &stepped, &basesink->segment,
2356       current, step_end);
2357
2358   if (G_UNLIKELY (stepped))
2359     goto step_skipped;
2360
2361   /* a syncable object needs to participate in preroll and
2362    * clocking. All buffers and EOS are syncable. */
2363   if (G_UNLIKELY (!syncable))
2364     goto not_syncable;
2365
2366   /* store timing info for current object */
2367   priv->current_rstart = rstart;
2368   priv->current_rstop = (GST_CLOCK_TIME_IS_VALID (rstop) ? rstop : rstart);
2369
2370   /* save sync time for eos when the previous object needed sync */
2371   priv->eos_rtime = (do_sync ? priv->current_rstop : GST_CLOCK_TIME_NONE);
2372
2373 again:
2374   /* first do preroll, this makes sure we commit our state
2375    * to PAUSED and can continue to PLAYING. We cannot perform
2376    * any clock sync in PAUSED because there is no clock. */
2377   ret = gst_base_sink_do_preroll (basesink, obj);
2378   if (G_UNLIKELY (ret != GST_FLOW_OK))
2379     goto preroll_failed;
2380
2381   /* update the segment with a pending step if the current one is invalid and we
2382    * have a new pending one. We only accept new step updates after a preroll */
2383   if (G_UNLIKELY (pending->valid && !current->valid)) {
2384     start_stepping (basesink, &basesink->segment, pending, current);
2385     goto do_step;
2386   }
2387
2388   /* After rendering we store the position of the last buffer so that we can use
2389    * it to report the position. We need to take the lock here. */
2390   GST_OBJECT_LOCK (basesink);
2391   priv->current_sstart = sstart;
2392   priv->current_sstop = (GST_CLOCK_TIME_IS_VALID (sstop) ? sstop : sstart);
2393   GST_OBJECT_UNLOCK (basesink);
2394
2395   if (!do_sync)
2396     goto done;
2397
2398   /* adjust for latency */
2399   stime = gst_base_sink_adjust_time (basesink, rstart);
2400
2401   /* adjust for render-delay, avoid underflows */
2402   if (GST_CLOCK_TIME_IS_VALID (stime)) {
2403     if (stime > priv->render_delay)
2404       stime -= priv->render_delay;
2405     else
2406       stime = 0;
2407   }
2408
2409   /* preroll done, we can sync since we are in PLAYING now. */
2410   GST_DEBUG_OBJECT (basesink, "possibly waiting for clock to reach %"
2411       GST_TIME_FORMAT ", adjusted %" GST_TIME_FORMAT,
2412       GST_TIME_ARGS (rstart), GST_TIME_ARGS (stime));
2413
2414   /* This function will return immediatly if start == -1, no clock
2415    * or sync is disabled with GST_CLOCK_BADTIME. */
2416   status = gst_base_sink_wait_clock (basesink, stime, &jitter);
2417
2418   GST_DEBUG_OBJECT (basesink, "clock returned %d, jitter %c%" GST_TIME_FORMAT,
2419       status, (jitter < 0 ? '-' : ' '), GST_TIME_ARGS (ABS (jitter)));
2420
2421   /* invalid time, no clock or sync disabled, just render */
2422   if (status == GST_CLOCK_BADTIME)
2423     goto done;
2424
2425   /* waiting could have been interrupted and we can be flushing now */
2426   if (G_UNLIKELY (basesink->flushing))
2427     goto flushing;
2428
2429   /* check for unlocked by a state change, we are not flushing so
2430    * we can try to preroll on the current buffer. */
2431   if (G_UNLIKELY (status == GST_CLOCK_UNSCHEDULED)) {
2432     GST_DEBUG_OBJECT (basesink, "unscheduled, waiting some more");
2433     priv->call_preroll = TRUE;
2434     goto again;
2435   }
2436
2437   /* successful syncing done, record observation */
2438   priv->current_jitter = jitter;
2439
2440   /* check if the object should be dropped */
2441   *late = gst_base_sink_is_too_late (basesink, obj, rstart, rstop,
2442       status, jitter);
2443
2444 done:
2445   return GST_FLOW_OK;
2446
2447   /* ERRORS */
2448 step_skipped:
2449   {
2450     GST_DEBUG_OBJECT (basesink, "skipped stepped object %p", obj);
2451     *late = TRUE;
2452     return GST_FLOW_OK;
2453   }
2454 not_syncable:
2455   {
2456     GST_DEBUG_OBJECT (basesink, "non syncable object %p", obj);
2457     return GST_FLOW_OK;
2458   }
2459 flushing:
2460   {
2461     GST_DEBUG_OBJECT (basesink, "we are flushing");
2462     return GST_FLOW_WRONG_STATE;
2463   }
2464 preroll_failed:
2465   {
2466     GST_DEBUG_OBJECT (basesink, "preroll failed");
2467     *step_end = FALSE;
2468     return ret;
2469   }
2470 }
2471
2472 static gboolean
2473 gst_base_sink_send_qos (GstBaseSink * basesink,
2474     gdouble proportion, GstClockTime time, GstClockTimeDiff diff)
2475 {
2476   GstEvent *event;
2477   gboolean res;
2478
2479   /* generate Quality-of-Service event */
2480   GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, basesink,
2481       "qos: proportion: %lf, diff %" G_GINT64_FORMAT ", timestamp %"
2482       GST_TIME_FORMAT, proportion, diff, GST_TIME_ARGS (time));
2483
2484   event = gst_event_new_qos (proportion, diff, time);
2485
2486   /* send upstream */
2487   res = gst_pad_push_event (basesink->sinkpad, event);
2488
2489   return res;
2490 }
2491
2492 static void
2493 gst_base_sink_perform_qos (GstBaseSink * sink, gboolean dropped)
2494 {
2495   GstBaseSinkPrivate *priv;
2496   GstClockTime start, stop;
2497   GstClockTimeDiff jitter;
2498   GstClockTime pt, entered, left;
2499   GstClockTime duration;
2500   gdouble rate;
2501
2502   priv = sink->priv;
2503
2504   start = priv->current_rstart;
2505
2506   if (priv->current_step.valid)
2507     return;
2508
2509   /* if Quality-of-Service disabled, do nothing */
2510   if (!g_atomic_int_get (&priv->qos_enabled) ||
2511       !GST_CLOCK_TIME_IS_VALID (start))
2512     return;
2513
2514   stop = priv->current_rstop;
2515   jitter = priv->current_jitter;
2516
2517   if (jitter < 0) {
2518     /* this is the time the buffer entered the sink */
2519     if (start < -jitter)
2520       entered = 0;
2521     else
2522       entered = start + jitter;
2523     left = start;
2524   } else {
2525     /* this is the time the buffer entered the sink */
2526     entered = start + jitter;
2527     /* this is the time the buffer left the sink */
2528     left = start + jitter;
2529   }
2530
2531   /* calculate duration of the buffer */
2532   if (GST_CLOCK_TIME_IS_VALID (stop))
2533     duration = stop - start;
2534   else
2535     duration = GST_CLOCK_TIME_NONE;
2536
2537   /* if we have the time when the last buffer left us, calculate
2538    * processing time */
2539   if (GST_CLOCK_TIME_IS_VALID (priv->last_left)) {
2540     if (entered > priv->last_left) {
2541       pt = entered - priv->last_left;
2542     } else {
2543       pt = 0;
2544     }
2545   } else {
2546     pt = priv->avg_pt;
2547   }
2548
2549   GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, sink, "start: %" GST_TIME_FORMAT
2550       ", entered %" GST_TIME_FORMAT ", left %" GST_TIME_FORMAT ", pt: %"
2551       GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT ",jitter %"
2552       G_GINT64_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (entered),
2553       GST_TIME_ARGS (left), GST_TIME_ARGS (pt), GST_TIME_ARGS (duration),
2554       jitter);
2555
2556   GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, sink, "avg_duration: %" GST_TIME_FORMAT
2557       ", avg_pt: %" GST_TIME_FORMAT ", avg_rate: %g",
2558       GST_TIME_ARGS (priv->avg_duration), GST_TIME_ARGS (priv->avg_pt),
2559       priv->avg_rate);
2560
2561   /* collect running averages. for first observations, we copy the
2562    * values */
2563   if (!GST_CLOCK_TIME_IS_VALID (priv->avg_duration))
2564     priv->avg_duration = duration;
2565   else
2566     priv->avg_duration = UPDATE_RUNNING_AVG (priv->avg_duration, duration);
2567
2568   if (!GST_CLOCK_TIME_IS_VALID (priv->avg_pt))
2569     priv->avg_pt = pt;
2570   else
2571     priv->avg_pt = UPDATE_RUNNING_AVG (priv->avg_pt, pt);
2572
2573   if (priv->avg_duration != 0)
2574     rate =
2575         gst_guint64_to_gdouble (priv->avg_pt) /
2576         gst_guint64_to_gdouble (priv->avg_duration);
2577   else
2578     rate = 0.0;
2579
2580   if (GST_CLOCK_TIME_IS_VALID (priv->last_left)) {
2581     if (dropped || priv->avg_rate < 0.0) {
2582       priv->avg_rate = rate;
2583     } else {
2584       if (rate > 1.0)
2585         priv->avg_rate = UPDATE_RUNNING_AVG_N (priv->avg_rate, rate);
2586       else
2587         priv->avg_rate = UPDATE_RUNNING_AVG_P (priv->avg_rate, rate);
2588     }
2589   }
2590
2591   GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, sink,
2592       "updated: avg_duration: %" GST_TIME_FORMAT ", avg_pt: %" GST_TIME_FORMAT
2593       ", avg_rate: %g", GST_TIME_ARGS (priv->avg_duration),
2594       GST_TIME_ARGS (priv->avg_pt), priv->avg_rate);
2595
2596
2597   if (priv->avg_rate >= 0.0) {
2598     /* if we have a valid rate, start sending QoS messages */
2599     if (priv->current_jitter < 0) {
2600       /* make sure we never go below 0 when adding the jitter to the
2601        * timestamp. */
2602       if (priv->current_rstart < -priv->current_jitter)
2603         priv->current_jitter = -priv->current_rstart;
2604     }
2605     gst_base_sink_send_qos (sink, priv->avg_rate, priv->current_rstart,
2606         priv->current_jitter);
2607   }
2608
2609   /* record when this buffer will leave us */
2610   priv->last_left = left;
2611 }
2612
2613 /* reset all qos measuring */
2614 static void
2615 gst_base_sink_reset_qos (GstBaseSink * sink)
2616 {
2617   GstBaseSinkPrivate *priv;
2618
2619   priv = sink->priv;
2620
2621   priv->last_in_time = GST_CLOCK_TIME_NONE;
2622   priv->last_left = GST_CLOCK_TIME_NONE;
2623   priv->avg_duration = GST_CLOCK_TIME_NONE;
2624   priv->avg_pt = GST_CLOCK_TIME_NONE;
2625   priv->avg_rate = -1.0;
2626   priv->avg_render = GST_CLOCK_TIME_NONE;
2627   priv->rendered = 0;
2628   priv->dropped = 0;
2629
2630 }
2631
2632 /* Checks if the object was scheduled too late.
2633  *
2634  * start/stop contain the raw timestamp start and stop values
2635  * of the object.
2636  *
2637  * status and jitter contain the return values from the clock wait.
2638  *
2639  * returns TRUE if the buffer was too late.
2640  */
2641 static gboolean
2642 gst_base_sink_is_too_late (GstBaseSink * basesink, GstMiniObject * obj,
2643     GstClockTime start, GstClockTime stop,
2644     GstClockReturn status, GstClockTimeDiff jitter)
2645 {
2646   gboolean late;
2647   gint64 max_lateness;
2648   GstBaseSinkPrivate *priv;
2649
2650   priv = basesink->priv;
2651
2652   late = FALSE;
2653
2654   /* only for objects that were too late */
2655   if (G_LIKELY (status != GST_CLOCK_EARLY))
2656     goto in_time;
2657
2658   max_lateness = basesink->abidata.ABI.max_lateness;
2659
2660   /* check if frame dropping is enabled */
2661   if (max_lateness == -1)
2662     goto no_drop;
2663
2664   /* only check for buffers */
2665   if (G_UNLIKELY (!GST_IS_BUFFER (obj)))
2666     goto not_buffer;
2667
2668   /* can't do check if we don't have a timestamp */
2669   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (start)))
2670     goto no_timestamp;
2671
2672   /* we can add a valid stop time */
2673   if (GST_CLOCK_TIME_IS_VALID (stop))
2674     max_lateness += stop;
2675   else
2676     max_lateness += start;
2677
2678   /* if the jitter bigger than duration and lateness we are too late */
2679   if ((late = start + jitter > max_lateness)) {
2680     GST_CAT_DEBUG_OBJECT (GST_CAT_PERFORMANCE, basesink,
2681         "buffer is too late %" GST_TIME_FORMAT
2682         " > %" GST_TIME_FORMAT, GST_TIME_ARGS (start + jitter),
2683         GST_TIME_ARGS (max_lateness));
2684     /* !!emergency!!, if we did not receive anything valid for more than a
2685      * second, render it anyway so the user sees something */
2686     if (GST_CLOCK_TIME_IS_VALID (priv->last_in_time) &&
2687         start - priv->last_in_time > GST_SECOND) {
2688       late = FALSE;
2689       GST_ELEMENT_WARNING (basesink, CORE, CLOCK,
2690           (_("A lot of buffers are being dropped.")),
2691           ("There may be a timestamping problem, or this computer is too slow."));
2692       GST_CAT_DEBUG_OBJECT (GST_CAT_PERFORMANCE, basesink,
2693           "**emergency** last buffer at %" GST_TIME_FORMAT " > GST_SECOND",
2694           GST_TIME_ARGS (priv->last_in_time));
2695     }
2696   }
2697
2698 done:
2699   if (!late || !GST_CLOCK_TIME_IS_VALID (priv->last_in_time)) {
2700     priv->last_in_time = start;
2701   }
2702   return late;
2703
2704   /* all is fine */
2705 in_time:
2706   {
2707     GST_DEBUG_OBJECT (basesink, "object was scheduled in time");
2708     goto done;
2709   }
2710 no_drop:
2711   {
2712     GST_DEBUG_OBJECT (basesink, "frame dropping disabled");
2713     goto done;
2714   }
2715 not_buffer:
2716   {
2717     GST_DEBUG_OBJECT (basesink, "object is not a buffer");
2718     return FALSE;
2719   }
2720 no_timestamp:
2721   {
2722     GST_DEBUG_OBJECT (basesink, "buffer has no timestamp");
2723     return FALSE;
2724   }
2725 }
2726
2727 /* called before and after calling the render vmethod. It keeps track of how
2728  * much time was spent in the render method and is used to check if we are
2729  * flooded */
2730 static void
2731 gst_base_sink_do_render_stats (GstBaseSink * basesink, gboolean start)
2732 {
2733   GstBaseSinkPrivate *priv;
2734
2735   priv = basesink->priv;
2736
2737   if (start) {
2738     priv->start = gst_util_get_timestamp ();
2739   } else {
2740     GstClockTime elapsed;
2741
2742     priv->stop = gst_util_get_timestamp ();
2743
2744     elapsed = GST_CLOCK_DIFF (priv->start, priv->stop);
2745
2746     if (!GST_CLOCK_TIME_IS_VALID (priv->avg_render))
2747       priv->avg_render = elapsed;
2748     else
2749       priv->avg_render = UPDATE_RUNNING_AVG (priv->avg_render, elapsed);
2750
2751     GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, basesink,
2752         "avg_render: %" GST_TIME_FORMAT, GST_TIME_ARGS (priv->avg_render));
2753   }
2754 }
2755
2756 /* with STREAM_LOCK, PREROLL_LOCK,
2757  *
2758  * Synchronize the object on the clock and then render it.
2759  *
2760  * takes ownership of obj.
2761  */
2762 static GstFlowReturn
2763 gst_base_sink_render_object (GstBaseSink * basesink, GstPad * pad,
2764     gboolean is_list, gpointer obj)
2765 {
2766   GstFlowReturn ret;
2767   GstBaseSinkClass *bclass;
2768   gboolean late, step_end;
2769   gpointer sync_obj;
2770   GstBaseSinkPrivate *priv;
2771
2772   priv = basesink->priv;
2773
2774   if (is_list) {
2775     /*
2776      * If buffer list, use the first group buffer within the list
2777      * for syncing
2778      */
2779     sync_obj = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0, 0);
2780     g_assert (NULL != sync_obj);
2781   } else {
2782     sync_obj = obj;
2783   }
2784
2785 again:
2786   late = FALSE;
2787   step_end = FALSE;
2788
2789   /* synchronize this object, non syncable objects return OK
2790    * immediatly. */
2791   ret = gst_base_sink_do_sync (basesink, pad, sync_obj, &late, &step_end);
2792   if (G_UNLIKELY (ret != GST_FLOW_OK))
2793     goto sync_failed;
2794
2795   /* and now render, event or buffer/buffer list. */
2796   if (G_LIKELY (is_list || GST_IS_BUFFER (obj))) {
2797     /* drop late buffers unconditionally, let's hope it's unlikely */
2798     if (G_UNLIKELY (late))
2799       goto dropped;
2800
2801     bclass = GST_BASE_SINK_GET_CLASS (basesink);
2802
2803     if (G_LIKELY ((is_list && bclass->render_list) ||
2804             (!is_list && bclass->render))) {
2805       gint do_qos;
2806
2807       /* read once, to get same value before and after */
2808       do_qos = g_atomic_int_get (&priv->qos_enabled);
2809
2810       GST_DEBUG_OBJECT (basesink, "rendering object %p", obj);
2811
2812       /* record rendering time for QoS and stats */
2813       if (do_qos)
2814         gst_base_sink_do_render_stats (basesink, TRUE);
2815
2816       if (!is_list) {
2817         GstBuffer *buf;
2818
2819         /* For buffer lists do not set last buffer. Creating buffer
2820          * with meaningful data can be done only with memcpy which will
2821          * significantly affect performance */
2822         buf = GST_BUFFER_CAST (obj);
2823         gst_base_sink_set_last_buffer (basesink, buf);
2824
2825         ret = bclass->render (basesink, buf);
2826       } else {
2827         GstBufferList *buflist;
2828
2829         buflist = GST_BUFFER_LIST_CAST (obj);
2830
2831         ret = bclass->render_list (basesink, buflist);
2832       }
2833
2834       if (do_qos)
2835         gst_base_sink_do_render_stats (basesink, FALSE);
2836
2837       if (ret == GST_FLOW_STEP)
2838         goto again;
2839
2840       if (G_UNLIKELY (basesink->flushing))
2841         goto flushing;
2842
2843       priv->rendered++;
2844     }
2845   } else if (G_LIKELY (GST_IS_EVENT (obj))) {
2846     GstEvent *event = GST_EVENT_CAST (obj);
2847     gboolean event_res = TRUE;
2848     GstEventType type;
2849
2850     bclass = GST_BASE_SINK_GET_CLASS (basesink);
2851
2852     type = GST_EVENT_TYPE (event);
2853
2854     GST_DEBUG_OBJECT (basesink, "rendering event %p, type %s", obj,
2855         gst_event_type_get_name (type));
2856
2857     if (bclass->event)
2858       event_res = bclass->event (basesink, event);
2859
2860     /* when we get here we could be flushing again when the event handler calls
2861      * _wait_eos(). We have to ignore this object in that case. */
2862     if (G_UNLIKELY (basesink->flushing))
2863       goto flushing;
2864
2865     if (G_LIKELY (event_res)) {
2866       guint32 seqnum;
2867
2868       seqnum = basesink->priv->seqnum = gst_event_get_seqnum (event);
2869       GST_DEBUG_OBJECT (basesink, "Got seqnum #%" G_GUINT32_FORMAT, seqnum);
2870
2871       switch (type) {
2872         case GST_EVENT_EOS:
2873         {
2874           GstMessage *message;
2875
2876           /* the EOS event is completely handled so we mark
2877            * ourselves as being in the EOS state. eos is also
2878            * protected by the object lock so we can read it when
2879            * answering the POSITION query. */
2880           GST_OBJECT_LOCK (basesink);
2881           basesink->eos = TRUE;
2882           GST_OBJECT_UNLOCK (basesink);
2883
2884           /* ok, now we can post the message */
2885           GST_DEBUG_OBJECT (basesink, "Now posting EOS");
2886
2887           message = gst_message_new_eos (GST_OBJECT_CAST (basesink));
2888           gst_message_set_seqnum (message, seqnum);
2889           gst_element_post_message (GST_ELEMENT_CAST (basesink), message);
2890           break;
2891         }
2892         case GST_EVENT_NEWSEGMENT:
2893           /* configure the segment */
2894           gst_base_sink_configure_segment (basesink, pad, event,
2895               &basesink->segment);
2896           break;
2897         case GST_EVENT_SINK_MESSAGE:{
2898           GstMessage *msg = NULL;
2899
2900           gst_event_parse_sink_message (event, &msg);
2901
2902           if (msg)
2903             gst_element_post_message (GST_ELEMENT_CAST (basesink), msg);
2904         }
2905         default:
2906           break;
2907       }
2908     }
2909   } else {
2910     g_return_val_if_reached (GST_FLOW_ERROR);
2911   }
2912
2913 done:
2914   if (step_end) {
2915     /* the step ended, check if we need to activate a new step */
2916     GST_DEBUG_OBJECT (basesink, "step ended");
2917     stop_stepping (basesink, &basesink->segment, &priv->current_step,
2918         priv->current_rstart, priv->current_rstop, basesink->eos);
2919     goto again;
2920   }
2921
2922   gst_base_sink_perform_qos (basesink, late);
2923
2924   GST_DEBUG_OBJECT (basesink, "object unref after render %p", obj);
2925   gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
2926   return ret;
2927
2928   /* ERRORS */
2929 sync_failed:
2930   {
2931     GST_DEBUG_OBJECT (basesink, "do_sync returned %s", gst_flow_get_name (ret));
2932     goto done;
2933   }
2934 dropped:
2935   {
2936     priv->dropped++;
2937     GST_DEBUG_OBJECT (basesink, "buffer late, dropping");
2938
2939     if (g_atomic_int_get (&priv->qos_enabled)) {
2940       GstMessage *qos_msg;
2941       GstClockTime timestamp, duration;
2942
2943       timestamp = GST_BUFFER_TIMESTAMP (GST_BUFFER_CAST (sync_obj));
2944       duration = GST_BUFFER_DURATION (GST_BUFFER_CAST (sync_obj));
2945
2946       GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, basesink,
2947           "qos: dropped buffer rt %" GST_TIME_FORMAT ", st %" GST_TIME_FORMAT
2948           ", ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT,
2949           GST_TIME_ARGS (priv->current_rstart),
2950           GST_TIME_ARGS (priv->current_sstart), GST_TIME_ARGS (timestamp),
2951           GST_TIME_ARGS (duration));
2952       GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, basesink,
2953           "qos: rendered %" G_GUINT64_FORMAT ", dropped %" G_GUINT64_FORMAT,
2954           priv->rendered, priv->dropped);
2955
2956       qos_msg =
2957           gst_message_new_qos (GST_OBJECT_CAST (basesink), basesink->sync,
2958           priv->current_rstart, priv->current_sstart, timestamp, duration);
2959       gst_message_set_qos_values (qos_msg, priv->current_jitter, priv->avg_rate,
2960           1000000);
2961       gst_message_set_qos_stats (qos_msg, GST_FORMAT_BUFFERS, priv->rendered,
2962           priv->dropped);
2963       gst_element_post_message (GST_ELEMENT_CAST (basesink), qos_msg);
2964     }
2965     goto done;
2966   }
2967 flushing:
2968   {
2969     GST_DEBUG_OBJECT (basesink, "we are flushing, ignore object");
2970     gst_mini_object_unref (obj);
2971     return GST_FLOW_WRONG_STATE;
2972   }
2973 }
2974
2975 /* with STREAM_LOCK, PREROLL_LOCK
2976  *
2977  * Perform preroll on the given object. For buffers this means
2978  * calling the preroll subclass method.
2979  * If that succeeds, the state will be commited.
2980  *
2981  * function does not take ownership of obj.
2982  */
2983 static GstFlowReturn
2984 gst_base_sink_preroll_object (GstBaseSink * basesink, gboolean is_list,
2985     GstMiniObject * obj)
2986 {
2987   GstFlowReturn ret;
2988
2989   GST_DEBUG_OBJECT (basesink, "prerolling object %p", obj);
2990
2991   /* if it's a buffer, we need to call the preroll method */
2992   if (G_LIKELY (is_list || GST_IS_BUFFER (obj)) && basesink->priv->call_preroll) {
2993     GstBaseSinkClass *bclass;
2994     GstBuffer *buf;
2995     GstClockTime timestamp;
2996
2997     if (is_list) {
2998       buf = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0, 0);
2999       g_assert (NULL != buf);
3000     } else {
3001       buf = GST_BUFFER_CAST (obj);
3002     }
3003
3004     timestamp = GST_BUFFER_TIMESTAMP (buf);
3005
3006     GST_DEBUG_OBJECT (basesink, "preroll buffer %" GST_TIME_FORMAT,
3007         GST_TIME_ARGS (timestamp));
3008
3009     /*
3010      * For buffer lists do not set last buffer. Creating buffer
3011      * with meaningful data can be done only with memcpy which will
3012      * significantly affect performance
3013      */
3014     if (!is_list) {
3015       gst_base_sink_set_last_buffer (basesink, buf);
3016     }
3017
3018     bclass = GST_BASE_SINK_GET_CLASS (basesink);
3019     if (bclass->preroll)
3020       if ((ret = bclass->preroll (basesink, buf)) != GST_FLOW_OK)
3021         goto preroll_failed;
3022
3023     basesink->priv->call_preroll = FALSE;
3024   }
3025
3026   /* commit state */
3027   if (G_LIKELY (basesink->playing_async)) {
3028     if (G_UNLIKELY (!gst_base_sink_commit_state (basesink)))
3029       goto stopping;
3030   }
3031
3032   return GST_FLOW_OK;
3033
3034   /* ERRORS */
3035 preroll_failed:
3036   {
3037     GST_DEBUG_OBJECT (basesink, "preroll failed, abort state");
3038     gst_element_abort_state (GST_ELEMENT_CAST (basesink));
3039     return ret;
3040   }
3041 stopping:
3042   {
3043     GST_DEBUG_OBJECT (basesink, "stopping while commiting state");
3044     return GST_FLOW_WRONG_STATE;
3045   }
3046 }
3047
3048 /* with STREAM_LOCK, PREROLL_LOCK
3049  *
3050  * Queue an object for rendering.
3051  * The first prerollable object queued will complete the preroll. If the
3052  * preroll queue if filled, we render all the objects in the queue.
3053  *
3054  * This function takes ownership of the object.
3055  */
3056 static GstFlowReturn
3057 gst_base_sink_queue_object_unlocked (GstBaseSink * basesink, GstPad * pad,
3058     gboolean is_list, gpointer obj, gboolean prerollable)
3059 {
3060   GstFlowReturn ret = GST_FLOW_OK;
3061   gint length;
3062   GQueue *q;
3063
3064   if (G_UNLIKELY (basesink->need_preroll)) {
3065     if (G_LIKELY (prerollable))
3066       basesink->preroll_queued++;
3067
3068     length = basesink->preroll_queued;
3069
3070     GST_DEBUG_OBJECT (basesink, "now %d prerolled items", length);
3071
3072     /* first prerollable item needs to finish the preroll */
3073     if (length == 1) {
3074       ret = gst_base_sink_preroll_object (basesink, is_list, obj);
3075       if (G_UNLIKELY (ret != GST_FLOW_OK))
3076         goto preroll_failed;
3077     }
3078     /* need to recheck if we need preroll, commmit state during preroll
3079      * could have made us not need more preroll. */
3080     if (G_UNLIKELY (basesink->need_preroll)) {
3081       /* see if we can render now, if we can't add the object to the preroll
3082        * queue. */
3083       if (G_UNLIKELY (length <= basesink->preroll_queue_max_len))
3084         goto more_preroll;
3085     }
3086   }
3087   /* we can start rendering (or blocking) the queued object
3088    * if any. */
3089   q = basesink->preroll_queue;
3090   while (G_UNLIKELY (!g_queue_is_empty (q))) {
3091     GstMiniObject *o;
3092
3093     o = g_queue_pop_head (q);
3094     GST_DEBUG_OBJECT (basesink, "rendering queued object %p", o);
3095
3096     /* do something with the return value */
3097     ret = gst_base_sink_render_object (basesink, pad, FALSE, o);
3098     if (ret != GST_FLOW_OK)
3099       goto dequeue_failed;
3100   }
3101
3102   /* now render the object */
3103   ret = gst_base_sink_render_object (basesink, pad, is_list, obj);
3104   basesink->preroll_queued = 0;
3105
3106   return ret;
3107
3108   /* special cases */
3109 preroll_failed:
3110   {
3111     GST_DEBUG_OBJECT (basesink, "preroll failed, reason %s",
3112         gst_flow_get_name (ret));
3113     gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
3114     return ret;
3115   }
3116 more_preroll:
3117   {
3118     /* add object to the queue and return */
3119     GST_DEBUG_OBJECT (basesink, "need more preroll data %d <= %d",
3120         length, basesink->preroll_queue_max_len);
3121     g_queue_push_tail (basesink->preroll_queue, obj);
3122     return GST_FLOW_OK;
3123   }
3124 dequeue_failed:
3125   {
3126     GST_DEBUG_OBJECT (basesink, "rendering queued objects failed, reason %s",
3127         gst_flow_get_name (ret));
3128     gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
3129     return ret;
3130   }
3131 }
3132
3133 /* with STREAM_LOCK
3134  *
3135  * This function grabs the PREROLL_LOCK and adds the object to
3136  * the queue.
3137  *
3138  * This function takes ownership of obj.
3139  */
3140 static GstFlowReturn
3141 gst_base_sink_queue_object (GstBaseSink * basesink, GstPad * pad,
3142     GstMiniObject * obj, gboolean prerollable)
3143 {
3144   GstFlowReturn ret;
3145
3146   GST_PAD_PREROLL_LOCK (pad);
3147   if (G_UNLIKELY (basesink->flushing))
3148     goto flushing;
3149
3150   if (G_UNLIKELY (basesink->priv->received_eos))
3151     goto was_eos;
3152
3153   ret =
3154       gst_base_sink_queue_object_unlocked (basesink, pad, FALSE, obj,
3155       prerollable);
3156   GST_PAD_PREROLL_UNLOCK (pad);
3157
3158   return ret;
3159
3160   /* ERRORS */
3161 flushing:
3162   {
3163     GST_DEBUG_OBJECT (basesink, "sink is flushing");
3164     GST_PAD_PREROLL_UNLOCK (pad);
3165     gst_mini_object_unref (obj);
3166     return GST_FLOW_WRONG_STATE;
3167   }
3168 was_eos:
3169   {
3170     GST_DEBUG_OBJECT (basesink,
3171         "we are EOS, dropping object, return UNEXPECTED");
3172     GST_PAD_PREROLL_UNLOCK (pad);
3173     gst_mini_object_unref (obj);
3174     return GST_FLOW_UNEXPECTED;
3175   }
3176 }
3177
3178 static void
3179 gst_base_sink_flush_start (GstBaseSink * basesink, GstPad * pad)
3180 {
3181   /* make sure we are not blocked on the clock also clear any pending
3182    * eos state. */
3183   gst_base_sink_set_flushing (basesink, pad, TRUE);
3184
3185   /* we grab the stream lock but that is not needed since setting the
3186    * sink to flushing would make sure no state commit is being done
3187    * anymore */
3188   GST_PAD_STREAM_LOCK (pad);
3189   gst_base_sink_reset_qos (basesink);
3190   if (basesink->priv->async_enabled) {
3191     /* and we need to commit our state again on the next
3192      * prerolled buffer */
3193     basesink->playing_async = TRUE;
3194     gst_element_lost_state (GST_ELEMENT_CAST (basesink));
3195   } else {
3196     basesink->priv->have_latency = TRUE;
3197     basesink->need_preroll = FALSE;
3198   }
3199   gst_base_sink_set_last_buffer (basesink, NULL);
3200   GST_PAD_STREAM_UNLOCK (pad);
3201 }
3202
3203 static void
3204 gst_base_sink_flush_stop (GstBaseSink * basesink, GstPad * pad)
3205 {
3206   /* unset flushing so we can accept new data, this also flushes out any EOS
3207    * event. */
3208   gst_base_sink_set_flushing (basesink, pad, FALSE);
3209
3210   /* for position reporting */
3211   GST_OBJECT_LOCK (basesink);
3212   basesink->priv->current_sstart = GST_CLOCK_TIME_NONE;
3213   basesink->priv->current_sstop = GST_CLOCK_TIME_NONE;
3214   basesink->priv->eos_rtime = GST_CLOCK_TIME_NONE;
3215   basesink->priv->call_preroll = TRUE;
3216   basesink->priv->current_step.valid = FALSE;
3217   basesink->priv->pending_step.valid = FALSE;
3218   if (basesink->pad_mode == GST_ACTIVATE_PUSH) {
3219     /* we need new segment info after the flush. */
3220     basesink->have_newsegment = FALSE;
3221     gst_segment_init (&basesink->segment, GST_FORMAT_UNDEFINED);
3222     gst_segment_init (basesink->abidata.ABI.clip_segment, GST_FORMAT_UNDEFINED);
3223   }
3224   GST_OBJECT_UNLOCK (basesink);
3225 }
3226
3227 static gboolean
3228 gst_base_sink_event (GstPad * pad, GstEvent * event)
3229 {
3230   GstBaseSink *basesink;
3231   gboolean result = TRUE;
3232   GstBaseSinkClass *bclass;
3233
3234   basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
3235
3236   bclass = GST_BASE_SINK_GET_CLASS (basesink);
3237
3238   GST_DEBUG_OBJECT (basesink, "reveived event %p %" GST_PTR_FORMAT, event,
3239       event);
3240
3241   switch (GST_EVENT_TYPE (event)) {
3242     case GST_EVENT_EOS:
3243     {
3244       GstFlowReturn ret;
3245
3246       GST_PAD_PREROLL_LOCK (pad);
3247       if (G_UNLIKELY (basesink->flushing))
3248         goto flushing;
3249
3250       if (G_UNLIKELY (basesink->priv->received_eos)) {
3251         /* we can't accept anything when we are EOS */
3252         result = FALSE;
3253         gst_event_unref (event);
3254       } else {
3255         /* we set the received EOS flag here so that we can use it when testing if
3256          * we are prerolled and to refuse more buffers. */
3257         basesink->priv->received_eos = TRUE;
3258
3259         /* EOS is a prerollable object, we call the unlocked version because it
3260          * does not check the received_eos flag. */
3261         ret = gst_base_sink_queue_object_unlocked (basesink, pad,
3262             FALSE, GST_MINI_OBJECT_CAST (event), TRUE);
3263         if (G_UNLIKELY (ret != GST_FLOW_OK))
3264           result = FALSE;
3265       }
3266       GST_PAD_PREROLL_UNLOCK (pad);
3267       break;
3268     }
3269     case GST_EVENT_NEWSEGMENT:
3270     {
3271       GstFlowReturn ret;
3272       gboolean update;
3273
3274       GST_DEBUG_OBJECT (basesink, "newsegment %p", event);
3275
3276       GST_PAD_PREROLL_LOCK (pad);
3277       if (G_UNLIKELY (basesink->flushing))
3278         goto flushing;
3279
3280       gst_event_parse_new_segment_full (event, &update, NULL, NULL, NULL, NULL,
3281           NULL, NULL);
3282
3283       if (G_UNLIKELY (basesink->priv->received_eos && !update)) {
3284         /* we can't accept anything when we are EOS */
3285         result = FALSE;
3286         gst_event_unref (event);
3287       } else {
3288         /* the new segment is a non prerollable item and does not block anything,
3289          * we need to configure the current clipping segment and insert the event
3290          * in the queue to serialize it with the buffers for rendering. */
3291         gst_base_sink_configure_segment (basesink, pad, event,
3292             basesink->abidata.ABI.clip_segment);
3293
3294         ret =
3295             gst_base_sink_queue_object_unlocked (basesink, pad,
3296             FALSE, GST_MINI_OBJECT_CAST (event), FALSE);
3297         if (G_UNLIKELY (ret != GST_FLOW_OK))
3298           result = FALSE;
3299         else {
3300           GST_OBJECT_LOCK (basesink);
3301           basesink->have_newsegment = TRUE;
3302           GST_OBJECT_UNLOCK (basesink);
3303         }
3304       }
3305       GST_PAD_PREROLL_UNLOCK (pad);
3306       break;
3307     }
3308     case GST_EVENT_FLUSH_START:
3309       if (bclass->event)
3310         bclass->event (basesink, event);
3311
3312       GST_DEBUG_OBJECT (basesink, "flush-start %p", event);
3313
3314       gst_base_sink_flush_start (basesink, pad);
3315
3316       gst_event_unref (event);
3317       break;
3318     case GST_EVENT_FLUSH_STOP:
3319       if (bclass->event)
3320         bclass->event (basesink, event);
3321
3322       GST_DEBUG_OBJECT (basesink, "flush-stop %p", event);
3323
3324       gst_base_sink_flush_stop (basesink, pad);
3325
3326       gst_event_unref (event);
3327       break;
3328     default:
3329       /* other events are sent to queue or subclass depending on if they
3330        * are serialized. */
3331       if (GST_EVENT_IS_SERIALIZED (event)) {
3332         gst_base_sink_queue_object (basesink, pad,
3333             GST_MINI_OBJECT_CAST (event), FALSE);
3334       } else {
3335         if (bclass->event)
3336           bclass->event (basesink, event);
3337         gst_event_unref (event);
3338       }
3339       break;
3340   }
3341 done:
3342   gst_object_unref (basesink);
3343
3344   return result;
3345
3346   /* ERRORS */
3347 flushing:
3348   {
3349     GST_DEBUG_OBJECT (basesink, "we are flushing");
3350     GST_PAD_PREROLL_UNLOCK (pad);
3351     result = FALSE;
3352     gst_event_unref (event);
3353     goto done;
3354   }
3355 }
3356
3357 /* default implementation to calculate the start and end
3358  * timestamps on a buffer, subclasses can override
3359  */
3360 static void
3361 gst_base_sink_get_times (GstBaseSink * basesink, GstBuffer * buffer,
3362     GstClockTime * start, GstClockTime * end)
3363 {
3364   GstClockTime timestamp, duration;
3365
3366   timestamp = GST_BUFFER_TIMESTAMP (buffer);
3367   if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
3368
3369     /* get duration to calculate end time */
3370     duration = GST_BUFFER_DURATION (buffer);
3371     if (GST_CLOCK_TIME_IS_VALID (duration)) {
3372       *end = timestamp + duration;
3373     }
3374     *start = timestamp;
3375   }
3376 }
3377
3378 /* must be called with PREROLL_LOCK */
3379 static gboolean
3380 gst_base_sink_needs_preroll (GstBaseSink * basesink)
3381 {
3382   gboolean is_prerolled, res;
3383
3384   /* we have 2 cases where the PREROLL_LOCK is released:
3385    *  1) we are blocking in the PREROLL_LOCK and thus are prerolled.
3386    *  2) we are syncing on the clock
3387    */
3388   is_prerolled = basesink->have_preroll || basesink->priv->received_eos;
3389   res = !is_prerolled;
3390
3391   GST_DEBUG_OBJECT (basesink, "have_preroll: %d, EOS: %d => needs preroll: %d",
3392       basesink->have_preroll, basesink->priv->received_eos, res);
3393
3394   return res;
3395 }
3396
3397 /* with STREAM_LOCK, PREROLL_LOCK
3398  *
3399  * Takes a buffer and compare the timestamps with the last segment.
3400  * If the buffer falls outside of the segment boundaries, drop it.
3401  * Else queue the buffer for preroll and rendering.
3402  *
3403  * This function takes ownership of the buffer.
3404  */
3405 static GstFlowReturn
3406 gst_base_sink_chain_unlocked (GstBaseSink * basesink, GstPad * pad,
3407     gboolean is_list, gpointer obj)
3408 {
3409   GstBaseSinkClass *bclass;
3410   GstFlowReturn result;
3411   GstClockTime start = GST_CLOCK_TIME_NONE, end = GST_CLOCK_TIME_NONE;
3412   GstSegment *clip_segment;
3413   GstBuffer *time_buf;
3414
3415   if (G_UNLIKELY (basesink->flushing))
3416     goto flushing;
3417
3418   if (G_UNLIKELY (basesink->priv->received_eos))
3419     goto was_eos;
3420
3421   if (is_list) {
3422     time_buf = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0, 0);
3423     g_assert (NULL != time_buf);
3424   } else {
3425     time_buf = GST_BUFFER_CAST (obj);
3426   }
3427
3428   /* for code clarity */
3429   clip_segment = basesink->abidata.ABI.clip_segment;
3430
3431   if (G_UNLIKELY (!basesink->have_newsegment)) {
3432     gboolean sync;
3433
3434     sync = gst_base_sink_get_sync (basesink);
3435     if (sync) {
3436       GST_ELEMENT_WARNING (basesink, STREAM, FAILED,
3437           (_("Internal data flow problem.")),
3438           ("Received buffer without a new-segment. Assuming timestamps start from 0."));
3439     }
3440
3441     /* this means this sink will assume timestamps start from 0 */
3442     GST_OBJECT_LOCK (basesink);
3443     clip_segment->start = 0;
3444     clip_segment->stop = -1;
3445     basesink->segment.start = 0;
3446     basesink->segment.stop = -1;
3447     basesink->have_newsegment = TRUE;
3448     GST_OBJECT_UNLOCK (basesink);
3449   }
3450
3451   bclass = GST_BASE_SINK_GET_CLASS (basesink);
3452
3453   /* check if the buffer needs to be dropped, we first ask the subclass for the
3454    * start and end */
3455   if (bclass->get_times)
3456     bclass->get_times (basesink, time_buf, &start, &end);
3457
3458   if (!GST_CLOCK_TIME_IS_VALID (start)) {
3459     /* if the subclass does not want sync, we use our own values so that we at
3460      * least clip the buffer to the segment */
3461     gst_base_sink_get_times (basesink, time_buf, &start, &end);
3462   }
3463
3464   GST_DEBUG_OBJECT (basesink, "got times start: %" GST_TIME_FORMAT
3465       ", end: %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (end));
3466
3467   /* a dropped buffer does not participate in anything */
3468   if (GST_CLOCK_TIME_IS_VALID (start) &&
3469       (clip_segment->format == GST_FORMAT_TIME)) {
3470     if (G_UNLIKELY (!gst_segment_clip (clip_segment,
3471                 GST_FORMAT_TIME, (gint64) start, (gint64) end, NULL, NULL)))
3472       goto out_of_segment;
3473   }
3474
3475   /* now we can process the buffer in the queue, this function takes ownership
3476    * of the buffer */
3477   result = gst_base_sink_queue_object_unlocked (basesink, pad,
3478       is_list, obj, TRUE);
3479   return result;
3480
3481   /* ERRORS */
3482 flushing:
3483   {
3484     GST_DEBUG_OBJECT (basesink, "sink is flushing");
3485     gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
3486     return GST_FLOW_WRONG_STATE;
3487   }
3488 was_eos:
3489   {
3490     GST_DEBUG_OBJECT (basesink,
3491         "we are EOS, dropping object, return UNEXPECTED");
3492     gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
3493     return GST_FLOW_UNEXPECTED;
3494   }
3495 out_of_segment:
3496   {
3497     GST_DEBUG_OBJECT (basesink, "dropping buffer, out of clipping segment");
3498     gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
3499     return GST_FLOW_OK;
3500   }
3501 }
3502
3503 /* with STREAM_LOCK
3504  */
3505 static GstFlowReturn
3506 gst_base_sink_chain_main (GstBaseSink * basesink, GstPad * pad,
3507     gboolean is_list, gpointer obj)
3508 {
3509   GstFlowReturn result;
3510
3511   if (G_UNLIKELY (basesink->pad_mode != GST_ACTIVATE_PUSH))
3512     goto wrong_mode;
3513
3514   GST_PAD_PREROLL_LOCK (pad);
3515   result = gst_base_sink_chain_unlocked (basesink, pad, is_list, obj);
3516   GST_PAD_PREROLL_UNLOCK (pad);
3517
3518 done:
3519   return result;
3520
3521   /* ERRORS */
3522 wrong_mode:
3523   {
3524     GST_OBJECT_LOCK (pad);
3525     GST_WARNING_OBJECT (basesink,
3526         "Push on pad %s:%s, but it was not activated in push mode",
3527         GST_DEBUG_PAD_NAME (pad));
3528     GST_OBJECT_UNLOCK (pad);
3529     gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
3530     /* we don't post an error message this will signal to the peer
3531      * pushing that EOS is reached. */
3532     result = GST_FLOW_UNEXPECTED;
3533     goto done;
3534   }
3535 }
3536
3537 static GstFlowReturn
3538 gst_base_sink_chain (GstPad * pad, GstBuffer * buf)
3539 {
3540   GstBaseSink *basesink;
3541
3542   basesink = GST_BASE_SINK (GST_OBJECT_PARENT (pad));
3543
3544   return gst_base_sink_chain_main (basesink, pad, FALSE, buf);
3545 }
3546
3547 static GstFlowReturn
3548 gst_base_sink_chain_list (GstPad * pad, GstBufferList * list)
3549 {
3550   GstBaseSink *basesink;
3551   GstBaseSinkClass *bclass;
3552   GstFlowReturn result;
3553
3554   basesink = GST_BASE_SINK (GST_OBJECT_PARENT (pad));
3555   bclass = GST_BASE_SINK_GET_CLASS (basesink);
3556
3557   if (G_LIKELY (bclass->render_list)) {
3558     result = gst_base_sink_chain_main (basesink, pad, TRUE, list);
3559   } else {
3560     GstBufferListIterator *it;
3561     GstBuffer *group;
3562
3563     GST_INFO_OBJECT (pad, "chaining each group in list as a merged buffer");
3564
3565     it = gst_buffer_list_iterate (list);
3566
3567     if (gst_buffer_list_iterator_next_group (it)) {
3568       do {
3569         group = gst_buffer_list_iterator_merge_group (it);
3570         if (group == NULL) {
3571           group = gst_buffer_new ();
3572           GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining empty group");
3573         } else {
3574           GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining group");
3575         }
3576         result = gst_base_sink_chain_main (basesink, pad, FALSE, group);
3577       } while (result == GST_FLOW_OK
3578           && gst_buffer_list_iterator_next_group (it));
3579     } else {
3580       GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining empty group");
3581       result =
3582           gst_base_sink_chain_main (basesink, pad, FALSE, gst_buffer_new ());
3583     }
3584     gst_buffer_list_iterator_free (it);
3585     gst_buffer_list_unref (list);
3586   }
3587   return result;
3588 }
3589
3590
3591 static gboolean
3592 gst_base_sink_default_do_seek (GstBaseSink * sink, GstSegment * segment)
3593 {
3594   gboolean res = TRUE;
3595
3596   /* update our offset if the start/stop position was updated */
3597   if (segment->format == GST_FORMAT_BYTES) {
3598     segment->time = segment->start;
3599   } else if (segment->start == 0) {
3600     /* seek to start, we can implement a default for this. */
3601     segment->time = 0;
3602   } else {
3603     res = FALSE;
3604     GST_INFO_OBJECT (sink, "Can't do a default seek");
3605   }
3606
3607   return res;
3608 }
3609
3610 #define SEEK_TYPE_IS_RELATIVE(t) (((t) != GST_SEEK_TYPE_NONE) && ((t) != GST_SEEK_TYPE_SET))
3611
3612 static gboolean
3613 gst_base_sink_default_prepare_seek_segment (GstBaseSink * sink,
3614     GstEvent * event, GstSegment * segment)
3615 {
3616   /* By default, we try one of 2 things:
3617    *   - For absolute seek positions, convert the requested position to our
3618    *     configured processing format and place it in the output segment \
3619    *   - For relative seek positions, convert our current (input) values to the
3620    *     seek format, adjust by the relative seek offset and then convert back to
3621    *     the processing format
3622    */
3623   GstSeekType cur_type, stop_type;
3624   gint64 cur, stop;
3625   GstSeekFlags flags;
3626   GstFormat seek_format, dest_format;
3627   gdouble rate;
3628   gboolean update;
3629   gboolean res = TRUE;
3630
3631   gst_event_parse_seek (event, &rate, &seek_format, &flags,
3632       &cur_type, &cur, &stop_type, &stop);
3633   dest_format = segment->format;
3634
3635   if (seek_format == dest_format) {
3636     gst_segment_set_seek (segment, rate, seek_format, flags,
3637         cur_type, cur, stop_type, stop, &update);
3638     return TRUE;
3639   }
3640
3641   if (cur_type != GST_SEEK_TYPE_NONE) {
3642     /* FIXME: Handle seek_cur & seek_end by converting the input segment vals */
3643     res =
3644         gst_pad_query_convert (sink->sinkpad, seek_format, cur, &dest_format,
3645         &cur);
3646     cur_type = GST_SEEK_TYPE_SET;
3647   }
3648
3649   if (res && stop_type != GST_SEEK_TYPE_NONE) {
3650     /* FIXME: Handle seek_cur & seek_end by converting the input segment vals */
3651     res =
3652         gst_pad_query_convert (sink->sinkpad, seek_format, stop, &dest_format,
3653         &stop);
3654     stop_type = GST_SEEK_TYPE_SET;
3655   }
3656
3657   /* And finally, configure our output segment in the desired format */
3658   gst_segment_set_seek (segment, rate, dest_format, flags, cur_type, cur,
3659       stop_type, stop, &update);
3660
3661   if (!res)
3662     goto no_format;
3663
3664   return res;
3665
3666 no_format:
3667   {
3668     GST_DEBUG_OBJECT (sink, "undefined format given, seek aborted.");
3669     return FALSE;
3670   }
3671 }
3672
3673 /* perform a seek, only executed in pull mode */
3674 static gboolean
3675 gst_base_sink_perform_seek (GstBaseSink * sink, GstPad * pad, GstEvent * event)
3676 {
3677   gboolean flush;
3678   gdouble rate;
3679   GstFormat seek_format, dest_format;
3680   GstSeekFlags flags;
3681   GstSeekType cur_type, stop_type;
3682   gboolean seekseg_configured = FALSE;
3683   gint64 cur, stop;
3684   gboolean update, res = TRUE;
3685   GstSegment seeksegment;
3686
3687   dest_format = sink->segment.format;
3688
3689   if (event) {
3690     GST_DEBUG_OBJECT (sink, "performing seek with event %p", event);
3691     gst_event_parse_seek (event, &rate, &seek_format, &flags,
3692         &cur_type, &cur, &stop_type, &stop);
3693
3694     flush = flags & GST_SEEK_FLAG_FLUSH;
3695   } else {
3696     GST_DEBUG_OBJECT (sink, "performing seek without event");
3697     flush = FALSE;
3698   }
3699
3700   if (flush) {
3701     GST_DEBUG_OBJECT (sink, "flushing upstream");
3702     gst_pad_push_event (pad, gst_event_new_flush_start ());
3703     gst_base_sink_flush_start (sink, pad);
3704   } else {
3705     GST_DEBUG_OBJECT (sink, "pausing pulling thread");
3706   }
3707
3708   GST_PAD_STREAM_LOCK (pad);
3709
3710   /* If we configured the seeksegment above, don't overwrite it now. Otherwise
3711    * copy the current segment info into the temp segment that we can actually
3712    * attempt the seek with. We only update the real segment if the seek suceeds. */
3713   if (!seekseg_configured) {
3714     memcpy (&seeksegment, &sink->segment, sizeof (GstSegment));
3715
3716     /* now configure the final seek segment */
3717     if (event) {
3718       if (sink->segment.format != seek_format) {
3719         /* OK, here's where we give the subclass a chance to convert the relative
3720          * seek into an absolute one in the processing format. We set up any
3721          * absolute seek above, before taking the stream lock. */
3722         if (!gst_base_sink_default_prepare_seek_segment (sink, event,
3723                 &seeksegment)) {
3724           GST_DEBUG_OBJECT (sink,
3725               "Preparing the seek failed after flushing. " "Aborting seek");
3726           res = FALSE;
3727         }
3728       } else {
3729         /* The seek format matches our processing format, no need to ask the
3730          * the subclass to configure the segment. */
3731         gst_segment_set_seek (&seeksegment, rate, seek_format, flags,
3732             cur_type, cur, stop_type, stop, &update);
3733       }
3734     }
3735     /* Else, no seek event passed, so we're just (re)starting the
3736        current segment. */
3737   }
3738
3739   if (res) {
3740     GST_DEBUG_OBJECT (sink, "segment configured from %" G_GINT64_FORMAT
3741         " to %" G_GINT64_FORMAT ", position %" G_GINT64_FORMAT,
3742         seeksegment.start, seeksegment.stop, seeksegment.last_stop);
3743
3744     /* do the seek, segment.last_stop contains the new position. */
3745     res = gst_base_sink_default_do_seek (sink, &seeksegment);
3746   }
3747
3748
3749   if (flush) {
3750     GST_DEBUG_OBJECT (sink, "stop flushing upstream");
3751     gst_pad_push_event (pad, gst_event_new_flush_stop ());
3752     gst_base_sink_flush_stop (sink, pad);
3753   } else if (res && sink->abidata.ABI.running) {
3754     /* we are running the current segment and doing a non-flushing seek,
3755      * close the segment first based on the last_stop. */
3756     GST_DEBUG_OBJECT (sink, "closing running segment %" G_GINT64_FORMAT
3757         " to %" G_GINT64_FORMAT, sink->segment.start, sink->segment.last_stop);
3758   }
3759
3760   /* The subclass must have converted the segment to the processing format
3761    * by now */
3762   if (res && seeksegment.format != dest_format) {
3763     GST_DEBUG_OBJECT (sink, "Subclass failed to prepare a seek segment "
3764         "in the correct format. Aborting seek.");
3765     res = FALSE;
3766   }
3767
3768   /* if successfull seek, we update our real segment and push
3769    * out the new segment. */
3770   if (res) {
3771     memcpy (&sink->segment, &seeksegment, sizeof (GstSegment));
3772
3773     if (sink->segment.flags & GST_SEEK_FLAG_SEGMENT) {
3774       gst_element_post_message (GST_ELEMENT (sink),
3775           gst_message_new_segment_start (GST_OBJECT (sink),
3776               sink->segment.format, sink->segment.last_stop));
3777     }
3778   }
3779
3780   sink->priv->discont = TRUE;
3781   sink->abidata.ABI.running = TRUE;
3782
3783   GST_PAD_STREAM_UNLOCK (pad);
3784
3785   return res;
3786 }
3787
3788 static void
3789 set_step_info (GstBaseSink * sink, GstStepInfo * current, GstStepInfo * pending,
3790     guint seqnum, GstFormat format, guint64 amount, gdouble rate,
3791     gboolean flush, gboolean intermediate)
3792 {
3793   GST_OBJECT_LOCK (sink);
3794   pending->seqnum = seqnum;
3795   pending->format = format;
3796   pending->amount = amount;
3797   pending->position = 0;
3798   pending->rate = rate;
3799   pending->flush = flush;
3800   pending->intermediate = intermediate;
3801   pending->valid = TRUE;
3802   /* flush invalidates the current stepping segment */
3803   if (flush)
3804     current->valid = FALSE;
3805   GST_OBJECT_UNLOCK (sink);
3806 }
3807
3808 static gboolean
3809 gst_base_sink_perform_step (GstBaseSink * sink, GstPad * pad, GstEvent * event)
3810 {
3811   GstBaseSinkPrivate *priv;
3812   GstBaseSinkClass *bclass;
3813   gboolean flush, intermediate;
3814   gdouble rate;
3815   GstFormat format;
3816   guint64 amount;
3817   guint seqnum;
3818   GstStepInfo *pending, *current;
3819   GstMessage *message;
3820
3821   bclass = GST_BASE_SINK_GET_CLASS (sink);
3822   priv = sink->priv;
3823
3824   GST_DEBUG_OBJECT (sink, "performing step with event %p", event);
3825
3826   gst_event_parse_step (event, &format, &amount, &rate, &flush, &intermediate);
3827   seqnum = gst_event_get_seqnum (event);
3828
3829   pending = &priv->pending_step;
3830   current = &priv->current_step;
3831
3832   /* post message first */
3833   message = gst_message_new_step_start (GST_OBJECT (sink), FALSE, format,
3834       amount, rate, flush, intermediate);
3835   gst_message_set_seqnum (message, seqnum);
3836   gst_element_post_message (GST_ELEMENT (sink), message);
3837
3838   if (flush) {
3839     /* we need to call ::unlock before locking PREROLL_LOCK
3840      * since we lock it before going into ::render */
3841     if (bclass->unlock)
3842       bclass->unlock (sink);
3843
3844     GST_PAD_PREROLL_LOCK (sink->sinkpad);
3845     /* now that we have the PREROLL lock, clear our unlock request */
3846     if (bclass->unlock_stop)
3847       bclass->unlock_stop (sink);
3848
3849     /* update the stepinfo and make it valid */
3850     set_step_info (sink, current, pending, seqnum, format, amount, rate, flush,
3851         intermediate);
3852
3853     if (sink->priv->async_enabled) {
3854       /* and we need to commit our state again on the next
3855        * prerolled buffer */
3856       sink->playing_async = TRUE;
3857       priv->pending_step.need_preroll = TRUE;
3858       sink->need_preroll = FALSE;
3859       gst_element_lost_state_full (GST_ELEMENT_CAST (sink), FALSE);
3860     } else {
3861       sink->priv->have_latency = TRUE;
3862       sink->need_preroll = FALSE;
3863     }
3864     priv->current_sstart = GST_CLOCK_TIME_NONE;
3865     priv->current_sstop = GST_CLOCK_TIME_NONE;
3866     priv->eos_rtime = GST_CLOCK_TIME_NONE;
3867     priv->call_preroll = TRUE;
3868     gst_base_sink_set_last_buffer (sink, NULL);
3869     gst_base_sink_reset_qos (sink);
3870
3871     if (sink->clock_id) {
3872       gst_clock_id_unschedule (sink->clock_id);
3873     }
3874
3875     if (sink->have_preroll) {
3876       GST_DEBUG_OBJECT (sink, "signal waiter");
3877       priv->step_unlock = TRUE;
3878       GST_PAD_PREROLL_SIGNAL (sink->sinkpad);
3879     }
3880     GST_PAD_PREROLL_UNLOCK (sink->sinkpad);
3881   } else {
3882     /* update the stepinfo and make it valid */
3883     set_step_info (sink, current, pending, seqnum, format, amount, rate, flush,
3884         intermediate);
3885   }
3886
3887   return TRUE;
3888 }
3889
3890 /* with STREAM_LOCK
3891  */
3892 static void
3893 gst_base_sink_loop (GstPad * pad)
3894 {
3895   GstBaseSink *basesink;
3896   GstBuffer *buf = NULL;
3897   GstFlowReturn result;
3898   guint blocksize;
3899   guint64 offset;
3900
3901   basesink = GST_BASE_SINK (GST_OBJECT_PARENT (pad));
3902
3903   g_assert (basesink->pad_mode == GST_ACTIVATE_PULL);
3904
3905   if ((blocksize = basesink->priv->blocksize) == 0)
3906     blocksize = -1;
3907
3908   offset = basesink->segment.last_stop;
3909
3910   GST_DEBUG_OBJECT (basesink, "pulling %" G_GUINT64_FORMAT ", %u",
3911       offset, blocksize);
3912
3913   result = gst_pad_pull_range (pad, offset, blocksize, &buf);
3914   if (G_UNLIKELY (result != GST_FLOW_OK))
3915     goto paused;
3916
3917   if (G_UNLIKELY (buf == NULL))
3918     goto no_buffer;
3919
3920   offset += GST_BUFFER_SIZE (buf);
3921
3922   gst_segment_set_last_stop (&basesink->segment, GST_FORMAT_BYTES, offset);
3923
3924   GST_PAD_PREROLL_LOCK (pad);
3925   result = gst_base_sink_chain_unlocked (basesink, pad, FALSE, buf);
3926   GST_PAD_PREROLL_UNLOCK (pad);
3927   if (G_UNLIKELY (result != GST_FLOW_OK))
3928     goto paused;
3929
3930   return;
3931
3932   /* ERRORS */
3933 paused:
3934   {
3935     GST_LOG_OBJECT (basesink, "pausing task, reason %s",
3936         gst_flow_get_name (result));
3937     gst_pad_pause_task (pad);
3938     if (result == GST_FLOW_UNEXPECTED) {
3939       /* perform EOS logic */
3940       if (basesink->segment.flags & GST_SEEK_FLAG_SEGMENT) {
3941         gst_element_post_message (GST_ELEMENT_CAST (basesink),
3942             gst_message_new_segment_done (GST_OBJECT_CAST (basesink),
3943                 basesink->segment.format, basesink->segment.last_stop));
3944       } else {
3945         gst_base_sink_event (pad, gst_event_new_eos ());
3946       }
3947     } else if (result == GST_FLOW_NOT_LINKED || result <= GST_FLOW_UNEXPECTED) {
3948       /* for fatal errors we post an error message, post the error
3949        * first so the app knows about the error first. 
3950        * wrong-state is not a fatal error because it happens due to
3951        * flushing and posting an error message in that case is the
3952        * wrong thing to do, e.g. when basesrc is doing a flushing
3953        * seek. */
3954       GST_ELEMENT_ERROR (basesink, STREAM, FAILED,
3955           (_("Internal data stream error.")),
3956           ("stream stopped, reason %s", gst_flow_get_name (result)));
3957       gst_base_sink_event (pad, gst_event_new_eos ());
3958     }
3959     return;
3960   }
3961 no_buffer:
3962   {
3963     GST_LOG_OBJECT (basesink, "no buffer, pausing");
3964     GST_ELEMENT_ERROR (basesink, STREAM, FAILED,
3965         (_("Internal data flow error.")), ("element returned NULL buffer"));
3966     result = GST_FLOW_ERROR;
3967     goto paused;
3968   }
3969 }
3970
3971 static gboolean
3972 gst_base_sink_set_flushing (GstBaseSink * basesink, GstPad * pad,
3973     gboolean flushing)
3974 {
3975   GstBaseSinkClass *bclass;
3976
3977   bclass = GST_BASE_SINK_GET_CLASS (basesink);
3978
3979   if (flushing) {
3980     /* unlock any subclasses, we need to do this before grabbing the
3981      * PREROLL_LOCK since we hold this lock before going into ::render. */
3982     if (bclass->unlock)
3983       bclass->unlock (basesink);
3984   }
3985
3986   GST_PAD_PREROLL_LOCK (pad);
3987   basesink->flushing = flushing;
3988   if (flushing) {
3989     /* step 1, now that we have the PREROLL lock, clear our unlock request */
3990     if (bclass->unlock_stop)
3991       bclass->unlock_stop (basesink);
3992
3993     /* set need_preroll before we unblock the clock. If the clock is unblocked
3994      * before timing out, we can reuse the buffer for preroll. */
3995     basesink->need_preroll = TRUE;
3996
3997     /* step 2, unblock clock sync (if any) or any other blocking thing */
3998     if (basesink->clock_id) {
3999       gst_clock_id_unschedule (basesink->clock_id);
4000     }
4001
4002     /* flush out the data thread if it's locked in finish_preroll, this will
4003      * also flush out the EOS state */
4004     GST_DEBUG_OBJECT (basesink,
4005         "flushing out data thread, need preroll to TRUE");
4006     gst_base_sink_preroll_queue_flush (basesink, pad);
4007   }
4008   GST_PAD_PREROLL_UNLOCK (pad);
4009
4010   return TRUE;
4011 }
4012
4013 static gboolean
4014 gst_base_sink_default_activate_pull (GstBaseSink * basesink, gboolean active)
4015 {
4016   gboolean result;
4017
4018   if (active) {
4019     /* start task */
4020     result = gst_pad_start_task (basesink->sinkpad,
4021         (GstTaskFunction) gst_base_sink_loop, basesink->sinkpad);
4022   } else {
4023     /* step 2, make sure streaming finishes */
4024     result = gst_pad_stop_task (basesink->sinkpad);
4025   }
4026
4027   return result;
4028 }
4029
4030 static gboolean
4031 gst_base_sink_pad_activate (GstPad * pad)
4032 {
4033   gboolean result = FALSE;
4034   GstBaseSink *basesink;
4035
4036   basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
4037
4038   GST_DEBUG_OBJECT (basesink, "Trying pull mode first");
4039
4040   gst_base_sink_set_flushing (basesink, pad, FALSE);
4041
4042   /* we need to have the pull mode enabled */
4043   if (!basesink->can_activate_pull) {
4044     GST_DEBUG_OBJECT (basesink, "pull mode disabled");
4045     goto fallback;
4046   }
4047
4048   /* check if downstreams supports pull mode at all */
4049   if (!gst_pad_check_pull_range (pad)) {
4050     GST_DEBUG_OBJECT (basesink, "pull mode not supported");
4051     goto fallback;
4052   }
4053
4054   /* set the pad mode before starting the task so that it's in the
4055    * correct state for the new thread. also the sink set_caps and get_caps
4056    * function checks this */
4057   basesink->pad_mode = GST_ACTIVATE_PULL;
4058
4059   /* we first try to negotiate a format so that when we try to activate
4060    * downstream, it knows about our format */
4061   if (!gst_base_sink_negotiate_pull (basesink)) {
4062     GST_DEBUG_OBJECT (basesink, "failed to negotiate in pull mode");
4063     goto fallback;
4064   }
4065
4066   /* ok activate now */
4067   if (!gst_pad_activate_pull (pad, TRUE)) {
4068     /* clear any pending caps */
4069     GST_OBJECT_LOCK (basesink);
4070     gst_caps_replace (&basesink->priv->pull_caps, NULL);
4071     GST_OBJECT_UNLOCK (basesink);
4072     GST_DEBUG_OBJECT (basesink, "failed to activate in pull mode");
4073     goto fallback;
4074   }
4075
4076   GST_DEBUG_OBJECT (basesink, "Success activating pull mode");
4077   result = TRUE;
4078   goto done;
4079
4080   /* push mode fallback */
4081 fallback:
4082   GST_DEBUG_OBJECT (basesink, "Falling back to push mode");
4083   if ((result = gst_pad_activate_push (pad, TRUE))) {
4084     GST_DEBUG_OBJECT (basesink, "Success activating push mode");
4085   }
4086
4087 done:
4088   if (!result) {
4089     GST_WARNING_OBJECT (basesink, "Could not activate pad in either mode");
4090     gst_base_sink_set_flushing (basesink, pad, TRUE);
4091   }
4092
4093   gst_object_unref (basesink);
4094
4095   return result;
4096 }
4097
4098 static gboolean
4099 gst_base_sink_pad_activate_push (GstPad * pad, gboolean active)
4100 {
4101   gboolean result;
4102   GstBaseSink *basesink;
4103
4104   basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
4105
4106   if (active) {
4107     if (!basesink->can_activate_push) {
4108       result = FALSE;
4109       basesink->pad_mode = GST_ACTIVATE_NONE;
4110     } else {
4111       result = TRUE;
4112       basesink->pad_mode = GST_ACTIVATE_PUSH;
4113     }
4114   } else {
4115     if (G_UNLIKELY (basesink->pad_mode != GST_ACTIVATE_PUSH)) {
4116       g_warning ("Internal GStreamer activation error!!!");
4117       result = FALSE;
4118     } else {
4119       gst_base_sink_set_flushing (basesink, pad, TRUE);
4120       result = TRUE;
4121       basesink->pad_mode = GST_ACTIVATE_NONE;
4122     }
4123   }
4124
4125   gst_object_unref (basesink);
4126
4127   return result;
4128 }
4129
4130 static gboolean
4131 gst_base_sink_negotiate_pull (GstBaseSink * basesink)
4132 {
4133   GstCaps *caps;
4134   gboolean result;
4135
4136   result = FALSE;
4137
4138   /* this returns the intersection between our caps and the peer caps. If there
4139    * is no peer, it returns NULL and we can't operate in pull mode so we can
4140    * fail the negotiation. */
4141   caps = gst_pad_get_allowed_caps (GST_BASE_SINK_PAD (basesink));
4142   if (caps == NULL || gst_caps_is_empty (caps))
4143     goto no_caps_possible;
4144
4145   GST_DEBUG_OBJECT (basesink, "allowed caps: %" GST_PTR_FORMAT, caps);
4146
4147   caps = gst_caps_make_writable (caps);
4148   /* get the first (prefered) format */
4149   gst_caps_truncate (caps);
4150   /* try to fixate */
4151   gst_pad_fixate_caps (GST_BASE_SINK_PAD (basesink), caps);
4152
4153   GST_DEBUG_OBJECT (basesink, "fixated to: %" GST_PTR_FORMAT, caps);
4154
4155   if (gst_caps_is_any (caps)) {
4156     GST_DEBUG_OBJECT (basesink, "caps were ANY after fixating, "
4157         "allowing pull()");
4158     /* neither side has template caps in this case, so they are prepared for
4159        pull() without setcaps() */
4160     result = TRUE;
4161   } else if (gst_caps_is_fixed (caps)) {
4162     if (!gst_pad_set_caps (GST_BASE_SINK_PAD (basesink), caps))
4163       goto could_not_set_caps;
4164
4165     GST_OBJECT_LOCK (basesink);
4166     gst_caps_replace (&basesink->priv->pull_caps, caps);
4167     GST_OBJECT_UNLOCK (basesink);
4168
4169     result = TRUE;
4170   }
4171
4172   gst_caps_unref (caps);
4173
4174   return result;
4175
4176 no_caps_possible:
4177   {
4178     GST_INFO_OBJECT (basesink, "Pipeline could not agree on caps");
4179     GST_DEBUG_OBJECT (basesink, "get_allowed_caps() returned EMPTY");
4180     if (caps)
4181       gst_caps_unref (caps);
4182     return FALSE;
4183   }
4184 could_not_set_caps:
4185   {
4186     GST_INFO_OBJECT (basesink, "Could not set caps: %" GST_PTR_FORMAT, caps);
4187     gst_caps_unref (caps);
4188     return FALSE;
4189   }
4190 }
4191
4192 /* this won't get called until we implement an activate function */
4193 static gboolean
4194 gst_base_sink_pad_activate_pull (GstPad * pad, gboolean active)
4195 {
4196   gboolean result = FALSE;
4197   GstBaseSink *basesink;
4198   GstBaseSinkClass *bclass;
4199
4200   basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
4201   bclass = GST_BASE_SINK_GET_CLASS (basesink);
4202
4203   if (active) {
4204     GstFormat format;
4205     gint64 duration;
4206
4207     /* we mark we have a newsegment here because pull based
4208      * mode works just fine without having a newsegment before the
4209      * first buffer */
4210     format = GST_FORMAT_BYTES;
4211
4212     gst_segment_init (&basesink->segment, format);
4213     gst_segment_init (basesink->abidata.ABI.clip_segment, format);
4214     GST_OBJECT_LOCK (basesink);
4215     basesink->have_newsegment = TRUE;
4216     GST_OBJECT_UNLOCK (basesink);
4217
4218     /* get the peer duration in bytes */
4219     result = gst_pad_query_peer_duration (pad, &format, &duration);
4220     if (result) {
4221       GST_DEBUG_OBJECT (basesink,
4222           "setting duration in bytes to %" G_GINT64_FORMAT, duration);
4223       gst_segment_set_duration (basesink->abidata.ABI.clip_segment, format,
4224           duration);
4225       gst_segment_set_duration (&basesink->segment, format, duration);
4226     } else {
4227       GST_DEBUG_OBJECT (basesink, "unknown duration");
4228     }
4229
4230     if (bclass->activate_pull)
4231       result = bclass->activate_pull (basesink, TRUE);
4232     else
4233       result = FALSE;
4234
4235     if (!result)
4236       goto activate_failed;
4237
4238   } else {
4239     if (G_UNLIKELY (basesink->pad_mode != GST_ACTIVATE_PULL)) {
4240       g_warning ("Internal GStreamer activation error!!!");
4241       result = FALSE;
4242     } else {
4243       result = gst_base_sink_set_flushing (basesink, pad, TRUE);
4244       if (bclass->activate_pull)
4245         result &= bclass->activate_pull (basesink, FALSE);
4246       basesink->pad_mode = GST_ACTIVATE_NONE;
4247       /* clear any pending caps */
4248       GST_OBJECT_LOCK (basesink);
4249       gst_caps_replace (&basesink->priv->pull_caps, NULL);
4250       GST_OBJECT_UNLOCK (basesink);
4251     }
4252   }
4253   gst_object_unref (basesink);
4254
4255   return result;
4256
4257   /* ERRORS */
4258 activate_failed:
4259   {
4260     /* reset, as starting the thread failed */
4261     basesink->pad_mode = GST_ACTIVATE_NONE;
4262
4263     GST_ERROR_OBJECT (basesink, "subclass failed to activate in pull mode");
4264     return FALSE;
4265   }
4266 }
4267
4268 /* send an event to our sinkpad peer. */
4269 static gboolean
4270 gst_base_sink_send_event (GstElement * element, GstEvent * event)
4271 {
4272   GstPad *pad;
4273   GstBaseSink *basesink = GST_BASE_SINK (element);
4274   gboolean forward, result = TRUE;
4275   GstActivateMode mode;
4276
4277   GST_OBJECT_LOCK (element);
4278   /* get the pad and the scheduling mode */
4279   pad = gst_object_ref (basesink->sinkpad);
4280   mode = basesink->pad_mode;
4281   GST_OBJECT_UNLOCK (element);
4282
4283   /* only push UPSTREAM events upstream */
4284   forward = GST_EVENT_IS_UPSTREAM (event);
4285
4286   GST_DEBUG_OBJECT (basesink, "handling event %p %" GST_PTR_FORMAT, event,
4287       event);
4288
4289   switch (GST_EVENT_TYPE (event)) {
4290     case GST_EVENT_LATENCY:
4291     {
4292       GstClockTime latency;
4293
4294       gst_event_parse_latency (event, &latency);
4295
4296       /* store the latency. We use this to adjust the running_time before syncing
4297        * it to the clock. */
4298       GST_OBJECT_LOCK (element);
4299       basesink->priv->latency = latency;
4300       if (!basesink->priv->have_latency)
4301         forward = FALSE;
4302       GST_OBJECT_UNLOCK (element);
4303       GST_DEBUG_OBJECT (basesink, "latency set to %" GST_TIME_FORMAT,
4304           GST_TIME_ARGS (latency));
4305
4306       /* We forward this event so that all elements know about the global pipeline
4307        * latency. This is interesting for an element when it wants to figure out
4308        * when a particular piece of data will be rendered. */
4309       break;
4310     }
4311     case GST_EVENT_SEEK:
4312       /* in pull mode we will execute the seek */
4313       if (mode == GST_ACTIVATE_PULL)
4314         result = gst_base_sink_perform_seek (basesink, pad, event);
4315       break;
4316     case GST_EVENT_STEP:
4317       result = gst_base_sink_perform_step (basesink, pad, event);
4318       forward = FALSE;
4319       break;
4320     default:
4321       break;
4322   }
4323
4324   if (forward) {
4325     result = gst_pad_push_event (pad, event);
4326   } else {
4327     /* not forwarded, unref the event */
4328     gst_event_unref (event);
4329   }
4330
4331   gst_object_unref (pad);
4332   return result;
4333 }
4334
4335 /* get the end position of the last seen object, this is used
4336  * for EOS and for making sure that we don't report a position we
4337  * have not reached yet. With LOCK. */
4338 static gboolean
4339 gst_base_sink_get_position_last (GstBaseSink * basesink, GstFormat format,
4340     gint64 * cur, gboolean * upstream)
4341 {
4342   GstFormat oformat;
4343   GstSegment *segment;
4344   gboolean ret = TRUE;
4345
4346   segment = &basesink->segment;
4347   oformat = segment->format;
4348
4349   if (oformat == GST_FORMAT_TIME) {
4350     /* return last observed stream time, we keep the stream time around in the
4351      * time format. */
4352     *cur = basesink->priv->current_sstop;
4353   } else {
4354     /* convert last stop to stream time */
4355     *cur = gst_segment_to_stream_time (segment, oformat, segment->last_stop);
4356   }
4357
4358   if (*cur != -1 && oformat != format) {
4359     GST_OBJECT_UNLOCK (basesink);
4360     /* convert to the target format if we need to, release lock first */
4361     ret =
4362         gst_pad_query_convert (basesink->sinkpad, oformat, *cur, &format, cur);
4363     if (!ret) {
4364       *cur = -1;
4365       *upstream = TRUE;
4366     }
4367     GST_OBJECT_LOCK (basesink);
4368   }
4369
4370   GST_DEBUG_OBJECT (basesink, "POSITION: %" GST_TIME_FORMAT,
4371       GST_TIME_ARGS (*cur));
4372
4373   return ret;
4374 }
4375
4376 /* get the position when we are PAUSED, this is the stream time of the buffer
4377  * that prerolled. If no buffer is prerolled (we are still flushing), this
4378  * value will be -1. With LOCK. */
4379 static gboolean
4380 gst_base_sink_get_position_paused (GstBaseSink * basesink, GstFormat format,
4381     gint64 * cur, gboolean * upstream)
4382 {
4383   gboolean res;
4384   gint64 time;
4385   GstSegment *segment;
4386   GstFormat oformat;
4387
4388   /* we don't use the clip segment in pull mode, when seeking we update the
4389    * main segment directly with the new segment values without it having to be
4390    * activated by the rendering after preroll */
4391   if (basesink->pad_mode == GST_ACTIVATE_PUSH)
4392     segment = basesink->abidata.ABI.clip_segment;
4393   else
4394     segment = &basesink->segment;
4395   oformat = segment->format;
4396
4397   if (oformat == GST_FORMAT_TIME) {
4398     *cur = basesink->priv->current_sstart;
4399     if (segment->rate < 0.0 &&
4400         GST_CLOCK_TIME_IS_VALID (basesink->priv->current_sstop)) {
4401       /* for reverse playback we prefer the stream time stop position if we have
4402        * one */
4403       *cur = basesink->priv->current_sstop;
4404     }
4405   } else {
4406     *cur = gst_segment_to_stream_time (segment, oformat, segment->last_stop);
4407   }
4408
4409   time = segment->time;
4410
4411   if (*cur != -1) {
4412     *cur = MAX (*cur, time);
4413     GST_DEBUG_OBJECT (basesink, "POSITION as max: %" GST_TIME_FORMAT
4414         ", time %" GST_TIME_FORMAT, GST_TIME_ARGS (*cur), GST_TIME_ARGS (time));
4415   } else {
4416     /* we have no buffer, use the segment times. */
4417     if (segment->rate >= 0.0) {
4418       /* forward, next position is always the time of the segment */
4419       *cur = time;
4420       GST_DEBUG_OBJECT (basesink, "POSITION as time: %" GST_TIME_FORMAT,
4421           GST_TIME_ARGS (*cur));
4422     } else {
4423       /* reverse, next expected timestamp is segment->stop. We use the function
4424        * to get things right for negative applied_rates. */
4425       *cur = gst_segment_to_stream_time (segment, oformat, segment->stop);
4426       GST_DEBUG_OBJECT (basesink, "reverse POSITION: %" GST_TIME_FORMAT,
4427           GST_TIME_ARGS (*cur));
4428     }
4429   }
4430
4431   res = (*cur != -1);
4432   if (res && oformat != format) {
4433     GST_OBJECT_UNLOCK (basesink);
4434     res =
4435         gst_pad_query_convert (basesink->sinkpad, oformat, *cur, &format, cur);
4436     if (!res) {
4437       *cur = -1;
4438       *upstream = TRUE;
4439     }
4440     GST_OBJECT_LOCK (basesink);
4441   }
4442
4443   return res;
4444 }
4445
4446 static gboolean
4447 gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format,
4448     gint64 * cur, gboolean * upstream)
4449 {
4450   GstClock *clock;
4451   gboolean res = FALSE;
4452   GstFormat oformat, tformat;
4453   GstClockTime now, latency;
4454   GstClockTimeDiff base;
4455   gint64 time, accum, duration;
4456   gdouble rate;
4457   gint64 last;
4458
4459   GST_OBJECT_LOCK (basesink);
4460   /* our intermediate time format */
4461   tformat = GST_FORMAT_TIME;
4462   /* get the format in the segment */
4463   oformat = basesink->segment.format;
4464
4465   /* can only give answer based on the clock if not EOS */
4466   if (G_UNLIKELY (basesink->eos))
4467     goto in_eos;
4468
4469   /* we can only get the segment when we are not NULL or READY */
4470   if (!basesink->have_newsegment)
4471     goto wrong_state;
4472
4473   /* when not in PLAYING or when we're busy with a state change, we
4474    * cannot read from the clock so we report time based on the
4475    * last seen timestamp. */
4476   if (GST_STATE (basesink) != GST_STATE_PLAYING ||
4477       GST_STATE_PENDING (basesink) != GST_STATE_VOID_PENDING)
4478     goto in_pause;
4479
4480   /* we need to sync on the clock. */
4481   if (basesink->sync == FALSE)
4482     goto no_sync;
4483
4484   /* and we need a clock */
4485   if (G_UNLIKELY ((clock = GST_ELEMENT_CLOCK (basesink)) == NULL))
4486     goto no_sync;
4487
4488   /* collect all data we need holding the lock */
4489   if (GST_CLOCK_TIME_IS_VALID (basesink->segment.time))
4490     time = basesink->segment.time;
4491   else
4492     time = 0;
4493
4494   if (GST_CLOCK_TIME_IS_VALID (basesink->segment.stop))
4495     duration = basesink->segment.stop - basesink->segment.start;
4496   else
4497     duration = 0;
4498
4499   base = GST_ELEMENT_CAST (basesink)->base_time;
4500   accum = basesink->segment.accum;
4501   rate = basesink->segment.rate * basesink->segment.applied_rate;
4502   latency = basesink->priv->latency;
4503
4504   gst_object_ref (clock);
4505
4506   /* this function might release the LOCK */
4507   gst_base_sink_get_position_last (basesink, format, &last, upstream);
4508
4509   /* need to release the object lock before we can get the time,
4510    * a clock might take the LOCK of the provider, which could be
4511    * a basesink subclass. */
4512   GST_OBJECT_UNLOCK (basesink);
4513
4514   now = gst_clock_get_time (clock);
4515
4516   if (oformat != tformat) {
4517     /* convert accum, time and duration to time */
4518     if (!gst_pad_query_convert (basesink->sinkpad, oformat, accum, &tformat,
4519             &accum))
4520       goto convert_failed;
4521     if (!gst_pad_query_convert (basesink->sinkpad, oformat, duration, &tformat,
4522             &duration))
4523       goto convert_failed;
4524     if (!gst_pad_query_convert (basesink->sinkpad, oformat, time, &tformat,
4525             &time))
4526       goto convert_failed;
4527   }
4528
4529   /* subtract base time and accumulated time from the clock time.
4530    * Make sure we don't go negative. This is the current time in
4531    * the segment which we need to scale with the combined
4532    * rate and applied rate. */
4533   base += accum;
4534   base += latency;
4535   if (GST_CLOCK_DIFF (base, now) < 0)
4536     base = now;
4537
4538   /* for negative rates we need to count back from the segment
4539    * duration. */
4540   if (rate < 0.0)
4541     time += duration;
4542
4543   *cur = time + gst_guint64_to_gdouble (now - base) * rate;
4544
4545   /* never report more than last seen position */
4546   if (last != -1)
4547     *cur = MIN (last, *cur);
4548
4549   gst_object_unref (clock);
4550
4551   GST_DEBUG_OBJECT (basesink,
4552       "now %" GST_TIME_FORMAT " - base %" GST_TIME_FORMAT " - accum %"
4553       GST_TIME_FORMAT " + time %" GST_TIME_FORMAT,
4554       GST_TIME_ARGS (now), GST_TIME_ARGS (base),
4555       GST_TIME_ARGS (accum), GST_TIME_ARGS (time));
4556
4557   if (oformat != format) {
4558     /* convert time to final format */
4559     if (!gst_pad_query_convert (basesink->sinkpad, tformat, *cur, &format, cur))
4560       goto convert_failed;
4561   }
4562
4563   res = TRUE;
4564
4565 done:
4566   GST_DEBUG_OBJECT (basesink, "res: %d, POSITION: %" GST_TIME_FORMAT,
4567       res, GST_TIME_ARGS (*cur));
4568   return res;
4569
4570   /* special cases */
4571 in_eos:
4572   {
4573     GST_DEBUG_OBJECT (basesink, "position in EOS");
4574     res = gst_base_sink_get_position_last (basesink, format, cur, upstream);
4575     GST_OBJECT_UNLOCK (basesink);
4576     goto done;
4577   }
4578 in_pause:
4579   {
4580     GST_DEBUG_OBJECT (basesink, "position in PAUSED");
4581     res = gst_base_sink_get_position_paused (basesink, format, cur, upstream);
4582     GST_OBJECT_UNLOCK (basesink);
4583     goto done;
4584   }
4585 wrong_state:
4586   {
4587     /* in NULL or READY we always return FALSE and -1 */
4588     GST_DEBUG_OBJECT (basesink, "position in wrong state, return -1");
4589     res = FALSE;
4590     *cur = -1;
4591     GST_OBJECT_UNLOCK (basesink);
4592     goto done;
4593   }
4594 no_sync:
4595   {
4596     /* report last seen timestamp if any, else ask upstream to answer */
4597     if ((*cur = basesink->priv->current_sstart) != -1)
4598       res = TRUE;
4599     else
4600       *upstream = TRUE;
4601
4602     GST_DEBUG_OBJECT (basesink, "no sync, res %d, POSITION %" GST_TIME_FORMAT,
4603         res, GST_TIME_ARGS (*cur));
4604     GST_OBJECT_UNLOCK (basesink);
4605     return res;
4606   }
4607 convert_failed:
4608   {
4609     GST_DEBUG_OBJECT (basesink, "convert failed, try upstream");
4610     *upstream = TRUE;
4611     return FALSE;
4612   }
4613 }
4614
4615 static gboolean
4616 gst_base_sink_get_duration (GstBaseSink * basesink, GstFormat format,
4617     gint64 * dur, gboolean * upstream)
4618 {
4619   gboolean res = FALSE;
4620
4621   if (basesink->pad_mode == GST_ACTIVATE_PULL) {
4622     GstFormat uformat = GST_FORMAT_BYTES;
4623     gint64 uduration;
4624
4625     /* get the duration in bytes, in pull mode that's all we are sure to
4626      * know. We have to explicitly get this value from upstream instead of
4627      * using our cached value because it might change. Duration caching
4628      * should be done at a higher level. */
4629     res = gst_pad_query_peer_duration (basesink->sinkpad, &uformat, &uduration);
4630     if (res) {
4631       gst_segment_set_duration (&basesink->segment, uformat, uduration);
4632       if (format != uformat) {
4633         /* convert to the requested format */
4634         res = gst_pad_query_convert (basesink->sinkpad, uformat, uduration,
4635             &format, dur);
4636       } else {
4637         *dur = uduration;
4638       }
4639     }
4640     *upstream = FALSE;
4641   } else {
4642     *upstream = TRUE;
4643   }
4644
4645   return res;
4646 }
4647
4648 static const GstQueryType *
4649 gst_base_sink_get_query_types (GstElement * element)
4650 {
4651   static const GstQueryType query_types[] = {
4652     GST_QUERY_DURATION,
4653     GST_QUERY_POSITION,
4654     GST_QUERY_SEGMENT,
4655     GST_QUERY_LATENCY,
4656     0
4657   };
4658
4659   return query_types;
4660 }
4661
4662 static gboolean
4663 gst_base_sink_query (GstElement * element, GstQuery * query)
4664 {
4665   gboolean res = FALSE;
4666
4667   GstBaseSink *basesink = GST_BASE_SINK (element);
4668
4669   switch (GST_QUERY_TYPE (query)) {
4670     case GST_QUERY_POSITION:
4671     {
4672       gint64 cur = 0;
4673       GstFormat format;
4674       gboolean upstream = FALSE;
4675
4676       gst_query_parse_position (query, &format, NULL);
4677
4678       GST_DEBUG_OBJECT (basesink, "position query in format %s",
4679           gst_format_get_name (format));
4680
4681       /* first try to get the position based on the clock */
4682       if ((res =
4683               gst_base_sink_get_position (basesink, format, &cur, &upstream))) {
4684         gst_query_set_position (query, format, cur);
4685       } else if (upstream) {
4686         /* fallback to peer query */
4687         res = gst_pad_peer_query (basesink->sinkpad, query);
4688       }
4689       if (!res) {
4690         /* we can handle a few things if upstream failed */
4691         if (format == GST_FORMAT_PERCENT) {
4692           gint64 dur = 0;
4693           GstFormat uformat = GST_FORMAT_TIME;
4694
4695           res = gst_base_sink_get_position (basesink, GST_FORMAT_TIME, &cur,
4696               &upstream);
4697           if (!res && upstream) {
4698             res = gst_pad_query_peer_position (basesink->sinkpad, &uformat,
4699                 &cur);
4700           }
4701           if (res) {
4702             res = gst_base_sink_get_duration (basesink, GST_FORMAT_TIME, &dur,
4703                 &upstream);
4704             if (!res && upstream) {
4705               res = gst_pad_query_peer_duration (basesink->sinkpad, &uformat,
4706                   &dur);
4707             }
4708           }
4709           if (res) {
4710             gint64 pos;
4711
4712             pos = gst_util_uint64_scale (100 * GST_FORMAT_PERCENT_SCALE, cur,
4713                 dur);
4714             gst_query_set_position (query, GST_FORMAT_PERCENT, pos);
4715           }
4716         }
4717       }
4718       break;
4719     }
4720     case GST_QUERY_DURATION:
4721     {
4722       gint64 dur = 0;
4723       GstFormat format;
4724       gboolean upstream = FALSE;
4725
4726       gst_query_parse_duration (query, &format, NULL);
4727
4728       GST_DEBUG_OBJECT (basesink, "duration query in format %s",
4729           gst_format_get_name (format));
4730
4731       if ((res =
4732               gst_base_sink_get_duration (basesink, format, &dur, &upstream))) {
4733         gst_query_set_duration (query, format, dur);
4734       } else if (upstream) {
4735         /* fallback to peer query */
4736         res = gst_pad_peer_query (basesink->sinkpad, query);
4737       }
4738       if (!res) {
4739         /* we can handle a few things if upstream failed */
4740         if (format == GST_FORMAT_PERCENT) {
4741           gst_query_set_duration (query, GST_FORMAT_PERCENT,
4742               GST_FORMAT_PERCENT_MAX);
4743           res = TRUE;
4744         }
4745       }
4746       break;
4747     }
4748     case GST_QUERY_LATENCY:
4749     {
4750       gboolean live, us_live;
4751       GstClockTime min, max;
4752
4753       if ((res = gst_base_sink_query_latency (basesink, &live, &us_live, &min,
4754                   &max))) {
4755         gst_query_set_latency (query, live, min, max);
4756       }
4757       break;
4758     }
4759     case GST_QUERY_JITTER:
4760       break;
4761     case GST_QUERY_RATE:
4762       /* gst_query_set_rate (query, basesink->segment_rate); */
4763       res = TRUE;
4764       break;
4765     case GST_QUERY_SEGMENT:
4766     {
4767       if (basesink->pad_mode == GST_ACTIVATE_PULL) {
4768         gst_query_set_segment (query, basesink->segment.rate,
4769             GST_FORMAT_TIME, basesink->segment.start, basesink->segment.stop);
4770         res = TRUE;
4771       } else {
4772         res = gst_pad_peer_query (basesink->sinkpad, query);
4773       }
4774       break;
4775     }
4776     case GST_QUERY_SEEKING:
4777     case GST_QUERY_CONVERT:
4778     case GST_QUERY_FORMATS:
4779     default:
4780       res = gst_pad_peer_query (basesink->sinkpad, query);
4781       break;
4782   }
4783   GST_DEBUG_OBJECT (basesink, "query %s returns %d",
4784       GST_QUERY_TYPE_NAME (query), res);
4785   return res;
4786 }
4787
4788 static GstStateChangeReturn
4789 gst_base_sink_change_state (GstElement * element, GstStateChange transition)
4790 {
4791   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4792   GstBaseSink *basesink = GST_BASE_SINK (element);
4793   GstBaseSinkClass *bclass;
4794   GstBaseSinkPrivate *priv;
4795
4796   priv = basesink->priv;
4797
4798   bclass = GST_BASE_SINK_GET_CLASS (basesink);
4799
4800   switch (transition) {
4801     case GST_STATE_CHANGE_NULL_TO_READY:
4802       if (bclass->start)
4803         if (!bclass->start (basesink))
4804           goto start_failed;
4805       break;
4806     case GST_STATE_CHANGE_READY_TO_PAUSED:
4807       /* need to complete preroll before this state change completes, there
4808        * is no data flow in READY so we can safely assume we need to preroll. */
4809       GST_PAD_PREROLL_LOCK (basesink->sinkpad);
4810       GST_DEBUG_OBJECT (basesink, "READY to PAUSED");
4811       basesink->have_newsegment = FALSE;
4812       gst_segment_init (&basesink->segment, GST_FORMAT_UNDEFINED);
4813       gst_segment_init (basesink->abidata.ABI.clip_segment,
4814           GST_FORMAT_UNDEFINED);
4815       basesink->offset = 0;
4816       basesink->have_preroll = FALSE;
4817       priv->step_unlock = FALSE;
4818       basesink->need_preroll = TRUE;
4819       basesink->playing_async = TRUE;
4820       priv->current_sstart = GST_CLOCK_TIME_NONE;
4821       priv->current_sstop = GST_CLOCK_TIME_NONE;
4822       priv->eos_rtime = GST_CLOCK_TIME_NONE;
4823       priv->latency = 0;
4824       basesink->eos = FALSE;
4825       priv->received_eos = FALSE;
4826       gst_base_sink_reset_qos (basesink);
4827       priv->commited = FALSE;
4828       priv->call_preroll = TRUE;
4829       priv->current_step.valid = FALSE;
4830       priv->pending_step.valid = FALSE;
4831       if (priv->async_enabled) {
4832         GST_DEBUG_OBJECT (basesink, "doing async state change");
4833         /* when async enabled, post async-start message and return ASYNC from
4834          * the state change function */
4835         ret = GST_STATE_CHANGE_ASYNC;
4836         gst_element_post_message (GST_ELEMENT_CAST (basesink),
4837             gst_message_new_async_start (GST_OBJECT_CAST (basesink), FALSE));
4838       } else {
4839         priv->have_latency = TRUE;
4840       }
4841       GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
4842       break;
4843     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
4844       GST_PAD_PREROLL_LOCK (basesink->sinkpad);
4845       if (!gst_base_sink_needs_preroll (basesink)) {
4846         GST_DEBUG_OBJECT (basesink, "PAUSED to PLAYING, don't need preroll");
4847         /* no preroll needed anymore now. */
4848         basesink->playing_async = FALSE;
4849         basesink->need_preroll = FALSE;
4850         if (basesink->eos) {
4851           GstMessage *message;
4852
4853           /* need to post EOS message here */
4854           GST_DEBUG_OBJECT (basesink, "Now posting EOS");
4855           message = gst_message_new_eos (GST_OBJECT_CAST (basesink));
4856           gst_message_set_seqnum (message, basesink->priv->seqnum);
4857           gst_element_post_message (GST_ELEMENT_CAST (basesink), message);
4858         } else {
4859           GST_DEBUG_OBJECT (basesink, "signal preroll");
4860           GST_PAD_PREROLL_SIGNAL (basesink->sinkpad);
4861         }
4862       } else {
4863         GST_DEBUG_OBJECT (basesink, "PAUSED to PLAYING, we are not prerolled");
4864         basesink->need_preroll = TRUE;
4865         basesink->playing_async = TRUE;
4866         priv->call_preroll = TRUE;
4867         priv->commited = FALSE;
4868         if (priv->async_enabled) {
4869           GST_DEBUG_OBJECT (basesink, "doing async state change");
4870           ret = GST_STATE_CHANGE_ASYNC;
4871           gst_element_post_message (GST_ELEMENT_CAST (basesink),
4872               gst_message_new_async_start (GST_OBJECT_CAST (basesink), FALSE));
4873         }
4874       }
4875       GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
4876       break;
4877     default:
4878       break;
4879   }
4880
4881   {
4882     GstStateChangeReturn bret;
4883
4884     bret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4885     if (G_UNLIKELY (bret == GST_STATE_CHANGE_FAILURE))
4886       goto activate_failed;
4887   }
4888
4889   switch (transition) {
4890     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
4891       GST_DEBUG_OBJECT (basesink, "PLAYING to PAUSED");
4892       /* FIXME, make sure we cannot enter _render first */
4893
4894       /* we need to call ::unlock before locking PREROLL_LOCK
4895        * since we lock it before going into ::render */
4896       if (bclass->unlock)
4897         bclass->unlock (basesink);
4898
4899       GST_PAD_PREROLL_LOCK (basesink->sinkpad);
4900       GST_DEBUG_OBJECT (basesink, "got preroll lock");
4901       /* now that we have the PREROLL lock, clear our unlock request */
4902       if (bclass->unlock_stop)
4903         bclass->unlock_stop (basesink);
4904
4905       /* we need preroll again and we set the flag before unlocking the clockid
4906        * because if the clockid is unlocked before a current buffer expired, we
4907        * can use that buffer to preroll with */
4908       basesink->need_preroll = TRUE;
4909
4910       if (basesink->clock_id) {
4911         GST_DEBUG_OBJECT (basesink, "unschedule clock");
4912         gst_clock_id_unschedule (basesink->clock_id);
4913       }
4914
4915       /* if we don't have a preroll buffer we need to wait for a preroll and
4916        * return ASYNC. */
4917       if (!gst_base_sink_needs_preroll (basesink)) {
4918         GST_DEBUG_OBJECT (basesink, "PLAYING to PAUSED, we are prerolled");
4919         basesink->playing_async = FALSE;
4920       } else {
4921         if (GST_STATE_TARGET (GST_ELEMENT (basesink)) <= GST_STATE_READY) {
4922           GST_DEBUG_OBJECT (basesink, "element is <= READY");
4923           ret = GST_STATE_CHANGE_SUCCESS;
4924         } else {
4925           GST_DEBUG_OBJECT (basesink,
4926               "PLAYING to PAUSED, we are not prerolled");
4927           basesink->playing_async = TRUE;
4928           priv->commited = FALSE;
4929           priv->call_preroll = TRUE;
4930           if (priv->async_enabled) {
4931             GST_DEBUG_OBJECT (basesink, "doing async state change");
4932             ret = GST_STATE_CHANGE_ASYNC;
4933             gst_element_post_message (GST_ELEMENT_CAST (basesink),
4934                 gst_message_new_async_start (GST_OBJECT_CAST (basesink),
4935                     FALSE));
4936           }
4937         }
4938       }
4939       GST_DEBUG_OBJECT (basesink, "rendered: %" G_GUINT64_FORMAT
4940           ", dropped: %" G_GUINT64_FORMAT, priv->rendered, priv->dropped);
4941
4942       gst_base_sink_reset_qos (basesink);
4943       GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
4944       break;
4945     case GST_STATE_CHANGE_PAUSED_TO_READY:
4946       GST_PAD_PREROLL_LOCK (basesink->sinkpad);
4947       /* start by reseting our position state with the object lock so that the
4948        * position query gets the right idea. We do this before we post the
4949        * messages so that the message handlers pick this up. */
4950       GST_OBJECT_LOCK (basesink);
4951       basesink->have_newsegment = FALSE;
4952       priv->current_sstart = GST_CLOCK_TIME_NONE;
4953       priv->current_sstop = GST_CLOCK_TIME_NONE;
4954       priv->have_latency = FALSE;
4955       GST_OBJECT_UNLOCK (basesink);
4956
4957       gst_base_sink_set_last_buffer (basesink, NULL);
4958       priv->call_preroll = FALSE;
4959
4960       if (!priv->commited) {
4961         if (priv->async_enabled) {
4962           GST_DEBUG_OBJECT (basesink, "PAUSED to READY, posting async-done");
4963
4964           gst_element_post_message (GST_ELEMENT_CAST (basesink),
4965               gst_message_new_state_changed (GST_OBJECT_CAST (basesink),
4966                   GST_STATE_PLAYING, GST_STATE_PAUSED, GST_STATE_READY));
4967
4968           gst_element_post_message (GST_ELEMENT_CAST (basesink),
4969               gst_message_new_async_done (GST_OBJECT_CAST (basesink)));
4970         }
4971         priv->commited = TRUE;
4972       } else {
4973         GST_DEBUG_OBJECT (basesink, "PAUSED to READY, don't need_preroll");
4974       }
4975       GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
4976       break;
4977     case GST_STATE_CHANGE_READY_TO_NULL:
4978       if (bclass->stop) {
4979         if (!bclass->stop (basesink)) {
4980           GST_WARNING_OBJECT (basesink, "failed to stop");
4981         }
4982       }
4983       gst_base_sink_set_last_buffer (basesink, NULL);
4984       priv->call_preroll = FALSE;
4985       break;
4986     default:
4987       break;
4988   }
4989
4990   return ret;
4991
4992   /* ERRORS */
4993 start_failed:
4994   {
4995     GST_DEBUG_OBJECT (basesink, "failed to start");
4996     return GST_STATE_CHANGE_FAILURE;
4997   }
4998 activate_failed:
4999   {
5000     GST_DEBUG_OBJECT (basesink,
5001         "element failed to change states -- activation problem?");
5002     return GST_STATE_CHANGE_FAILURE;
5003   }
5004 }