2 * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
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.
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.
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.
26 #include "gstbasesink.h"
27 #include <gst/gstmarshal.h>
29 GST_DEBUG_CATEGORY_STATIC (gst_base_sink_debug);
30 #define GST_CAT_DEFAULT gst_base_sink_debug
32 /* BaseSink signals and properties */
40 /* FIXME, need to figure out a better way to handle the pull mode */
41 #define DEFAULT_SIZE 1024
42 #define DEFAULT_HAS_LOOP FALSE
43 #define DEFAULT_HAS_CHAIN TRUE
50 PROP_PREROLL_QUEUE_LEN
53 static GstElementClass *parent_class = NULL;
55 static void gst_base_sink_base_init (gpointer g_class);
56 static void gst_base_sink_class_init (GstBaseSinkClass * klass);
57 static void gst_base_sink_init (GstBaseSink * trans, gpointer g_class);
58 static void gst_base_sink_finalize (GObject * object);
61 gst_base_sink_get_type (void)
63 static GType base_sink_type = 0;
65 if (!base_sink_type) {
66 static const GTypeInfo base_sink_info = {
67 sizeof (GstBaseSinkClass),
68 (GBaseInitFunc) gst_base_sink_base_init,
70 (GClassInitFunc) gst_base_sink_class_init,
75 (GInstanceInitFunc) gst_base_sink_init,
78 base_sink_type = g_type_register_static (GST_TYPE_ELEMENT,
79 "GstBaseSink", &base_sink_info, G_TYPE_FLAG_ABSTRACT);
81 return base_sink_type;
84 static void gst_base_sink_set_clock (GstElement * element, GstClock * clock);
86 static void gst_base_sink_set_property (GObject * object, guint prop_id,
87 const GValue * value, GParamSpec * pspec);
88 static void gst_base_sink_get_property (GObject * object, guint prop_id,
89 GValue * value, GParamSpec * pspec);
91 static GstCaps *gst_base_sink_get_caps (GstBaseSink * sink);
92 static gboolean gst_base_sink_set_caps (GstBaseSink * sink, GstCaps * caps);
93 static GstFlowReturn gst_base_sink_buffer_alloc (GstBaseSink * sink,
94 guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
95 static void gst_base_sink_get_times (GstBaseSink * basesink, GstBuffer * buffer,
96 GstClockTime * start, GstClockTime * end);
98 static GstElementStateReturn gst_base_sink_change_state (GstElement * element);
100 static GstFlowReturn gst_base_sink_chain (GstPad * pad, GstBuffer * buffer);
101 static void gst_base_sink_loop (GstPad * pad);
102 static GstFlowReturn gst_base_sink_chain (GstPad * pad, GstBuffer * buffer);
103 static gboolean gst_base_sink_activate_push (GstPad * pad, gboolean active);
104 static gboolean gst_base_sink_activate_pull (GstPad * pad, gboolean active);
105 static gboolean gst_base_sink_event (GstPad * pad, GstEvent * event);
106 static inline GstFlowReturn gst_base_sink_handle_buffer (GstBaseSink * basesink,
108 static inline gboolean gst_base_sink_handle_event (GstBaseSink * basesink,
112 gst_base_sink_base_init (gpointer g_class)
114 GST_DEBUG_CATEGORY_INIT (gst_base_sink_debug, "basesink", 0,
119 gst_base_sink_class_init (GstBaseSinkClass * klass)
121 GObjectClass *gobject_class;
122 GstElementClass *gstelement_class;
124 gobject_class = (GObjectClass *) klass;
125 gstelement_class = (GstElementClass *) klass;
127 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
129 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_base_sink_finalize);
130 gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_base_sink_set_property);
131 gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_base_sink_get_property);
133 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_LOOP,
134 g_param_spec_boolean ("has-loop", "has-loop",
135 "Enable loop-based operation", DEFAULT_HAS_LOOP,
136 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
137 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_CHAIN,
138 g_param_spec_boolean ("has-chain", "has-chain",
139 "Enable chain-based operation", DEFAULT_HAS_CHAIN,
140 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
141 /* FIXME, this next value should be configured using an event from the
142 * upstream element */
143 g_object_class_install_property (G_OBJECT_CLASS (klass),
144 PROP_PREROLL_QUEUE_LEN,
145 g_param_spec_uint ("preroll-queue-len", "preroll-queue-len",
146 "Number of buffers to queue during preroll", 0, G_MAXUINT, 0,
147 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
149 gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_base_sink_set_clock);
150 gstelement_class->change_state =
151 GST_DEBUG_FUNCPTR (gst_base_sink_change_state);
153 klass->get_caps = GST_DEBUG_FUNCPTR (gst_base_sink_get_caps);
154 klass->set_caps = GST_DEBUG_FUNCPTR (gst_base_sink_set_caps);
155 klass->buffer_alloc = GST_DEBUG_FUNCPTR (gst_base_sink_buffer_alloc);
156 klass->get_times = GST_DEBUG_FUNCPTR (gst_base_sink_get_times);
160 gst_base_sink_pad_getcaps (GstPad * pad)
162 GstBaseSinkClass *bclass;
164 GstCaps *caps = NULL;
166 bsink = GST_BASESINK (GST_PAD_PARENT (pad));
167 bclass = GST_BASESINK_GET_CLASS (bsink);
168 if (bclass->get_caps)
169 caps = bclass->get_caps (bsink);
172 GstPadTemplate *pad_template;
175 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink");
176 if (pad_template != NULL) {
177 caps = gst_caps_ref (gst_pad_template_get_caps (pad_template));
185 gst_base_sink_pad_setcaps (GstPad * pad, GstCaps * caps)
187 GstBaseSinkClass *bclass;
189 gboolean res = FALSE;
191 bsink = GST_BASESINK (GST_PAD_PARENT (pad));
192 bclass = GST_BASESINK_GET_CLASS (bsink);
194 if (bclass->set_caps)
195 res = bclass->set_caps (bsink, caps);
201 gst_base_sink_pad_buffer_alloc (GstPad * pad, guint64 offset, guint size,
202 GstCaps * caps, GstBuffer ** buf)
204 GstBaseSinkClass *bclass;
206 GstFlowReturn result = GST_FLOW_OK;
208 bsink = GST_BASESINK (GST_PAD_PARENT (pad));
209 bclass = GST_BASESINK_GET_CLASS (bsink);
211 if (bclass->buffer_alloc)
212 result = bclass->buffer_alloc (bsink, offset, size, caps, buf);
220 gst_base_sink_init (GstBaseSink * basesink, gpointer g_class)
222 GstPadTemplate *pad_template;
225 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "sink");
226 g_return_if_fail (pad_template != NULL);
228 basesink->sinkpad = gst_pad_new_from_template (pad_template, "sink");
230 gst_pad_set_getcaps_function (basesink->sinkpad,
231 GST_DEBUG_FUNCPTR (gst_base_sink_pad_getcaps));
232 gst_pad_set_setcaps_function (basesink->sinkpad,
233 GST_DEBUG_FUNCPTR (gst_base_sink_pad_setcaps));
234 gst_pad_set_bufferalloc_function (basesink->sinkpad,
235 GST_DEBUG_FUNCPTR (gst_base_sink_pad_buffer_alloc));
236 gst_element_add_pad (GST_ELEMENT (basesink), basesink->sinkpad);
238 basesink->pad_mode = GST_ACTIVATE_NONE;
239 GST_PAD_TASK (basesink->sinkpad) = NULL;
240 basesink->preroll_queue = g_queue_new ();
242 GST_FLAG_SET (basesink, GST_ELEMENT_IS_SINK);
246 gst_base_sink_finalize (GObject * object)
248 GstBaseSink *basesink;
250 basesink = GST_BASESINK (object);
252 g_queue_free (basesink->preroll_queue);
254 G_OBJECT_CLASS (parent_class)->finalize (object);
258 gst_base_sink_set_pad_functions (GstBaseSink * this, GstPad * pad)
260 gst_pad_set_activatepush_function (pad,
261 GST_DEBUG_FUNCPTR (gst_base_sink_activate_push));
262 gst_pad_set_activatepull_function (pad,
263 GST_DEBUG_FUNCPTR (gst_base_sink_activate_pull));
264 gst_pad_set_event_function (pad, GST_DEBUG_FUNCPTR (gst_base_sink_event));
267 gst_pad_set_chain_function (pad, GST_DEBUG_FUNCPTR (gst_base_sink_chain));
269 gst_pad_set_chain_function (pad, NULL);
273 gst_base_sink_set_all_pad_functions (GstBaseSink * this)
277 for (l = GST_ELEMENT_PADS (this); l; l = l->next)
278 gst_base_sink_set_pad_functions (this, (GstPad *) l->data);
282 gst_base_sink_set_clock (GstElement * element, GstClock * clock)
286 sink = GST_BASESINK (element);
292 gst_base_sink_set_property (GObject * object, guint prop_id,
293 const GValue * value, GParamSpec * pspec)
297 sink = GST_BASESINK (object);
302 sink->has_loop = g_value_get_boolean (value);
303 gst_base_sink_set_all_pad_functions (sink);
308 sink->has_chain = g_value_get_boolean (value);
309 gst_base_sink_set_all_pad_functions (sink);
312 case PROP_PREROLL_QUEUE_LEN:
313 /* preroll lock necessary to serialize with finish_preroll */
314 GST_PREROLL_LOCK (sink->sinkpad);
315 sink->preroll_queue_max_len = g_value_get_uint (value);
316 GST_PREROLL_UNLOCK (sink->sinkpad);
319 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
325 gst_base_sink_get_property (GObject * object, guint prop_id, GValue * value,
330 sink = GST_BASESINK (object);
335 g_value_set_boolean (value, sink->has_loop);
338 g_value_set_boolean (value, sink->has_chain);
340 case PROP_PREROLL_QUEUE_LEN:
341 g_value_set_uint (value, sink->preroll_queue_max_len);
344 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
351 gst_base_sink_get_caps (GstBaseSink * sink)
357 gst_base_sink_set_caps (GstBaseSink * sink, GstCaps * caps)
363 gst_base_sink_buffer_alloc (GstBaseSink * sink, guint64 offset, guint size,
364 GstCaps * caps, GstBuffer ** buf)
370 /* with PREROLL_LOCK */
372 gst_base_sink_preroll_queue_empty (GstBaseSink * basesink, GstPad * pad)
375 GQueue *q = basesink->preroll_queue;
381 GST_DEBUG ("emptying queue");
382 while ((obj = g_queue_pop_head (q))) {
383 /* we release the preroll lock while pushing so that we
384 * can still flush it while blocking on the clock or
385 * inside the element. */
386 GST_PREROLL_UNLOCK (pad);
388 if (GST_IS_BUFFER (obj)) {
389 GST_DEBUG ("poped buffer %p", obj);
390 ret = gst_base_sink_handle_buffer (basesink, GST_BUFFER (obj));
392 GST_DEBUG ("poped event %p", obj);
393 gst_base_sink_handle_event (basesink, GST_EVENT (obj));
397 GST_PREROLL_LOCK (pad);
399 GST_DEBUG ("queue empty");
404 /* with PREROLL_LOCK */
406 gst_base_sink_preroll_queue_flush (GstBaseSink * basesink, GstPad * pad)
409 GQueue *q = basesink->preroll_queue;
411 GST_DEBUG ("flushing queue %p", basesink);
413 while ((obj = g_queue_pop_head (q))) {
414 GST_DEBUG ("poped %p", obj);
415 gst_mini_object_unref (obj);
418 /* we can't have EOS anymore now */
419 basesink->eos = FALSE;
420 /* and signal any waiters now */
421 GST_PREROLL_SIGNAL (pad);
424 /* with STREAM_LOCK */
426 gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad,
433 GST_PREROLL_LOCK (pad);
434 /* push object on the queue */
435 GST_DEBUG ("push on queue %p %p", basesink, obj);
436 g_queue_push_tail (basesink->preroll_queue, obj);
438 have_event = GST_IS_EVENT (obj);
440 if (have_event && GST_EVENT_TYPE (obj) == GST_EVENT_EOS) {
441 basesink->eos = TRUE;
444 /* check if we are prerolling */
445 if (!basesink->need_preroll)
448 length = basesink->preroll_queue->length;
449 /* this is the first object we queued */
451 GST_DEBUG ("do preroll %p", obj);
453 /* if it's a buffer, we need to call the preroll method */
454 if (GST_IS_BUFFER (obj)) {
455 GstBaseSinkClass *bclass;
457 bclass = GST_BASESINK_GET_CLASS (basesink);
459 bclass->preroll (basesink, GST_BUFFER (obj));
462 /* we are prerolling */
463 GST_DEBUG ("finish preroll %p >", basesink);
464 basesink->have_preroll = TRUE;
465 GST_PREROLL_UNLOCK (pad);
467 /* have to release STREAM_LOCK as we cannot take the STATE_LOCK
468 * inside the STREAM_LOCK */
469 t = GST_STREAM_UNLOCK_FULL (pad);
470 GST_DEBUG ("released stream lock %d times", t);
472 GST_WARNING ("STREAM_LOCK should have been locked !!");
473 g_warning ("STREAM_LOCK should have been locked !!");
476 /* now we commit our state */
477 GST_STATE_LOCK (basesink);
478 GST_DEBUG ("commit state %p >", basesink);
479 gst_element_commit_state (GST_ELEMENT (basesink));
480 GST_STATE_UNLOCK (basesink);
482 /* reacquire stream lock, pad could be flushing now */
483 /* FIXME in glib, if t==0, the lock is still taken... hmmm */
485 GST_STREAM_LOCK_FULL (pad, t);
487 /* and wait if needed */
488 GST_PREROLL_LOCK (pad);
491 if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
495 /* it is possible that the application set the state to PLAYING
496 * now in which case we don't need to block anymore. */
497 if (!basesink->need_preroll)
500 length = basesink->preroll_queue->length;
501 GST_DEBUG ("prerolled length %d", length);
502 /* see if we need to block now. We cannot block on events, only
503 * on buffers, the reason is that events can be sent from the
504 * application thread and we don't want to block there. */
505 if (length > basesink->preroll_queue_max_len && !have_event) {
506 /* block until the state changes, or we get a flush, or something */
507 GST_DEBUG ("element %s waiting to finish preroll",
508 GST_ELEMENT_NAME (basesink));
509 GST_PREROLL_WAIT (pad);
510 GST_DEBUG ("done preroll");
511 basesink->have_preroll = FALSE;
514 if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
518 GST_PREROLL_UNLOCK (pad);
526 GST_DEBUG ("no preroll needed");
527 /* maybe it was another sink that blocked in preroll, need to check for
529 basesink->have_preroll = FALSE;
530 ret = gst_base_sink_preroll_queue_empty (basesink, pad);
531 GST_PREROLL_UNLOCK (pad);
538 basesink->have_preroll = FALSE;
539 GST_PREROLL_UNLOCK (pad);
540 GST_DEBUG ("pad is flushing");
541 return GST_FLOW_WRONG_STATE;
546 gst_base_sink_event (GstPad * pad, GstEvent * event)
548 GstBaseSink *basesink;
549 gboolean result = TRUE;
550 GstBaseSinkClass *bclass;
552 basesink = GST_BASESINK (GST_OBJECT_PARENT (pad));
554 bclass = GST_BASESINK_GET_CLASS (basesink);
556 GST_DEBUG ("event %p", event);
558 switch (GST_EVENT_TYPE (event)) {
563 GST_STREAM_LOCK (pad);
564 /* EOS also finishes the preroll */
566 gst_base_sink_handle_object (basesink, pad, GST_MINI_OBJECT (event));
567 GST_STREAM_UNLOCK (pad);
570 case GST_EVENT_DISCONTINUOUS:
574 GST_STREAM_LOCK (pad);
575 if (basesink->clock) {
576 //gint64 value = GST_EVENT_DISCONT_OFFSET (event, 0).value;
579 gst_base_sink_handle_object (basesink, pad, GST_MINI_OBJECT (event));
580 GST_STREAM_UNLOCK (pad);
583 case GST_EVENT_FLUSH:
584 /* make sure we are not blocked on the clock also clear any pending
587 bclass->event (basesink, event);
589 if (!GST_EVENT_FLUSH_DONE (event)) {
590 GST_PREROLL_LOCK (pad);
591 /* we need preroll after the flush */
592 basesink->need_preroll = TRUE;
593 /* unlock from a possible state change/preroll */
594 gst_base_sink_preroll_queue_flush (basesink, pad);
597 if (basesink->clock_id) {
598 gst_clock_id_unschedule (basesink->clock_id);
600 GST_UNLOCK (basesink);
601 GST_PREROLL_UNLOCK (pad);
603 /* and we need to commit our state again on the next
604 * prerolled buffer */
605 GST_STATE_LOCK (basesink);
606 GST_STREAM_LOCK (pad);
607 gst_element_lost_state (GST_ELEMENT (basesink));
608 GST_STREAM_UNLOCK (pad);
609 GST_STATE_UNLOCK (basesink);
611 /* now we are completely unblocked and the _chain method
613 GST_STREAM_LOCK (pad);
614 GST_STREAM_UNLOCK (pad);
619 result = gst_pad_event_default (pad, event);
626 /* default implementation to calculate the start and end
627 * timestamps on a buffer, subclasses cna override
630 gst_base_sink_get_times (GstBaseSink * basesink, GstBuffer * buffer,
631 GstClockTime * start, GstClockTime * end)
633 GstClockTime timestamp, duration;
635 timestamp = GST_BUFFER_TIMESTAMP (buffer);
636 if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
637 duration = GST_BUFFER_DURATION (buffer);
638 if (GST_CLOCK_TIME_IS_VALID (duration)) {
639 *end = timestamp + duration;
645 /* perform synchronisation on a buffer
647 * 1) check if we have a clock, if not, do nothing
648 * 2) calculate the start and end time of the buffer
649 * 3) create a single shot notification to wait on
650 * the clock, save the entry so we can unlock it
651 * 4) wait on the clock, this blocks
652 * 5) unref the clockid again
655 gst_base_sink_do_sync (GstBaseSink * basesink, GstBuffer * buffer)
657 gboolean result = TRUE;
659 if (basesink->clock) {
660 GstClockTime start, end;
661 GstBaseSinkClass *bclass;
663 bclass = GST_BASESINK_GET_CLASS (basesink);
665 if (bclass->get_times)
666 bclass->get_times (basesink, buffer, &start, &end);
668 GST_DEBUG_OBJECT (basesink, "got times start: %" GST_TIME_FORMAT
669 ", end: %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (end));
671 if (GST_CLOCK_TIME_IS_VALID (start)) {
674 /* save clock id so that we can unlock it if needed */
676 basesink->clock_id = gst_clock_new_single_shot_id (basesink->clock,
677 start + GST_ELEMENT (basesink)->base_time);
678 basesink->end_time = end;
679 GST_UNLOCK (basesink);
681 ret = gst_clock_id_wait (basesink->clock_id, NULL);
684 if (basesink->clock_id) {
685 gst_clock_id_unref (basesink->clock_id);
686 basesink->clock_id = NULL;
688 GST_UNLOCK (basesink);
690 GST_LOG_OBJECT (basesink, "clock entry done: %d", ret);
691 if (ret == GST_CLOCK_UNSCHEDULED)
701 * 2) render the event
704 static inline gboolean
705 gst_base_sink_handle_event (GstBaseSink * basesink, GstEvent * event)
707 GstBaseSinkClass *bclass;
710 switch (GST_EVENT_TYPE (event)) {
713 if (basesink->clock) {
714 /* wait for last buffer to finish if we have a valid end time */
715 if (GST_CLOCK_TIME_IS_VALID (basesink->end_time)) {
716 basesink->clock_id = gst_clock_new_single_shot_id (basesink->clock,
717 basesink->end_time + GST_ELEMENT (basesink)->base_time);
718 GST_UNLOCK (basesink);
720 gst_clock_id_wait (basesink->clock_id, NULL);
723 if (basesink->clock_id) {
724 gst_clock_id_unref (basesink->clock_id);
725 basesink->clock_id = NULL;
727 basesink->end_time = GST_CLOCK_TIME_NONE;
730 GST_UNLOCK (basesink);
736 bclass = GST_BASESINK_GET_CLASS (basesink);
738 ret = bclass->event (basesink, event);
742 switch (GST_EVENT_TYPE (event)) {
744 GST_PREROLL_LOCK (basesink->sinkpad);
745 /* if we are still EOS, we can post the EOS message */
747 /* ok, now we can post the message */
748 gst_element_post_message (GST_ELEMENT (basesink),
749 gst_message_new_eos (GST_OBJECT (basesink)));
751 GST_PREROLL_UNLOCK (basesink->sinkpad);
757 GST_DEBUG ("event unref %p %p", basesink, event);
758 gst_event_unref (event);
765 * 1) first sync on the buffer
766 * 2) render the buffer
767 * 3) unref the buffer
769 static inline GstFlowReturn
770 gst_base_sink_handle_buffer (GstBaseSink * basesink, GstBuffer * buf)
772 GstBaseSinkClass *bclass;
775 gst_base_sink_do_sync (basesink, buf);
777 bclass = GST_BASESINK_GET_CLASS (basesink);
779 ret = bclass->render (basesink, buf);
783 GST_DEBUG ("buffer unref after render %p", basesink, buf);
784 gst_buffer_unref (buf);
790 gst_base_sink_chain (GstPad * pad, GstBuffer * buf)
792 GstBaseSink *basesink;
793 GstFlowReturn result;
795 basesink = GST_BASESINK (GST_OBJECT_PARENT (pad));
797 result = gst_base_sink_handle_object (basesink, pad, GST_MINI_OBJECT (buf));
802 /* FIXME, not all sinks can operate in pull mode
805 gst_base_sink_loop (GstPad * pad)
807 GstBaseSink *basesink;
808 GstBuffer *buf = NULL;
809 GstFlowReturn result;
811 basesink = GST_BASESINK (GST_OBJECT_PARENT (pad));
813 g_assert (basesink->pad_mode == GST_ACTIVATE_PULL);
815 result = gst_pad_pull_range (pad, basesink->offset, DEFAULT_SIZE, &buf);
816 if (result != GST_FLOW_OK)
819 result = gst_base_sink_chain (pad, buf);
820 if (result != GST_FLOW_OK)
827 gst_pad_pause_task (pad);
832 gst_base_sink_deactivate (GstBaseSink * basesink, GstPad * pad)
834 gboolean result = FALSE;
835 GstBaseSinkClass *bclass;
837 bclass = GST_BASESINK_GET_CLASS (basesink);
839 /* step 1, unblock clock sync (if any) or any other blocking thing */
840 GST_PREROLL_LOCK (pad);
842 if (basesink->clock_id) {
843 gst_clock_id_unschedule (basesink->clock_id);
845 GST_UNLOCK (basesink);
847 /* unlock any subclasses */
849 bclass->unlock (basesink);
851 /* flush out the data thread if it's locked in finish_preroll */
852 basesink->need_preroll = FALSE;
853 gst_base_sink_preroll_queue_flush (basesink, pad);
854 GST_PREROLL_UNLOCK (pad);
856 /* step 2, make sure streaming finishes */
857 result = gst_pad_stop_task (pad);
863 gst_base_sink_activate_push (GstPad * pad, gboolean active)
865 gboolean result = FALSE;
866 GstBaseSink *basesink;
868 basesink = GST_BASESINK (GST_OBJECT_PARENT (pad));
871 g_return_val_if_fail (basesink->has_chain, FALSE);
874 result = gst_base_sink_deactivate (basesink, pad);
876 basesink->pad_mode = GST_ACTIVATE_PUSH;
881 /* this won't get called until we implement an activate function */
883 gst_base_sink_activate_pull (GstPad * pad, gboolean active)
885 gboolean result = FALSE;
886 GstBaseSink *basesink;
888 basesink = GST_BASESINK (GST_OBJECT_PARENT (pad));
891 /* if we have a scheduler we can start the task */
892 g_return_val_if_fail (basesink->has_loop, FALSE);
894 gst_pad_start_task (pad, (GstTaskFunction) gst_base_sink_loop, pad);
896 result = gst_base_sink_deactivate (basesink, pad);
902 static GstElementStateReturn
903 gst_base_sink_change_state (GstElement * element)
905 GstElementStateReturn ret = GST_STATE_SUCCESS;
906 GstBaseSink *basesink = GST_BASESINK (element);
907 GstElementState transition = GST_STATE_TRANSITION (element);
909 switch (transition) {
910 case GST_STATE_NULL_TO_READY:
912 case GST_STATE_READY_TO_PAUSED:
913 /* need to complete preroll before this state change completes, there
914 * is no data flow in READY so we can safely assume we need to preroll. */
915 basesink->offset = 0;
916 GST_PREROLL_LOCK (basesink->sinkpad);
917 basesink->have_preroll = FALSE;
918 basesink->need_preroll = TRUE;
919 GST_PREROLL_UNLOCK (basesink->sinkpad);
920 ret = GST_STATE_ASYNC;
922 case GST_STATE_PAUSED_TO_PLAYING:
924 GST_PREROLL_LOCK (basesink->sinkpad);
925 /* if we have EOS, we should empty the queue now as there will
926 * be no more data received in the chain function.
927 * FIXME, this could block the state change function too long when
928 * we are pushing and syncing the buffers, better start a new
929 * thread to do this. */
931 gst_base_sink_preroll_queue_empty (basesink, basesink->sinkpad);
933 /* don't need the preroll anymore */
934 basesink->need_preroll = FALSE;
935 if (basesink->have_preroll) {
936 /* now let it play */
937 GST_PREROLL_SIGNAL (basesink->sinkpad);
939 GST_PREROLL_UNLOCK (basesink->sinkpad);
946 GST_ELEMENT_CLASS (parent_class)->change_state (element);
948 switch (transition) {
949 case GST_STATE_PLAYING_TO_PAUSED:
951 GstBaseSinkClass *bclass;
953 bclass = GST_BASESINK_GET_CLASS (basesink);
955 GST_PREROLL_LOCK (basesink->sinkpad);
957 /* unlock clock wait if any */
958 if (basesink->clock_id) {
959 gst_clock_id_unschedule (basesink->clock_id);
961 GST_UNLOCK (basesink);
963 /* unlock any subclasses */
965 bclass->unlock (basesink);
967 /* if we don't have a preroll buffer and we have not received EOS,
968 * we need to wait for a preroll */
969 GST_DEBUG ("have_preroll: %d, EOS: %d", basesink->have_preroll,
971 if (!basesink->have_preroll && !basesink->eos) {
972 basesink->need_preroll = TRUE;
973 ret = GST_STATE_ASYNC;
975 GST_PREROLL_UNLOCK (basesink->sinkpad);
978 case GST_STATE_PAUSED_TO_READY:
980 case GST_STATE_READY_TO_NULL: