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