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