e94a1e2cda25eadbd27bf380a5988c8383043a98
[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     /* start time reset in above case as well;
3285      * arranges for a.o. proper position reporting when flushing in PAUSED */
3286     gst_element_set_start_time (GST_ELEMENT_CAST (basesink), 0);
3287     basesink->priv->have_latency = TRUE;
3288   }
3289   gst_base_sink_set_last_buffer (basesink, NULL);
3290   GST_PAD_STREAM_UNLOCK (pad);
3291 }
3292
3293 static void
3294 gst_base_sink_flush_stop (GstBaseSink * basesink, GstPad * pad,
3295     gboolean reset_time)
3296 {
3297   /* unset flushing so we can accept new data, this also flushes out any EOS
3298    * event. */
3299   gst_base_sink_set_flushing (basesink, pad, FALSE);
3300
3301   /* for position reporting */
3302   GST_OBJECT_LOCK (basesink);
3303   basesink->priv->current_sstart = GST_CLOCK_TIME_NONE;
3304   basesink->priv->current_sstop = GST_CLOCK_TIME_NONE;
3305   basesink->priv->eos_rtime = GST_CLOCK_TIME_NONE;
3306   basesink->priv->call_preroll = TRUE;
3307   basesink->priv->current_step.valid = FALSE;
3308   basesink->priv->pending_step.valid = FALSE;
3309   if (basesink->pad_mode == GST_ACTIVATE_PUSH) {
3310     /* we need new segment info after the flush. */
3311     basesink->have_newsegment = FALSE;
3312     if (reset_time) {
3313       gst_segment_init (&basesink->segment, GST_FORMAT_UNDEFINED);
3314       gst_segment_init (&basesink->clip_segment, GST_FORMAT_UNDEFINED);
3315     }
3316   }
3317   basesink->priv->reset_time = reset_time;
3318   GST_OBJECT_UNLOCK (basesink);
3319 }
3320
3321 static gboolean
3322 gst_base_sink_event (GstPad * pad, GstEvent * event)
3323 {
3324   GstBaseSink *basesink;
3325   gboolean result = TRUE;
3326   GstBaseSinkClass *bclass;
3327
3328   basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
3329   if (G_UNLIKELY (basesink == NULL)) {
3330     gst_event_unref (event);
3331     return FALSE;
3332   }
3333
3334   bclass = GST_BASE_SINK_GET_CLASS (basesink);
3335
3336   GST_DEBUG_OBJECT (basesink, "received event %p %" GST_PTR_FORMAT, event,
3337       event);
3338
3339   switch (GST_EVENT_TYPE (event)) {
3340     case GST_EVENT_EOS:
3341     {
3342       GstFlowReturn ret;
3343
3344       GST_BASE_SINK_PREROLL_LOCK (basesink);
3345       if (G_UNLIKELY (basesink->flushing))
3346         goto flushing;
3347
3348       if (G_UNLIKELY (basesink->priv->received_eos))
3349         goto after_eos;
3350
3351       /* we set the received EOS flag here so that we can use it when testing if
3352        * we are prerolled and to refuse more buffers. */
3353       basesink->priv->received_eos = TRUE;
3354
3355       /* EOS is a prerollable object, we call the unlocked version because it
3356        * does not check the received_eos flag. */
3357       ret = gst_base_sink_queue_object_unlocked (basesink, pad,
3358           _PR_IS_EVENT, GST_MINI_OBJECT_CAST (event), TRUE);
3359       if (G_UNLIKELY (ret != GST_FLOW_OK))
3360         result = FALSE;
3361
3362       GST_BASE_SINK_PREROLL_UNLOCK (basesink);
3363       break;
3364     }
3365     case GST_EVENT_CAPS:
3366     {
3367       GstCaps *caps;
3368
3369       GST_DEBUG_OBJECT (basesink, "caps %p", event);
3370
3371       gst_event_parse_caps (event, &caps);
3372       if (bclass->set_caps)
3373         result = bclass->set_caps (basesink, caps);
3374
3375       gst_event_unref (event);
3376       break;
3377     }
3378     case GST_EVENT_SEGMENT:
3379     {
3380       GstFlowReturn ret;
3381
3382       GST_DEBUG_OBJECT (basesink, "segment %p", event);
3383
3384       GST_BASE_SINK_PREROLL_LOCK (basesink);
3385       if (G_UNLIKELY (basesink->flushing))
3386         goto flushing;
3387
3388       if (G_UNLIKELY (basesink->priv->received_eos))
3389         goto after_eos;
3390
3391       /* the new segment is a non prerollable item and does not block anything,
3392        * we need to configure the current clipping segment and insert the event
3393        * in the queue to serialize it with the buffers for rendering. */
3394       gst_base_sink_configure_segment (basesink, pad, event,
3395           &basesink->clip_segment);
3396
3397       ret =
3398           gst_base_sink_queue_object_unlocked (basesink, pad,
3399           _PR_IS_EVENT, GST_MINI_OBJECT_CAST (event), FALSE);
3400       if (G_UNLIKELY (ret != GST_FLOW_OK))
3401         result = FALSE;
3402       else {
3403         GST_OBJECT_LOCK (basesink);
3404         basesink->have_newsegment = TRUE;
3405         GST_OBJECT_UNLOCK (basesink);
3406       }
3407       GST_BASE_SINK_PREROLL_UNLOCK (basesink);
3408       break;
3409     }
3410     case GST_EVENT_FLUSH_START:
3411       if (bclass->event)
3412         bclass->event (basesink, event);
3413
3414       GST_DEBUG_OBJECT (basesink, "flush-start %p", event);
3415
3416       gst_base_sink_flush_start (basesink, pad);
3417
3418       gst_event_unref (event);
3419       break;
3420     case GST_EVENT_FLUSH_STOP:
3421     {
3422       gboolean reset_time;
3423
3424       if (bclass->event)
3425         bclass->event (basesink, event);
3426
3427       gst_event_parse_flush_stop (event, &reset_time);
3428       GST_DEBUG_OBJECT (basesink, "flush-stop %p, reset_time: %d", event,
3429           reset_time);
3430
3431       gst_base_sink_flush_stop (basesink, pad, reset_time);
3432
3433       gst_event_unref (event);
3434       break;
3435     }
3436     default:
3437       /* other events are sent to queue or subclass depending on if they
3438        * are serialized. */
3439       if (GST_EVENT_IS_SERIALIZED (event)) {
3440         gst_base_sink_queue_object (basesink, pad,
3441             GST_MINI_OBJECT_CAST (event), FALSE);
3442       } else {
3443         if (bclass->event)
3444           bclass->event (basesink, event);
3445         gst_event_unref (event);
3446       }
3447       break;
3448   }
3449 done:
3450   gst_object_unref (basesink);
3451
3452   return result;
3453
3454   /* ERRORS */
3455 flushing:
3456   {
3457     GST_DEBUG_OBJECT (basesink, "we are flushing");
3458     GST_BASE_SINK_PREROLL_UNLOCK (basesink);
3459     result = FALSE;
3460     gst_event_unref (event);
3461     goto done;
3462   }
3463
3464 after_eos:
3465   {
3466     GST_DEBUG_OBJECT (basesink, "Event received after EOS, dropping");
3467     GST_BASE_SINK_PREROLL_UNLOCK (basesink);
3468     result = FALSE;
3469     gst_event_unref (event);
3470     goto done;
3471   }
3472 }
3473
3474 /* default implementation to calculate the start and end
3475  * timestamps on a buffer, subclasses can override
3476  */
3477 static void
3478 gst_base_sink_get_times (GstBaseSink * basesink, GstBuffer * buffer,
3479     GstClockTime * start, GstClockTime * end)
3480 {
3481   GstClockTime timestamp, duration;
3482
3483   timestamp = GST_BUFFER_TIMESTAMP (buffer);
3484   if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
3485
3486     /* get duration to calculate end time */
3487     duration = GST_BUFFER_DURATION (buffer);
3488     if (GST_CLOCK_TIME_IS_VALID (duration)) {
3489       *end = timestamp + duration;
3490     }
3491     *start = timestamp;
3492   }
3493 }
3494
3495 /* must be called with PREROLL_LOCK */
3496 static gboolean
3497 gst_base_sink_needs_preroll (GstBaseSink * basesink)
3498 {
3499   gboolean is_prerolled, res;
3500
3501   /* we have 2 cases where the PREROLL_LOCK is released:
3502    *  1) we are blocking in the PREROLL_LOCK and thus are prerolled.
3503    *  2) we are syncing on the clock
3504    */
3505   is_prerolled = basesink->have_preroll || basesink->priv->received_eos;
3506   res = !is_prerolled;
3507
3508   GST_DEBUG_OBJECT (basesink, "have_preroll: %d, EOS: %d => needs preroll: %d",
3509       basesink->have_preroll, basesink->priv->received_eos, res);
3510
3511   return res;
3512 }
3513
3514 /* with STREAM_LOCK, PREROLL_LOCK
3515  *
3516  * Takes a buffer and compare the timestamps with the last segment.
3517  * If the buffer falls outside of the segment boundaries, drop it.
3518  * Else queue the buffer for preroll and rendering.
3519  *
3520  * This function takes ownership of the buffer.
3521  */
3522 static GstFlowReturn
3523 gst_base_sink_chain_unlocked (GstBaseSink * basesink, GstPad * pad,
3524     guint8 obj_type, gpointer obj)
3525 {
3526   GstBaseSinkClass *bclass;
3527   GstFlowReturn result;
3528   GstClockTime start = GST_CLOCK_TIME_NONE, end = GST_CLOCK_TIME_NONE;
3529   GstSegment *clip_segment;
3530   GstBuffer *time_buf;
3531
3532   if (G_UNLIKELY (basesink->flushing))
3533     goto flushing;
3534
3535   if (G_UNLIKELY (basesink->priv->received_eos))
3536     goto was_eos;
3537
3538   if (OBJ_IS_BUFFERLIST (obj_type)) {
3539     time_buf = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0);
3540     g_assert (NULL != time_buf);
3541   } else {
3542     time_buf = GST_BUFFER_CAST (obj);
3543   }
3544
3545   /* for code clarity */
3546   clip_segment = &basesink->clip_segment;
3547
3548   if (G_UNLIKELY (!basesink->have_newsegment)) {
3549     gboolean sync;
3550
3551     sync = gst_base_sink_get_sync (basesink);
3552     if (sync) {
3553       GST_ELEMENT_WARNING (basesink, STREAM, FAILED,
3554           (_("Internal data flow problem.")),
3555           ("Received buffer without a new-segment. Assuming timestamps start from 0."));
3556     }
3557
3558     /* this means this sink will assume timestamps start from 0 */
3559     GST_OBJECT_LOCK (basesink);
3560     clip_segment->start = 0;
3561     clip_segment->stop = -1;
3562     basesink->segment.start = 0;
3563     basesink->segment.stop = -1;
3564     basesink->have_newsegment = TRUE;
3565     GST_OBJECT_UNLOCK (basesink);
3566   }
3567
3568   bclass = GST_BASE_SINK_GET_CLASS (basesink);
3569
3570   /* check if the buffer needs to be dropped, we first ask the subclass for the
3571    * start and end */
3572   if (bclass->get_times)
3573     bclass->get_times (basesink, time_buf, &start, &end);
3574
3575   if (!GST_CLOCK_TIME_IS_VALID (start)) {
3576     /* if the subclass does not want sync, we use our own values so that we at
3577      * least clip the buffer to the segment */
3578     gst_base_sink_get_times (basesink, time_buf, &start, &end);
3579   }
3580
3581   GST_DEBUG_OBJECT (basesink, "got times start: %" GST_TIME_FORMAT
3582       ", end: %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (end));
3583
3584   /* a dropped buffer does not participate in anything */
3585   if (GST_CLOCK_TIME_IS_VALID (start) &&
3586       (clip_segment->format == GST_FORMAT_TIME)) {
3587     if (G_UNLIKELY (!gst_segment_clip (clip_segment,
3588                 GST_FORMAT_TIME, start, end, NULL, NULL)))
3589       goto out_of_segment;
3590   }
3591
3592   /* now we can process the buffer in the queue, this function takes ownership
3593    * of the buffer */
3594   result = gst_base_sink_queue_object_unlocked (basesink, pad,
3595       obj_type, obj, TRUE);
3596   return result;
3597
3598   /* ERRORS */
3599 flushing:
3600   {
3601     GST_DEBUG_OBJECT (basesink, "sink is flushing");
3602     gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
3603     return GST_FLOW_WRONG_STATE;
3604   }
3605 was_eos:
3606   {
3607     GST_DEBUG_OBJECT (basesink,
3608         "we are EOS, dropping object, return UNEXPECTED");
3609     gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
3610     return GST_FLOW_UNEXPECTED;
3611   }
3612 out_of_segment:
3613   {
3614     GST_DEBUG_OBJECT (basesink, "dropping buffer, out of clipping segment");
3615     gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
3616     return GST_FLOW_OK;
3617   }
3618 }
3619
3620 /* with STREAM_LOCK
3621  */
3622 static GstFlowReturn
3623 gst_base_sink_chain_main (GstBaseSink * basesink, GstPad * pad,
3624     guint8 obj_type, gpointer obj)
3625 {
3626   GstFlowReturn result;
3627
3628   if (G_UNLIKELY (basesink->pad_mode != GST_ACTIVATE_PUSH))
3629     goto wrong_mode;
3630
3631   GST_BASE_SINK_PREROLL_LOCK (basesink);
3632   result = gst_base_sink_chain_unlocked (basesink, pad, obj_type, obj);
3633   GST_BASE_SINK_PREROLL_UNLOCK (basesink);
3634
3635 done:
3636   return result;
3637
3638   /* ERRORS */
3639 wrong_mode:
3640   {
3641     GST_OBJECT_LOCK (pad);
3642     GST_WARNING_OBJECT (basesink,
3643         "Push on pad %s:%s, but it was not activated in push mode",
3644         GST_DEBUG_PAD_NAME (pad));
3645     GST_OBJECT_UNLOCK (pad);
3646     gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
3647     /* we don't post an error message this will signal to the peer
3648      * pushing that EOS is reached. */
3649     result = GST_FLOW_UNEXPECTED;
3650     goto done;
3651   }
3652 }
3653
3654 static GstFlowReturn
3655 gst_base_sink_chain (GstPad * pad, GstBuffer * buf)
3656 {
3657   GstBaseSink *basesink;
3658
3659   basesink = GST_BASE_SINK (GST_OBJECT_PARENT (pad));
3660
3661   return gst_base_sink_chain_main (basesink, pad, _PR_IS_BUFFER, buf);
3662 }
3663
3664 static GstFlowReturn
3665 gst_base_sink_chain_list (GstPad * pad, GstBufferList * list)
3666 {
3667   GstBaseSink *basesink;
3668   GstBaseSinkClass *bclass;
3669   GstFlowReturn result;
3670
3671   basesink = GST_BASE_SINK (GST_OBJECT_PARENT (pad));
3672   bclass = GST_BASE_SINK_GET_CLASS (basesink);
3673
3674   if (G_LIKELY (bclass->render_list)) {
3675     result = gst_base_sink_chain_main (basesink, pad, _PR_IS_BUFFERLIST, list);
3676   } else {
3677     guint i, len;
3678     GstBuffer *buffer;
3679
3680     GST_INFO_OBJECT (pad, "chaining each group in list as a merged buffer");
3681
3682     len = gst_buffer_list_len (list);
3683
3684     result = GST_FLOW_OK;
3685     for (i = 0; i < len; i++) {
3686       buffer = gst_buffer_list_get (list, 0);
3687       result = gst_base_sink_chain_main (basesink, pad, _PR_IS_BUFFER,
3688           gst_buffer_ref (buffer));
3689       if (result != GST_FLOW_OK)
3690         break;
3691     }
3692     gst_buffer_list_unref (list);
3693   }
3694   return result;
3695 }
3696
3697
3698 static gboolean
3699 gst_base_sink_default_do_seek (GstBaseSink * sink, GstSegment * segment)
3700 {
3701   gboolean res = TRUE;
3702
3703   /* update our offset if the start/stop position was updated */
3704   if (segment->format == GST_FORMAT_BYTES) {
3705     segment->time = segment->start;
3706   } else if (segment->start == 0) {
3707     /* seek to start, we can implement a default for this. */
3708     segment->time = 0;
3709   } else {
3710     res = FALSE;
3711     GST_INFO_OBJECT (sink, "Can't do a default seek");
3712   }
3713
3714   return res;
3715 }
3716
3717 #define SEEK_TYPE_IS_RELATIVE(t) (((t) != GST_SEEK_TYPE_NONE) && ((t) != GST_SEEK_TYPE_SET))
3718
3719 static gboolean
3720 gst_base_sink_default_prepare_seek_segment (GstBaseSink * sink,
3721     GstEvent * event, GstSegment * segment)
3722 {
3723   /* By default, we try one of 2 things:
3724    *   - For absolute seek positions, convert the requested position to our
3725    *     configured processing format and place it in the output segment \
3726    *   - For relative seek positions, convert our current (input) values to the
3727    *     seek format, adjust by the relative seek offset and then convert back to
3728    *     the processing format
3729    */
3730   GstSeekType cur_type, stop_type;
3731   gint64 cur, stop;
3732   GstSeekFlags flags;
3733   GstFormat seek_format;
3734   gdouble rate;
3735   gboolean update;
3736   gboolean res = TRUE;
3737
3738   gst_event_parse_seek (event, &rate, &seek_format, &flags,
3739       &cur_type, &cur, &stop_type, &stop);
3740
3741   if (seek_format == segment->format) {
3742     gst_segment_do_seek (segment, rate, seek_format, flags,
3743         cur_type, cur, stop_type, stop, &update);
3744     return TRUE;
3745   }
3746
3747   if (cur_type != GST_SEEK_TYPE_NONE) {
3748     /* FIXME: Handle seek_cur & seek_end by converting the input segment vals */
3749     res =
3750         gst_pad_query_convert (sink->sinkpad, seek_format, cur, segment->format,
3751         &cur);
3752     cur_type = GST_SEEK_TYPE_SET;
3753   }
3754
3755   if (res && stop_type != GST_SEEK_TYPE_NONE) {
3756     /* FIXME: Handle seek_cur & seek_end by converting the input segment vals */
3757     res =
3758         gst_pad_query_convert (sink->sinkpad, seek_format, stop,
3759         segment->format, &stop);
3760     stop_type = GST_SEEK_TYPE_SET;
3761   }
3762
3763   /* And finally, configure our output segment in the desired format */
3764   gst_segment_do_seek (segment, rate, segment->format, flags, cur_type, cur,
3765       stop_type, stop, &update);
3766
3767   if (!res)
3768     goto no_format;
3769
3770   return res;
3771
3772 no_format:
3773   {
3774     GST_DEBUG_OBJECT (sink, "undefined format given, seek aborted.");
3775     return FALSE;
3776   }
3777 }
3778
3779 /* perform a seek, only executed in pull mode */
3780 static gboolean
3781 gst_base_sink_perform_seek (GstBaseSink * sink, GstPad * pad, GstEvent * event)
3782 {
3783   gboolean flush;
3784   gdouble rate;
3785   GstFormat seek_format, dest_format;
3786   GstSeekFlags flags;
3787   GstSeekType cur_type, stop_type;
3788   gboolean seekseg_configured = FALSE;
3789   gint64 cur, stop;
3790   gboolean update, res = TRUE;
3791   GstSegment seeksegment;
3792
3793   dest_format = sink->segment.format;
3794
3795   if (event) {
3796     GST_DEBUG_OBJECT (sink, "performing seek with event %p", event);
3797     gst_event_parse_seek (event, &rate, &seek_format, &flags,
3798         &cur_type, &cur, &stop_type, &stop);
3799
3800     flush = flags & GST_SEEK_FLAG_FLUSH;
3801   } else {
3802     GST_DEBUG_OBJECT (sink, "performing seek without event");
3803     flush = FALSE;
3804   }
3805
3806   if (flush) {
3807     GST_DEBUG_OBJECT (sink, "flushing upstream");
3808     gst_pad_push_event (pad, gst_event_new_flush_start ());
3809     gst_base_sink_flush_start (sink, pad);
3810   } else {
3811     GST_DEBUG_OBJECT (sink, "pausing pulling thread");
3812   }
3813
3814   GST_PAD_STREAM_LOCK (pad);
3815
3816   /* If we configured the seeksegment above, don't overwrite it now. Otherwise
3817    * copy the current segment info into the temp segment that we can actually
3818    * attempt the seek with. We only update the real segment if the seek suceeds. */
3819   if (!seekseg_configured) {
3820     memcpy (&seeksegment, &sink->segment, sizeof (GstSegment));
3821
3822     /* now configure the final seek segment */
3823     if (event) {
3824       if (sink->segment.format != seek_format) {
3825         /* OK, here's where we give the subclass a chance to convert the relative
3826          * seek into an absolute one in the processing format. We set up any
3827          * absolute seek above, before taking the stream lock. */
3828         if (!gst_base_sink_default_prepare_seek_segment (sink, event,
3829                 &seeksegment)) {
3830           GST_DEBUG_OBJECT (sink,
3831               "Preparing the seek failed after flushing. " "Aborting seek");
3832           res = FALSE;
3833         }
3834       } else {
3835         /* The seek format matches our processing format, no need to ask the
3836          * the subclass to configure the segment. */
3837         gst_segment_do_seek (&seeksegment, rate, seek_format, flags,
3838             cur_type, cur, stop_type, stop, &update);
3839       }
3840     }
3841     /* Else, no seek event passed, so we're just (re)starting the
3842        current segment. */
3843   }
3844
3845   if (res) {
3846     GST_DEBUG_OBJECT (sink, "segment configured from %" G_GINT64_FORMAT
3847         " to %" G_GINT64_FORMAT ", position %" G_GINT64_FORMAT,
3848         seeksegment.start, seeksegment.stop, seeksegment.position);
3849
3850     /* do the seek, segment.position contains the new position. */
3851     res = gst_base_sink_default_do_seek (sink, &seeksegment);
3852   }
3853
3854
3855   if (flush) {
3856     GST_DEBUG_OBJECT (sink, "stop flushing upstream");
3857     gst_pad_push_event (pad, gst_event_new_flush_stop (TRUE));
3858     gst_base_sink_flush_stop (sink, pad, TRUE);
3859   } else if (res && sink->running) {
3860     /* we are running the current segment and doing a non-flushing seek,
3861      * close the segment first based on the position. */
3862     GST_DEBUG_OBJECT (sink, "closing running segment %" G_GINT64_FORMAT
3863         " to %" G_GINT64_FORMAT, sink->segment.start, sink->segment.position);
3864   }
3865
3866   /* The subclass must have converted the segment to the processing format
3867    * by now */
3868   if (res && seeksegment.format != dest_format) {
3869     GST_DEBUG_OBJECT (sink, "Subclass failed to prepare a seek segment "
3870         "in the correct format. Aborting seek.");
3871     res = FALSE;
3872   }
3873
3874   /* if successfull seek, we update our real segment and push
3875    * out the new segment. */
3876   if (res) {
3877     gst_segment_copy_into (&seeksegment, &sink->segment);
3878
3879     if (sink->segment.flags & GST_SEEK_FLAG_SEGMENT) {
3880       gst_element_post_message (GST_ELEMENT (sink),
3881           gst_message_new_segment_start (GST_OBJECT (sink),
3882               sink->segment.format, sink->segment.position));
3883     }
3884   }
3885
3886   sink->priv->discont = TRUE;
3887   sink->running = TRUE;
3888
3889   GST_PAD_STREAM_UNLOCK (pad);
3890
3891   return res;
3892 }
3893
3894 static void
3895 set_step_info (GstBaseSink * sink, GstStepInfo * current, GstStepInfo * pending,
3896     guint seqnum, GstFormat format, guint64 amount, gdouble rate,
3897     gboolean flush, gboolean intermediate)
3898 {
3899   GST_OBJECT_LOCK (sink);
3900   pending->seqnum = seqnum;
3901   pending->format = format;
3902   pending->amount = amount;
3903   pending->position = 0;
3904   pending->rate = rate;
3905   pending->flush = flush;
3906   pending->intermediate = intermediate;
3907   pending->valid = TRUE;
3908   /* flush invalidates the current stepping segment */
3909   if (flush)
3910     current->valid = FALSE;
3911   GST_OBJECT_UNLOCK (sink);
3912 }
3913
3914 static gboolean
3915 gst_base_sink_perform_step (GstBaseSink * sink, GstPad * pad, GstEvent * event)
3916 {
3917   GstBaseSinkPrivate *priv;
3918   GstBaseSinkClass *bclass;
3919   gboolean flush, intermediate;
3920   gdouble rate;
3921   GstFormat format;
3922   guint64 amount;
3923   guint seqnum;
3924   GstStepInfo *pending, *current;
3925   GstMessage *message;
3926
3927   bclass = GST_BASE_SINK_GET_CLASS (sink);
3928   priv = sink->priv;
3929
3930   GST_DEBUG_OBJECT (sink, "performing step with event %p", event);
3931
3932   gst_event_parse_step (event, &format, &amount, &rate, &flush, &intermediate);
3933   seqnum = gst_event_get_seqnum (event);
3934
3935   pending = &priv->pending_step;
3936   current = &priv->current_step;
3937
3938   /* post message first */
3939   message = gst_message_new_step_start (GST_OBJECT (sink), FALSE, format,
3940       amount, rate, flush, intermediate);
3941   gst_message_set_seqnum (message, seqnum);
3942   gst_element_post_message (GST_ELEMENT (sink), message);
3943
3944   if (flush) {
3945     /* we need to call ::unlock before locking PREROLL_LOCK
3946      * since we lock it before going into ::render */
3947     if (bclass->unlock)
3948       bclass->unlock (sink);
3949
3950     GST_BASE_SINK_PREROLL_LOCK (sink);
3951     /* now that we have the PREROLL lock, clear our unlock request */
3952     if (bclass->unlock_stop)
3953       bclass->unlock_stop (sink);
3954
3955     /* update the stepinfo and make it valid */
3956     set_step_info (sink, current, pending, seqnum, format, amount, rate, flush,
3957         intermediate);
3958
3959     if (sink->priv->async_enabled) {
3960       /* and we need to commit our state again on the next
3961        * prerolled buffer */
3962       sink->playing_async = TRUE;
3963       priv->pending_step.need_preroll = TRUE;
3964       sink->need_preroll = FALSE;
3965       gst_element_lost_state (GST_ELEMENT_CAST (sink));
3966     } else {
3967       sink->priv->have_latency = TRUE;
3968       sink->need_preroll = FALSE;
3969     }
3970     priv->current_sstart = GST_CLOCK_TIME_NONE;
3971     priv->current_sstop = GST_CLOCK_TIME_NONE;
3972     priv->eos_rtime = GST_CLOCK_TIME_NONE;
3973     priv->call_preroll = TRUE;
3974     gst_base_sink_set_last_buffer (sink, NULL);
3975     gst_base_sink_reset_qos (sink);
3976
3977     if (sink->clock_id) {
3978       gst_clock_id_unschedule (sink->clock_id);
3979     }
3980
3981     if (sink->have_preroll) {
3982       GST_DEBUG_OBJECT (sink, "signal waiter");
3983       priv->step_unlock = TRUE;
3984       GST_BASE_SINK_PREROLL_SIGNAL (sink);
3985     }
3986     GST_BASE_SINK_PREROLL_UNLOCK (sink);
3987   } else {
3988     /* update the stepinfo and make it valid */
3989     set_step_info (sink, current, pending, seqnum, format, amount, rate, flush,
3990         intermediate);
3991   }
3992
3993   return TRUE;
3994 }
3995
3996 /* with STREAM_LOCK
3997  */
3998 static void
3999 gst_base_sink_loop (GstPad * pad)
4000 {
4001   GstBaseSink *basesink;
4002   GstBuffer *buf = NULL;
4003   GstFlowReturn result;
4004   guint blocksize;
4005   guint64 offset;
4006
4007   basesink = GST_BASE_SINK (GST_OBJECT_PARENT (pad));
4008
4009   g_assert (basesink->pad_mode == GST_ACTIVATE_PULL);
4010
4011   if ((blocksize = basesink->priv->blocksize) == 0)
4012     blocksize = -1;
4013
4014   offset = basesink->segment.position;
4015
4016   GST_DEBUG_OBJECT (basesink, "pulling %" G_GUINT64_FORMAT ", %u",
4017       offset, blocksize);
4018
4019   result = gst_pad_pull_range (pad, offset, blocksize, &buf);
4020   if (G_UNLIKELY (result != GST_FLOW_OK))
4021     goto paused;
4022
4023   if (G_UNLIKELY (buf == NULL))
4024     goto no_buffer;
4025
4026   offset += gst_buffer_get_size (buf);
4027
4028   basesink->segment.position = offset;
4029
4030   GST_BASE_SINK_PREROLL_LOCK (basesink);
4031   result = gst_base_sink_chain_unlocked (basesink, pad, _PR_IS_BUFFER, buf);
4032   GST_BASE_SINK_PREROLL_UNLOCK (basesink);
4033   if (G_UNLIKELY (result != GST_FLOW_OK))
4034     goto paused;
4035
4036   return;
4037
4038   /* ERRORS */
4039 paused:
4040   {
4041     GST_LOG_OBJECT (basesink, "pausing task, reason %s",
4042         gst_flow_get_name (result));
4043     gst_pad_pause_task (pad);
4044     if (result == GST_FLOW_UNEXPECTED) {
4045       /* perform EOS logic */
4046       if (basesink->segment.flags & GST_SEEK_FLAG_SEGMENT) {
4047         gst_element_post_message (GST_ELEMENT_CAST (basesink),
4048             gst_message_new_segment_done (GST_OBJECT_CAST (basesink),
4049                 basesink->segment.format, basesink->segment.position));
4050       } else {
4051         gst_base_sink_event (pad, gst_event_new_eos ());
4052       }
4053     } else if (result == GST_FLOW_NOT_LINKED || result <= GST_FLOW_UNEXPECTED) {
4054       /* for fatal errors we post an error message, post the error
4055        * first so the app knows about the error first. 
4056        * wrong-state is not a fatal error because it happens due to
4057        * flushing and posting an error message in that case is the
4058        * wrong thing to do, e.g. when basesrc is doing a flushing
4059        * seek. */
4060       GST_ELEMENT_ERROR (basesink, STREAM, FAILED,
4061           (_("Internal data stream error.")),
4062           ("stream stopped, reason %s", gst_flow_get_name (result)));
4063       gst_base_sink_event (pad, gst_event_new_eos ());
4064     }
4065     return;
4066   }
4067 no_buffer:
4068   {
4069     GST_LOG_OBJECT (basesink, "no buffer, pausing");
4070     GST_ELEMENT_ERROR (basesink, STREAM, FAILED,
4071         (_("Internal data flow error.")), ("element returned NULL buffer"));
4072     result = GST_FLOW_ERROR;
4073     goto paused;
4074   }
4075 }
4076
4077 static gboolean
4078 gst_base_sink_set_flushing (GstBaseSink * basesink, GstPad * pad,
4079     gboolean flushing)
4080 {
4081   GstBaseSinkClass *bclass;
4082
4083   bclass = GST_BASE_SINK_GET_CLASS (basesink);
4084
4085   if (flushing) {
4086     /* unlock any subclasses, we need to do this before grabbing the
4087      * PREROLL_LOCK since we hold this lock before going into ::render. */
4088     if (bclass->unlock)
4089       bclass->unlock (basesink);
4090   }
4091
4092   GST_BASE_SINK_PREROLL_LOCK (basesink);
4093   basesink->flushing = flushing;
4094   if (flushing) {
4095     /* step 1, now that we have the PREROLL lock, clear our unlock request */
4096     if (bclass->unlock_stop)
4097       bclass->unlock_stop (basesink);
4098
4099     /* set need_preroll before we unblock the clock. If the clock is unblocked
4100      * before timing out, we can reuse the buffer for preroll. */
4101     basesink->need_preroll = TRUE;
4102
4103     /* step 2, unblock clock sync (if any) or any other blocking thing */
4104     if (basesink->clock_id) {
4105       gst_clock_id_unschedule (basesink->clock_id);
4106     }
4107
4108     /* flush out the data thread if it's locked in finish_preroll, this will
4109      * also flush out the EOS state */
4110     GST_DEBUG_OBJECT (basesink,
4111         "flushing out data thread, need preroll to TRUE");
4112     gst_base_sink_preroll_queue_flush (basesink, pad);
4113   }
4114   GST_BASE_SINK_PREROLL_UNLOCK (basesink);
4115
4116   return TRUE;
4117 }
4118
4119 static gboolean
4120 gst_base_sink_default_activate_pull (GstBaseSink * basesink, gboolean active)
4121 {
4122   gboolean result;
4123
4124   if (active) {
4125     /* start task */
4126     result = gst_pad_start_task (basesink->sinkpad,
4127         (GstTaskFunction) gst_base_sink_loop, basesink->sinkpad);
4128   } else {
4129     /* step 2, make sure streaming finishes */
4130     result = gst_pad_stop_task (basesink->sinkpad);
4131   }
4132
4133   return result;
4134 }
4135
4136 static gboolean
4137 gst_base_sink_pad_activate (GstPad * pad)
4138 {
4139   gboolean result = FALSE;
4140   GstBaseSink *basesink;
4141   GstQuery *query;
4142   gboolean pull_mode;
4143
4144   basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
4145
4146   GST_DEBUG_OBJECT (basesink, "Trying pull mode first");
4147
4148   gst_base_sink_set_flushing (basesink, pad, FALSE);
4149
4150   /* we need to have the pull mode enabled */
4151   if (!basesink->can_activate_pull) {
4152     GST_DEBUG_OBJECT (basesink, "pull mode disabled");
4153     goto fallback;
4154   }
4155
4156   /* check if downstreams supports pull mode at all */
4157   query = gst_query_new_scheduling ();
4158
4159   if (!gst_pad_peer_query (pad, query)) {
4160     gst_query_unref (query);
4161     GST_DEBUG_OBJECT (basesink, "peer query faild, no pull mode");
4162     goto fallback;
4163   }
4164
4165   /* parse result of the query */
4166   gst_query_parse_scheduling (query, &pull_mode, NULL, NULL, NULL, NULL, NULL);
4167   gst_query_unref (query);
4168
4169   if (!pull_mode) {
4170     GST_DEBUG_OBJECT (basesink, "pull mode not supported");
4171     goto fallback;
4172   }
4173
4174   /* set the pad mode before starting the task so that it's in the
4175    * correct state for the new thread. also the sink set_caps and get_caps
4176    * function checks this */
4177   basesink->pad_mode = GST_ACTIVATE_PULL;
4178
4179   /* we first try to negotiate a format so that when we try to activate
4180    * downstream, it knows about our format */
4181   if (!gst_base_sink_negotiate_pull (basesink)) {
4182     GST_DEBUG_OBJECT (basesink, "failed to negotiate in pull mode");
4183     goto fallback;
4184   }
4185
4186   /* ok activate now */
4187   if (!gst_pad_activate_pull (pad, TRUE)) {
4188     /* clear any pending caps */
4189     GST_OBJECT_LOCK (basesink);
4190     gst_caps_replace (&basesink->priv->pull_caps, NULL);
4191     GST_OBJECT_UNLOCK (basesink);
4192     GST_DEBUG_OBJECT (basesink, "failed to activate in pull mode");
4193     goto fallback;
4194   }
4195
4196   GST_DEBUG_OBJECT (basesink, "Success activating pull mode");
4197   result = TRUE;
4198   goto done;
4199
4200   /* push mode fallback */
4201 fallback:
4202   GST_DEBUG_OBJECT (basesink, "Falling back to push mode");
4203   if ((result = gst_pad_activate_push (pad, TRUE))) {
4204     GST_DEBUG_OBJECT (basesink, "Success activating push mode");
4205   }
4206
4207 done:
4208   if (!result) {
4209     GST_WARNING_OBJECT (basesink, "Could not activate pad in either mode");
4210     gst_base_sink_set_flushing (basesink, pad, TRUE);
4211   }
4212
4213   gst_object_unref (basesink);
4214
4215   return result;
4216 }
4217
4218 static gboolean
4219 gst_base_sink_pad_activate_push (GstPad * pad, gboolean active)
4220 {
4221   gboolean result;
4222   GstBaseSink *basesink;
4223
4224   basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
4225
4226   if (active) {
4227     if (!basesink->can_activate_push) {
4228       result = FALSE;
4229       basesink->pad_mode = GST_ACTIVATE_NONE;
4230     } else {
4231       result = TRUE;
4232       basesink->pad_mode = GST_ACTIVATE_PUSH;
4233     }
4234   } else {
4235     if (G_UNLIKELY (basesink->pad_mode != GST_ACTIVATE_PUSH)) {
4236       g_warning ("Internal GStreamer activation error!!!");
4237       result = FALSE;
4238     } else {
4239       gst_base_sink_set_flushing (basesink, pad, TRUE);
4240       result = TRUE;
4241       basesink->pad_mode = GST_ACTIVATE_NONE;
4242     }
4243   }
4244
4245   gst_object_unref (basesink);
4246
4247   return result;
4248 }
4249
4250 static gboolean
4251 gst_base_sink_negotiate_pull (GstBaseSink * basesink)
4252 {
4253   GstCaps *caps;
4254   gboolean result;
4255
4256   result = FALSE;
4257
4258   /* this returns the intersection between our caps and the peer caps. If there
4259    * is no peer, it returns NULL and we can't operate in pull mode so we can
4260    * fail the negotiation. */
4261   caps = gst_pad_get_allowed_caps (GST_BASE_SINK_PAD (basesink));
4262   if (caps == NULL || gst_caps_is_empty (caps))
4263     goto no_caps_possible;
4264
4265   GST_DEBUG_OBJECT (basesink, "allowed caps: %" GST_PTR_FORMAT, caps);
4266
4267   caps = gst_caps_make_writable (caps);
4268   /* get the first (prefered) format */
4269   gst_caps_truncate (caps);
4270
4271   GST_DEBUG_OBJECT (basesink, "have caps: %" GST_PTR_FORMAT, caps);
4272
4273   if (gst_caps_is_any (caps)) {
4274     GST_DEBUG_OBJECT (basesink, "caps were ANY after fixating, "
4275         "allowing pull()");
4276     /* neither side has template caps in this case, so they are prepared for
4277        pull() without setcaps() */
4278     result = TRUE;
4279   } else {
4280     /* try to fixate */
4281     gst_pad_fixate_caps (GST_BASE_SINK_PAD (basesink), caps);
4282     GST_DEBUG_OBJECT (basesink, "fixated to: %" GST_PTR_FORMAT, caps);
4283
4284     if (gst_caps_is_fixed (caps)) {
4285       if (!gst_pad_send_event (GST_BASE_SINK_PAD (basesink),
4286               gst_event_new_caps (caps)))
4287         goto could_not_set_caps;
4288
4289       GST_OBJECT_LOCK (basesink);
4290       gst_caps_replace (&basesink->priv->pull_caps, caps);
4291       GST_OBJECT_UNLOCK (basesink);
4292
4293       result = TRUE;
4294     }
4295   }
4296
4297   gst_caps_unref (caps);
4298
4299   return result;
4300
4301 no_caps_possible:
4302   {
4303     GST_INFO_OBJECT (basesink, "Pipeline could not agree on caps");
4304     GST_DEBUG_OBJECT (basesink, "get_allowed_caps() returned EMPTY");
4305     if (caps)
4306       gst_caps_unref (caps);
4307     return FALSE;
4308   }
4309 could_not_set_caps:
4310   {
4311     GST_INFO_OBJECT (basesink, "Could not set caps: %" GST_PTR_FORMAT, caps);
4312     gst_caps_unref (caps);
4313     return FALSE;
4314   }
4315 }
4316
4317 /* this won't get called until we implement an activate function */
4318 static gboolean
4319 gst_base_sink_pad_activate_pull (GstPad * pad, gboolean active)
4320 {
4321   gboolean result = FALSE;
4322   GstBaseSink *basesink;
4323   GstBaseSinkClass *bclass;
4324
4325   basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
4326   bclass = GST_BASE_SINK_GET_CLASS (basesink);
4327
4328   if (active) {
4329     gint64 duration;
4330
4331     /* we mark we have a newsegment here because pull based
4332      * mode works just fine without having a newsegment before the
4333      * first buffer */
4334     gst_segment_init (&basesink->segment, GST_FORMAT_BYTES);
4335     gst_segment_init (&basesink->clip_segment, GST_FORMAT_BYTES);
4336     GST_OBJECT_LOCK (basesink);
4337     basesink->have_newsegment = TRUE;
4338     GST_OBJECT_UNLOCK (basesink);
4339
4340     /* get the peer duration in bytes */
4341     result = gst_pad_query_peer_duration (pad, GST_FORMAT_BYTES, &duration);
4342     if (result) {
4343       GST_DEBUG_OBJECT (basesink,
4344           "setting duration in bytes to %" G_GINT64_FORMAT, duration);
4345       basesink->clip_segment.duration = duration;
4346       basesink->segment.duration = duration;
4347     } else {
4348       GST_DEBUG_OBJECT (basesink, "unknown duration");
4349     }
4350
4351     if (bclass->activate_pull)
4352       result = bclass->activate_pull (basesink, TRUE);
4353     else
4354       result = FALSE;
4355
4356     if (!result)
4357       goto activate_failed;
4358
4359   } else {
4360     if (G_UNLIKELY (basesink->pad_mode != GST_ACTIVATE_PULL)) {
4361       g_warning ("Internal GStreamer activation error!!!");
4362       result = FALSE;
4363     } else {
4364       result = gst_base_sink_set_flushing (basesink, pad, TRUE);
4365       if (bclass->activate_pull)
4366         result &= bclass->activate_pull (basesink, FALSE);
4367       basesink->pad_mode = GST_ACTIVATE_NONE;
4368       /* clear any pending caps */
4369       GST_OBJECT_LOCK (basesink);
4370       gst_caps_replace (&basesink->priv->pull_caps, NULL);
4371       GST_OBJECT_UNLOCK (basesink);
4372     }
4373   }
4374   gst_object_unref (basesink);
4375
4376   return result;
4377
4378   /* ERRORS */
4379 activate_failed:
4380   {
4381     /* reset, as starting the thread failed */
4382     basesink->pad_mode = GST_ACTIVATE_NONE;
4383
4384     GST_ERROR_OBJECT (basesink, "subclass failed to activate in pull mode");
4385     return FALSE;
4386   }
4387 }
4388
4389 /* send an event to our sinkpad peer. */
4390 static gboolean
4391 gst_base_sink_send_event (GstElement * element, GstEvent * event)
4392 {
4393   GstPad *pad;
4394   GstBaseSink *basesink = GST_BASE_SINK (element);
4395   gboolean forward, result = TRUE;
4396   GstActivateMode mode;
4397
4398   GST_OBJECT_LOCK (element);
4399   /* get the pad and the scheduling mode */
4400   pad = gst_object_ref (basesink->sinkpad);
4401   mode = basesink->pad_mode;
4402   GST_OBJECT_UNLOCK (element);
4403
4404   /* only push UPSTREAM events upstream */
4405   forward = GST_EVENT_IS_UPSTREAM (event);
4406
4407   GST_DEBUG_OBJECT (basesink, "handling event %p %" GST_PTR_FORMAT, event,
4408       event);
4409
4410   switch (GST_EVENT_TYPE (event)) {
4411     case GST_EVENT_LATENCY:
4412     {
4413       GstClockTime latency;
4414
4415       gst_event_parse_latency (event, &latency);
4416
4417       /* store the latency. We use this to adjust the running_time before syncing
4418        * it to the clock. */
4419       GST_OBJECT_LOCK (element);
4420       basesink->priv->latency = latency;
4421       if (!basesink->priv->have_latency)
4422         forward = FALSE;
4423       GST_OBJECT_UNLOCK (element);
4424       GST_DEBUG_OBJECT (basesink, "latency set to %" GST_TIME_FORMAT,
4425           GST_TIME_ARGS (latency));
4426
4427       /* We forward this event so that all elements know about the global pipeline
4428        * latency. This is interesting for an element when it wants to figure out
4429        * when a particular piece of data will be rendered. */
4430       break;
4431     }
4432     case GST_EVENT_SEEK:
4433       /* in pull mode we will execute the seek */
4434       if (mode == GST_ACTIVATE_PULL)
4435         result = gst_base_sink_perform_seek (basesink, pad, event);
4436       break;
4437     case GST_EVENT_STEP:
4438       result = gst_base_sink_perform_step (basesink, pad, event);
4439       forward = FALSE;
4440       break;
4441     default:
4442       break;
4443   }
4444
4445   if (forward) {
4446     result = gst_pad_push_event (pad, event);
4447   } else {
4448     /* not forwarded, unref the event */
4449     gst_event_unref (event);
4450   }
4451
4452   gst_object_unref (pad);
4453   return result;
4454 }
4455
4456 static gboolean
4457 gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format,
4458     gint64 * cur, gboolean * upstream)
4459 {
4460   GstClock *clock = NULL;
4461   gboolean res = FALSE;
4462   GstFormat oformat;
4463   GstSegment *segment;
4464   GstClockTime now, latency;
4465   GstClockTimeDiff base_time;
4466   gint64 time, base, duration;
4467   gdouble rate;
4468   gint64 last;
4469   gboolean last_seen, with_clock, in_paused;
4470
4471   GST_OBJECT_LOCK (basesink);
4472   /* we can only get the segment when we are not NULL or READY */
4473   if (!basesink->have_newsegment)
4474     goto wrong_state;
4475
4476   in_paused = FALSE;
4477   /* when not in PLAYING or when we're busy with a state change, we
4478    * cannot read from the clock so we report time based on the
4479    * last seen timestamp. */
4480   if (GST_STATE (basesink) != GST_STATE_PLAYING ||
4481       GST_STATE_PENDING (basesink) != GST_STATE_VOID_PENDING) {
4482     in_paused = TRUE;
4483   }
4484
4485   /* we don't use the clip segment in pull mode, when seeking we update the
4486    * main segment directly with the new segment values without it having to be
4487    * activated by the rendering after preroll */
4488   if (basesink->pad_mode == GST_ACTIVATE_PUSH)
4489     segment = &basesink->clip_segment;
4490   else
4491     segment = &basesink->segment;
4492
4493   /* get the format in the segment */
4494   oformat = segment->format;
4495
4496   /* report with last seen position when EOS */
4497   last_seen = basesink->eos;
4498
4499   /* assume we will use the clock for getting the current position */
4500   with_clock = TRUE;
4501   if (basesink->sync == FALSE)
4502     with_clock = FALSE;
4503
4504   /* and we need a clock */
4505   if (G_UNLIKELY ((clock = GST_ELEMENT_CLOCK (basesink)) == NULL))
4506     with_clock = FALSE;
4507   else
4508     gst_object_ref (clock);
4509
4510   /* mainloop might be querying position when going to playing async,
4511    * while (audio) rendering might be quickly advancing stream position,
4512    * so use clock asap rather than last reported position */
4513   if (in_paused && with_clock && g_atomic_int_get (&basesink->priv->to_playing)) {
4514     GST_DEBUG_OBJECT (basesink, "going to PLAYING, so not PAUSED");
4515     in_paused = FALSE;
4516   }
4517
4518   /* collect all data we need holding the lock */
4519   if (GST_CLOCK_TIME_IS_VALID (segment->time))
4520     time = segment->time;
4521   else
4522     time = 0;
4523
4524   if (GST_CLOCK_TIME_IS_VALID (segment->stop))
4525     duration = segment->stop - segment->start;
4526   else
4527     duration = 0;
4528
4529   base = segment->base;
4530   rate = segment->rate * segment->applied_rate;
4531   latency = basesink->priv->latency;
4532
4533   if (oformat == GST_FORMAT_TIME) {
4534     gint64 start, stop;
4535
4536     start = basesink->priv->current_sstart;
4537     stop = basesink->priv->current_sstop;
4538
4539     if (in_paused) {
4540       /* in paused we use the last position as a lower bound */
4541       if (stop == -1 || segment->rate > 0.0)
4542         last = start;
4543       else
4544         last = stop;
4545     } else {
4546       /* in playing, use last stop time as upper bound */
4547       if (start == -1 || segment->rate > 0.0)
4548         last = stop;
4549       else
4550         last = start;
4551     }
4552   } else {
4553     /* convert last stop to stream time */
4554     last = gst_segment_to_stream_time (segment, oformat, segment->position);
4555   }
4556
4557   if (in_paused) {
4558     /* in paused, use start_time */
4559     base_time = GST_ELEMENT_START_TIME (basesink);
4560     GST_DEBUG_OBJECT (basesink, "in paused, using start time %" GST_TIME_FORMAT,
4561         GST_TIME_ARGS (base_time));
4562   } else if (with_clock) {
4563     /* else use clock when needed */
4564     base_time = GST_ELEMENT_CAST (basesink)->base_time;
4565     GST_DEBUG_OBJECT (basesink, "using clock and base time %" GST_TIME_FORMAT,
4566         GST_TIME_ARGS (base_time));
4567   } else {
4568     /* else, no sync or clock -> no base time */
4569     GST_DEBUG_OBJECT (basesink, "no sync or no clock");
4570     base_time = -1;
4571   }
4572
4573   /* no base_time, we can't calculate running_time, use last seem timestamp to report
4574    * time */
4575   if (base_time == -1)
4576     last_seen = TRUE;
4577
4578   /* need to release the object lock before we can get the time,
4579    * a clock might take the LOCK of the provider, which could be
4580    * a basesink subclass. */
4581   GST_OBJECT_UNLOCK (basesink);
4582
4583   if (last_seen) {
4584     /* in EOS or when no valid stream_time, report the value of last seen
4585      * timestamp */
4586     if (last == -1) {
4587       /* no timestamp, we need to ask upstream */
4588       GST_DEBUG_OBJECT (basesink, "no last seen timestamp, asking upstream");
4589       res = FALSE;
4590       *upstream = TRUE;
4591       goto done;
4592     }
4593     GST_DEBUG_OBJECT (basesink, "using last seen timestamp %" GST_TIME_FORMAT,
4594         GST_TIME_ARGS (last));
4595     *cur = last;
4596   } else {
4597     if (oformat != GST_FORMAT_TIME) {
4598       /* convert base, time and duration to time */
4599       if (!gst_pad_query_convert (basesink->sinkpad, oformat, base,
4600               GST_FORMAT_TIME, &base))
4601         goto convert_failed;
4602       if (!gst_pad_query_convert (basesink->sinkpad, oformat, duration,
4603               GST_FORMAT_TIME, &duration))
4604         goto convert_failed;
4605       if (!gst_pad_query_convert (basesink->sinkpad, oformat, time,
4606               GST_FORMAT_TIME, &time))
4607         goto convert_failed;
4608       if (!gst_pad_query_convert (basesink->sinkpad, oformat, last,
4609               GST_FORMAT_TIME, &last))
4610         goto convert_failed;
4611
4612       /* assume time format from now on */
4613       oformat = GST_FORMAT_TIME;
4614     }
4615
4616     if (!in_paused && with_clock) {
4617       now = gst_clock_get_time (clock);
4618     } else {
4619       now = base_time;
4620       base_time = 0;
4621     }
4622
4623     /* subtract base time and base time from the clock time.
4624      * Make sure we don't go negative. This is the current time in
4625      * the segment which we need to scale with the combined
4626      * rate and applied rate. */
4627     base_time += base;
4628     base_time += latency;
4629     if (GST_CLOCK_DIFF (base_time, now) < 0)
4630       base_time = now;
4631
4632     /* for negative rates we need to count back from the segment
4633      * duration. */
4634     if (rate < 0.0)
4635       time += duration;
4636
4637     *cur = time + gst_guint64_to_gdouble (now - base_time) * rate;
4638
4639     if (in_paused) {
4640       /* never report less than segment values in paused */
4641       if (last != -1)
4642         *cur = MAX (last, *cur);
4643     } else {
4644       /* never report more than last seen position in playing */
4645       if (last != -1)
4646         *cur = MIN (last, *cur);
4647     }
4648
4649     GST_DEBUG_OBJECT (basesink,
4650         "now %" GST_TIME_FORMAT " - base_time %" GST_TIME_FORMAT " - base %"
4651         GST_TIME_FORMAT " + time %" GST_TIME_FORMAT "  last %" GST_TIME_FORMAT,
4652         GST_TIME_ARGS (now), GST_TIME_ARGS (base_time), GST_TIME_ARGS (base),
4653         GST_TIME_ARGS (time), GST_TIME_ARGS (last));
4654   }
4655
4656   if (oformat != format) {
4657     /* convert to final format */
4658     if (!gst_pad_query_convert (basesink->sinkpad, oformat, *cur, format, cur))
4659       goto convert_failed;
4660   }
4661
4662   res = TRUE;
4663
4664 done:
4665   GST_DEBUG_OBJECT (basesink, "res: %d, POSITION: %" GST_TIME_FORMAT,
4666       res, GST_TIME_ARGS (*cur));
4667
4668   if (clock)
4669     gst_object_unref (clock);
4670
4671   return res;
4672
4673   /* special cases */
4674 wrong_state:
4675   {
4676     /* in NULL or READY we always return FALSE and -1 */
4677     GST_DEBUG_OBJECT (basesink, "position in wrong state, return -1");
4678     res = FALSE;
4679     *cur = -1;
4680     GST_OBJECT_UNLOCK (basesink);
4681     goto done;
4682   }
4683 convert_failed:
4684   {
4685     GST_DEBUG_OBJECT (basesink, "convert failed, try upstream");
4686     *upstream = TRUE;
4687     res = FALSE;
4688     goto done;
4689   }
4690 }
4691
4692 static gboolean
4693 gst_base_sink_get_duration (GstBaseSink * basesink, GstFormat format,
4694     gint64 * dur, gboolean * upstream)
4695 {
4696   gboolean res = FALSE;
4697
4698   if (basesink->pad_mode == GST_ACTIVATE_PULL) {
4699     gint64 uduration;
4700
4701     /* get the duration in bytes, in pull mode that's all we are sure to
4702      * know. We have to explicitly get this value from upstream instead of
4703      * using our cached value because it might change. Duration caching
4704      * should be done at a higher level. */
4705     res =
4706         gst_pad_query_peer_duration (basesink->sinkpad, GST_FORMAT_BYTES,
4707         &uduration);
4708     if (res) {
4709       basesink->segment.duration = uduration;
4710       if (format != GST_FORMAT_BYTES) {
4711         /* convert to the requested format */
4712         res =
4713             gst_pad_query_convert (basesink->sinkpad, GST_FORMAT_BYTES,
4714             uduration, format, dur);
4715       } else {
4716         *dur = uduration;
4717       }
4718     }
4719     *upstream = FALSE;
4720   } else {
4721     *upstream = TRUE;
4722   }
4723
4724   return res;
4725 }
4726
4727 static const GstQueryType *
4728 gst_base_sink_get_query_types (GstElement * element)
4729 {
4730   static const GstQueryType query_types[] = {
4731     GST_QUERY_DURATION,
4732     GST_QUERY_POSITION,
4733     GST_QUERY_SEGMENT,
4734     GST_QUERY_LATENCY,
4735     0
4736   };
4737
4738   return query_types;
4739 }
4740
4741 static gboolean
4742 default_element_query (GstElement * element, GstQuery * query)
4743 {
4744   gboolean res = FALSE;
4745
4746   GstBaseSink *basesink = GST_BASE_SINK (element);
4747
4748   switch (GST_QUERY_TYPE (query)) {
4749     case GST_QUERY_POSITION:
4750     {
4751       gint64 cur = 0;
4752       GstFormat format;
4753       gboolean upstream = FALSE;
4754
4755       gst_query_parse_position (query, &format, NULL);
4756
4757       GST_DEBUG_OBJECT (basesink, "position query in format %s",
4758           gst_format_get_name (format));
4759
4760       /* first try to get the position based on the clock */
4761       if ((res =
4762               gst_base_sink_get_position (basesink, format, &cur, &upstream))) {
4763         gst_query_set_position (query, format, cur);
4764       } else if (upstream) {
4765         /* fallback to peer query */
4766         res = gst_pad_peer_query (basesink->sinkpad, query);
4767       }
4768       if (!res) {
4769         /* we can handle a few things if upstream failed */
4770         if (format == GST_FORMAT_PERCENT) {
4771           gint64 dur = 0;
4772
4773           res = gst_base_sink_get_position (basesink, GST_FORMAT_TIME, &cur,
4774               &upstream);
4775           if (!res && upstream) {
4776             res =
4777                 gst_pad_query_peer_position (basesink->sinkpad, GST_FORMAT_TIME,
4778                 &cur);
4779           }
4780           if (res) {
4781             res = gst_base_sink_get_duration (basesink, GST_FORMAT_TIME, &dur,
4782                 &upstream);
4783             if (!res && upstream) {
4784               res =
4785                   gst_pad_query_peer_duration (basesink->sinkpad,
4786                   GST_FORMAT_TIME, &dur);
4787             }
4788           }
4789           if (res) {
4790             gint64 pos;
4791
4792             pos = gst_util_uint64_scale (100 * GST_FORMAT_PERCENT_SCALE, cur,
4793                 dur);
4794             gst_query_set_position (query, GST_FORMAT_PERCENT, pos);
4795           }
4796         }
4797       }
4798       break;
4799     }
4800     case GST_QUERY_DURATION:
4801     {
4802       gint64 dur = 0;
4803       GstFormat format;
4804       gboolean upstream = FALSE;
4805
4806       gst_query_parse_duration (query, &format, NULL);
4807
4808       GST_DEBUG_OBJECT (basesink, "duration query in format %s",
4809           gst_format_get_name (format));
4810
4811       if ((res =
4812               gst_base_sink_get_duration (basesink, format, &dur, &upstream))) {
4813         gst_query_set_duration (query, format, dur);
4814       } else if (upstream) {
4815         /* fallback to peer query */
4816         res = gst_pad_peer_query (basesink->sinkpad, query);
4817       }
4818       if (!res) {
4819         /* we can handle a few things if upstream failed */
4820         if (format == GST_FORMAT_PERCENT) {
4821           gst_query_set_duration (query, GST_FORMAT_PERCENT,
4822               GST_FORMAT_PERCENT_MAX);
4823           res = TRUE;
4824         }
4825       }
4826       break;
4827     }
4828     case GST_QUERY_LATENCY:
4829     {
4830       gboolean live, us_live;
4831       GstClockTime min, max;
4832
4833       if ((res = gst_base_sink_query_latency (basesink, &live, &us_live, &min,
4834                   &max))) {
4835         gst_query_set_latency (query, live, min, max);
4836       }
4837       break;
4838     }
4839     case GST_QUERY_JITTER:
4840       break;
4841     case GST_QUERY_RATE:
4842       /* gst_query_set_rate (query, basesink->segment_rate); */
4843       res = TRUE;
4844       break;
4845     case GST_QUERY_SEGMENT:
4846     {
4847       if (basesink->pad_mode == GST_ACTIVATE_PULL) {
4848         gst_query_set_segment (query, basesink->segment.rate,
4849             GST_FORMAT_TIME, basesink->segment.start, basesink->segment.stop);
4850         res = TRUE;
4851       } else {
4852         res = gst_pad_peer_query (basesink->sinkpad, query);
4853       }
4854       break;
4855     }
4856     case GST_QUERY_SEEKING:
4857     case GST_QUERY_CONVERT:
4858     case GST_QUERY_FORMATS:
4859     default:
4860       res = gst_pad_peer_query (basesink->sinkpad, query);
4861       break;
4862   }
4863   GST_DEBUG_OBJECT (basesink, "query %s returns %d",
4864       GST_QUERY_TYPE_NAME (query), res);
4865   return res;
4866 }
4867
4868
4869 static gboolean
4870 default_sink_query (GstBaseSink * basesink, GstQuery * query)
4871 {
4872   gboolean res;
4873   GstBaseSinkClass *bclass;
4874
4875   bclass = GST_BASE_SINK_GET_CLASS (basesink);
4876
4877   switch (GST_QUERY_TYPE (query)) {
4878     case GST_QUERY_ALLOCATION:
4879     {
4880       if (bclass->setup_allocation)
4881         res = bclass->setup_allocation (basesink, query);
4882       else
4883         res = FALSE;
4884       break;
4885     }
4886     default:
4887       res = gst_pad_query_default (basesink->sinkpad, query);
4888       break;
4889   }
4890   return res;
4891 }
4892
4893 static gboolean
4894 gst_base_sink_sink_query (GstPad * pad, GstQuery * query)
4895 {
4896   GstBaseSink *basesink;
4897   GstBaseSinkClass *bclass;
4898   gboolean res;
4899
4900   basesink = GST_BASE_SINK_CAST (gst_pad_get_parent (pad));
4901   if (G_UNLIKELY (basesink == NULL)) {
4902     gst_query_unref (query);
4903     return FALSE;
4904   }
4905
4906   bclass = GST_BASE_SINK_GET_CLASS (basesink);
4907
4908   if (bclass->query)
4909     res = bclass->query (basesink, query);
4910   else
4911     res = FALSE;
4912
4913   gst_object_unref (basesink);
4914
4915   return res;
4916 }
4917
4918 static GstStateChangeReturn
4919 gst_base_sink_change_state (GstElement * element, GstStateChange transition)
4920 {
4921   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
4922   GstBaseSink *basesink = GST_BASE_SINK (element);
4923   GstBaseSinkClass *bclass;
4924   GstBaseSinkPrivate *priv;
4925
4926   priv = basesink->priv;
4927
4928   bclass = GST_BASE_SINK_GET_CLASS (basesink);
4929
4930   switch (transition) {
4931     case GST_STATE_CHANGE_NULL_TO_READY:
4932       if (bclass->start)
4933         if (!bclass->start (basesink))
4934           goto start_failed;
4935       break;
4936     case GST_STATE_CHANGE_READY_TO_PAUSED:
4937       /* need to complete preroll before this state change completes, there
4938        * is no data flow in READY so we can safely assume we need to preroll. */
4939       GST_BASE_SINK_PREROLL_LOCK (basesink);
4940       GST_DEBUG_OBJECT (basesink, "READY to PAUSED");
4941       basesink->have_newsegment = FALSE;
4942       gst_segment_init (&basesink->segment, GST_FORMAT_UNDEFINED);
4943       gst_segment_init (&basesink->clip_segment, GST_FORMAT_UNDEFINED);
4944       basesink->offset = 0;
4945       basesink->have_preroll = FALSE;
4946       priv->step_unlock = FALSE;
4947       basesink->need_preroll = TRUE;
4948       basesink->playing_async = TRUE;
4949       basesink->priv->reset_time = FALSE;
4950       priv->current_sstart = GST_CLOCK_TIME_NONE;
4951       priv->current_sstop = GST_CLOCK_TIME_NONE;
4952       priv->eos_rtime = GST_CLOCK_TIME_NONE;
4953       priv->latency = 0;
4954       basesink->eos = FALSE;
4955       priv->received_eos = FALSE;
4956       gst_base_sink_reset_qos (basesink);
4957       priv->commited = FALSE;
4958       priv->call_preroll = TRUE;
4959       priv->current_step.valid = FALSE;
4960       priv->pending_step.valid = FALSE;
4961       if (priv->async_enabled) {
4962         GST_DEBUG_OBJECT (basesink, "doing async state change");
4963         /* when async enabled, post async-start message and return ASYNC from
4964          * the state change function */
4965         ret = GST_STATE_CHANGE_ASYNC;
4966         gst_element_post_message (GST_ELEMENT_CAST (basesink),
4967             gst_message_new_async_start (GST_OBJECT_CAST (basesink)));
4968       } else {
4969         priv->have_latency = TRUE;
4970       }
4971       GST_BASE_SINK_PREROLL_UNLOCK (basesink);
4972       break;
4973     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
4974       GST_BASE_SINK_PREROLL_LOCK (basesink);
4975       g_atomic_int_set (&basesink->priv->to_playing, TRUE);
4976       if (!gst_base_sink_needs_preroll (basesink)) {
4977         GST_DEBUG_OBJECT (basesink, "PAUSED to PLAYING, don't need preroll");
4978         /* no preroll needed anymore now. */
4979         basesink->playing_async = FALSE;
4980         basesink->need_preroll = FALSE;
4981         if (basesink->eos) {
4982           GstMessage *message;
4983
4984           /* need to post EOS message here */
4985           GST_DEBUG_OBJECT (basesink, "Now posting EOS");
4986           message = gst_message_new_eos (GST_OBJECT_CAST (basesink));
4987           gst_message_set_seqnum (message, basesink->priv->seqnum);
4988           gst_element_post_message (GST_ELEMENT_CAST (basesink), message);
4989         } else {
4990           GST_DEBUG_OBJECT (basesink, "signal preroll");
4991           GST_BASE_SINK_PREROLL_SIGNAL (basesink);
4992         }
4993       } else {
4994         GST_DEBUG_OBJECT (basesink, "PAUSED to PLAYING, we are not prerolled");
4995         basesink->need_preroll = TRUE;
4996         basesink->playing_async = TRUE;
4997         priv->call_preroll = TRUE;
4998         priv->commited = FALSE;
4999         if (priv->async_enabled) {
5000           GST_DEBUG_OBJECT (basesink, "doing async state change");
5001           ret = GST_STATE_CHANGE_ASYNC;
5002           gst_element_post_message (GST_ELEMENT_CAST (basesink),
5003               gst_message_new_async_start (GST_OBJECT_CAST (basesink)));
5004         }
5005       }
5006       GST_BASE_SINK_PREROLL_UNLOCK (basesink);
5007       break;
5008     default:
5009       break;
5010   }
5011
5012   {
5013     GstStateChangeReturn bret;
5014
5015     bret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
5016     if (G_UNLIKELY (bret == GST_STATE_CHANGE_FAILURE))
5017       goto activate_failed;
5018   }
5019
5020   switch (transition) {
5021     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
5022       /* completed transition, so need not be marked any longer
5023        * And it should be unmarked, since e.g. losing our position upon flush
5024        * does not really change state to PAUSED ... */
5025       g_atomic_int_set (&basesink->priv->to_playing, FALSE);
5026       break;
5027     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
5028       g_atomic_int_set (&basesink->priv->to_playing, FALSE);
5029       GST_DEBUG_OBJECT (basesink, "PLAYING to PAUSED");
5030       /* FIXME, make sure we cannot enter _render first */
5031
5032       /* we need to call ::unlock before locking PREROLL_LOCK
5033        * since we lock it before going into ::render */
5034       if (bclass->unlock)
5035         bclass->unlock (basesink);
5036
5037       GST_BASE_SINK_PREROLL_LOCK (basesink);
5038       GST_DEBUG_OBJECT (basesink, "got preroll lock");
5039       /* now that we have the PREROLL lock, clear our unlock request */
5040       if (bclass->unlock_stop)
5041         bclass->unlock_stop (basesink);
5042
5043       /* we need preroll again and we set the flag before unlocking the clockid
5044        * because if the clockid is unlocked before a current buffer expired, we
5045        * can use that buffer to preroll with */
5046       basesink->need_preroll = TRUE;
5047
5048       if (basesink->clock_id) {
5049         GST_DEBUG_OBJECT (basesink, "unschedule clock");
5050         gst_clock_id_unschedule (basesink->clock_id);
5051       }
5052
5053       /* if we don't have a preroll buffer we need to wait for a preroll and
5054        * return ASYNC. */
5055       if (!gst_base_sink_needs_preroll (basesink)) {
5056         GST_DEBUG_OBJECT (basesink, "PLAYING to PAUSED, we are prerolled");
5057         basesink->playing_async = FALSE;
5058       } else {
5059         if (GST_STATE_TARGET (GST_ELEMENT (basesink)) <= GST_STATE_READY) {
5060           GST_DEBUG_OBJECT (basesink, "element is <= READY");
5061           ret = GST_STATE_CHANGE_SUCCESS;
5062         } else {
5063           GST_DEBUG_OBJECT (basesink,
5064               "PLAYING to PAUSED, we are not prerolled");
5065           basesink->playing_async = TRUE;
5066           priv->commited = FALSE;
5067           priv->call_preroll = TRUE;
5068           if (priv->async_enabled) {
5069             GST_DEBUG_OBJECT (basesink, "doing async state change");
5070             ret = GST_STATE_CHANGE_ASYNC;
5071             gst_element_post_message (GST_ELEMENT_CAST (basesink),
5072                 gst_message_new_async_start (GST_OBJECT_CAST (basesink)));
5073           }
5074         }
5075       }
5076       GST_DEBUG_OBJECT (basesink, "rendered: %" G_GUINT64_FORMAT
5077           ", dropped: %" G_GUINT64_FORMAT, priv->rendered, priv->dropped);
5078
5079       gst_base_sink_reset_qos (basesink);
5080       GST_BASE_SINK_PREROLL_UNLOCK (basesink);
5081       break;
5082     case GST_STATE_CHANGE_PAUSED_TO_READY:
5083       GST_BASE_SINK_PREROLL_LOCK (basesink);
5084       /* start by reseting our position state with the object lock so that the
5085        * position query gets the right idea. We do this before we post the
5086        * messages so that the message handlers pick this up. */
5087       GST_OBJECT_LOCK (basesink);
5088       basesink->have_newsegment = FALSE;
5089       priv->current_sstart = GST_CLOCK_TIME_NONE;
5090       priv->current_sstop = GST_CLOCK_TIME_NONE;
5091       priv->have_latency = FALSE;
5092       if (priv->cached_clock_id) {
5093         gst_clock_id_unref (priv->cached_clock_id);
5094         priv->cached_clock_id = NULL;
5095       }
5096       GST_OBJECT_UNLOCK (basesink);
5097
5098       gst_base_sink_set_last_buffer (basesink, NULL);
5099       priv->call_preroll = FALSE;
5100
5101       if (!priv->commited) {
5102         if (priv->async_enabled) {
5103           GST_DEBUG_OBJECT (basesink, "PAUSED to READY, posting async-done");
5104
5105           gst_element_post_message (GST_ELEMENT_CAST (basesink),
5106               gst_message_new_state_changed (GST_OBJECT_CAST (basesink),
5107                   GST_STATE_PLAYING, GST_STATE_PAUSED, GST_STATE_READY));
5108
5109           gst_element_post_message (GST_ELEMENT_CAST (basesink),
5110               gst_message_new_async_done (GST_OBJECT_CAST (basesink), FALSE));
5111         }
5112         priv->commited = TRUE;
5113       } else {
5114         GST_DEBUG_OBJECT (basesink, "PAUSED to READY, don't need_preroll");
5115       }
5116       GST_BASE_SINK_PREROLL_UNLOCK (basesink);
5117       break;
5118     case GST_STATE_CHANGE_READY_TO_NULL:
5119       if (bclass->stop) {
5120         if (!bclass->stop (basesink)) {
5121           GST_WARNING_OBJECT (basesink, "failed to stop");
5122         }
5123       }
5124       gst_base_sink_set_last_buffer (basesink, NULL);
5125       priv->call_preroll = FALSE;
5126       break;
5127     default:
5128       break;
5129   }
5130
5131   return ret;
5132
5133   /* ERRORS */
5134 start_failed:
5135   {
5136     GST_DEBUG_OBJECT (basesink, "failed to start");
5137     return GST_STATE_CHANGE_FAILURE;
5138   }
5139 activate_failed:
5140   {
5141     GST_DEBUG_OBJECT (basesink,
5142         "element failed to change states -- activation problem?");
5143     return GST_STATE_CHANGE_FAILURE;
5144   }
5145 }