debug fixes
[platform/upstream/gstreamer.git] / gst / base / gstbasesink.c
1 /* GStreamer
2  * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
3  *
4  * gstbasesink.c:
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 /**
23  * SECTION:gstbasesink
24  * @short_description: Base class for sink elements
25  * @see_also: #GstBaseTransformc, #GstBaseSource
26  *
27  * This class is for elements that do output operations.
28  *
29  * <itemizedlist>
30  *   <listitem><para>one sinkpad</para></listitem>
31  *   <listitem><para>handles state changes</para></listitem>
32  *   <listitem><para>pull/push mode</para></listitem>
33  *   <listitem><para>handles seeking/query</para></listitem>
34  *   <listitem><para>handles preroll</para></listitem>
35  *   <listitem><para>EOS handling</para></listitem>
36  * </itemizedlist>
37  */
38
39 #ifdef HAVE_CONFIG_H
40 #  include "config.h"
41 #endif
42
43 #include "gstbasesink.h"
44 #include <gst/gstmarshal.h>
45
46 GST_DEBUG_CATEGORY_STATIC (gst_base_sink_debug);
47 #define GST_CAT_DEFAULT gst_base_sink_debug
48
49 /* BaseSink signals and properties */
50 enum
51 {
52   /* FILL ME */
53   SIGNAL_HANDOFF,
54   LAST_SIGNAL
55 };
56
57 #define DEFAULT_SIZE 1024
58 #define DEFAULT_CAN_ACTIVATE_PULL FALSE /* fixme: enable me */
59 #define DEFAULT_CAN_ACTIVATE_PUSH TRUE
60
61 enum
62 {
63   PROP_0,
64   PROP_PREROLL_QUEUE_LEN
65 };
66
67 static GstElementClass *parent_class = NULL;
68
69 static void gst_base_sink_base_init (gpointer g_class);
70 static void gst_base_sink_class_init (GstBaseSinkClass * klass);
71 static void gst_base_sink_init (GstBaseSink * trans, gpointer g_class);
72 static void gst_base_sink_finalize (GObject * object);
73
74 GType
75 gst_base_sink_get_type (void)
76 {
77   static GType base_sink_type = 0;
78
79   if (!base_sink_type) {
80     static const GTypeInfo base_sink_info = {
81       sizeof (GstBaseSinkClass),
82       (GBaseInitFunc) gst_base_sink_base_init,
83       NULL,
84       (GClassInitFunc) gst_base_sink_class_init,
85       NULL,
86       NULL,
87       sizeof (GstBaseSink),
88       0,
89       (GInstanceInitFunc) gst_base_sink_init,
90     };
91
92     base_sink_type = g_type_register_static (GST_TYPE_ELEMENT,
93         "GstBaseSink", &base_sink_info, G_TYPE_FLAG_ABSTRACT);
94   }
95   return base_sink_type;
96 }
97
98 static void gst_base_sink_set_clock (GstElement * element, GstClock * clock);
99
100 static void gst_base_sink_set_property (GObject * object, guint prop_id,
101     const GValue * value, GParamSpec * pspec);
102 static void gst_base_sink_get_property (GObject * object, guint prop_id,
103     GValue * value, GParamSpec * pspec);
104
105 static GstCaps *gst_base_sink_get_caps (GstBaseSink * sink);
106 static gboolean gst_base_sink_set_caps (GstBaseSink * sink, GstCaps * caps);
107 static GstFlowReturn gst_base_sink_buffer_alloc (GstBaseSink * sink,
108     guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
109 static void gst_base_sink_get_times (GstBaseSink * basesink, GstBuffer * buffer,
110     GstClockTime * start, GstClockTime * end);
111
112 static GstStateChangeReturn gst_base_sink_change_state (GstElement * element,
113     GstStateChange transition);
114
115 static GstFlowReturn gst_base_sink_chain (GstPad * pad, GstBuffer * buffer);
116 static void gst_base_sink_loop (GstPad * pad);
117 static gboolean gst_base_sink_activate (GstPad * pad);
118 static gboolean gst_base_sink_activate_push (GstPad * pad, gboolean active);
119 static gboolean gst_base_sink_activate_pull (GstPad * pad, gboolean active);
120 static gboolean gst_base_sink_event (GstPad * pad, GstEvent * event);
121 static inline GstFlowReturn gst_base_sink_handle_buffer (GstBaseSink * basesink,
122     GstBuffer * buf);
123 static inline gboolean gst_base_sink_handle_event (GstBaseSink * basesink,
124     GstEvent * event);
125
126 static void
127 gst_base_sink_base_init (gpointer g_class)
128 {
129   GST_DEBUG_CATEGORY_INIT (gst_base_sink_debug, "basesink", 0,
130       "basesink element");
131 }
132
133 static void
134 gst_base_sink_class_init (GstBaseSinkClass * klass)
135 {
136   GObjectClass *gobject_class;
137   GstElementClass *gstelement_class;
138
139   gobject_class = (GObjectClass *) klass;
140   gstelement_class = (GstElementClass *) klass;
141
142   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
143
144   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_base_sink_finalize);
145   gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_base_sink_set_property);
146   gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_base_sink_get_property);
147
148   /* FIXME, this next value should be configured using an event from the
149    * upstream element */
150   g_object_class_install_property (G_OBJECT_CLASS (klass),
151       PROP_PREROLL_QUEUE_LEN,
152       g_param_spec_uint ("preroll-queue-len", "preroll-queue-len",
153           "Number of buffers to queue during preroll", 0, G_MAXUINT, 0,
154           G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
155
156   gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_base_sink_set_clock);
157   gstelement_class->change_state =
158       GST_DEBUG_FUNCPTR (gst_base_sink_change_state);
159
160   klass->get_caps = GST_DEBUG_FUNCPTR (gst_base_sink_get_caps);
161   klass->set_caps = GST_DEBUG_FUNCPTR (gst_base_sink_set_caps);
162   klass->buffer_alloc = GST_DEBUG_FUNCPTR (gst_base_sink_buffer_alloc);
163   klass->get_times = GST_DEBUG_FUNCPTR (gst_base_sink_get_times);
164 }
165
166 static GstCaps *
167 gst_base_sink_pad_getcaps (GstPad * pad)
168 {
169   GstBaseSinkClass *bclass;
170   GstBaseSink *bsink;
171   GstCaps *caps = NULL;
172
173   bsink = GST_BASE_SINK (gst_pad_get_parent (pad));
174   bclass = GST_BASE_SINK_GET_CLASS (bsink);
175   if (bclass->get_caps)
176     caps = bclass->get_caps (bsink);
177
178   if (caps == NULL) {
179     GstPadTemplate *pad_template;
180
181     pad_template =
182         gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink");
183     if (pad_template != NULL) {
184       caps = gst_caps_ref (gst_pad_template_get_caps (pad_template));
185     }
186   }
187   gst_object_unref (bsink);
188
189   return caps;
190 }
191
192 static gboolean
193 gst_base_sink_pad_setcaps (GstPad * pad, GstCaps * caps)
194 {
195   GstBaseSinkClass *bclass;
196   GstBaseSink *bsink;
197   gboolean res = FALSE;
198
199   bsink = GST_BASE_SINK (gst_pad_get_parent (pad));
200   bclass = GST_BASE_SINK_GET_CLASS (bsink);
201
202   if (bclass->set_caps)
203     res = bclass->set_caps (bsink, caps);
204
205   gst_object_unref (bsink);
206
207   return res;
208 }
209
210 static GstFlowReturn
211 gst_base_sink_pad_buffer_alloc (GstPad * pad, guint64 offset, guint size,
212     GstCaps * caps, GstBuffer ** buf)
213 {
214   GstBaseSinkClass *bclass;
215   GstBaseSink *bsink;
216   GstFlowReturn result = GST_FLOW_OK;
217
218   bsink = GST_BASE_SINK (gst_pad_get_parent (pad));
219   bclass = GST_BASE_SINK_GET_CLASS (bsink);
220
221   if (bclass->buffer_alloc)
222     result = bclass->buffer_alloc (bsink, offset, size, caps, buf);
223   else
224     *buf = NULL;                /* fallback in gstpad.c will allocate generic buffer */
225
226   gst_object_unref (bsink);
227
228   return result;
229 }
230
231 static void
232 gst_base_sink_init (GstBaseSink * basesink, gpointer g_class)
233 {
234   GstPadTemplate *pad_template;
235
236   pad_template =
237       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "sink");
238   g_return_if_fail (pad_template != NULL);
239
240   basesink->sinkpad = gst_pad_new_from_template (pad_template, "sink");
241
242   gst_pad_set_getcaps_function (basesink->sinkpad,
243       GST_DEBUG_FUNCPTR (gst_base_sink_pad_getcaps));
244   gst_pad_set_setcaps_function (basesink->sinkpad,
245       GST_DEBUG_FUNCPTR (gst_base_sink_pad_setcaps));
246   gst_pad_set_bufferalloc_function (basesink->sinkpad,
247       GST_DEBUG_FUNCPTR (gst_base_sink_pad_buffer_alloc));
248   gst_pad_set_activate_function (basesink->sinkpad,
249       GST_DEBUG_FUNCPTR (gst_base_sink_activate));
250   gst_pad_set_activatepush_function (basesink->sinkpad,
251       GST_DEBUG_FUNCPTR (gst_base_sink_activate_push));
252   gst_pad_set_activatepull_function (basesink->sinkpad,
253       GST_DEBUG_FUNCPTR (gst_base_sink_activate_pull));
254   gst_pad_set_event_function (basesink->sinkpad,
255       GST_DEBUG_FUNCPTR (gst_base_sink_event));
256   gst_pad_set_chain_function (basesink->sinkpad,
257       GST_DEBUG_FUNCPTR (gst_base_sink_chain));
258   gst_element_add_pad (GST_ELEMENT (basesink), basesink->sinkpad);
259
260   basesink->pad_mode = GST_ACTIVATE_NONE;
261   GST_PAD_TASK (basesink->sinkpad) = NULL;
262   basesink->preroll_queue = g_queue_new ();
263
264   basesink->can_activate_push = DEFAULT_CAN_ACTIVATE_PUSH;
265   basesink->can_activate_pull = DEFAULT_CAN_ACTIVATE_PULL;
266
267   GST_FLAG_SET (basesink, GST_ELEMENT_IS_SINK);
268 }
269
270 static void
271 gst_base_sink_finalize (GObject * object)
272 {
273   GstBaseSink *basesink;
274
275   basesink = GST_BASE_SINK (object);
276
277   g_queue_free (basesink->preroll_queue);
278
279   G_OBJECT_CLASS (parent_class)->finalize (object);
280 }
281
282 static void
283 gst_base_sink_set_clock (GstElement * element, GstClock * clock)
284 {
285   GstBaseSink *sink;
286
287   sink = GST_BASE_SINK (element);
288
289   sink->clock = clock;
290 }
291
292 static void
293 gst_base_sink_set_property (GObject * object, guint prop_id,
294     const GValue * value, GParamSpec * pspec)
295 {
296   GstBaseSink *sink = GST_BASE_SINK (object);
297
298   switch (prop_id) {
299     case PROP_PREROLL_QUEUE_LEN:
300       /* preroll lock necessary to serialize with finish_preroll */
301       GST_PREROLL_LOCK (sink->sinkpad);
302       sink->preroll_queue_max_len = g_value_get_uint (value);
303       GST_PREROLL_UNLOCK (sink->sinkpad);
304       break;
305     default:
306       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
307       break;
308   }
309 }
310
311 static void
312 gst_base_sink_get_property (GObject * object, guint prop_id, GValue * value,
313     GParamSpec * pspec)
314 {
315   GstBaseSink *sink = GST_BASE_SINK (object);
316
317   GST_LOCK (sink);
318   switch (prop_id) {
319     case PROP_PREROLL_QUEUE_LEN:
320       g_value_set_uint (value, sink->preroll_queue_max_len);
321       break;
322     default:
323       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
324       break;
325   }
326   GST_UNLOCK (sink);
327 }
328
329 static GstCaps *
330 gst_base_sink_get_caps (GstBaseSink * sink)
331 {
332   return NULL;
333 }
334
335 static gboolean
336 gst_base_sink_set_caps (GstBaseSink * sink, GstCaps * caps)
337 {
338   return TRUE;
339 }
340
341 static GstFlowReturn
342 gst_base_sink_buffer_alloc (GstBaseSink * sink, guint64 offset, guint size,
343     GstCaps * caps, GstBuffer ** buf)
344 {
345   *buf = NULL;
346   return GST_FLOW_OK;
347 }
348
349 /* with PREROLL_LOCK */
350 static GstFlowReturn
351 gst_base_sink_preroll_queue_empty (GstBaseSink * basesink, GstPad * pad)
352 {
353   GstMiniObject *obj;
354   GQueue *q = basesink->preroll_queue;
355   GstFlowReturn ret;
356
357   ret = GST_FLOW_OK;
358
359   if (q) {
360     GST_DEBUG_OBJECT (basesink, "emptying queue");
361     while ((obj = g_queue_pop_head (q))) {
362       gboolean is_buffer;
363
364       is_buffer = GST_IS_BUFFER (obj);
365       if (is_buffer) {
366         basesink->preroll_queued--;
367         basesink->buffers_queued--;
368       } else {
369         switch (GST_EVENT_TYPE (obj)) {
370           case GST_EVENT_EOS:
371             basesink->preroll_queued--;
372             break;
373           default:
374             break;
375         }
376         basesink->events_queued--;
377       }
378       /* we release the preroll lock while pushing so that we
379        * can still flush it while blocking on the clock or
380        * inside the element. */
381       GST_PREROLL_UNLOCK (pad);
382
383       if (is_buffer) {
384         GST_DEBUG_OBJECT (basesink, "popped buffer %p", obj);
385         ret = gst_base_sink_handle_buffer (basesink, GST_BUFFER (obj));
386       } else {
387         GST_DEBUG_OBJECT (basesink, "popped event %p", obj);
388         gst_base_sink_handle_event (basesink, GST_EVENT (obj));
389         ret = GST_FLOW_OK;
390       }
391
392       GST_PREROLL_LOCK (pad);
393     }
394     GST_DEBUG_OBJECT (basesink, "queue empty");
395   }
396   return ret;
397 }
398
399 /* with PREROLL_LOCK */
400 static void
401 gst_base_sink_preroll_queue_flush (GstBaseSink * basesink, GstPad * pad)
402 {
403   GstMiniObject *obj;
404   GQueue *q = basesink->preroll_queue;
405
406   GST_DEBUG_OBJECT (basesink, "flushing queue %p", basesink);
407   if (q) {
408     while ((obj = g_queue_pop_head (q))) {
409       GST_DEBUG_OBJECT (basesink, "popped %p", obj);
410       gst_mini_object_unref (obj);
411     }
412   }
413   /* we can't have EOS anymore now */
414   basesink->eos = FALSE;
415   basesink->preroll_queued = 0;
416   basesink->buffers_queued = 0;
417   basesink->events_queued = 0;
418   basesink->have_preroll = FALSE;
419   /* and signal any waiters now */
420   GST_PREROLL_SIGNAL (pad);
421 }
422
423 /* with STREAM_LOCK */
424 static GstFlowReturn
425 gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad,
426     GstMiniObject * obj)
427 {
428   gint length;
429   gboolean have_event;
430
431   GST_PREROLL_LOCK (pad);
432   /* push object on the queue */
433   GST_DEBUG_OBJECT (basesink, "push %p on preroll_queue", obj);
434   g_queue_push_tail (basesink->preroll_queue, obj);
435
436   have_event = GST_IS_EVENT (obj);
437   if (have_event) {
438     GstEvent *event = GST_EVENT (obj);
439
440     switch (GST_EVENT_TYPE (obj)) {
441       case GST_EVENT_EOS:
442         basesink->preroll_queued++;
443         basesink->eos = TRUE;
444         break;
445       case GST_EVENT_NEWSEGMENT:
446       {
447         GstFormat format;
448         gint64 segment_start;
449         gint64 segment_stop;
450
451         /* the newsegment event is needed to bring the buffer timestamps to the
452          * stream time and to drop samples outside of the playback segment. */
453         gst_event_parse_newsegment (event, &basesink->segment_rate, &format,
454             &segment_start, &segment_stop, &basesink->segment_base);
455
456         basesink->have_newsegment = TRUE;
457
458         if (format != GST_FORMAT_TIME) {
459           GST_DEBUG_OBJECT (basesink,
460               "received non time %d NEW_SEGMENT %" G_GINT64_FORMAT
461               " -- %" G_GINT64_FORMAT ", base %" G_GINT64_FORMAT,
462               format, basesink->segment_start, basesink->segment_stop,
463               basesink->segment_base);
464
465           /* this means this sink will not be able to clip or drop samples
466            * and timestamps have to start from 0. */
467           basesink->segment_start = -1;
468           basesink->segment_stop = -1;
469           basesink->segment_base = -1;
470           goto done_newsegment;
471         }
472         /* check if we really have a new segment or the previous one is
473          * closed */
474         if (basesink->segment_start != segment_start) {
475           /* the new segment has to be aligned with the old segment.
476            * We first update the accumulated time of the previous
477            * segment. the accumulated time is used when syncing to the
478            * clock. A flush event sets the accumulated time back to 0
479            */
480           if (GST_CLOCK_TIME_IS_VALID (basesink->segment_stop)) {
481             basesink->segment_accum +=
482                 basesink->segment_stop - basesink->segment_start;
483           } else if (GST_CLOCK_TIME_IS_VALID (basesink->current_end)) {
484             /* else use last seen timestamp as segment stop */
485             basesink->segment_accum +=
486                 basesink->current_end - basesink->segment_start;
487           } else {
488             basesink->segment_accum = 0;
489           }
490         }
491
492         basesink->segment_start = segment_start;
493         basesink->segment_stop = segment_stop;
494
495         GST_DEBUG_OBJECT (basesink,
496             "received DISCONT %" GST_TIME_FORMAT " -- %"
497             GST_TIME_FORMAT ", base %" GST_TIME_FORMAT ", accum %"
498             GST_TIME_FORMAT,
499             GST_TIME_ARGS (basesink->segment_start),
500             GST_TIME_ARGS (basesink->segment_stop),
501             GST_TIME_ARGS (basesink->segment_base),
502             GST_TIME_ARGS (basesink->segment_accum));
503       done_newsegment:
504         break;
505       }
506       default:
507         break;
508     }
509     basesink->events_queued++;
510   } else {
511     GstBuffer *buf = GST_BUFFER (obj);
512
513     if (!basesink->have_newsegment) {
514       GST_ELEMENT_WARNING (basesink, STREAM, STOPPED,
515           ("Received buffer without a new-segment. Cannot sync to clock."),
516           ("Received buffer without a new-segment. Cannot sync to clock."));
517       basesink->have_newsegment = TRUE;
518       /* this means this sink will not be able to sync to the clock */
519       basesink->segment_start = -1;
520       basesink->segment_stop = -1;
521     }
522
523     /* check if the buffer needs to be dropped */
524     if (TRUE) {
525       GstClockTime start = -1, end = -1;
526
527       /* we don't use the subclassed method as it may not return
528        * valid values for our purpose here */
529       gst_base_sink_get_times (basesink, buf, &start, &end);
530
531       GST_DEBUG_OBJECT (basesink, "got times start: %" GST_TIME_FORMAT
532           ", end: %" GST_TIME_FORMAT, GST_TIME_ARGS (start),
533           GST_TIME_ARGS (end));
534
535       /* need to drop if the timestamp is not between segment_start and
536        * segment_stop. we check if the complete sample is outside of the
537        * range since the sink might be able to clip the sample. */
538       if (GST_CLOCK_TIME_IS_VALID (end) &&
539           GST_CLOCK_TIME_IS_VALID (basesink->segment_start)) {
540         if (end <= basesink->segment_start) {
541           GST_DEBUG_OBJECT (basesink,
542               "buffer end %" GST_TIME_FORMAT " <= segment start %"
543               GST_TIME_FORMAT ", dropping buffer", GST_TIME_ARGS (end),
544               GST_TIME_ARGS (basesink->segment_start));
545           goto dropping;
546         }
547       }
548       if (GST_CLOCK_TIME_IS_VALID (start) &&
549           GST_CLOCK_TIME_IS_VALID (basesink->segment_stop)) {
550         if (basesink->segment_stop <= start) {
551           GST_DEBUG_OBJECT (basesink,
552               "buffer start %" GST_TIME_FORMAT " >= segment stop %"
553               GST_TIME_FORMAT ", dropping buffer", GST_TIME_ARGS (start),
554               GST_TIME_ARGS (basesink->segment_stop));
555           goto dropping;
556         }
557       }
558     }
559     basesink->preroll_queued++;
560     basesink->buffers_queued++;
561   }
562   GST_DEBUG_OBJECT (basesink,
563       "now %d preroll, %d buffers, %d events on queue",
564       basesink->preroll_queued,
565       basesink->buffers_queued, basesink->events_queued);
566
567   if (basesink->playing_async)
568     goto playing_async;
569
570   /* check if we are prerolling */
571   if (!basesink->need_preroll)
572     goto no_preroll;
573
574   /* there is a buffer queued */
575   if (basesink->buffers_queued == 1) {
576     GST_DEBUG_OBJECT (basesink, "do preroll %p", obj);
577
578     /* if it's a buffer, we need to call the preroll method */
579     if (GST_IS_BUFFER (obj)) {
580       GstBaseSinkClass *bclass;
581       GstFlowReturn pres;
582
583       bclass = GST_BASE_SINK_GET_CLASS (basesink);
584       if (bclass->preroll)
585         if ((pres =
586                 bclass->preroll (basesink, GST_BUFFER (obj))) != GST_FLOW_OK)
587           goto preroll_failed;
588     }
589   }
590   length = basesink->preroll_queued;
591   GST_DEBUG_OBJECT (basesink, "prerolled length %d", length);
592
593   if (length == 1) {
594     gint t;
595
596     basesink->have_preroll = TRUE;
597     /* we are prerolling */
598     GST_PREROLL_UNLOCK (pad);
599
600     /* have to release STREAM_LOCK as we cannot take the STATE_LOCK
601      * inside the STREAM_LOCK */
602     t = GST_STREAM_UNLOCK_FULL (pad);
603     GST_DEBUG_OBJECT (basesink, "released stream lock %d times", t);
604     if (t <= 0) {
605       GST_WARNING ("STREAM_LOCK should have been locked !!");
606       g_warning ("STREAM_LOCK should have been locked !!");
607     }
608
609     /* now we commit our state */
610     GST_STATE_LOCK (basesink);
611     GST_DEBUG_OBJECT (basesink, "commit state");
612     gst_element_commit_state (GST_ELEMENT (basesink));
613     GST_STATE_UNLOCK (basesink);
614
615     /* reacquire stream lock, pad could be flushing now */
616     /* FIXME in glib, if t==0, the lock is still taken... hmmm */
617     if (t > 0)
618       GST_STREAM_LOCK_FULL (pad, t);
619
620     /* and wait if needed */
621     GST_PREROLL_LOCK (pad);
622
623     GST_LOCK (pad);
624     if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
625       goto flushing;
626     GST_UNLOCK (pad);
627
628     /* it is possible that the application set the state to PLAYING
629      * now in which case we don't need to block anymore. */
630     if (!basesink->need_preroll)
631       goto no_preroll;
632
633     length = basesink->preroll_queued;
634
635     g_assert (length == 1);
636   }
637
638   /* see if we need to block now. We cannot block on events, only
639    * on buffers, the reason is that events can be sent from the
640    * application thread and we don't want to block there. */
641   if (length > basesink->preroll_queue_max_len && !have_event) {
642     /* block until the state changes, or we get a flush, or something */
643     GST_DEBUG_OBJECT (basesink, "waiting to finish preroll");
644     GST_PREROLL_WAIT (pad);
645     GST_DEBUG_OBJECT (basesink, "done preroll");
646   }
647   GST_LOCK (pad);
648   if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
649     goto flushing;
650   GST_UNLOCK (pad);
651
652   GST_PREROLL_UNLOCK (pad);
653
654   return GST_FLOW_OK;
655
656 no_preroll:
657   {
658     GstFlowReturn ret;
659
660     GST_DEBUG_OBJECT (basesink, "no preroll needed");
661     /* maybe it was another sink that blocked in preroll, need to check for
662        buffers to drain */
663     basesink->have_preroll = FALSE;
664     ret = gst_base_sink_preroll_queue_empty (basesink, pad);
665     GST_PREROLL_UNLOCK (pad);
666
667     return ret;
668   }
669 dropping:
670   {
671     GstBuffer *buf;
672
673     buf = GST_BUFFER (g_queue_pop_tail (basesink->preroll_queue));
674
675     gst_buffer_unref (buf);
676     GST_PREROLL_UNLOCK (pad);
677
678     return GST_FLOW_OK;
679   }
680 playing_async:
681   {
682     GstFlowReturn ret;
683     gint t;
684
685     basesink->have_preroll = FALSE;
686     basesink->playing_async = FALSE;
687
688     /* handle buffer first */
689     ret = gst_base_sink_preroll_queue_empty (basesink, pad);
690
691     /* unroll locks, commit state, reacquire stream lock */
692     GST_PREROLL_UNLOCK (pad);
693     t = GST_STREAM_UNLOCK_FULL (pad);
694     GST_DEBUG_OBJECT (basesink, "released stream lock %d times", t);
695     if (t <= 0) {
696       GST_WARNING ("STREAM_LOCK should have been locked !!");
697       g_warning ("STREAM_LOCK should have been locked !!");
698     }
699     GST_STATE_LOCK (basesink);
700     GST_DEBUG_OBJECT (basesink, "commit state");
701     gst_element_commit_state (GST_ELEMENT (basesink));
702     GST_STATE_UNLOCK (basesink);
703     if (t > 0)
704       GST_STREAM_LOCK_FULL (pad, t);
705
706     return ret;
707   }
708 flushing:
709   {
710     GST_UNLOCK (pad);
711     gst_base_sink_preroll_queue_flush (basesink, pad);
712     GST_PREROLL_UNLOCK (pad);
713     GST_DEBUG_OBJECT (basesink, "pad is flushing");
714     return GST_FLOW_WRONG_STATE;
715   }
716 preroll_failed:
717   {
718     gint t;
719
720     GST_DEBUG_OBJECT (basesink, "preroll failed");
721     gst_base_sink_preroll_queue_flush (basesink, pad);
722     GST_PREROLL_UNLOCK (pad);
723
724     /* have to release STREAM_LOCK as we cannot take the STATE_LOCK
725      * inside the STREAM_LOCK */
726     t = GST_STREAM_UNLOCK_FULL (pad);
727     GST_DEBUG_OBJECT (basesink, "released stream lock %d times", t);
728     if (t <= 0) {
729       GST_WARNING ("STREAM_LOCK should have been locked !!");
730       g_warning ("STREAM_LOCK should have been locked !!");
731     }
732
733     /* now we abort our state */
734     GST_STATE_LOCK (basesink);
735     GST_DEBUG_OBJECT (basesink, "abort state");
736     gst_element_abort_state (GST_ELEMENT (basesink));
737     GST_STATE_UNLOCK (basesink);
738
739     /* reacquire stream lock, pad could be flushing now */
740     if (t > 0)
741       GST_STREAM_LOCK_FULL (pad, t);
742
743     return GST_FLOW_ERROR;
744   }
745 }
746
747 static gboolean
748 gst_base_sink_event (GstPad * pad, GstEvent * event)
749 {
750   GstBaseSink *basesink;
751   gboolean result = TRUE;
752   GstBaseSinkClass *bclass;
753
754   basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
755
756   bclass = GST_BASE_SINK_GET_CLASS (basesink);
757
758   GST_DEBUG_OBJECT (basesink, "event %p", event);
759
760   switch (GST_EVENT_TYPE (event)) {
761     case GST_EVENT_EOS:
762     {
763       GstFlowReturn ret;
764
765       GST_STREAM_LOCK (pad);
766       /* EOS also finishes the preroll */
767       ret =
768           gst_base_sink_handle_object (basesink, pad, GST_MINI_OBJECT (event));
769       GST_STREAM_UNLOCK (pad);
770       break;
771     }
772     case GST_EVENT_NEWSEGMENT:
773     {
774       GstFlowReturn ret;
775
776       GST_STREAM_LOCK (pad);
777       ret =
778           gst_base_sink_handle_object (basesink, pad, GST_MINI_OBJECT (event));
779       GST_STREAM_UNLOCK (pad);
780       break;
781     }
782     case GST_EVENT_FLUSH_START:
783       /* make sure we are not blocked on the clock also clear any pending
784        * eos state. */
785       if (bclass->event)
786         bclass->event (basesink, event);
787
788       GST_PREROLL_LOCK (pad);
789       /* we need preroll after the flush */
790       GST_DEBUG_OBJECT (basesink, "flushing, need preroll after flush");
791       basesink->need_preroll = TRUE;
792       /* unlock from a possible state change/preroll */
793       gst_base_sink_preroll_queue_flush (basesink, pad);
794
795       GST_LOCK (basesink);
796       if (basesink->clock_id) {
797         gst_clock_id_unschedule (basesink->clock_id);
798       }
799       GST_UNLOCK (basesink);
800       GST_PREROLL_UNLOCK (pad);
801
802       /* and we need to commit our state again on the next
803        * prerolled buffer */
804       GST_STATE_LOCK (basesink);
805       GST_STREAM_LOCK (pad);
806       gst_element_lost_state (GST_ELEMENT (basesink));
807       GST_STREAM_UNLOCK (pad);
808       GST_STATE_UNLOCK (basesink);
809       GST_DEBUG_OBJECT (basesink, "event unref %p %p", basesink, event);
810       gst_event_unref (event);
811       break;
812     case GST_EVENT_FLUSH_STOP:
813       if (bclass->event)
814         bclass->event (basesink, event);
815
816       /* now we are completely unblocked and the _chain method
817        * will return */
818       GST_STREAM_LOCK (pad);
819       /* we need new segment info after the flush. */
820       basesink->segment_start = -1;
821       basesink->segment_stop = -1;
822       basesink->current_start = -1;
823       basesink->current_end = -1;
824       GST_DEBUG_OBJECT (basesink, "reset accum %" GST_TIME_FORMAT,
825           GST_TIME_ARGS (basesink->segment_accum));
826       basesink->segment_accum = 0;
827       GST_STREAM_UNLOCK (pad);
828
829       GST_DEBUG_OBJECT (basesink, "event unref %p %p", basesink, event);
830       gst_event_unref (event);
831       break;
832     default:
833       gst_event_unref (event);
834       break;
835   }
836   gst_object_unref (basesink);
837
838   return result;
839 }
840
841 /* default implementation to calculate the start and end
842  * timestamps on a buffer, subclasses can override
843  */
844 static void
845 gst_base_sink_get_times (GstBaseSink * basesink, GstBuffer * buffer,
846     GstClockTime * start, GstClockTime * end)
847 {
848   GstClockTime timestamp, duration;
849
850   timestamp = GST_BUFFER_TIMESTAMP (buffer);
851   if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
852
853     /* get duration to calculate end time */
854     duration = GST_BUFFER_DURATION (buffer);
855     if (GST_CLOCK_TIME_IS_VALID (duration)) {
856       *end = timestamp + duration;
857     }
858     *start = timestamp;
859   }
860 }
861
862 /* perform synchronisation on a buffer
863  * 
864  * 1) check if we have a clock, if not, do nothing
865  * 2) calculate the start and end time of the buffer
866  * 3) create a single shot notification to wait on
867  *    the clock, save the entry so we can unlock it
868  * 4) wait on the clock, this blocks
869  * 5) unref the clockid again
870  */
871 static gboolean
872 gst_base_sink_do_sync (GstBaseSink * basesink, GstBuffer * buffer)
873 {
874   gboolean result = TRUE;
875   GstClockTime start, end;
876   GstClockTimeDiff stream_start, stream_end;
877   GstBaseSinkClass *bclass;
878   gboolean start_valid, end_valid;
879
880   bclass = GST_BASE_SINK_GET_CLASS (basesink);
881
882   start = end = -1;
883   if (bclass->get_times)
884     bclass->get_times (basesink, buffer, &start, &end);
885
886   start_valid = GST_CLOCK_TIME_IS_VALID (start);
887   end_valid = GST_CLOCK_TIME_IS_VALID (start);
888
889   GST_DEBUG_OBJECT (basesink, "got times start: %" GST_TIME_FORMAT
890       ", end: %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (end));
891
892   /* if we don't have a timestamp, we don't sync */
893   if (!start_valid)
894     goto done;
895
896   /* save last times seen. */
897   basesink->current_start = start;
898   if (end_valid)
899     basesink->current_end = end;
900   else
901     basesink->current_end = start;
902
903   if (GST_CLOCK_TIME_IS_VALID (basesink->segment_stop)) {
904     /* check if not outside of the segment range, start is
905      * always valid here. */
906     if (start > basesink->segment_stop)
907       goto out_of_segment;
908   }
909
910   /* bring timestamp to stream time using last segment offset. */
911   if (GST_CLOCK_TIME_IS_VALID (basesink->segment_start)) {
912     /* check if not outside of the segment range */
913     if (end_valid && end < basesink->segment_start)
914       goto out_of_segment;
915
916     stream_start = (gint64) start - basesink->segment_start;
917     stream_end = (gint64) end - basesink->segment_start;
918   } else {
919     stream_start = (gint64) start;
920     stream_end = (gint64) end;
921   }
922
923   stream_start += basesink->segment_accum;
924   if (end_valid)
925     stream_end += basesink->segment_accum;
926
927   /* now do clocking */
928   if (basesink->clock) {
929     GstClockReturn ret;
930     GstClockTime base_time;
931
932     GST_LOCK (basesink);
933     base_time = GST_ELEMENT (basesink)->base_time;
934
935     GST_LOG_OBJECT (basesink,
936         "waiting for clock, base time %" GST_TIME_FORMAT,
937         GST_TIME_ARGS (base_time));
938
939     /* save clock id so that we can unlock it if needed */
940     basesink->clock_id = gst_clock_new_single_shot_id (basesink->clock,
941         stream_start + base_time);
942     /* also save end_time of this buffer so that we can wait
943      * to signal EOS */
944     if (end_valid)
945       basesink->end_time = stream_end + base_time;
946     else
947       basesink->end_time = GST_CLOCK_TIME_NONE;
948     GST_UNLOCK (basesink);
949
950     ret = gst_clock_id_wait (basesink->clock_id, NULL);
951
952     GST_LOCK (basesink);
953     if (basesink->clock_id) {
954       gst_clock_id_unref (basesink->clock_id);
955       basesink->clock_id = NULL;
956     }
957     GST_UNLOCK (basesink);
958
959     GST_LOG_OBJECT (basesink, "clock entry done: %d", ret);
960     if (ret == GST_CLOCK_UNSCHEDULED)
961       result = FALSE;
962   }
963
964 done:
965   return result;
966
967 out_of_segment:
968   {
969     GST_LOG_OBJECT (basesink, "buffer skipped, not in segment");
970     return FALSE;
971   }
972 }
973
974
975 /* handle an event
976  *
977  * 2) render the event
978  * 3) unref the event
979  */
980 static inline gboolean
981 gst_base_sink_handle_event (GstBaseSink * basesink, GstEvent * event)
982 {
983   GstBaseSinkClass *bclass;
984   gboolean ret;
985
986   switch (GST_EVENT_TYPE (event)) {
987     case GST_EVENT_EOS:
988       GST_LOCK (basesink);
989       if (basesink->clock) {
990         /* wait for last buffer to finish if we have a valid end time */
991         if (GST_CLOCK_TIME_IS_VALID (basesink->end_time)) {
992           basesink->clock_id = gst_clock_new_single_shot_id (basesink->clock,
993               basesink->end_time);
994           GST_UNLOCK (basesink);
995
996           gst_clock_id_wait (basesink->clock_id, NULL);
997
998           GST_LOCK (basesink);
999           if (basesink->clock_id) {
1000             gst_clock_id_unref (basesink->clock_id);
1001             basesink->clock_id = NULL;
1002           }
1003           basesink->end_time = GST_CLOCK_TIME_NONE;
1004         }
1005       }
1006       GST_UNLOCK (basesink);
1007       break;
1008     default:
1009       break;
1010   }
1011
1012   bclass = GST_BASE_SINK_GET_CLASS (basesink);
1013   if (bclass->event)
1014     ret = bclass->event (basesink, event);
1015   else
1016     ret = TRUE;
1017
1018   switch (GST_EVENT_TYPE (event)) {
1019     case GST_EVENT_EOS:
1020       GST_PREROLL_LOCK (basesink->sinkpad);
1021       /* if we are still EOS, we can post the EOS message */
1022       if (basesink->eos) {
1023         /* ok, now we can post the message */
1024         GST_DEBUG_OBJECT (basesink, "Now posting EOS");
1025         gst_element_post_message (GST_ELEMENT (basesink),
1026             gst_message_new_eos (GST_OBJECT (basesink)));
1027       }
1028       GST_PREROLL_UNLOCK (basesink->sinkpad);
1029       break;
1030     default:
1031       break;
1032   }
1033
1034   GST_DEBUG_OBJECT (basesink, "event unref %p %p", basesink, event);
1035   gst_event_unref (event);
1036
1037   return ret;
1038 }
1039
1040 /* handle a buffer
1041  *
1042  * 1) first sync on the buffer
1043  * 2) render the buffer
1044  * 3) unref the buffer
1045  */
1046 static inline GstFlowReturn
1047 gst_base_sink_handle_buffer (GstBaseSink * basesink, GstBuffer * buf)
1048 {
1049   GstFlowReturn ret = GST_FLOW_OK;
1050   gboolean render;
1051
1052   render = gst_base_sink_do_sync (basesink, buf);
1053
1054   if (render) {
1055     GstBaseSinkClass *bclass;
1056
1057     bclass = GST_BASE_SINK_GET_CLASS (basesink);
1058     if (bclass->render)
1059       ret = bclass->render (basesink, buf);
1060   }
1061
1062   GST_DEBUG_OBJECT (basesink, "buffer unref after render %p", basesink, buf);
1063   gst_buffer_unref (buf);
1064
1065   return ret;
1066 }
1067
1068 static GstFlowReturn
1069 gst_base_sink_chain (GstPad * pad, GstBuffer * buf)
1070 {
1071   GstBaseSink *basesink;
1072   GstFlowReturn result;
1073
1074   basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
1075
1076   if (!(basesink->pad_mode == GST_ACTIVATE_PUSH)) {
1077     GST_LOCK (pad);
1078     g_warning ("Push on pad %s:%s, but it was not activated in push mode",
1079         GST_DEBUG_PAD_NAME (pad));
1080     GST_UNLOCK (pad);
1081     result = GST_FLOW_UNEXPECTED;
1082     goto done;
1083   }
1084
1085   result = gst_base_sink_handle_object (basesink, pad, GST_MINI_OBJECT (buf));
1086
1087 done:
1088   gst_object_unref (basesink);
1089
1090   return result;
1091 }
1092
1093 static void
1094 gst_base_sink_loop (GstPad * pad)
1095 {
1096   GstBaseSink *basesink;
1097   GstBuffer *buf = NULL;
1098   GstFlowReturn result;
1099
1100   basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
1101
1102   g_assert (basesink->pad_mode == GST_ACTIVATE_PULL);
1103
1104   result = gst_pad_pull_range (pad, basesink->offset, DEFAULT_SIZE, &buf);
1105   if (result != GST_FLOW_OK)
1106     goto paused;
1107
1108   result = gst_base_sink_handle_object (basesink, pad, GST_MINI_OBJECT (buf));
1109   if (result != GST_FLOW_OK)
1110     goto paused;
1111
1112   gst_object_unref (basesink);
1113
1114   /* default */
1115   return;
1116
1117 paused:
1118   {
1119     gst_base_sink_event (pad, gst_event_new_eos ());
1120     gst_object_unref (basesink);
1121     gst_pad_pause_task (pad);
1122     return;
1123   }
1124 }
1125
1126 static gboolean
1127 gst_base_sink_deactivate (GstBaseSink * basesink, GstPad * pad)
1128 {
1129   gboolean result = FALSE;
1130   GstBaseSinkClass *bclass;
1131
1132   bclass = GST_BASE_SINK_GET_CLASS (basesink);
1133
1134   /* step 1, unblock clock sync (if any) or any other blocking thing */
1135   GST_PREROLL_LOCK (pad);
1136   GST_LOCK (basesink);
1137   if (basesink->clock_id) {
1138     gst_clock_id_unschedule (basesink->clock_id);
1139   }
1140   GST_UNLOCK (basesink);
1141
1142   /* unlock any subclasses */
1143   if (bclass->unlock)
1144     bclass->unlock (basesink);
1145
1146   /* flush out the data thread if it's locked in finish_preroll */
1147   GST_DEBUG_OBJECT (basesink,
1148       "flushing out data thread, need preroll to FALSE");
1149   basesink->need_preroll = FALSE;
1150   gst_base_sink_preroll_queue_flush (basesink, pad);
1151   GST_PREROLL_SIGNAL (pad);
1152   GST_PREROLL_UNLOCK (pad);
1153
1154   /* step 2, make sure streaming finishes */
1155   result = gst_pad_stop_task (pad);
1156
1157   return result;
1158 }
1159
1160 static gboolean
1161 gst_base_sink_activate (GstPad * pad)
1162 {
1163   gboolean result = FALSE;
1164   GstBaseSink *basesink;
1165
1166   basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
1167
1168   GST_DEBUG_OBJECT (basesink, "Trying pull mode first");
1169
1170   if (basesink->can_activate_pull && gst_pad_check_pull_range (pad)
1171       && gst_pad_activate_pull (pad, TRUE)) {
1172     GST_DEBUG_OBJECT (basesink, "Success activating pull mode");
1173     result = TRUE;
1174   } else {
1175     GST_DEBUG_OBJECT (basesink, "Falling back to push mode");
1176     if (gst_pad_activate_push (pad, TRUE)) {
1177       GST_DEBUG_OBJECT (basesink, "Success activating push mode");
1178       result = TRUE;
1179     }
1180   }
1181
1182   if (!result) {
1183     GST_WARNING_OBJECT (basesink, "Could not activate pad in either mode");
1184   }
1185
1186   gst_object_unref (basesink);
1187
1188   return result;
1189 }
1190
1191 static gboolean
1192 gst_base_sink_activate_push (GstPad * pad, gboolean active)
1193 {
1194   gboolean result;
1195   GstBaseSink *basesink;
1196
1197   basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
1198
1199   if (active) {
1200     if (!basesink->can_activate_push) {
1201       result = FALSE;
1202       basesink->pad_mode = GST_ACTIVATE_NONE;
1203     } else {
1204       result = TRUE;
1205       basesink->pad_mode = GST_ACTIVATE_PUSH;
1206     }
1207   } else {
1208     if (G_UNLIKELY (basesink->pad_mode != GST_ACTIVATE_PUSH)) {
1209       g_warning ("Internal GStreamer activation error!!!");
1210       result = FALSE;
1211     } else {
1212       result = gst_base_sink_deactivate (basesink, pad);
1213       basesink->pad_mode = GST_ACTIVATE_NONE;
1214     }
1215   }
1216
1217   gst_object_unref (basesink);
1218
1219   return result;
1220 }
1221
1222 /* this won't get called until we implement an activate function */
1223 static gboolean
1224 gst_base_sink_activate_pull (GstPad * pad, gboolean active)
1225 {
1226   gboolean result = FALSE;
1227   GstBaseSink *basesink;
1228
1229   basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
1230
1231   if (active) {
1232     if (!basesink->can_activate_pull) {
1233       result = FALSE;
1234       basesink->pad_mode = GST_ACTIVATE_NONE;
1235     } else {
1236       GstPad *peer = gst_pad_get_peer (pad);
1237
1238       if (G_UNLIKELY (peer == NULL)) {
1239         g_warning ("Trying to activate pad in pull mode, but no peer");
1240         result = FALSE;
1241         basesink->pad_mode = GST_ACTIVATE_NONE;
1242       } else {
1243         if (gst_pad_activate_pull (peer, TRUE)) {
1244           basesink->have_newsegment = TRUE;
1245           basesink->segment_start = basesink->segment_stop = 0;
1246
1247           /* set the pad mode before starting the task so that it's in the
1248              correct state for the new thread... */
1249           basesink->pad_mode = GST_ACTIVATE_PULL;
1250           result =
1251               gst_pad_start_task (pad, (GstTaskFunction) gst_base_sink_loop,
1252               pad);
1253           /* but if starting the thread fails, set it back */
1254           if (!result)
1255             basesink->pad_mode = GST_ACTIVATE_NONE;
1256         } else {
1257           GST_DEBUG_OBJECT (pad, "Failed to activate peer in pull mode");
1258           result = FALSE;
1259           basesink->pad_mode = GST_ACTIVATE_NONE;
1260         }
1261         gst_object_unref (peer);
1262       }
1263     }
1264   } else {
1265     if (G_UNLIKELY (basesink->pad_mode != GST_ACTIVATE_PULL)) {
1266       g_warning ("Internal GStreamer activation error!!!");
1267       result = FALSE;
1268     } else {
1269       basesink->have_newsegment = FALSE;
1270       result = gst_base_sink_deactivate (basesink, pad);
1271       basesink->pad_mode = GST_ACTIVATE_NONE;
1272     }
1273   }
1274
1275   gst_object_unref (basesink);
1276
1277   return result;
1278 }
1279
1280 static GstStateChangeReturn
1281 gst_base_sink_change_state (GstElement * element, GstStateChange transition)
1282 {
1283   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1284   GstBaseSink *basesink = GST_BASE_SINK (element);
1285   GstBaseSinkClass *bclass;
1286
1287   bclass = GST_BASE_SINK_GET_CLASS (basesink);
1288
1289   switch (transition) {
1290     case GST_STATE_CHANGE_NULL_TO_READY:
1291       if (bclass->start)
1292         if (!bclass->start (basesink))
1293           goto start_failed;
1294       break;
1295     case GST_STATE_CHANGE_READY_TO_PAUSED:
1296       /* need to complete preroll before this state change completes, there
1297        * is no data flow in READY so we can safely assume we need to preroll. */
1298       basesink->offset = 0;
1299       GST_PREROLL_LOCK (basesink->sinkpad);
1300       basesink->have_preroll = FALSE;
1301       GST_DEBUG_OBJECT (basesink, "READY to PAUSED, need preroll to FALSE");
1302       basesink->need_preroll = TRUE;
1303       GST_PREROLL_UNLOCK (basesink->sinkpad);
1304       basesink->have_newsegment = FALSE;
1305       basesink->segment_rate = 1.0;
1306       basesink->segment_start = 0;
1307       basesink->segment_stop = 0;
1308       ret = GST_STATE_CHANGE_ASYNC;
1309       break;
1310     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1311     {
1312       GST_PREROLL_LOCK (basesink->sinkpad);
1313       /* if we have EOS, we should empty the queue now as there will
1314        * be no more data received in the chain function.
1315        * FIXME, this could block the state change function too long when
1316        * we are pushing and syncing the buffers, better start a new
1317        * thread to do this. */
1318       if (basesink->eos) {
1319         gst_base_sink_preroll_queue_empty (basesink, basesink->sinkpad);
1320       } else if (!basesink->have_preroll) {
1321         /* don't need preroll, but do queue a commit_state */
1322         GST_DEBUG_OBJECT (basesink,
1323             "PAUSED to PLAYING, !eos, !have_preroll, need preroll to FALSE");
1324         basesink->need_preroll = FALSE;
1325         basesink->playing_async = TRUE;
1326         ret = GST_STATE_CHANGE_ASYNC;
1327         /* we know it's not waiting, no need to signal */
1328       } else {
1329         /* don't need the preroll anymore */
1330         basesink->need_preroll = FALSE;
1331         GST_DEBUG_OBJECT (basesink,
1332             "PAUSED to PLAYING, !eos, have_preroll, need preroll to FALSE");
1333         /* now let it play */
1334         GST_PREROLL_SIGNAL (basesink->sinkpad);
1335       }
1336       GST_PREROLL_UNLOCK (basesink->sinkpad);
1337       break;
1338     }
1339     default:
1340       break;
1341   }
1342
1343   {
1344     GstStateChangeReturn bret;
1345
1346     bret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1347
1348     if (bret != GST_STATE_CHANGE_SUCCESS)
1349       goto activate_failed;
1350   }
1351
1352   switch (transition) {
1353     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1354     {
1355       GstBaseSinkClass *bclass;
1356
1357       bclass = GST_BASE_SINK_GET_CLASS (basesink);
1358
1359       GST_PREROLL_LOCK (basesink->sinkpad);
1360       GST_LOCK (basesink);
1361       /* unlock clock wait if any */
1362       if (basesink->clock_id) {
1363         gst_clock_id_unschedule (basesink->clock_id);
1364       }
1365       GST_UNLOCK (basesink);
1366
1367       basesink->playing_async = FALSE;
1368
1369       /* unlock any subclasses */
1370       if (bclass->unlock)
1371         bclass->unlock (basesink);
1372
1373       /* if we don't have a preroll buffer and we have not received EOS,
1374        * we need to wait for a preroll */
1375       GST_DEBUG_OBJECT (basesink, "have_preroll: %d, EOS: %d",
1376           basesink->have_preroll, basesink->eos);
1377       if (!basesink->have_preroll && !basesink->eos) {
1378         GST_DEBUG_OBJECT (basesink, "PLAYING to PAUSED, need preroll to TRUE");
1379         basesink->need_preroll = TRUE;
1380         ret = GST_STATE_CHANGE_ASYNC;
1381       }
1382       GST_PREROLL_UNLOCK (basesink->sinkpad);
1383       break;
1384     }
1385     case GST_STATE_CHANGE_PAUSED_TO_READY:
1386       break;
1387     case GST_STATE_CHANGE_READY_TO_NULL:
1388       if (bclass->stop)
1389         if (!bclass->stop (basesink)) {
1390           GST_WARNING ("failed to stop");
1391         }
1392       break;
1393     default:
1394       break;
1395   }
1396
1397   return ret;
1398
1399   /* ERRORS */
1400 start_failed:
1401   {
1402     GST_DEBUG_OBJECT (basesink, "failed to start");
1403     return GST_STATE_CHANGE_FAILURE;
1404   }
1405 activate_failed:
1406   {
1407     GST_DEBUG_OBJECT (basesink,
1408         "element failed to change states -- activation problem?");
1409     return GST_STATE_CHANGE_FAILURE;
1410   }
1411 }