2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3 * 2000,2005 Wim Taymans <wim@fluendo.com>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
31 #include "gstbasesrc.h"
32 #include "gsttypefindhelper.h"
33 #include <gst/gstmarshal.h>
35 #define DEFAULT_BLOCKSIZE 4096
37 GST_DEBUG_CATEGORY_STATIC (gst_basesrc_debug);
38 #define GST_CAT_DEFAULT gst_basesrc_debug
40 /* BaseSrc signals and args */
53 static GstElementClass *parent_class = NULL;
55 static void gst_basesrc_base_init (gpointer g_class);
56 static void gst_basesrc_class_init (GstBaseSrcClass * klass);
57 static void gst_basesrc_init (GstBaseSrc * src, gpointer g_class);
60 gst_basesrc_get_type (void)
62 static GType basesrc_type = 0;
65 static const GTypeInfo basesrc_info = {
66 sizeof (GstBaseSrcClass),
67 (GBaseInitFunc) gst_basesrc_base_init,
69 (GClassInitFunc) gst_basesrc_class_init,
74 (GInstanceInitFunc) gst_basesrc_init,
77 basesrc_type = g_type_register_static (GST_TYPE_ELEMENT,
78 "GstBaseSrc", &basesrc_info, G_TYPE_FLAG_ABSTRACT);
83 static gboolean gst_basesrc_activate (GstPad * pad, GstActivateMode mode);
84 static void gst_basesrc_set_property (GObject * object, guint prop_id,
85 const GValue * value, GParamSpec * pspec);
86 static void gst_basesrc_get_property (GObject * object, guint prop_id,
87 GValue * value, GParamSpec * pspec);
88 static gboolean gst_basesrc_event_handler (GstPad * pad, GstEvent * event);
89 static const GstEventMask *gst_basesrc_get_event_mask (GstPad * pad);
90 static const GstQueryType *gst_basesrc_get_query_types (GstPad * pad);
91 static gboolean gst_basesrc_query (GstPad * pad, GstQueryType type,
92 GstFormat * format, gint64 * value);
93 static const GstFormat *gst_basesrc_get_formats (GstPad * pad);
95 static gboolean gst_basesrc_unlock (GstBaseSrc * basesrc);
96 static gboolean gst_basesrc_get_size (GstBaseSrc * basesrc, guint64 * size);
97 static gboolean gst_basesrc_start (GstBaseSrc * basesrc);
98 static gboolean gst_basesrc_stop (GstBaseSrc * basesrc);
100 static GstElementStateReturn gst_basesrc_change_state (GstElement * element);
102 static void gst_basesrc_loop (GstPad * pad);
103 static gboolean gst_basesrc_check_get_range (GstPad * pad);
104 static GstFlowReturn gst_basesrc_get_range (GstPad * pad, guint64 offset,
105 guint length, GstBuffer ** buf);
108 gst_basesrc_base_init (gpointer g_class)
110 GST_DEBUG_CATEGORY_INIT (gst_basesrc_debug, "basesrc", 0, "basesrc element");
114 gst_basesrc_class_init (GstBaseSrcClass * klass)
116 GObjectClass *gobject_class;
117 GstElementClass *gstelement_class;
119 gobject_class = (GObjectClass *) klass;
120 gstelement_class = (GstElementClass *) klass;
122 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
124 gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_basesrc_set_property);
125 gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_basesrc_get_property);
127 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BLOCKSIZE,
128 g_param_spec_ulong ("blocksize", "Block size",
129 "Size in bytes to read per buffer", 1, G_MAXULONG, DEFAULT_BLOCKSIZE,
132 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_basesrc_change_state);
136 gst_basesrc_init (GstBaseSrc * basesrc, gpointer g_class)
139 GstPadTemplate *pad_template;
142 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
143 g_return_if_fail (pad_template != NULL);
145 pad = gst_pad_new_from_template (pad_template, "src");
147 gst_pad_set_activate_function (pad, gst_basesrc_activate);
148 gst_pad_set_event_function (pad, gst_basesrc_event_handler);
149 gst_pad_set_event_mask_function (pad, gst_basesrc_get_event_mask);
150 gst_pad_set_query_function (pad, gst_basesrc_query);
151 gst_pad_set_query_type_function (pad, gst_basesrc_get_query_types);
152 gst_pad_set_formats_function (pad, gst_basesrc_get_formats);
153 gst_pad_set_loop_function (pad, gst_basesrc_loop);
154 gst_pad_set_checkgetrange_function (pad, gst_basesrc_check_get_range);
155 gst_pad_set_getrange_function (pad, gst_basesrc_get_range);
156 /* hold ref to pad */
157 basesrc->srcpad = pad;
158 gst_element_add_pad (GST_ELEMENT (basesrc), pad);
160 basesrc->segment_start = -1;
161 basesrc->segment_end = -1;
162 basesrc->blocksize = DEFAULT_BLOCKSIZE;
164 GST_FLAG_UNSET (basesrc, GST_BASESRC_STARTED);
167 static const GstFormat *
168 gst_basesrc_get_formats (GstPad * pad)
170 static const GstFormat formats[] = {
179 static const GstQueryType *
180 gst_basesrc_get_query_types (GstPad * pad)
182 static const GstQueryType types[] = {
186 GST_QUERY_SEGMENT_END,
194 gst_basesrc_query (GstPad * pad, GstQueryType type,
195 GstFormat * format, gint64 * value)
197 GstBaseSrc *src = GST_BASESRC (GST_PAD_PARENT (pad));
199 if (*format == GST_FORMAT_DEFAULT)
200 *format = GST_FORMAT_BYTES;
203 case GST_QUERY_TOTAL:
205 case GST_FORMAT_BYTES:
209 ret = gst_basesrc_get_size (src, value);
210 GST_DEBUG ("getting length %d %lld", ret, *value);
213 case GST_FORMAT_PERCENT:
214 *value = GST_FORMAT_PERCENT_MAX;
220 case GST_QUERY_POSITION:
222 case GST_FORMAT_BYTES:
223 *value = src->offset;
225 case GST_FORMAT_PERCENT:
226 if (!gst_basesrc_get_size (src, value))
228 *value = src->offset * GST_FORMAT_PERCENT_MAX / *value;
234 case GST_QUERY_START:
235 *value = src->segment_start;
237 case GST_QUERY_SEGMENT_END:
238 *value = src->segment_end;
246 static const GstEventMask *
247 gst_basesrc_get_event_mask (GstPad * pad)
249 static const GstEventMask masks[] = {
250 {GST_EVENT_SEEK, GST_SEEK_METHOD_CUR | GST_SEEK_METHOD_SET |
251 GST_SEEK_METHOD_END | GST_SEEK_FLAG_FLUSH |
252 GST_SEEK_FLAG_SEGMENT_LOOP},
253 {GST_EVENT_FLUSH, 0},
261 gst_basesrc_do_seek (GstBaseSrc * src, GstEvent * event)
266 format = GST_EVENT_SEEK_FORMAT (event);
268 /* get seek format */
269 if (format == GST_FORMAT_DEFAULT)
270 format = GST_FORMAT_BYTES;
271 /* we can only seek bytes */
272 if (format != GST_FORMAT_BYTES)
275 /* get seek positions */
276 offset = GST_EVENT_SEEK_OFFSET (event);
277 src->segment_start = offset;
278 src->segment_end = GST_EVENT_SEEK_ENDOFFSET (event);
279 src->segment_loop = GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_SEGMENT_LOOP;
281 /* send flush start */
282 gst_pad_push_event (src->srcpad, gst_event_new_flush (FALSE));
284 /* unblock streaming thread */
285 gst_basesrc_unlock (src);
287 /* grab streaming lock */
288 GST_STREAM_LOCK (src->srcpad);
290 switch (GST_EVENT_SEEK_METHOD (event)) {
291 case GST_SEEK_METHOD_SET:
294 src->offset = MIN (offset, src->size);
295 GST_DEBUG_OBJECT (src, "seek set pending to %" G_GINT64_FORMAT,
298 case GST_SEEK_METHOD_CUR:
299 offset += src->offset;
300 src->offset = CLAMP (offset, 0, src->size);
301 GST_DEBUG_OBJECT (src, "seek cur pending to %" G_GINT64_FORMAT,
304 case GST_SEEK_METHOD_END:
307 offset = src->size + offset;
308 src->offset = MAX (0, offset);
309 GST_DEBUG_OBJECT (src, "seek end pending to %" G_GINT64_FORMAT,
316 gst_pad_push_event (src->srcpad, gst_event_new_flush (TRUE));
318 /* now send discont */
322 event = gst_event_new_discontinuous (1.0,
324 (gint64) src->segment_start, (gint64) src->segment_end, NULL);
326 gst_pad_push_event (src->srcpad, event);
329 /* and restart the task */
330 if (GST_RPAD_TASK (src->srcpad)) {
331 gst_task_start (GST_RPAD_TASK (src->srcpad));
333 GST_STREAM_UNLOCK (src->srcpad);
335 gst_event_unref (event);
342 GST_DEBUG_OBJECT (src, "seek error");
343 GST_STREAM_UNLOCK (src->srcpad);
344 gst_event_unref (event);
350 gst_basesrc_event_handler (GstPad * pad, GstEvent * event)
353 GstBaseSrcClass *bclass;
356 src = GST_BASESRC (GST_PAD_PARENT (pad));
357 bclass = GST_BASESRC_GET_CLASS (src);
360 result = bclass->event (src, event);
362 switch (GST_EVENT_TYPE (event)) {
364 return gst_basesrc_do_seek (src, event);
369 format = GST_EVENT_SIZE_FORMAT (event);
370 if (format == GST_FORMAT_DEFAULT)
371 format = GST_FORMAT_BYTES;
372 /* we can only accept bytes */
373 if (format != GST_FORMAT_BYTES)
376 src->blocksize = GST_EVENT_SIZE_VALUE (event);
377 g_object_notify (G_OBJECT (src), "blocksize");
380 case GST_EVENT_FLUSH:
381 /* cancel any blocking getrange */
382 if (!GST_EVENT_FLUSH_DONE (event))
383 gst_basesrc_unlock (src);
388 gst_event_unref (event);
394 gst_basesrc_set_property (GObject * object, guint prop_id, const GValue * value,
399 src = GST_BASESRC (object);
403 src->blocksize = g_value_get_ulong (value);
406 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
412 gst_basesrc_get_property (GObject * object, guint prop_id, GValue * value,
417 src = GST_BASESRC (object);
421 g_value_set_ulong (value, src->blocksize);
424 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
430 gst_basesrc_get_range_unlocked (GstPad * pad, guint64 offset, guint length,
435 GstBaseSrcClass *bclass;
437 src = GST_BASESRC (GST_OBJECT_PARENT (pad));
438 bclass = GST_BASESRC_GET_CLASS (src);
440 if (!GST_FLAG_IS_SET (src, GST_BASESRC_STARTED))
447 if (src->size != -1) {
448 if (offset + length > src->size) {
449 if (bclass->get_size)
450 bclass->get_size (src, &src->size);
452 if (offset + length > src->size) {
453 length = src->size - offset;
458 goto unexpected_length;
460 ret = bclass->create (src, offset, length, buf);
467 GST_DEBUG_OBJECT (src, "getrange but not started");
468 return GST_FLOW_WRONG_STATE;
472 GST_DEBUG_OBJECT (src, "no create function");
473 return GST_FLOW_ERROR;
477 GST_DEBUG_OBJECT (src, "unexpected length %u", length);
478 return GST_FLOW_UNEXPECTED;
483 gst_basesrc_get_range (GstPad * pad, guint64 offset, guint length,
488 GST_STREAM_LOCK (pad);
490 fret = gst_basesrc_get_range_unlocked (pad, offset, length, ret);
492 GST_STREAM_UNLOCK (pad);
498 gst_basesrc_check_get_range (GstPad * pad)
502 src = GST_BASESRC (GST_OBJECT_PARENT (pad));
504 if (!GST_FLAG_IS_SET (src, GST_BASESRC_STARTED)) {
505 gst_basesrc_start (src);
506 gst_basesrc_stop (src);
509 return src->seekable;
513 gst_basesrc_loop (GstPad * pad)
516 GstBuffer *buf = NULL;
519 src = GST_BASESRC (GST_OBJECT_PARENT (pad));
521 GST_STREAM_LOCK (pad);
523 ret = gst_basesrc_get_range_unlocked (pad, src->offset, src->blocksize, &buf);
524 if (ret != GST_FLOW_OK)
527 src->offset += GST_BUFFER_SIZE (buf);
529 ret = gst_pad_push (pad, buf);
530 if (ret != GST_FLOW_OK)
533 GST_STREAM_UNLOCK (pad);
538 GST_DEBUG_OBJECT (src, "going to EOS");
539 gst_task_pause (GST_RPAD_TASK (pad));
540 gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
541 GST_STREAM_UNLOCK (pad);
546 GST_DEBUG_OBJECT (src, "pausing task");
547 gst_task_pause (GST_RPAD_TASK (pad));
548 GST_STREAM_UNLOCK (pad);
554 gst_basesrc_unlock (GstBaseSrc * basesrc)
556 GstBaseSrcClass *bclass;
557 gboolean result = FALSE;
559 bclass = GST_BASESRC_GET_CLASS (basesrc);
561 result = bclass->unlock (basesrc);
567 gst_basesrc_get_size (GstBaseSrc * basesrc, guint64 * size)
569 GstBaseSrcClass *bclass;
570 gboolean result = FALSE;
572 bclass = GST_BASESRC_GET_CLASS (basesrc);
573 if (bclass->get_size)
574 result = bclass->get_size (basesrc, size);
577 basesrc->size = *size;
583 gst_basesrc_start (GstBaseSrc * basesrc)
585 GstBaseSrcClass *bclass;
588 if (GST_FLAG_IS_SET (basesrc, GST_BASESRC_STARTED))
591 bclass = GST_BASESRC_GET_CLASS (basesrc);
593 result = bclass->start (basesrc);
598 goto could_not_start;
600 GST_FLAG_SET (basesrc, GST_BASESRC_STARTED);
602 /* start in the beginning */
604 basesrc->segment_start = 0;
606 /* figure out the size */
607 if (bclass->get_size) {
608 result = bclass->get_size (basesrc, &basesrc->size);
616 GST_DEBUG ("size %d %lld", result, basesrc->size);
618 /* we always run to the end */
619 basesrc->segment_end = -1;
621 /* check if we can seek */
622 if (bclass->is_seekable)
623 basesrc->seekable = bclass->is_seekable (basesrc);
625 basesrc->seekable = FALSE;
629 if (basesrc->seekable) {
632 caps = gst_type_find_helper (basesrc->srcpad, basesrc->size);
633 gst_pad_set_caps (basesrc->srcpad, caps);
642 GST_DEBUG_OBJECT (basesrc, "could not start");
648 gst_basesrc_stop (GstBaseSrc * basesrc)
650 GstBaseSrcClass *bclass;
651 gboolean result = TRUE;
653 if (!GST_FLAG_IS_SET (basesrc, GST_BASESRC_STARTED))
656 bclass = GST_BASESRC_GET_CLASS (basesrc);
658 result = bclass->stop (basesrc);
661 GST_FLAG_UNSET (basesrc, GST_BASESRC_STARTED);
667 gst_basesrc_activate (GstPad * pad, GstActivateMode mode)
672 basesrc = GST_BASESRC (GST_OBJECT_PARENT (pad));
674 /* prepare subclass first */
676 case GST_ACTIVATE_PUSH:
677 case GST_ACTIVATE_PULL:
678 result = gst_basesrc_start (basesrc);
684 /* if that failed we can stop here */
690 case GST_ACTIVATE_PUSH:
691 /* if we have a scheduler we can start the task */
692 if (GST_ELEMENT_SCHEDULER (basesrc)) {
693 GST_STREAM_LOCK (pad);
694 GST_RPAD_TASK (pad) =
695 gst_scheduler_create_task (GST_ELEMENT_SCHEDULER (basesrc),
696 (GstTaskFunction) gst_basesrc_loop, pad);
698 gst_task_start (GST_RPAD_TASK (pad));
699 GST_STREAM_UNLOCK (pad);
703 case GST_ACTIVATE_PULL:
706 case GST_ACTIVATE_NONE:
707 /* step 1, unblock clock sync (if any) */
709 /* step 2, make sure streaming finishes */
710 GST_STREAM_LOCK (pad);
711 /* step 3, stop the task */
712 if (GST_RPAD_TASK (pad)) {
713 gst_task_stop (GST_RPAD_TASK (pad));
714 gst_object_unref (GST_OBJECT (GST_RPAD_TASK (pad)));
715 GST_RPAD_TASK (pad) = NULL;
717 GST_STREAM_UNLOCK (pad);
727 GST_DEBUG_OBJECT (basesrc, "failed to start");
732 static GstElementStateReturn
733 gst_basesrc_change_state (GstElement * element)
736 GstElementStateReturn result = GST_STATE_FAILURE;
737 GstElementState transition;
739 basesrc = GST_BASESRC (element);
741 transition = GST_STATE_TRANSITION (element);
743 switch (transition) {
744 case GST_STATE_NULL_TO_READY:
746 case GST_STATE_READY_TO_PAUSED:
748 case GST_STATE_PAUSED_TO_PLAYING:
754 result = GST_ELEMENT_CLASS (parent_class)->change_state (element);
756 switch (transition) {
757 case GST_STATE_PLAYING_TO_PAUSED:
759 case GST_STATE_PAUSED_TO_READY:
760 result = gst_basesrc_stop (basesrc);
762 case GST_STATE_READY_TO_NULL: