Added draft for new query API.
[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 };
52
53 static GstElementClass *parent_class = NULL;
54
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);
58
59 GType
60 gst_basesrc_get_type (void)
61 {
62   static GType basesrc_type = 0;
63
64   if (!basesrc_type) {
65     static const GTypeInfo basesrc_info = {
66       sizeof (GstBaseSrcClass),
67       (GBaseInitFunc) gst_basesrc_base_init,
68       NULL,
69       (GClassInitFunc) gst_basesrc_class_init,
70       NULL,
71       NULL,
72       sizeof (GstBaseSrc),
73       0,
74       (GInstanceInitFunc) gst_basesrc_init,
75     };
76
77     basesrc_type = g_type_register_static (GST_TYPE_ELEMENT,
78         "GstBaseSrc", &basesrc_info, G_TYPE_FLAG_ABSTRACT);
79   }
80   return basesrc_type;
81 }
82
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);
94
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);
99
100 static GstElementStateReturn gst_basesrc_change_state (GstElement * element);
101
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);
106
107 static void
108 gst_basesrc_base_init (gpointer g_class)
109 {
110   GST_DEBUG_CATEGORY_INIT (gst_basesrc_debug, "basesrc", 0, "basesrc element");
111 }
112
113 static void
114 gst_basesrc_class_init (GstBaseSrcClass * klass)
115 {
116   GObjectClass *gobject_class;
117   GstElementClass *gstelement_class;
118
119   gobject_class = (GObjectClass *) klass;
120   gstelement_class = (GstElementClass *) klass;
121
122   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
123
124   gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_basesrc_set_property);
125   gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_basesrc_get_property);
126
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,
130           G_PARAM_READWRITE));
131
132   gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_basesrc_change_state);
133 }
134
135 static void
136 gst_basesrc_init (GstBaseSrc * basesrc, gpointer g_class)
137 {
138   GstPad *pad;
139   GstPadTemplate *pad_template;
140
141   pad_template =
142       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
143   g_return_if_fail (pad_template != NULL);
144
145   pad = gst_pad_new_from_template (pad_template, "src");
146
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);
159
160   basesrc->segment_start = -1;
161   basesrc->segment_end = -1;
162   basesrc->blocksize = DEFAULT_BLOCKSIZE;
163
164   GST_FLAG_UNSET (basesrc, GST_BASESRC_STARTED);
165 }
166
167 static const GstFormat *
168 gst_basesrc_get_formats (GstPad * pad)
169 {
170   static const GstFormat formats[] = {
171     GST_FORMAT_DEFAULT,
172     GST_FORMAT_BYTES,
173     0,
174   };
175
176   return formats;
177 }
178
179 static const GstQueryType *
180 gst_basesrc_get_query_types (GstPad * pad)
181 {
182   static const GstQueryType types[] = {
183     GST_QUERY_TOTAL,
184     GST_QUERY_POSITION,
185     GST_QUERY_START,
186     GST_QUERY_SEGMENT_END,
187     0,
188   };
189
190   return types;
191 }
192
193 static gboolean
194 gst_basesrc_query (GstPad * pad, GstQueryType type,
195     GstFormat * format, gint64 * value)
196 {
197   GstBaseSrc *src = GST_BASESRC (GST_PAD_PARENT (pad));
198
199   if (*format == GST_FORMAT_DEFAULT)
200     *format = GST_FORMAT_BYTES;
201
202   switch (type) {
203     case GST_QUERY_TOTAL:
204       switch (*format) {
205         case GST_FORMAT_BYTES:
206         {
207           gboolean ret;
208
209           ret = gst_basesrc_get_size (src, value);
210           GST_DEBUG ("getting length %d %lld", ret, *value);
211           return ret;
212         }
213         case GST_FORMAT_PERCENT:
214           *value = GST_FORMAT_PERCENT_MAX;
215           return TRUE;
216         default:
217           return FALSE;
218       }
219       break;
220     case GST_QUERY_POSITION:
221       switch (*format) {
222         case GST_FORMAT_BYTES:
223           *value = src->offset;
224           break;
225         case GST_FORMAT_PERCENT:
226           if (!gst_basesrc_get_size (src, value))
227             return FALSE;
228           *value = src->offset * GST_FORMAT_PERCENT_MAX / *value;
229           return TRUE;
230         default:
231           return FALSE;
232       }
233       break;
234     case GST_QUERY_START:
235       *value = src->segment_start;
236       return TRUE;
237     case GST_QUERY_SEGMENT_END:
238       *value = src->segment_end;
239       return TRUE;
240     default:
241       return FALSE;
242   }
243   return FALSE;
244 }
245
246 static const GstEventMask *
247 gst_basesrc_get_event_mask (GstPad * pad)
248 {
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},
254     {GST_EVENT_SIZE, 0},
255     {0, 0},
256   };
257   return masks;
258 }
259
260 static gboolean
261 gst_basesrc_do_seek (GstBaseSrc * src, GstEvent * event)
262 {
263   GstFormat format;
264   gint64 offset;
265
266   format = GST_EVENT_SEEK_FORMAT (event);
267
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)
273     return FALSE;
274
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;
280
281   /* send flush start */
282   gst_pad_push_event (src->srcpad, gst_event_new_flush (FALSE));
283
284   /* unblock streaming thread */
285   gst_basesrc_unlock (src);
286
287   /* grab streaming lock */
288   GST_STREAM_LOCK (src->srcpad);
289
290   switch (GST_EVENT_SEEK_METHOD (event)) {
291     case GST_SEEK_METHOD_SET:
292       if (offset < 0)
293         goto error;
294       src->offset = MIN (offset, src->size);
295       GST_DEBUG_OBJECT (src, "seek set pending to %" G_GINT64_FORMAT,
296           src->offset);
297       break;
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,
302           src->offset);
303       break;
304     case GST_SEEK_METHOD_END:
305       if (offset > 0)
306         goto error;
307       offset = src->size + offset;
308       src->offset = MAX (0, offset);
309       GST_DEBUG_OBJECT (src, "seek end pending to %" G_GINT64_FORMAT,
310           src->offset);
311       break;
312     default:
313       goto error;
314   }
315   /* send flush end */
316   gst_pad_push_event (src->srcpad, gst_event_new_flush (TRUE));
317
318   /* now send discont */
319   {
320     GstEvent *event;
321
322     event = gst_event_new_discontinuous (1.0,
323         GST_FORMAT_TIME,
324         (gint64) src->segment_start, (gint64) src->segment_end, NULL);
325
326     gst_pad_push_event (src->srcpad, event);
327   }
328
329   /* and restart the task */
330   if (GST_RPAD_TASK (src->srcpad)) {
331     gst_task_start (GST_RPAD_TASK (src->srcpad));
332   }
333   GST_STREAM_UNLOCK (src->srcpad);
334
335   gst_event_unref (event);
336
337   return TRUE;
338
339   /* ERROR */
340 error:
341   {
342     GST_DEBUG_OBJECT (src, "seek error");
343     GST_STREAM_UNLOCK (src->srcpad);
344     gst_event_unref (event);
345     return FALSE;
346   }
347 }
348
349 static gboolean
350 gst_basesrc_event_handler (GstPad * pad, GstEvent * event)
351 {
352   GstBaseSrc *src;
353   GstBaseSrcClass *bclass;
354   gboolean result;
355
356   src = GST_BASESRC (GST_PAD_PARENT (pad));
357   bclass = GST_BASESRC_GET_CLASS (src);
358
359   if (bclass->event)
360     result = bclass->event (src, event);
361
362   switch (GST_EVENT_TYPE (event)) {
363     case GST_EVENT_SEEK:
364       return gst_basesrc_do_seek (src, event);
365     case GST_EVENT_SIZE:
366     {
367       GstFormat format;
368
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)
374         return FALSE;
375
376       src->blocksize = GST_EVENT_SIZE_VALUE (event);
377       g_object_notify (G_OBJECT (src), "blocksize");
378       break;
379     }
380     case GST_EVENT_FLUSH:
381       /* cancel any blocking getrange */
382       if (!GST_EVENT_FLUSH_DONE (event))
383         gst_basesrc_unlock (src);
384       break;
385     default:
386       break;
387   }
388   gst_event_unref (event);
389
390   return TRUE;
391 }
392
393 static void
394 gst_basesrc_set_property (GObject * object, guint prop_id, const GValue * value,
395     GParamSpec * pspec)
396 {
397   GstBaseSrc *src;
398
399   src = GST_BASESRC (object);
400
401   switch (prop_id) {
402     case PROP_BLOCKSIZE:
403       src->blocksize = g_value_get_ulong (value);
404       break;
405     default:
406       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
407       break;
408   }
409 }
410
411 static void
412 gst_basesrc_get_property (GObject * object, guint prop_id, GValue * value,
413     GParamSpec * pspec)
414 {
415   GstBaseSrc *src;
416
417   src = GST_BASESRC (object);
418
419   switch (prop_id) {
420     case PROP_BLOCKSIZE:
421       g_value_set_ulong (value, src->blocksize);
422       break;
423     default:
424       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
425       break;
426   }
427 }
428
429 static GstFlowReturn
430 gst_basesrc_get_range_unlocked (GstPad * pad, guint64 offset, guint length,
431     GstBuffer ** buf)
432 {
433   GstFlowReturn ret;
434   GstBaseSrc *src;
435   GstBaseSrcClass *bclass;
436
437   src = GST_BASESRC (GST_OBJECT_PARENT (pad));
438   bclass = GST_BASESRC_GET_CLASS (src);
439
440   if (!GST_FLAG_IS_SET (src, GST_BASESRC_STARTED))
441     goto not_started;
442
443   if (!bclass->create)
444     goto no_function;
445
446   /* check size */
447   if (src->size != -1) {
448     if (offset + length > src->size) {
449       if (bclass->get_size)
450         bclass->get_size (src, &src->size);
451
452       if (offset + length > src->size) {
453         length = src->size - offset;
454       }
455     }
456   }
457   if (length == 0)
458     goto unexpected_length;
459
460   ret = bclass->create (src, offset, length, buf);
461
462   return ret;
463
464   /* ERROR */
465 not_started:
466   {
467     GST_DEBUG_OBJECT (src, "getrange but not started");
468     return GST_FLOW_WRONG_STATE;
469   }
470 no_function:
471   {
472     GST_DEBUG_OBJECT (src, "no create function");
473     return GST_FLOW_ERROR;
474   }
475 unexpected_length:
476   {
477     GST_DEBUG_OBJECT (src, "unexpected length %u", length);
478     return GST_FLOW_UNEXPECTED;
479   }
480 }
481
482 static GstFlowReturn
483 gst_basesrc_get_range (GstPad * pad, guint64 offset, guint length,
484     GstBuffer ** ret)
485 {
486   GstFlowReturn fret;
487
488   GST_STREAM_LOCK (pad);
489
490   fret = gst_basesrc_get_range_unlocked (pad, offset, length, ret);
491
492   GST_STREAM_UNLOCK (pad);
493
494   return fret;
495 }
496
497 static gboolean
498 gst_basesrc_check_get_range (GstPad * pad)
499 {
500   GstBaseSrc *src;
501
502   src = GST_BASESRC (GST_OBJECT_PARENT (pad));
503
504   if (!GST_FLAG_IS_SET (src, GST_BASESRC_STARTED)) {
505     gst_basesrc_start (src);
506     gst_basesrc_stop (src);
507   }
508
509   return src->seekable;
510 }
511
512 static void
513 gst_basesrc_loop (GstPad * pad)
514 {
515   GstBaseSrc *src;
516   GstBuffer *buf = NULL;
517   GstFlowReturn ret;
518
519   src = GST_BASESRC (GST_OBJECT_PARENT (pad));
520
521   GST_STREAM_LOCK (pad);
522
523   ret = gst_basesrc_get_range_unlocked (pad, src->offset, src->blocksize, &buf);
524   if (ret != GST_FLOW_OK)
525     goto eos;
526
527   src->offset += GST_BUFFER_SIZE (buf);
528
529   ret = gst_pad_push (pad, buf);
530   if (ret != GST_FLOW_OK)
531     goto pause;
532
533   GST_STREAM_UNLOCK (pad);
534   return;
535
536 eos:
537   {
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);
542     return;
543   }
544 pause:
545   {
546     GST_DEBUG_OBJECT (src, "pausing task");
547     gst_task_pause (GST_RPAD_TASK (pad));
548     GST_STREAM_UNLOCK (pad);
549     return;
550   }
551 }
552
553 static gboolean
554 gst_basesrc_unlock (GstBaseSrc * basesrc)
555 {
556   GstBaseSrcClass *bclass;
557   gboolean result = FALSE;
558
559   bclass = GST_BASESRC_GET_CLASS (basesrc);
560   if (bclass->unlock)
561     result = bclass->unlock (basesrc);
562
563   return result;
564 }
565
566 static gboolean
567 gst_basesrc_get_size (GstBaseSrc * basesrc, guint64 * size)
568 {
569   GstBaseSrcClass *bclass;
570   gboolean result = FALSE;
571
572   bclass = GST_BASESRC_GET_CLASS (basesrc);
573   if (bclass->get_size)
574     result = bclass->get_size (basesrc, size);
575
576   if (result)
577     basesrc->size = *size;
578
579   return result;
580 }
581
582 static gboolean
583 gst_basesrc_start (GstBaseSrc * basesrc)
584 {
585   GstBaseSrcClass *bclass;
586   gboolean result;
587
588   if (GST_FLAG_IS_SET (basesrc, GST_BASESRC_STARTED))
589     return TRUE;
590
591   bclass = GST_BASESRC_GET_CLASS (basesrc);
592   if (bclass->start)
593     result = bclass->start (basesrc);
594   else
595     result = TRUE;
596
597   if (!result)
598     goto could_not_start;
599
600   GST_FLAG_SET (basesrc, GST_BASESRC_STARTED);
601
602   /* start in the beginning */
603   basesrc->offset = 0;
604   basesrc->segment_start = 0;
605
606   /* figure out the size */
607   if (bclass->get_size) {
608     result = bclass->get_size (basesrc, &basesrc->size);
609     if (result == FALSE)
610       basesrc->size = -1;
611   } else {
612     result = FALSE;
613     basesrc->size = -1;
614   }
615
616   GST_DEBUG ("size %d %lld", result, basesrc->size);
617
618   /* we always run to the end */
619   basesrc->segment_end = -1;
620
621   /* check if we can seek */
622   if (bclass->is_seekable)
623     basesrc->seekable = bclass->is_seekable (basesrc);
624   else
625     basesrc->seekable = FALSE;
626
627   /* run typefind */
628 #if 0
629   if (basesrc->seekable) {
630     GstCaps *caps;
631
632     caps = gst_type_find_helper (basesrc->srcpad, basesrc->size);
633     gst_pad_set_caps (basesrc->srcpad, caps);
634   }
635 #endif
636
637   return TRUE;
638
639   /* ERROR */
640 could_not_start:
641   {
642     GST_DEBUG_OBJECT (basesrc, "could not start");
643     return FALSE;
644   }
645 }
646
647 static gboolean
648 gst_basesrc_stop (GstBaseSrc * basesrc)
649 {
650   GstBaseSrcClass *bclass;
651   gboolean result = TRUE;
652
653   if (!GST_FLAG_IS_SET (basesrc, GST_BASESRC_STARTED))
654     return TRUE;
655
656   bclass = GST_BASESRC_GET_CLASS (basesrc);
657   if (bclass->stop)
658     result = bclass->stop (basesrc);
659
660   if (result)
661     GST_FLAG_UNSET (basesrc, GST_BASESRC_STARTED);
662
663   return result;
664 }
665
666 static gboolean
667 gst_basesrc_activate (GstPad * pad, GstActivateMode mode)
668 {
669   gboolean result;
670   GstBaseSrc *basesrc;
671
672   basesrc = GST_BASESRC (GST_OBJECT_PARENT (pad));
673
674   /* prepare subclass first */
675   switch (mode) {
676     case GST_ACTIVATE_PUSH:
677     case GST_ACTIVATE_PULL:
678       result = gst_basesrc_start (basesrc);
679       break;
680     default:
681       result = TRUE;
682       break;
683   }
684   /* if that failed we can stop here */
685   if (!result)
686     goto error_start;
687
688   result = FALSE;
689   switch (mode) {
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);
697
698         gst_task_start (GST_RPAD_TASK (pad));
699         GST_STREAM_UNLOCK (pad);
700         result = TRUE;
701       }
702       break;
703     case GST_ACTIVATE_PULL:
704       result = TRUE;
705       break;
706     case GST_ACTIVATE_NONE:
707       /* step 1, unblock clock sync (if any) */
708
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;
716       }
717       GST_STREAM_UNLOCK (pad);
718
719       result = TRUE;
720       break;
721   }
722   return result;
723
724   /* ERROR */
725 error_start:
726   {
727     GST_DEBUG_OBJECT (basesrc, "failed to start");
728     return FALSE;
729   }
730 }
731
732 static GstElementStateReturn
733 gst_basesrc_change_state (GstElement * element)
734 {
735   GstBaseSrc *basesrc;
736   GstElementStateReturn result = GST_STATE_FAILURE;
737   GstElementState transition;
738
739   basesrc = GST_BASESRC (element);
740
741   transition = GST_STATE_TRANSITION (element);
742
743   switch (transition) {
744     case GST_STATE_NULL_TO_READY:
745       break;
746     case GST_STATE_READY_TO_PAUSED:
747       break;
748     case GST_STATE_PAUSED_TO_PLAYING:
749       break;
750     default:
751       break;
752   }
753
754   result = GST_ELEMENT_CLASS (parent_class)->change_state (element);
755
756   switch (transition) {
757     case GST_STATE_PLAYING_TO_PAUSED:
758       break;
759     case GST_STATE_PAUSED_TO_READY:
760       result = gst_basesrc_stop (basesrc);
761       break;
762     case GST_STATE_READY_TO_NULL:
763       break;
764     default:
765       break;
766   }
767
768   return result;
769 }