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_base_src_debug);
38 #define GST_CAT_DEFAULT gst_base_src_debug
40 /* BaseSrc signals and args */
55 static GstElementClass *parent_class = NULL;
57 static void gst_base_src_base_init (gpointer g_class);
58 static void gst_base_src_class_init (GstBaseSrcClass * klass);
59 static void gst_base_src_init (GstBaseSrc * src, gpointer g_class);
62 gst_base_src_get_type (void)
64 static GType base_src_type = 0;
67 static const GTypeInfo base_src_info = {
68 sizeof (GstBaseSrcClass),
69 (GBaseInitFunc) gst_base_src_base_init,
71 (GClassInitFunc) gst_base_src_class_init,
76 (GInstanceInitFunc) gst_base_src_init,
79 base_src_type = g_type_register_static (GST_TYPE_ELEMENT,
80 "GstBaseSrc", &base_src_info, G_TYPE_FLAG_ABSTRACT);
85 static gboolean gst_base_src_activate_push (GstPad * pad, gboolean active);
86 static gboolean gst_base_src_activate_pull (GstPad * pad, gboolean active);
87 static void gst_base_src_set_property (GObject * object, guint prop_id,
88 const GValue * value, GParamSpec * pspec);
89 static void gst_base_src_get_property (GObject * object, guint prop_id,
90 GValue * value, GParamSpec * pspec);
91 static gboolean gst_base_src_event_handler (GstPad * pad, GstEvent * event);
93 static gboolean gst_base_src_query (GstPad * pad, GstQuery * query);
96 static const GstEventMask *gst_base_src_get_event_mask (GstPad * pad);
99 static gboolean gst_base_src_unlock (GstBaseSrc * basesrc);
100 static gboolean gst_base_src_get_size (GstBaseSrc * basesrc, guint64 * size);
101 static gboolean gst_base_src_start (GstBaseSrc * basesrc);
102 static gboolean gst_base_src_stop (GstBaseSrc * basesrc);
104 static GstElementStateReturn gst_base_src_change_state (GstElement * element);
106 static void gst_base_src_set_dataflow_funcs (GstBaseSrc * this);
107 static void gst_base_src_loop (GstPad * pad);
108 static gboolean gst_base_src_check_get_range (GstPad * pad);
109 static GstFlowReturn gst_base_src_get_range (GstPad * pad, guint64 offset,
110 guint length, GstBuffer ** buf);
113 gst_base_src_base_init (gpointer g_class)
115 GST_DEBUG_CATEGORY_INIT (gst_base_src_debug, "basesrc", 0, "basesrc element");
119 gst_base_src_class_init (GstBaseSrcClass * 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->set_property = GST_DEBUG_FUNCPTR (gst_base_src_set_property);
130 gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_base_src_get_property);
132 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BLOCKSIZE,
133 g_param_spec_ulong ("blocksize", "Block size",
134 "Size in bytes to read per buffer", 1, G_MAXULONG, DEFAULT_BLOCKSIZE,
137 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_LOOP,
138 g_param_spec_boolean ("has-loop", "Has loop function",
139 "True if the element should expose a loop function", TRUE,
140 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
142 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_GETRANGE,
143 g_param_spec_boolean ("has-getrange", "Has getrange function",
144 "True if the element should expose a getrange function", TRUE,
145 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
147 gstelement_class->change_state =
148 GST_DEBUG_FUNCPTR (gst_base_src_change_state);
152 gst_base_src_init (GstBaseSrc * basesrc, gpointer g_class)
155 GstPadTemplate *pad_template;
158 gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
159 g_return_if_fail (pad_template != NULL);
161 pad = gst_pad_new_from_template (pad_template, "src");
163 gst_pad_set_activatepush_function (pad, gst_base_src_activate_push);
164 gst_pad_set_activatepull_function (pad, gst_base_src_activate_pull);
165 gst_pad_set_event_function (pad, gst_base_src_event_handler);
166 gst_pad_set_query_function (pad, gst_base_src_query);
168 gst_pad_set_checkgetrange_function (pad, gst_base_src_check_get_range);
170 basesrc->is_live = FALSE;
171 basesrc->live_lock = g_mutex_new ();
172 basesrc->live_cond = g_cond_new ();
174 /* hold ref to pad */
175 basesrc->srcpad = pad;
176 gst_element_add_pad (GST_ELEMENT (basesrc), pad);
178 basesrc->segment_start = -1;
179 basesrc->segment_end = -1;
180 basesrc->blocksize = DEFAULT_BLOCKSIZE;
181 basesrc->clock_id = NULL;
183 GST_FLAG_UNSET (basesrc, GST_BASESRC_STARTED);
187 gst_base_src_set_live (GstBaseSrc * src, gboolean live)
191 GST_LIVE_UNLOCK (src);
195 gst_base_src_is_live (GstBaseSrc * src)
200 result = src->is_live;
201 GST_LIVE_UNLOCK (src);
207 gst_base_src_set_dataflow_funcs (GstBaseSrc * this)
209 GST_DEBUG ("updating dataflow functions");
211 if (this->has_getrange)
212 gst_pad_set_getrange_function (this->srcpad, gst_base_src_get_range);
214 gst_pad_set_getrange_function (this->srcpad, NULL);
218 gst_base_src_query (GstPad * pad, GstQuery * query)
225 src = GST_BASESRC (GST_PAD_PARENT (pad));
227 switch (GST_QUERY_TYPE (query)) {
228 case GST_QUERY_POSITION:
232 gst_query_parse_position (query, &format, NULL, NULL);
234 case GST_FORMAT_DEFAULT:
235 case GST_FORMAT_BYTES:
236 b = gst_base_src_get_size (src, &ui64);
237 /* better to make get_size take an int64 */
238 i64 = b ? (gint64) ui64 : -1;
239 gst_query_set_position (query, GST_FORMAT_BYTES, src->offset, i64);
241 case GST_FORMAT_PERCENT:
242 b = gst_base_src_get_size (src, &ui64);
243 i64 = GST_FORMAT_PERCENT_MAX;
244 i64 *= b ? (src->offset / (gdouble) ui64) : 1.0;
245 gst_query_set_position (query, GST_FORMAT_PERCENT,
246 i64, GST_FORMAT_PERCENT_MAX);
253 case GST_QUERY_SEEKING:
254 gst_query_set_seeking (query, GST_FORMAT_BYTES,
255 src->seekable, src->segment_start, src->segment_end);
258 case GST_QUERY_FORMATS:
259 gst_query_set_formats (query, 3, GST_FORMAT_DEFAULT,
260 GST_FORMAT_BYTES, GST_FORMAT_PERCENT);
263 case GST_QUERY_LATENCY:
264 case GST_QUERY_JITTER:
266 case GST_QUERY_CONVERT:
268 return gst_pad_query_default (pad, query);
273 static const GstEventMask *
274 gst_base_src_get_event_mask (GstPad * pad)
276 static const GstEventMask masks[] = {
277 {GST_EVENT_SEEK, GST_SEEK_METHOD_CUR | GST_SEEK_METHOD_SET |
278 GST_SEEK_METHOD_END | GST_SEEK_FLAG_FLUSH |
279 GST_SEEK_FLAG_SEGMENT_LOOP},
280 {GST_EVENT_FLUSH, 0},
289 gst_base_src_do_seek (GstBaseSrc * src, GstEvent * event)
294 format = GST_EVENT_SEEK_FORMAT (event);
296 /* get seek format */
297 if (format == GST_FORMAT_DEFAULT)
298 format = GST_FORMAT_BYTES;
299 /* we can only seek bytes */
300 if (format != GST_FORMAT_BYTES)
303 /* get seek positions */
304 offset = GST_EVENT_SEEK_OFFSET (event);
305 src->segment_loop = GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_SEGMENT_LOOP;
307 switch (GST_EVENT_SEEK_METHOD (event)) {
308 case GST_SEEK_METHOD_SET:
311 src->offset = MIN (offset, src->size);
312 src->segment_start = src->offset;
313 src->segment_end = MIN (GST_EVENT_SEEK_ENDOFFSET (event), src->size);
314 GST_DEBUG_OBJECT (src, "seek set pending to %" G_GINT64_FORMAT,
317 case GST_SEEK_METHOD_CUR:
318 offset += src->offset;
319 src->offset = CLAMP (offset, 0, src->size);
320 src->segment_start = src->offset;
321 src->segment_end = GST_EVENT_SEEK_ENDOFFSET (event);
322 GST_DEBUG_OBJECT (src, "seek cur pending to %" G_GINT64_FORMAT,
325 case GST_SEEK_METHOD_END:
328 offset = src->size + offset;
329 src->offset = MAX (0, offset);
330 src->segment_start = src->offset;
331 src->segment_end = GST_EVENT_SEEK_ENDOFFSET (event);
332 GST_DEBUG_OBJECT (src, "seek end pending to %" G_GINT64_FORMAT,
339 /* send flush start */
340 gst_pad_push_event (src->srcpad, gst_event_new_flush (FALSE));
342 /* unblock streaming thread */
343 gst_base_src_unlock (src);
345 /* grab streaming lock */
346 GST_STREAM_LOCK (src->srcpad);
349 gst_pad_push_event (src->srcpad, gst_event_new_flush (TRUE));
351 /* now send discont */
355 event = gst_event_new_discontinuous (1.0,
357 (gint64) src->segment_start, (gint64) src->segment_end, NULL);
359 gst_pad_push_event (src->srcpad, event);
362 /* and restart the task */
363 gst_pad_start_task (src->srcpad, (GstTaskFunction) gst_base_src_loop,
365 GST_STREAM_UNLOCK (src->srcpad);
367 gst_event_unref (event);
374 GST_DEBUG_OBJECT (src, "seek error");
375 gst_event_unref (event);
381 gst_base_src_event_handler (GstPad * pad, GstEvent * event)
384 GstBaseSrcClass *bclass;
387 src = GST_BASESRC (GST_PAD_PARENT (pad));
388 bclass = GST_BASESRC_GET_CLASS (src);
391 result = bclass->event (src, event);
393 switch (GST_EVENT_TYPE (event)) {
395 return gst_base_src_do_seek (src, event);
400 format = GST_EVENT_SIZE_FORMAT (event);
401 if (format == GST_FORMAT_DEFAULT)
402 format = GST_FORMAT_BYTES;
403 /* we can only accept bytes */
404 if (format != GST_FORMAT_BYTES)
407 src->blocksize = GST_EVENT_SIZE_VALUE (event);
408 g_object_notify (G_OBJECT (src), "blocksize");
411 case GST_EVENT_FLUSH:
412 /* cancel any blocking getrange */
413 if (!GST_EVENT_FLUSH_DONE (event))
414 gst_base_src_unlock (src);
419 gst_event_unref (event);
425 gst_base_src_set_property (GObject * object, guint prop_id,
426 const GValue * value, GParamSpec * pspec)
430 src = GST_BASESRC (object);
434 src->blocksize = g_value_get_ulong (value);
437 src->has_loop = g_value_get_boolean (value);
438 gst_base_src_set_dataflow_funcs (src);
440 case PROP_HAS_GETRANGE:
441 src->has_getrange = g_value_get_boolean (value);
442 gst_base_src_set_dataflow_funcs (src);
445 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
451 gst_base_src_get_property (GObject * object, guint prop_id, GValue * value,
456 src = GST_BASESRC (object);
460 g_value_set_ulong (value, src->blocksize);
463 g_value_set_boolean (value, src->has_loop);
465 case PROP_HAS_GETRANGE:
466 g_value_set_boolean (value, src->has_getrange);
469 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
475 gst_base_src_get_range (GstPad * pad, guint64 offset, guint length,
480 GstBaseSrcClass *bclass;
482 src = GST_BASESRC (GST_OBJECT_PARENT (pad));
483 bclass = GST_BASESRC_GET_CLASS (src);
487 while (!src->live_running) {
488 GST_DEBUG ("live source waiting for running state");
490 GST_DEBUG ("live source unlocked");
493 GST_LIVE_UNLOCK (src);
495 if (!GST_FLAG_IS_SET (src, GST_BASESRC_STARTED))
502 if (src->size != -1) {
503 if (offset > src->size)
504 goto unexpected_length;
506 if (offset + length > src->size) {
507 if (bclass->get_size)
508 bclass->get_size (src, &src->size);
510 if (offset + length > src->size) {
511 length = src->size - offset;
516 goto unexpected_length;
518 ret = bclass->create (src, offset, length, buf);
525 GST_DEBUG_OBJECT (src, "getrange but not started");
526 return GST_FLOW_WRONG_STATE;
530 GST_DEBUG_OBJECT (src, "no create function");
531 return GST_FLOW_ERROR;
535 GST_DEBUG_OBJECT (src, "unexpected length %u", length);
536 return GST_FLOW_UNEXPECTED;
541 gst_base_src_check_get_range (GstPad * pad)
545 src = GST_BASESRC (GST_OBJECT_PARENT (pad));
547 if (!GST_FLAG_IS_SET (src, GST_BASESRC_STARTED)) {
548 gst_base_src_start (src);
549 gst_base_src_stop (src);
552 return src->seekable;
556 gst_base_src_loop (GstPad * pad)
559 GstBuffer *buf = NULL;
562 src = GST_BASESRC (GST_OBJECT_PARENT (pad));
564 ret = gst_base_src_get_range (pad, src->offset, src->blocksize, &buf);
565 if (ret != GST_FLOW_OK)
568 src->offset += GST_BUFFER_SIZE (buf);
570 ret = gst_pad_push (pad, buf);
571 if (ret != GST_FLOW_OK)
578 GST_DEBUG_OBJECT (src, "going to EOS");
579 gst_pad_pause_task (pad);
580 gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
585 GST_DEBUG_OBJECT (src, "pausing task");
586 gst_pad_pause_task (pad);
592 gst_base_src_unlock (GstBaseSrc * basesrc)
594 GstBaseSrcClass *bclass;
595 gboolean result = FALSE;
597 GST_DEBUG ("unlock");
598 /* unblock whatever the subclass is doing */
599 bclass = GST_BASESRC_GET_CLASS (basesrc);
601 result = bclass->unlock (basesrc);
603 GST_DEBUG ("unschedule clock");
604 /* and unblock the clock as well, if any */
606 if (basesrc->clock_id) {
607 gst_clock_id_unschedule (basesrc->clock_id);
609 GST_UNLOCK (basesrc);
611 GST_DEBUG ("unlock done");
617 gst_base_src_get_size (GstBaseSrc * basesrc, guint64 * size)
619 GstBaseSrcClass *bclass;
620 gboolean result = FALSE;
622 bclass = GST_BASESRC_GET_CLASS (basesrc);
623 if (bclass->get_size)
624 result = bclass->get_size (basesrc, size);
627 basesrc->size = *size;
633 gst_base_src_is_seekable (GstBaseSrc * basesrc)
635 GstBaseSrcClass *bclass;
637 bclass = GST_BASESRC_GET_CLASS (basesrc);
639 /* check if we can seek */
640 if (bclass->is_seekable)
641 basesrc->seekable = bclass->is_seekable (basesrc);
643 basesrc->seekable = FALSE;
645 return basesrc->seekable;
649 gst_base_src_start (GstBaseSrc * basesrc)
651 GstBaseSrcClass *bclass;
654 if (GST_FLAG_IS_SET (basesrc, GST_BASESRC_STARTED))
657 bclass = GST_BASESRC_GET_CLASS (basesrc);
659 result = bclass->start (basesrc);
664 goto could_not_start;
666 GST_FLAG_SET (basesrc, GST_BASESRC_STARTED);
668 /* start in the beginning */
670 basesrc->segment_start = 0;
672 /* figure out the size */
673 if (bclass->get_size) {
674 result = bclass->get_size (basesrc, &basesrc->size);
682 GST_DEBUG ("size %d %lld", result, basesrc->size);
684 /* we always run to the end */
685 basesrc->segment_end = -1;
687 /* check if we can seek, updates ->seekable */
688 gst_base_src_is_seekable (basesrc);
692 if (basesrc->seekable) {
695 caps = gst_type_find_helper (basesrc->srcpad, basesrc->size);
696 gst_pad_set_caps (basesrc->srcpad, caps);
705 GST_DEBUG_OBJECT (basesrc, "could not start");
711 gst_base_src_stop (GstBaseSrc * basesrc)
713 GstBaseSrcClass *bclass;
714 gboolean result = TRUE;
716 if (!GST_FLAG_IS_SET (basesrc, GST_BASESRC_STARTED))
719 bclass = GST_BASESRC_GET_CLASS (basesrc);
721 result = bclass->stop (basesrc);
724 GST_FLAG_UNSET (basesrc, GST_BASESRC_STARTED);
730 gst_base_src_deactivate (GstBaseSrc * basesrc, GstPad * pad)
734 GST_LIVE_LOCK (basesrc);
735 basesrc->live_running = TRUE;
736 GST_LIVE_SIGNAL (basesrc);
737 GST_LIVE_UNLOCK (basesrc);
739 /* step 1, unblock clock sync (if any) */
740 gst_base_src_unlock (basesrc);
742 /* step 2, make sure streaming finishes */
743 result = gst_pad_stop_task (pad);
749 gst_base_src_activate_push (GstPad * pad, gboolean active)
753 basesrc = GST_BASESRC (GST_OBJECT_PARENT (pad));
755 /* prepare subclass first */
757 if (!gst_base_src_start (basesrc))
760 return gst_pad_start_task (pad, (GstTaskFunction) gst_base_src_loop, pad);
762 return gst_base_src_deactivate (basesrc, pad);
767 GST_DEBUG_OBJECT (basesrc, "failed to start");
773 gst_base_src_activate_pull (GstPad * pad, gboolean active)
777 basesrc = GST_BASESRC (GST_OBJECT_PARENT (pad));
779 /* prepare subclass first */
781 if (!gst_base_src_start (basesrc))
784 if (!basesrc->seekable) {
785 gst_base_src_stop (basesrc);
791 return gst_base_src_deactivate (basesrc, pad);
796 GST_DEBUG_OBJECT (basesrc, "failed to start");
801 static GstElementStateReturn
802 gst_base_src_change_state (GstElement * element)
805 GstElementStateReturn result = GST_STATE_SUCCESS;
806 GstElementStateReturn presult;
807 GstElementState transition;
809 basesrc = GST_BASESRC (element);
811 transition = GST_STATE_TRANSITION (element);
813 switch (transition) {
814 case GST_STATE_NULL_TO_READY:
816 case GST_STATE_READY_TO_PAUSED:
817 GST_LIVE_LOCK (element);
818 if (basesrc->is_live) {
819 result = GST_STATE_NO_PREROLL;
820 basesrc->live_running = FALSE;
822 GST_LIVE_UNLOCK (element);
824 case GST_STATE_PAUSED_TO_PLAYING:
825 GST_LIVE_LOCK (element);
826 basesrc->live_running = TRUE;
827 GST_LIVE_SIGNAL (element);
828 GST_LIVE_UNLOCK (element);
834 if ((presult = GST_ELEMENT_CLASS (parent_class)->change_state (element)) !=
838 switch (transition) {
839 case GST_STATE_PLAYING_TO_PAUSED:
840 GST_LIVE_LOCK (element);
841 if (basesrc->is_live) {
842 result = GST_STATE_NO_PREROLL;
843 basesrc->live_running = FALSE;
845 GST_LIVE_UNLOCK (element);
847 case GST_STATE_PAUSED_TO_READY:
848 if (!gst_base_src_stop (basesrc))
849 result = GST_STATE_FAILURE;
851 case GST_STATE_READY_TO_NULL: