gst/base/gstbasesink.c: Add comment.
[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 ("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 ("popped buffer %p", obj);
385         ret = gst_base_sink_handle_buffer (basesink, GST_BUFFER (obj));
386       } else {
387         GST_DEBUG ("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 ("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 ("flushing queue %p", basesink);
407   if (q) {
408     while ((obj = g_queue_pop_head (q))) {
409       GST_DEBUG ("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 ("buffer end %" GST_TIME_FORMAT " <= segment start %"
542               GST_TIME_FORMAT ", dropping buffer", GST_TIME_ARGS (end),
543               GST_TIME_ARGS (basesink->segment_start));
544           goto dropping;
545         }
546       }
547       if (GST_CLOCK_TIME_IS_VALID (start) &&
548           GST_CLOCK_TIME_IS_VALID (basesink->segment_stop)) {
549         if (basesink->segment_stop <= start) {
550           GST_DEBUG ("buffer start %" GST_TIME_FORMAT " >= segment stop %"
551               GST_TIME_FORMAT ", dropping buffer", GST_TIME_ARGS (start),
552               GST_TIME_ARGS (basesink->segment_stop));
553           goto dropping;
554         }
555       }
556     }
557     basesink->preroll_queued++;
558     basesink->buffers_queued++;
559   }
560   GST_DEBUG ("now %d preroll, %d buffers, %d events on queue",
561       basesink->preroll_queued,
562       basesink->buffers_queued, basesink->events_queued);
563
564   if (basesink->playing_async)
565     goto playing_async;
566
567   /* check if we are prerolling */
568   if (!basesink->need_preroll)
569     goto no_preroll;
570
571   /* there is a buffer queued */
572   if (basesink->buffers_queued == 1) {
573     GST_DEBUG ("do preroll %p", obj);
574
575     /* if it's a buffer, we need to call the preroll method */
576     if (GST_IS_BUFFER (obj)) {
577       GstBaseSinkClass *bclass;
578       GstFlowReturn pres;
579
580       bclass = GST_BASE_SINK_GET_CLASS (basesink);
581       if (bclass->preroll)
582         if ((pres =
583                 bclass->preroll (basesink, GST_BUFFER (obj))) != GST_FLOW_OK)
584           goto preroll_failed;
585     }
586   }
587   length = basesink->preroll_queued;
588   GST_DEBUG ("prerolled length %d", length);
589
590   if (length == 1) {
591     gint t;
592
593     basesink->have_preroll = TRUE;
594     /* we are prerolling */
595     GST_PREROLL_UNLOCK (pad);
596
597     /* have to release STREAM_LOCK as we cannot take the STATE_LOCK
598      * inside the STREAM_LOCK */
599     t = GST_STREAM_UNLOCK_FULL (pad);
600     GST_DEBUG ("released stream lock %d times", t);
601     if (t <= 0) {
602       GST_WARNING ("STREAM_LOCK should have been locked !!");
603       g_warning ("STREAM_LOCK should have been locked !!");
604     }
605
606     /* now we commit our state */
607     GST_STATE_LOCK (basesink);
608     GST_DEBUG_OBJECT (basesink, "commit state");
609     gst_element_commit_state (GST_ELEMENT (basesink));
610     GST_STATE_UNLOCK (basesink);
611
612     /* reacquire stream lock, pad could be flushing now */
613     /* FIXME in glib, if t==0, the lock is still taken... hmmm */
614     if (t > 0)
615       GST_STREAM_LOCK_FULL (pad, t);
616
617     /* and wait if needed */
618     GST_PREROLL_LOCK (pad);
619
620     GST_LOCK (pad);
621     if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
622       goto flushing;
623     GST_UNLOCK (pad);
624
625     /* it is possible that the application set the state to PLAYING
626      * now in which case we don't need to block anymore. */
627     if (!basesink->need_preroll)
628       goto no_preroll;
629
630     length = basesink->preroll_queued;
631
632     g_assert (length == 1);
633   }
634
635   /* see if we need to block now. We cannot block on events, only
636    * on buffers, the reason is that events can be sent from the
637    * application thread and we don't want to block there. */
638   if (length > basesink->preroll_queue_max_len && !have_event) {
639     /* block until the state changes, or we get a flush, or something */
640     GST_DEBUG_OBJECT (basesink, "waiting to finish preroll");
641     GST_PREROLL_WAIT (pad);
642     GST_DEBUG_OBJECT (basesink, "done preroll");
643   }
644   GST_LOCK (pad);
645   if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
646     goto flushing;
647   GST_UNLOCK (pad);
648
649   GST_PREROLL_UNLOCK (pad);
650
651   return GST_FLOW_OK;
652
653 no_preroll:
654   {
655     GstFlowReturn ret;
656
657     GST_DEBUG ("no preroll needed");
658     /* maybe it was another sink that blocked in preroll, need to check for
659        buffers to drain */
660     basesink->have_preroll = FALSE;
661     ret = gst_base_sink_preroll_queue_empty (basesink, pad);
662     GST_PREROLL_UNLOCK (pad);
663
664     return ret;
665   }
666 dropping:
667   {
668     GstBuffer *buf;
669
670     buf = GST_BUFFER (g_queue_pop_tail (basesink->preroll_queue));
671
672     gst_buffer_unref (buf);
673     GST_PREROLL_UNLOCK (pad);
674
675     return GST_FLOW_OK;
676   }
677 playing_async:
678   {
679     GstFlowReturn ret;
680     gint t;
681
682     basesink->have_preroll = FALSE;
683     basesink->playing_async = FALSE;
684
685     /* handle buffer first */
686     ret = gst_base_sink_preroll_queue_empty (basesink, pad);
687
688     /* unroll locks, commit state, reacquire stream lock */
689     GST_PREROLL_UNLOCK (pad);
690     t = GST_STREAM_UNLOCK_FULL (pad);
691     GST_DEBUG ("released stream lock %d times", t);
692     if (t <= 0) {
693       GST_WARNING ("STREAM_LOCK should have been locked !!");
694       g_warning ("STREAM_LOCK should have been locked !!");
695     }
696     GST_STATE_LOCK (basesink);
697     GST_DEBUG_OBJECT (basesink, "commit state");
698     gst_element_commit_state (GST_ELEMENT (basesink));
699     GST_STATE_UNLOCK (basesink);
700     if (t > 0)
701       GST_STREAM_LOCK_FULL (pad, t);
702
703     return ret;
704   }
705 flushing:
706   {
707     GST_UNLOCK (pad);
708     gst_base_sink_preroll_queue_flush (basesink, pad);
709     GST_PREROLL_UNLOCK (pad);
710     GST_DEBUG ("pad is flushing");
711     return GST_FLOW_WRONG_STATE;
712   }
713 preroll_failed:
714   {
715     gint t;
716
717     GST_DEBUG ("preroll failed");
718     gst_base_sink_preroll_queue_flush (basesink, pad);
719     GST_PREROLL_UNLOCK (pad);
720
721     /* have to release STREAM_LOCK as we cannot take the STATE_LOCK
722      * inside the STREAM_LOCK */
723     t = GST_STREAM_UNLOCK_FULL (pad);
724     GST_DEBUG ("released stream lock %d times", t);
725     if (t <= 0) {
726       GST_WARNING ("STREAM_LOCK should have been locked !!");
727       g_warning ("STREAM_LOCK should have been locked !!");
728     }
729
730     /* now we abort our state */
731     GST_STATE_LOCK (basesink);
732     GST_DEBUG_OBJECT (basesink, "abort state");
733     gst_element_abort_state (GST_ELEMENT (basesink));
734     GST_STATE_UNLOCK (basesink);
735
736     /* reacquire stream lock, pad could be flushing now */
737     if (t > 0)
738       GST_STREAM_LOCK_FULL (pad, t);
739
740     return GST_FLOW_ERROR;
741   }
742 }
743
744 static gboolean
745 gst_base_sink_event (GstPad * pad, GstEvent * event)
746 {
747   GstBaseSink *basesink;
748   gboolean result = TRUE;
749   GstBaseSinkClass *bclass;
750
751   basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
752
753   bclass = GST_BASE_SINK_GET_CLASS (basesink);
754
755   GST_DEBUG ("event %p", event);
756
757   switch (GST_EVENT_TYPE (event)) {
758     case GST_EVENT_EOS:
759     {
760       GstFlowReturn ret;
761
762       GST_STREAM_LOCK (pad);
763       /* EOS also finishes the preroll */
764       ret =
765           gst_base_sink_handle_object (basesink, pad, GST_MINI_OBJECT (event));
766       GST_STREAM_UNLOCK (pad);
767       break;
768     }
769     case GST_EVENT_NEWSEGMENT:
770     {
771       GstFlowReturn ret;
772
773       GST_STREAM_LOCK (pad);
774       ret =
775           gst_base_sink_handle_object (basesink, pad, GST_MINI_OBJECT (event));
776       GST_STREAM_UNLOCK (pad);
777       break;
778     }
779     case GST_EVENT_FLUSH_START:
780       /* make sure we are not blocked on the clock also clear any pending
781        * eos state. */
782       if (bclass->event)
783         bclass->event (basesink, event);
784
785       GST_PREROLL_LOCK (pad);
786       /* we need preroll after the flush */
787       basesink->need_preroll = TRUE;
788       /* unlock from a possible state change/preroll */
789       gst_base_sink_preroll_queue_flush (basesink, pad);
790
791       GST_LOCK (basesink);
792       if (basesink->clock_id) {
793         gst_clock_id_unschedule (basesink->clock_id);
794       }
795       GST_UNLOCK (basesink);
796       GST_PREROLL_UNLOCK (pad);
797
798       /* and we need to commit our state again on the next
799        * prerolled buffer */
800       GST_STATE_LOCK (basesink);
801       GST_STREAM_LOCK (pad);
802       gst_element_lost_state (GST_ELEMENT (basesink));
803       GST_STREAM_UNLOCK (pad);
804       GST_STATE_UNLOCK (basesink);
805       GST_DEBUG ("event unref %p %p", basesink, event);
806       gst_event_unref (event);
807       break;
808     case GST_EVENT_FLUSH_STOP:
809       if (bclass->event)
810         bclass->event (basesink, event);
811
812       /* now we are completely unblocked and the _chain method
813        * will return */
814       GST_STREAM_LOCK (pad);
815       /* we need new segment info after the flush. */
816       basesink->segment_start = -1;
817       basesink->segment_stop = -1;
818       basesink->current_start = -1;
819       basesink->current_end = -1;
820       GST_DEBUG ("reset accum %" GST_TIME_FORMAT,
821           GST_TIME_ARGS (basesink->segment_accum));
822       basesink->segment_accum = 0;
823       GST_STREAM_UNLOCK (pad);
824
825       GST_DEBUG ("event unref %p %p", basesink, event);
826       gst_event_unref (event);
827       break;
828     default:
829       gst_event_unref (event);
830       break;
831   }
832   gst_object_unref (basesink);
833
834   return result;
835 }
836
837 /* default implementation to calculate the start and end
838  * timestamps on a buffer, subclasses can override
839  */
840 static void
841 gst_base_sink_get_times (GstBaseSink * basesink, GstBuffer * buffer,
842     GstClockTime * start, GstClockTime * end)
843 {
844   GstClockTime timestamp, duration;
845
846   timestamp = GST_BUFFER_TIMESTAMP (buffer);
847   if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
848
849     /* get duration to calculate end time */
850     duration = GST_BUFFER_DURATION (buffer);
851     if (GST_CLOCK_TIME_IS_VALID (duration)) {
852       *end = timestamp + duration;
853     }
854     *start = timestamp;
855   }
856 }
857
858 /* perform synchronisation on a buffer
859  * 
860  * 1) check if we have a clock, if not, do nothing
861  * 2) calculate the start and end time of the buffer
862  * 3) create a single shot notification to wait on
863  *    the clock, save the entry so we can unlock it
864  * 4) wait on the clock, this blocks
865  * 5) unref the clockid again
866  */
867 static gboolean
868 gst_base_sink_do_sync (GstBaseSink * basesink, GstBuffer * buffer)
869 {
870   gboolean result = TRUE;
871   GstClockTime start, end;
872   GstClockTimeDiff stream_start, stream_end;
873   GstBaseSinkClass *bclass;
874   gboolean start_valid, end_valid;
875
876   bclass = GST_BASE_SINK_GET_CLASS (basesink);
877
878   start = end = -1;
879   if (bclass->get_times)
880     bclass->get_times (basesink, buffer, &start, &end);
881
882   start_valid = GST_CLOCK_TIME_IS_VALID (start);
883   end_valid = GST_CLOCK_TIME_IS_VALID (start);
884
885   GST_DEBUG_OBJECT (basesink, "got times start: %" GST_TIME_FORMAT
886       ", end: %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (end));
887
888   /* if we don't have a timestamp, we don't sync */
889   if (!start_valid)
890     goto done;
891
892   /* save last times seen. */
893   basesink->current_start = start;
894   if (end_valid)
895     basesink->current_end = end;
896   else
897     basesink->current_end = start;
898
899   if (GST_CLOCK_TIME_IS_VALID (basesink->segment_stop)) {
900     /* check if not outside of the segment range, start is
901      * always valid here. */
902     if (start > basesink->segment_stop)
903       goto out_of_segment;
904   }
905
906   /* bring timestamp to stream time using last segment offset. */
907   if (GST_CLOCK_TIME_IS_VALID (basesink->segment_start)) {
908     /* check if not outside of the segment range */
909     if (end_valid && end < basesink->segment_start)
910       goto out_of_segment;
911
912     stream_start = (gint64) start - basesink->segment_start;
913     stream_end = (gint64) end - basesink->segment_start;
914   } else {
915     stream_start = (gint64) start;
916     stream_end = (gint64) end;
917   }
918
919   stream_start += basesink->segment_accum;
920   if (end_valid)
921     stream_end += basesink->segment_accum;
922
923   /* now do clocking */
924   if (basesink->clock) {
925     GstClockReturn ret;
926     GstClockTime base_time;
927
928     GST_LOCK (basesink);
929     base_time = GST_ELEMENT (basesink)->base_time;
930
931     GST_LOG_OBJECT (basesink,
932         "waiting for clock, base time %" GST_TIME_FORMAT,
933         GST_TIME_ARGS (base_time));
934
935     /* save clock id so that we can unlock it if needed */
936     basesink->clock_id = gst_clock_new_single_shot_id (basesink->clock,
937         stream_start + base_time);
938     /* also save end_time of this buffer so that we can wait
939      * to signal EOS */
940     if (end_valid)
941       basesink->end_time = stream_end + base_time;
942     else
943       basesink->end_time = GST_CLOCK_TIME_NONE;
944     GST_UNLOCK (basesink);
945
946     ret = gst_clock_id_wait (basesink->clock_id, NULL);
947
948     GST_LOCK (basesink);
949     if (basesink->clock_id) {
950       gst_clock_id_unref (basesink->clock_id);
951       basesink->clock_id = NULL;
952     }
953     GST_UNLOCK (basesink);
954
955     GST_LOG_OBJECT (basesink, "clock entry done: %d", ret);
956     if (ret == GST_CLOCK_UNSCHEDULED)
957       result = FALSE;
958   }
959
960 done:
961   return result;
962
963 out_of_segment:
964   {
965     GST_LOG_OBJECT (basesink, "buffer skipped, not in segment");
966     return FALSE;
967   }
968 }
969
970
971 /* handle an event
972  *
973  * 2) render the event
974  * 3) unref the event
975  */
976 static inline gboolean
977 gst_base_sink_handle_event (GstBaseSink * basesink, GstEvent * event)
978 {
979   GstBaseSinkClass *bclass;
980   gboolean ret;
981
982   switch (GST_EVENT_TYPE (event)) {
983     case GST_EVENT_EOS:
984       GST_LOCK (basesink);
985       if (basesink->clock) {
986         /* wait for last buffer to finish if we have a valid end time */
987         if (GST_CLOCK_TIME_IS_VALID (basesink->end_time)) {
988           basesink->clock_id = gst_clock_new_single_shot_id (basesink->clock,
989               basesink->end_time);
990           GST_UNLOCK (basesink);
991
992           gst_clock_id_wait (basesink->clock_id, NULL);
993
994           GST_LOCK (basesink);
995           if (basesink->clock_id) {
996             gst_clock_id_unref (basesink->clock_id);
997             basesink->clock_id = NULL;
998           }
999           basesink->end_time = GST_CLOCK_TIME_NONE;
1000         }
1001       }
1002       GST_UNLOCK (basesink);
1003       break;
1004     default:
1005       break;
1006   }
1007
1008   bclass = GST_BASE_SINK_GET_CLASS (basesink);
1009   if (bclass->event)
1010     ret = bclass->event (basesink, event);
1011   else
1012     ret = TRUE;
1013
1014   switch (GST_EVENT_TYPE (event)) {
1015     case GST_EVENT_EOS:
1016       GST_PREROLL_LOCK (basesink->sinkpad);
1017       /* if we are still EOS, we can post the EOS message */
1018       if (basesink->eos) {
1019         /* ok, now we can post the message */
1020         GST_DEBUG_OBJECT (basesink, "Now posting EOS");
1021         gst_element_post_message (GST_ELEMENT (basesink),
1022             gst_message_new_eos (GST_OBJECT (basesink)));
1023       }
1024       GST_PREROLL_UNLOCK (basesink->sinkpad);
1025       break;
1026     default:
1027       break;
1028   }
1029
1030   GST_DEBUG ("event unref %p %p", basesink, event);
1031   gst_event_unref (event);
1032
1033   return ret;
1034 }
1035
1036 /* handle a buffer
1037  *
1038  * 1) first sync on the buffer
1039  * 2) render the buffer
1040  * 3) unref the buffer
1041  */
1042 static inline GstFlowReturn
1043 gst_base_sink_handle_buffer (GstBaseSink * basesink, GstBuffer * buf)
1044 {
1045   GstFlowReturn ret = GST_FLOW_OK;
1046   gboolean render;
1047
1048   render = gst_base_sink_do_sync (basesink, buf);
1049
1050   if (render) {
1051     GstBaseSinkClass *bclass;
1052
1053     bclass = GST_BASE_SINK_GET_CLASS (basesink);
1054     if (bclass->render)
1055       ret = bclass->render (basesink, buf);
1056   }
1057
1058   GST_DEBUG ("buffer unref after render %p", basesink, buf);
1059   gst_buffer_unref (buf);
1060
1061   return ret;
1062 }
1063
1064 static GstFlowReturn
1065 gst_base_sink_chain (GstPad * pad, GstBuffer * buf)
1066 {
1067   GstBaseSink *basesink;
1068   GstFlowReturn result;
1069
1070   basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
1071
1072   if (!(basesink->pad_mode == GST_ACTIVATE_PUSH)) {
1073     GST_LOCK (pad);
1074     g_warning ("Push on pad %s:%s, but it was not activated in push mode",
1075         GST_DEBUG_PAD_NAME (pad));
1076     GST_UNLOCK (pad);
1077     result = GST_FLOW_UNEXPECTED;
1078     goto done;
1079   }
1080
1081   result = gst_base_sink_handle_object (basesink, pad, GST_MINI_OBJECT (buf));
1082
1083 done:
1084   gst_object_unref (basesink);
1085
1086   return result;
1087 }
1088
1089 static void
1090 gst_base_sink_loop (GstPad * pad)
1091 {
1092   GstBaseSink *basesink;
1093   GstBuffer *buf = NULL;
1094   GstFlowReturn result;
1095
1096   basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
1097
1098   g_assert (basesink->pad_mode == GST_ACTIVATE_PULL);
1099
1100   result = gst_pad_pull_range (pad, basesink->offset, DEFAULT_SIZE, &buf);
1101   if (result != GST_FLOW_OK)
1102     goto paused;
1103
1104   result = gst_base_sink_handle_object (basesink, pad, GST_MINI_OBJECT (buf));
1105   if (result != GST_FLOW_OK)
1106     goto paused;
1107
1108   gst_object_unref (basesink);
1109
1110   /* default */
1111   return;
1112
1113 paused:
1114   {
1115     gst_base_sink_event (pad, gst_event_new_eos ());
1116     gst_object_unref (basesink);
1117     gst_pad_pause_task (pad);
1118     return;
1119   }
1120 }
1121
1122 static gboolean
1123 gst_base_sink_deactivate (GstBaseSink * basesink, GstPad * pad)
1124 {
1125   gboolean result = FALSE;
1126   GstBaseSinkClass *bclass;
1127
1128   bclass = GST_BASE_SINK_GET_CLASS (basesink);
1129
1130   /* step 1, unblock clock sync (if any) or any other blocking thing */
1131   GST_PREROLL_LOCK (pad);
1132   GST_LOCK (basesink);
1133   if (basesink->clock_id) {
1134     gst_clock_id_unschedule (basesink->clock_id);
1135   }
1136   GST_UNLOCK (basesink);
1137
1138   /* unlock any subclasses */
1139   if (bclass->unlock)
1140     bclass->unlock (basesink);
1141
1142   /* flush out the data thread if it's locked in finish_preroll */
1143   basesink->need_preroll = FALSE;
1144   gst_base_sink_preroll_queue_flush (basesink, pad);
1145   GST_PREROLL_SIGNAL (pad);
1146   GST_PREROLL_UNLOCK (pad);
1147
1148   /* step 2, make sure streaming finishes */
1149   result = gst_pad_stop_task (pad);
1150
1151   return result;
1152 }
1153
1154 static gboolean
1155 gst_base_sink_activate (GstPad * pad)
1156 {
1157   gboolean result = FALSE;
1158   GstBaseSink *basesink;
1159
1160   basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
1161
1162   GST_DEBUG_OBJECT (basesink, "Trying pull mode first");
1163
1164   if (basesink->can_activate_pull && gst_pad_check_pull_range (pad)
1165       && gst_pad_activate_pull (pad, TRUE)) {
1166     GST_DEBUG_OBJECT (basesink, "Success activating pull mode");
1167     result = TRUE;
1168   } else {
1169     GST_DEBUG_OBJECT (basesink, "Falling back to push mode");
1170     if (gst_pad_activate_push (pad, TRUE)) {
1171       GST_DEBUG_OBJECT (basesink, "Success activating push mode");
1172       result = TRUE;
1173     }
1174   }
1175
1176   if (!result) {
1177     GST_WARNING_OBJECT (basesink, "Could not activate pad in either mode");
1178   }
1179
1180   gst_object_unref (basesink);
1181
1182   return result;
1183 }
1184
1185 static gboolean
1186 gst_base_sink_activate_push (GstPad * pad, gboolean active)
1187 {
1188   gboolean result;
1189   GstBaseSink *basesink;
1190
1191   basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
1192
1193   if (active) {
1194     if (!basesink->can_activate_push) {
1195       result = FALSE;
1196       basesink->pad_mode = GST_ACTIVATE_NONE;
1197     } else {
1198       result = TRUE;
1199       basesink->pad_mode = GST_ACTIVATE_PUSH;
1200     }
1201   } else {
1202     if (G_UNLIKELY (basesink->pad_mode != GST_ACTIVATE_PUSH)) {
1203       g_warning ("Internal GStreamer activation error!!!");
1204       result = FALSE;
1205     } else {
1206       result = gst_base_sink_deactivate (basesink, pad);
1207       basesink->pad_mode = GST_ACTIVATE_NONE;
1208     }
1209   }
1210
1211   gst_object_unref (basesink);
1212
1213   return result;
1214 }
1215
1216 /* this won't get called until we implement an activate function */
1217 static gboolean
1218 gst_base_sink_activate_pull (GstPad * pad, gboolean active)
1219 {
1220   gboolean result = FALSE;
1221   GstBaseSink *basesink;
1222
1223   basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
1224
1225   if (active) {
1226     if (!basesink->can_activate_pull) {
1227       result = FALSE;
1228       basesink->pad_mode = GST_ACTIVATE_NONE;
1229     } else {
1230       GstPad *peer = gst_pad_get_peer (pad);
1231
1232       if (G_UNLIKELY (peer == NULL)) {
1233         g_warning ("Trying to activate pad in pull mode, but no peer");
1234         result = FALSE;
1235       } else {
1236         if (gst_pad_activate_pull (peer, TRUE)) {
1237           basesink->have_newsegment = TRUE;
1238           basesink->segment_start = basesink->segment_stop = 0;
1239           result =
1240               gst_pad_start_task (pad, (GstTaskFunction) gst_base_sink_loop,
1241               pad);
1242         } else {
1243           GST_DEBUG_OBJECT (pad, "Failed to activate peer in pull mode");
1244           result = FALSE;
1245         }
1246         gst_object_unref (peer);
1247       }
1248
1249       basesink->pad_mode = result ? GST_ACTIVATE_PULL : GST_ACTIVATE_NONE;
1250     }
1251   } else {
1252     if (G_UNLIKELY (basesink->pad_mode != GST_ACTIVATE_PULL)) {
1253       g_warning ("Internal GStreamer activation error!!!");
1254       result = FALSE;
1255     } else {
1256       basesink->have_newsegment = FALSE;
1257       result = gst_base_sink_deactivate (basesink, pad);
1258       basesink->pad_mode = GST_ACTIVATE_NONE;
1259     }
1260   }
1261
1262   gst_object_unref (basesink);
1263
1264   return result;
1265 }
1266
1267 static GstStateChangeReturn
1268 gst_base_sink_change_state (GstElement * element, GstStateChange transition)
1269 {
1270   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1271   GstBaseSink *basesink = GST_BASE_SINK (element);
1272   GstBaseSinkClass *bclass;
1273
1274   bclass = GST_BASE_SINK_GET_CLASS (basesink);
1275
1276   switch (transition) {
1277     case GST_STATE_CHANGE_NULL_TO_READY:
1278       if (bclass->start)
1279         if (!bclass->start (basesink))
1280           goto start_failed;
1281       break;
1282     case GST_STATE_CHANGE_READY_TO_PAUSED:
1283       /* need to complete preroll before this state change completes, there
1284        * is no data flow in READY so we can safely assume we need to preroll. */
1285       basesink->offset = 0;
1286       GST_PREROLL_LOCK (basesink->sinkpad);
1287       basesink->have_preroll = FALSE;
1288       basesink->need_preroll = TRUE;
1289       GST_PREROLL_UNLOCK (basesink->sinkpad);
1290       basesink->have_newsegment = FALSE;
1291       basesink->segment_rate = 1.0;
1292       basesink->segment_start = 0;
1293       basesink->segment_stop = 0;
1294       ret = GST_STATE_CHANGE_ASYNC;
1295       break;
1296     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1297     {
1298       GST_PREROLL_LOCK (basesink->sinkpad);
1299       /* if we have EOS, we should empty the queue now as there will
1300        * be no more data received in the chain function.
1301        * FIXME, this could block the state change function too long when
1302        * we are pushing and syncing the buffers, better start a new
1303        * thread to do this. */
1304       if (basesink->eos) {
1305         gst_base_sink_preroll_queue_empty (basesink, basesink->sinkpad);
1306       } else if (!basesink->have_preroll) {
1307         /* don't need preroll, but do queue a commit_state */
1308         basesink->need_preroll = FALSE;
1309         basesink->playing_async = TRUE;
1310         ret = GST_STATE_CHANGE_ASYNC;
1311         /* we know it's not waiting, no need to signal */
1312       } else {
1313         /* don't need the preroll anymore */
1314         basesink->need_preroll = FALSE;
1315         /* now let it play */
1316         GST_PREROLL_SIGNAL (basesink->sinkpad);
1317       }
1318       GST_PREROLL_UNLOCK (basesink->sinkpad);
1319       break;
1320     }
1321     default:
1322       break;
1323   }
1324
1325   {
1326     GstStateChangeReturn bret;
1327
1328     bret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1329
1330     if (bret != GST_STATE_CHANGE_SUCCESS)
1331       goto activate_failed;
1332   }
1333
1334   switch (transition) {
1335     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1336     {
1337       GstBaseSinkClass *bclass;
1338
1339       bclass = GST_BASE_SINK_GET_CLASS (basesink);
1340
1341       GST_PREROLL_LOCK (basesink->sinkpad);
1342       GST_LOCK (basesink);
1343       /* unlock clock wait if any */
1344       if (basesink->clock_id) {
1345         gst_clock_id_unschedule (basesink->clock_id);
1346       }
1347       GST_UNLOCK (basesink);
1348
1349       basesink->playing_async = FALSE;
1350
1351       /* unlock any subclasses */
1352       if (bclass->unlock)
1353         bclass->unlock (basesink);
1354
1355       /* if we don't have a preroll buffer and we have not received EOS,
1356        * we need to wait for a preroll */
1357       GST_DEBUG ("have_preroll: %d, EOS: %d", basesink->have_preroll,
1358           basesink->eos);
1359       if (!basesink->have_preroll && !basesink->eos) {
1360         basesink->need_preroll = TRUE;
1361         ret = GST_STATE_CHANGE_ASYNC;
1362       }
1363       GST_PREROLL_UNLOCK (basesink->sinkpad);
1364       break;
1365     }
1366     case GST_STATE_CHANGE_PAUSED_TO_READY:
1367       break;
1368     case GST_STATE_CHANGE_READY_TO_NULL:
1369       if (bclass->stop)
1370         if (!bclass->stop (basesink)) {
1371           GST_WARNING ("failed to stop");
1372         }
1373       break;
1374     default:
1375       break;
1376   }
1377
1378   return ret;
1379
1380   /* ERRORS */
1381 start_failed:
1382   {
1383     GST_DEBUG ("failed to start");
1384     return GST_STATE_CHANGE_FAILURE;
1385   }
1386 activate_failed:
1387   {
1388     GST_DEBUG ("element failed to change states -- activation problem?");
1389     return GST_STATE_CHANGE_FAILURE;
1390   }
1391 }