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