gst/gstquery.h
[platform/upstream/gstreamer.git] / libs / gst / base / gstbasesrc.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *               2000,2005 Wim Taymans <wim@fluendo.com>
4  *
5  * gstbasesrc.c: 
6  *
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.
11  *
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.
16  *
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.
21  */
22
23
24 #include <stdlib.h>
25 #include <string.h>
26
27 #ifdef HAVE_CONFIG_H
28 #  include "config.h"
29 #endif
30
31 #include "gstbasesrc.h"
32 #include "gsttypefindhelper.h"
33 #include <gst/gstmarshal.h>
34
35 #define DEFAULT_BLOCKSIZE       4096
36
37 GST_DEBUG_CATEGORY_STATIC (gst_basesrc_debug);
38 #define GST_CAT_DEFAULT gst_basesrc_debug
39
40 /* BaseSrc signals and args */
41 enum
42 {
43   /* FILL ME */
44   LAST_SIGNAL
45 };
46
47 enum
48 {
49   PROP_0,
50   PROP_BLOCKSIZE,
51   PROP_HAS_LOOP,
52   PROP_HAS_GETRANGE
53 };
54
55 static GstElementClass *parent_class = NULL;
56
57 static void gst_basesrc_base_init (gpointer g_class);
58 static void gst_basesrc_class_init (GstBaseSrcClass * klass);
59 static void gst_basesrc_init (GstBaseSrc * src, gpointer g_class);
60
61 GType
62 gst_basesrc_get_type (void)
63 {
64   static GType basesrc_type = 0;
65
66   if (!basesrc_type) {
67     static const GTypeInfo basesrc_info = {
68       sizeof (GstBaseSrcClass),
69       (GBaseInitFunc) gst_basesrc_base_init,
70       NULL,
71       (GClassInitFunc) gst_basesrc_class_init,
72       NULL,
73       NULL,
74       sizeof (GstBaseSrc),
75       0,
76       (GInstanceInitFunc) gst_basesrc_init,
77     };
78
79     basesrc_type = g_type_register_static (GST_TYPE_ELEMENT,
80         "GstBaseSrc", &basesrc_info, G_TYPE_FLAG_ABSTRACT);
81   }
82   return basesrc_type;
83 }
84
85 static gboolean gst_basesrc_activate (GstPad * pad, GstActivateMode mode);
86 static void gst_basesrc_set_property (GObject * object, guint prop_id,
87     const GValue * value, GParamSpec * pspec);
88 static void gst_basesrc_get_property (GObject * object, guint prop_id,
89     GValue * value, GParamSpec * pspec);
90 static gboolean gst_basesrc_event_handler (GstPad * pad, GstEvent * event);
91
92 static gboolean gst_basesrc_query2 (GstPad * pad, GstQuery * query);
93
94 static const GstEventMask *gst_basesrc_get_event_mask (GstPad * pad);
95
96 static gboolean gst_basesrc_unlock (GstBaseSrc * basesrc);
97 static gboolean gst_basesrc_get_size (GstBaseSrc * basesrc, guint64 * size);
98 static gboolean gst_basesrc_start (GstBaseSrc * basesrc);
99 static gboolean gst_basesrc_stop (GstBaseSrc * basesrc);
100
101 static GstElementStateReturn gst_basesrc_change_state (GstElement * element);
102
103 static void gst_basesrc_set_dataflow_funcs (GstBaseSrc * this);
104 static void gst_basesrc_loop (GstPad * pad);
105 static gboolean gst_basesrc_check_get_range (GstPad * pad);
106 static GstFlowReturn gst_basesrc_get_range (GstPad * pad, guint64 offset,
107     guint length, GstBuffer ** buf);
108
109 static void
110 gst_basesrc_base_init (gpointer g_class)
111 {
112   GST_DEBUG_CATEGORY_INIT (gst_basesrc_debug, "basesrc", 0, "basesrc element");
113 }
114
115 static void
116 gst_basesrc_class_init (GstBaseSrcClass * klass)
117 {
118   GObjectClass *gobject_class;
119   GstElementClass *gstelement_class;
120
121   gobject_class = (GObjectClass *) klass;
122   gstelement_class = (GstElementClass *) klass;
123
124   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
125
126   gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_basesrc_set_property);
127   gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_basesrc_get_property);
128
129   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BLOCKSIZE,
130       g_param_spec_ulong ("blocksize", "Block size",
131           "Size in bytes to read per buffer", 1, G_MAXULONG, DEFAULT_BLOCKSIZE,
132           G_PARAM_READWRITE));
133
134   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_LOOP,
135       g_param_spec_boolean ("has-loop", "Has loop function",
136           "True if the element should expose a loop function", TRUE,
137           G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
138
139   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_GETRANGE,
140       g_param_spec_boolean ("has-getrange", "Has getrange function",
141           "True if the element should expose a getrange function", TRUE,
142           G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
143
144   gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_basesrc_change_state);
145 }
146
147 static void
148 gst_basesrc_init (GstBaseSrc * basesrc, gpointer g_class)
149 {
150   GstPad *pad;
151   GstPadTemplate *pad_template;
152
153   pad_template =
154       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
155   g_return_if_fail (pad_template != NULL);
156
157   pad = gst_pad_new_from_template (pad_template, "src");
158
159   gst_pad_set_activate_function (pad, gst_basesrc_activate);
160   gst_pad_set_event_function (pad, gst_basesrc_event_handler);
161   gst_pad_set_event_mask_function (pad, gst_basesrc_get_event_mask);
162
163   gst_pad_set_query2_function (pad, gst_basesrc_query2);
164
165   gst_pad_set_checkgetrange_function (pad, gst_basesrc_check_get_range);
166
167   /* hold ref to pad */
168   basesrc->srcpad = pad;
169   gst_element_add_pad (GST_ELEMENT (basesrc), pad);
170
171   basesrc->segment_start = -1;
172   basesrc->segment_end = -1;
173   basesrc->blocksize = DEFAULT_BLOCKSIZE;
174   basesrc->clock_id = NULL;
175
176   GST_FLAG_UNSET (basesrc, GST_BASESRC_STARTED);
177 }
178
179 static void
180 gst_basesrc_set_dataflow_funcs (GstBaseSrc * this)
181 {
182   GST_DEBUG ("updating dataflow functions");
183
184   if (this->has_loop)
185     gst_pad_set_loop_function (this->srcpad, gst_basesrc_loop);
186   else
187     gst_pad_set_loop_function (this->srcpad, NULL);
188
189   if (this->has_getrange)
190     gst_pad_set_getrange_function (this->srcpad, gst_basesrc_get_range);
191   else
192     gst_pad_set_getrange_function (this->srcpad, NULL);
193 }
194
195 static gboolean
196 gst_basesrc_query2 (GstPad * pad, GstQuery * query)
197 {
198   gboolean b;
199   guint64 ui64;
200   gint64 i64;
201   GstBaseSrc *src;
202
203   src = GST_BASESRC (GST_PAD_PARENT (pad));
204
205   switch (GST_QUERY_TYPE (query)) {
206     case GST_QUERY_POSITION:
207     {
208       GstFormat format;
209
210       gst_query_parse_position_query (query, &format);
211       switch (format) {
212         case GST_FORMAT_DEFAULT:
213         case GST_FORMAT_BYTES:
214           b = gst_basesrc_get_size (src, &ui64);
215           /* better to make get_size take an int64 */
216           i64 = b ? (gint64) ui64 : -1;
217           gst_query_set_position (query, GST_FORMAT_BYTES, src->offset, i64);
218           return TRUE;
219         case GST_FORMAT_PERCENT:
220           b = gst_basesrc_get_size (src, &ui64);
221           i64 = GST_FORMAT_PERCENT_MAX;
222           i64 *= b ? (src->offset / (gdouble) ui64) : 1.0;
223           gst_query_set_position (query, GST_FORMAT_PERCENT,
224               i64, GST_FORMAT_PERCENT_MAX);
225           return TRUE;
226         default:
227           return FALSE;
228       }
229     }
230
231     case GST_QUERY_SEEKING:
232       gst_query_set_seeking (query, GST_FORMAT_BYTES,
233           src->seekable, src->segment_start, src->segment_end);
234       return TRUE;
235
236     case GST_QUERY_FORMATS:
237       gst_query_set_formats (query, 3, GST_FORMAT_DEFAULT,
238           GST_FORMAT_BYTES, GST_FORMAT_PERCENT);
239       return TRUE;
240
241     case GST_QUERY_LATENCY:
242     case GST_QUERY_JITTER:
243     case GST_QUERY_RATE:
244     case GST_QUERY_CONVERT:
245     default:
246       return gst_pad_query2_default (pad, query);
247   }
248 }
249
250 static const GstEventMask *
251 gst_basesrc_get_event_mask (GstPad * pad)
252 {
253   static const GstEventMask masks[] = {
254     {GST_EVENT_SEEK, GST_SEEK_METHOD_CUR | GST_SEEK_METHOD_SET |
255           GST_SEEK_METHOD_END | GST_SEEK_FLAG_FLUSH |
256           GST_SEEK_FLAG_SEGMENT_LOOP},
257     {GST_EVENT_FLUSH, 0},
258     {GST_EVENT_SIZE, 0},
259     {0, 0},
260   };
261   return masks;
262 }
263
264 static gboolean
265 gst_basesrc_do_seek (GstBaseSrc * src, GstEvent * event)
266 {
267   GstFormat format;
268   gint64 offset;
269
270   format = GST_EVENT_SEEK_FORMAT (event);
271
272   /* get seek format */
273   if (format == GST_FORMAT_DEFAULT)
274     format = GST_FORMAT_BYTES;
275   /* we can only seek bytes */
276   if (format != GST_FORMAT_BYTES)
277     return FALSE;
278
279   /* get seek positions */
280   offset = GST_EVENT_SEEK_OFFSET (event);
281   src->segment_start = offset;
282   src->segment_end = GST_EVENT_SEEK_ENDOFFSET (event);
283   src->segment_loop = GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_SEGMENT_LOOP;
284
285   /* send flush start */
286   gst_pad_push_event (src->srcpad, gst_event_new_flush (FALSE));
287
288   /* unblock streaming thread */
289   gst_basesrc_unlock (src);
290
291   /* grab streaming lock */
292   GST_STREAM_LOCK (src->srcpad);
293
294   switch (GST_EVENT_SEEK_METHOD (event)) {
295     case GST_SEEK_METHOD_SET:
296       if (offset < 0)
297         goto error;
298       src->offset = MIN (offset, src->size);
299       GST_DEBUG_OBJECT (src, "seek set pending to %" G_GINT64_FORMAT,
300           src->offset);
301       break;
302     case GST_SEEK_METHOD_CUR:
303       offset += src->offset;
304       src->offset = CLAMP (offset, 0, src->size);
305       GST_DEBUG_OBJECT (src, "seek cur pending to %" G_GINT64_FORMAT,
306           src->offset);
307       break;
308     case GST_SEEK_METHOD_END:
309       if (offset > 0)
310         goto error;
311       offset = src->size + offset;
312       src->offset = MAX (0, offset);
313       GST_DEBUG_OBJECT (src, "seek end pending to %" G_GINT64_FORMAT,
314           src->offset);
315       break;
316     default:
317       goto error;
318   }
319   /* send flush end */
320   gst_pad_push_event (src->srcpad, gst_event_new_flush (TRUE));
321
322   /* now send discont */
323   {
324     GstEvent *event;
325
326     event = gst_event_new_discontinuous (1.0,
327         GST_FORMAT_TIME,
328         (gint64) src->segment_start, (gint64) src->segment_end, NULL);
329
330     gst_pad_push_event (src->srcpad, event);
331   }
332
333   /* and restart the task */
334   if (GST_RPAD_TASK (src->srcpad)) {
335     gst_task_start (GST_RPAD_TASK (src->srcpad));
336   }
337   GST_STREAM_UNLOCK (src->srcpad);
338
339   gst_event_unref (event);
340
341   return TRUE;
342
343   /* ERROR */
344 error:
345   {
346     GST_DEBUG_OBJECT (src, "seek error");
347     GST_STREAM_UNLOCK (src->srcpad);
348     gst_event_unref (event);
349     return FALSE;
350   }
351 }
352
353 static gboolean
354 gst_basesrc_event_handler (GstPad * pad, GstEvent * event)
355 {
356   GstBaseSrc *src;
357   GstBaseSrcClass *bclass;
358   gboolean result;
359
360   src = GST_BASESRC (GST_PAD_PARENT (pad));
361   bclass = GST_BASESRC_GET_CLASS (src);
362
363   if (bclass->event)
364     result = bclass->event (src, event);
365
366   switch (GST_EVENT_TYPE (event)) {
367     case GST_EVENT_SEEK:
368       return gst_basesrc_do_seek (src, event);
369     case GST_EVENT_SIZE:
370     {
371       GstFormat format;
372
373       format = GST_EVENT_SIZE_FORMAT (event);
374       if (format == GST_FORMAT_DEFAULT)
375         format = GST_FORMAT_BYTES;
376       /* we can only accept bytes */
377       if (format != GST_FORMAT_BYTES)
378         return FALSE;
379
380       src->blocksize = GST_EVENT_SIZE_VALUE (event);
381       g_object_notify (G_OBJECT (src), "blocksize");
382       break;
383     }
384     case GST_EVENT_FLUSH:
385       /* cancel any blocking getrange */
386       if (!GST_EVENT_FLUSH_DONE (event))
387         gst_basesrc_unlock (src);
388       break;
389     default:
390       break;
391   }
392   gst_event_unref (event);
393
394   return TRUE;
395 }
396
397 static void
398 gst_basesrc_set_property (GObject * object, guint prop_id, const GValue * value,
399     GParamSpec * pspec)
400 {
401   GstBaseSrc *src;
402
403   src = GST_BASESRC (object);
404
405   switch (prop_id) {
406     case PROP_BLOCKSIZE:
407       src->blocksize = g_value_get_ulong (value);
408       break;
409     case PROP_HAS_LOOP:
410       src->has_loop = g_value_get_boolean (value);
411       gst_basesrc_set_dataflow_funcs (src);
412       break;
413     case PROP_HAS_GETRANGE:
414       src->has_getrange = g_value_get_boolean (value);
415       gst_basesrc_set_dataflow_funcs (src);
416       break;
417     default:
418       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
419       break;
420   }
421 }
422
423 static void
424 gst_basesrc_get_property (GObject * object, guint prop_id, GValue * value,
425     GParamSpec * pspec)
426 {
427   GstBaseSrc *src;
428
429   src = GST_BASESRC (object);
430
431   switch (prop_id) {
432     case PROP_BLOCKSIZE:
433       g_value_set_ulong (value, src->blocksize);
434       break;
435     case PROP_HAS_LOOP:
436       g_value_set_boolean (value, src->has_loop);
437       break;
438     case PROP_HAS_GETRANGE:
439       g_value_set_boolean (value, src->has_getrange);
440       break;
441     default:
442       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
443       break;
444   }
445 }
446
447 static GstFlowReturn
448 gst_basesrc_get_range_unlocked (GstPad * pad, guint64 offset, guint length,
449     GstBuffer ** buf)
450 {
451   GstFlowReturn ret;
452   GstBaseSrc *src;
453   GstBaseSrcClass *bclass;
454
455   src = GST_BASESRC (GST_OBJECT_PARENT (pad));
456   bclass = GST_BASESRC_GET_CLASS (src);
457
458   if (!GST_FLAG_IS_SET (src, GST_BASESRC_STARTED))
459     goto not_started;
460
461   if (!bclass->create)
462     goto no_function;
463
464   /* check size */
465   if (src->size != -1) {
466     if (offset + length > src->size) {
467       if (bclass->get_size)
468         bclass->get_size (src, &src->size);
469
470       if (offset + length > src->size) {
471         length = src->size - offset;
472       }
473     }
474   }
475   if (length == 0)
476     goto unexpected_length;
477
478   ret = bclass->create (src, offset, length, buf);
479
480   return ret;
481
482   /* ERROR */
483 not_started:
484   {
485     GST_DEBUG_OBJECT (src, "getrange but not started");
486     return GST_FLOW_WRONG_STATE;
487   }
488 no_function:
489   {
490     GST_DEBUG_OBJECT (src, "no create function");
491     return GST_FLOW_ERROR;
492   }
493 unexpected_length:
494   {
495     GST_DEBUG_OBJECT (src, "unexpected length %u", length);
496     return GST_FLOW_UNEXPECTED;
497   }
498 }
499
500 static GstFlowReturn
501 gst_basesrc_get_range (GstPad * pad, guint64 offset, guint length,
502     GstBuffer ** ret)
503 {
504   GstFlowReturn fret;
505
506   GST_STREAM_LOCK (pad);
507
508   fret = gst_basesrc_get_range_unlocked (pad, offset, length, ret);
509
510   GST_STREAM_UNLOCK (pad);
511
512   return fret;
513 }
514
515 static gboolean
516 gst_basesrc_check_get_range (GstPad * pad)
517 {
518   GstBaseSrc *src;
519
520   src = GST_BASESRC (GST_OBJECT_PARENT (pad));
521
522   if (!GST_FLAG_IS_SET (src, GST_BASESRC_STARTED)) {
523     gst_basesrc_start (src);
524     gst_basesrc_stop (src);
525   }
526
527   return src->seekable;
528 }
529
530 static void
531 gst_basesrc_loop (GstPad * pad)
532 {
533   GstBaseSrc *src;
534   GstBuffer *buf = NULL;
535   GstFlowReturn ret;
536
537   src = GST_BASESRC (GST_OBJECT_PARENT (pad));
538
539   GST_STREAM_LOCK (pad);
540
541   ret = gst_basesrc_get_range_unlocked (pad, src->offset, src->blocksize, &buf);
542   if (ret != GST_FLOW_OK)
543     goto eos;
544
545   src->offset += GST_BUFFER_SIZE (buf);
546
547   ret = gst_pad_push (pad, buf);
548   if (ret != GST_FLOW_OK)
549     goto pause;
550
551   GST_STREAM_UNLOCK (pad);
552   return;
553
554 eos:
555   {
556     GST_DEBUG_OBJECT (src, "going to EOS");
557     gst_task_pause (GST_RPAD_TASK (pad));
558     gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
559     GST_STREAM_UNLOCK (pad);
560     return;
561   }
562 pause:
563   {
564     GST_DEBUG_OBJECT (src, "pausing task");
565     gst_task_pause (GST_RPAD_TASK (pad));
566     GST_STREAM_UNLOCK (pad);
567     return;
568   }
569 }
570
571 static gboolean
572 gst_basesrc_unlock (GstBaseSrc * basesrc)
573 {
574   GstBaseSrcClass *bclass;
575   gboolean result = FALSE;
576
577   /* unblock whatever the subclass is doing */
578   bclass = GST_BASESRC_GET_CLASS (basesrc);
579   if (bclass->unlock)
580     result = bclass->unlock (basesrc);
581
582   /* and unblock the clock as well, if any */
583   GST_LOCK (basesrc);
584   if (basesrc->clock_id) {
585     gst_clock_id_unschedule (basesrc->clock_id);
586   }
587   GST_UNLOCK (basesrc);
588
589   return result;
590 }
591
592 static gboolean
593 gst_basesrc_get_size (GstBaseSrc * basesrc, guint64 * size)
594 {
595   GstBaseSrcClass *bclass;
596   gboolean result = FALSE;
597
598   bclass = GST_BASESRC_GET_CLASS (basesrc);
599   if (bclass->get_size)
600     result = bclass->get_size (basesrc, size);
601
602   if (result)
603     basesrc->size = *size;
604
605   return result;
606 }
607
608 static gboolean
609 gst_basesrc_start (GstBaseSrc * basesrc)
610 {
611   GstBaseSrcClass *bclass;
612   gboolean result;
613
614   if (GST_FLAG_IS_SET (basesrc, GST_BASESRC_STARTED))
615     return TRUE;
616
617   bclass = GST_BASESRC_GET_CLASS (basesrc);
618   if (bclass->start)
619     result = bclass->start (basesrc);
620   else
621     result = TRUE;
622
623   if (!result)
624     goto could_not_start;
625
626   GST_FLAG_SET (basesrc, GST_BASESRC_STARTED);
627
628   /* start in the beginning */
629   basesrc->offset = 0;
630   basesrc->segment_start = 0;
631
632   /* figure out the size */
633   if (bclass->get_size) {
634     result = bclass->get_size (basesrc, &basesrc->size);
635     if (result == FALSE)
636       basesrc->size = -1;
637   } else {
638     result = FALSE;
639     basesrc->size = -1;
640   }
641
642   GST_DEBUG ("size %d %lld", result, basesrc->size);
643
644   /* we always run to the end */
645   basesrc->segment_end = -1;
646
647   /* check if we can seek */
648   if (bclass->is_seekable)
649     basesrc->seekable = bclass->is_seekable (basesrc);
650   else
651     basesrc->seekable = FALSE;
652
653   /* run typefind */
654 #if 0
655   if (basesrc->seekable) {
656     GstCaps *caps;
657
658     caps = gst_type_find_helper (basesrc->srcpad, basesrc->size);
659     gst_pad_set_caps (basesrc->srcpad, caps);
660   }
661 #endif
662
663   return TRUE;
664
665   /* ERROR */
666 could_not_start:
667   {
668     GST_DEBUG_OBJECT (basesrc, "could not start");
669     return FALSE;
670   }
671 }
672
673 static gboolean
674 gst_basesrc_stop (GstBaseSrc * basesrc)
675 {
676   GstBaseSrcClass *bclass;
677   gboolean result = TRUE;
678
679   if (!GST_FLAG_IS_SET (basesrc, GST_BASESRC_STARTED))
680     return TRUE;
681
682   bclass = GST_BASESRC_GET_CLASS (basesrc);
683   if (bclass->stop)
684     result = bclass->stop (basesrc);
685
686   if (result)
687     GST_FLAG_UNSET (basesrc, GST_BASESRC_STARTED);
688
689   return result;
690 }
691
692 static gboolean
693 gst_basesrc_activate (GstPad * pad, GstActivateMode mode)
694 {
695   gboolean result;
696   GstBaseSrc *basesrc;
697
698   basesrc = GST_BASESRC (GST_OBJECT_PARENT (pad));
699
700   /* prepare subclass first */
701   switch (mode) {
702     case GST_ACTIVATE_PUSH:
703     case GST_ACTIVATE_PULL:
704       result = gst_basesrc_start (basesrc);
705       break;
706     default:
707       result = TRUE;
708       break;
709   }
710   /* if that failed we can stop here */
711   if (!result)
712     goto error_start;
713
714   result = FALSE;
715   switch (mode) {
716     case GST_ACTIVATE_PUSH:
717       /* if we have a scheduler we can start the task */
718       if (GST_ELEMENT_SCHEDULER (basesrc)) {
719         GST_STREAM_LOCK (pad);
720         GST_RPAD_TASK (pad) =
721             gst_scheduler_create_task (GST_ELEMENT_SCHEDULER (basesrc),
722             (GstTaskFunction) gst_basesrc_loop, pad);
723
724         gst_task_start (GST_RPAD_TASK (pad));
725         GST_STREAM_UNLOCK (pad);
726         result = TRUE;
727       }
728       break;
729     case GST_ACTIVATE_PULL:
730       result = TRUE;
731       break;
732     case GST_ACTIVATE_NONE:
733       /* step 1, unblock clock sync (if any) */
734       gst_basesrc_unlock (basesrc);
735
736       /* step 2, make sure streaming finishes */
737       GST_STREAM_LOCK (pad);
738       /* step 3, stop the task */
739       if (GST_RPAD_TASK (pad)) {
740         gst_task_stop (GST_RPAD_TASK (pad));
741         gst_object_unref (GST_OBJECT (GST_RPAD_TASK (pad)));
742         GST_RPAD_TASK (pad) = NULL;
743       }
744       GST_STREAM_UNLOCK (pad);
745
746       result = TRUE;
747       break;
748   }
749   return result;
750
751   /* ERROR */
752 error_start:
753   {
754     GST_DEBUG_OBJECT (basesrc, "failed to start");
755     return FALSE;
756   }
757 }
758
759 static GstElementStateReturn
760 gst_basesrc_change_state (GstElement * element)
761 {
762   GstBaseSrc *basesrc;
763   GstElementStateReturn result = GST_STATE_FAILURE;
764   GstElementState transition;
765
766   basesrc = GST_BASESRC (element);
767
768   transition = GST_STATE_TRANSITION (element);
769
770   switch (transition) {
771     case GST_STATE_NULL_TO_READY:
772       break;
773     case GST_STATE_READY_TO_PAUSED:
774       break;
775     case GST_STATE_PAUSED_TO_PLAYING:
776       break;
777     default:
778       break;
779   }
780
781   result = GST_ELEMENT_CLASS (parent_class)->change_state (element);
782
783   switch (transition) {
784     case GST_STATE_PLAYING_TO_PAUSED:
785       break;
786     case GST_STATE_PAUSED_TO_READY:
787       result = gst_basesrc_stop (basesrc);
788       break;
789     case GST_STATE_READY_TO_NULL:
790       break;
791     default:
792       break;
793   }
794
795   return result;
796 }