Add -Wmissing-declarations -Wmissing-prototypes to warning flags
[platform/upstream/gstreamer.git] / ext / ogg / gstoggparse.c
1 /* GStreamer
2  * Copyright (C) 2005 Michael Smith <msmith@fluendo.com>
3  *
4  * gstoggparse.c: ogg stream parser
5  *
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.
10  *
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.
15  *
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.
20  */
21
22 /* This ogg parser is essentially a subset of the ogg demuxer - rather than
23  * fully demuxing into packets, we only parse out the pages, create one
24  * GstBuffer per page, set all the appropriate flags on those pages, set caps
25  * appropriately (particularly the 'streamheader' which gives all the header
26  * pages required for initialing decode).
27  *
28  * It's dramatically simpler than the full demuxer as it does not  support 
29  * seeking.
30  */
31
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35 #include <gst/gst.h>
36 #include <ogg/ogg.h>
37 #include <string.h>
38
39 #include "gstogg.h"
40 #include "gstoggstream.h"
41
42 static const GstElementDetails gst_ogg_parse_details =
43 GST_ELEMENT_DETAILS ("Ogg parser",
44     "Codec/Parser",
45     "parse ogg streams into pages (info about ogg: http://xiph.org)",
46     "Michael Smith <msmith@fluendo.com>");
47
48 GST_DEBUG_CATEGORY_STATIC (gst_ogg_parse_debug);
49 #define GST_CAT_DEFAULT gst_ogg_parse_debug
50
51 #define GST_TYPE_OGG_PARSE (gst_ogg_parse_get_type())
52 #define GST_OGG_PARSE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OGG_PARSE, GstOggParse))
53 #define GST_OGG_PARSE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OGG_PARSE, GstOggParse))
54 #define GST_IS_OGG_PARSE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OGG_PARSE))
55 #define GST_IS_OGG_PARSE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OGG_PARSE))
56
57 static GType gst_ogg_parse_get_type (void);
58
59 typedef struct _GstOggParse GstOggParse;
60 typedef struct _GstOggParseClass GstOggParseClass;
61
62 struct _GstOggParse
63 {
64   GstElement element;
65
66   GstPad *sinkpad;              /* Sink pad we're reading data from */
67
68   GstPad *srcpad;               /* Source pad we're writing to */
69
70   GSList *oggstreams;           /* list of GstOggStreams for known streams */
71
72   gint64 offset;                /* Current stream offset */
73
74   gboolean in_headers;          /* Set if we're reading headers for streams */
75
76   gboolean last_page_not_bos;   /* Set if we've seen a non-BOS page */
77
78   ogg_sync_state sync;          /* Ogg page synchronisation */
79
80   GstCaps *caps;                /* Our src caps */
81 };
82
83 struct _GstOggParseClass
84 {
85   GstElementClass parent_class;
86 };
87
88 static void gst_ogg_parse_base_init (gpointer g_class);
89 static void gst_ogg_parse_class_init (GstOggParseClass * klass);
90 static void gst_ogg_parse_init (GstOggParse * ogg);
91 static GstElementClass *parent_class = NULL;
92
93 static GType
94 gst_ogg_parse_get_type (void)
95 {
96   static GType ogg_parse_type = 0;
97
98   if (!ogg_parse_type) {
99     static const GTypeInfo ogg_parse_info = {
100       sizeof (GstOggParseClass),
101       gst_ogg_parse_base_init,
102       NULL,
103       (GClassInitFunc) gst_ogg_parse_class_init,
104       NULL,
105       NULL,
106       sizeof (GstOggParse),
107       0,
108       (GInstanceInitFunc) gst_ogg_parse_init,
109     };
110
111     ogg_parse_type = g_type_register_static (GST_TYPE_ELEMENT, "GstOggParse",
112         &ogg_parse_info, 0);
113   }
114   return ogg_parse_type;
115 }
116
117 static void
118 free_stream (GstOggStream * stream)
119 {
120   g_list_foreach (stream->headers, (GFunc) gst_mini_object_unref, NULL);
121   g_list_foreach (stream->unknown_pages, (GFunc) gst_mini_object_unref, NULL);
122
123   g_free (stream);
124 }
125
126 static void
127 gst_ogg_parse_delete_all_streams (GstOggParse * ogg)
128 {
129   g_slist_foreach (ogg->oggstreams, (GFunc) free_stream, NULL);
130   g_slist_free (ogg->oggstreams);
131   ogg->oggstreams = NULL;
132 }
133
134 static GstOggStream *
135 gst_ogg_parse_new_stream (GstOggParse * parser, ogg_page * page)
136 {
137   GstOggStream *stream;
138   ogg_packet packet;
139   int ret;
140   guint32 serialno;
141
142   serialno = ogg_page_serialno (page);
143
144   GST_DEBUG_OBJECT (parser, "creating new stream %08x", serialno);
145
146   stream = g_new0 (GstOggStream, 1);
147
148   stream->serialno = serialno;
149   stream->in_headers = 1;
150
151   if (ogg_stream_init (&stream->stream, serialno) != 0) {
152     GST_ERROR ("Could not initialize ogg_stream struct for serial %08x.",
153         serialno);
154     return NULL;
155   }
156
157   /* FIXME check return */
158   ogg_stream_pagein (&stream->stream, page);
159
160   /* FIXME check return */
161   ret = ogg_stream_packetout (&stream->stream, &packet);
162   if (ret == 1) {
163     gst_ogg_stream_setup_map (stream, &packet);
164   }
165
166   parser->oggstreams = g_slist_append (parser->oggstreams, stream);
167
168   return stream;
169 }
170
171 static GstOggStream *
172 gst_ogg_parse_find_stream (GstOggParse * parser, guint32 serialno)
173 {
174   GSList *l;
175
176   for (l = parser->oggstreams; l != NULL; l = l->next) {
177     GstOggStream *stream = (GstOggStream *) l->data;
178
179     if (stream->serialno == serialno)
180       return stream;
181   }
182   return NULL;
183 }
184
185 /* signals and args */
186 enum
187 {
188   /* FILL ME */
189   LAST_SIGNAL
190 };
191
192 enum
193 {
194   ARG_0
195       /* FILL ME */
196 };
197
198 static GstStaticPadTemplate ogg_parse_src_template_factory =
199 GST_STATIC_PAD_TEMPLATE ("src",
200     GST_PAD_SRC,
201     GST_PAD_ALWAYS,
202     GST_STATIC_CAPS ("application/ogg")
203     );
204
205 static GstStaticPadTemplate ogg_parse_sink_template_factory =
206 GST_STATIC_PAD_TEMPLATE ("sink",
207     GST_PAD_SINK,
208     GST_PAD_ALWAYS,
209     GST_STATIC_CAPS ("application/ogg")
210     );
211
212 static void gst_ogg_parse_dispose (GObject * object);
213 static GstStateChangeReturn gst_ogg_parse_change_state (GstElement * element,
214     GstStateChange transition);
215 static GstFlowReturn gst_ogg_parse_chain (GstPad * pad, GstBuffer * buffer);
216
217 static void
218 gst_ogg_parse_base_init (gpointer g_class)
219 {
220   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
221
222   gst_element_class_set_details (element_class, &gst_ogg_parse_details);
223
224   gst_element_class_add_pad_template (element_class,
225       gst_static_pad_template_get (&ogg_parse_sink_template_factory));
226   gst_element_class_add_pad_template (element_class,
227       gst_static_pad_template_get (&ogg_parse_src_template_factory));
228 }
229
230 static void
231 gst_ogg_parse_class_init (GstOggParseClass * klass)
232 {
233   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
234   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
235
236   parent_class = g_type_class_peek_parent (klass);
237
238   gstelement_class->change_state = gst_ogg_parse_change_state;
239
240   gobject_class->dispose = gst_ogg_parse_dispose;
241 }
242
243 static void
244 gst_ogg_parse_init (GstOggParse * ogg)
245 {
246   /* create the sink and source pads */
247   ogg->sinkpad =
248       gst_pad_new_from_static_template (&ogg_parse_sink_template_factory,
249       "sink");
250   ogg->srcpad =
251       gst_pad_new_from_static_template (&ogg_parse_src_template_factory, "src");
252
253   /* TODO: Are there any events we must handle? */
254   /* gst_pad_set_event_function (ogg->sinkpad, gst_ogg_parse_handle_event); */
255   gst_pad_set_chain_function (ogg->sinkpad, gst_ogg_parse_chain);
256
257   gst_element_add_pad (GST_ELEMENT (ogg), ogg->sinkpad);
258   gst_element_add_pad (GST_ELEMENT (ogg), ogg->srcpad);
259
260   ogg->oggstreams = NULL;
261 }
262
263 static void
264 gst_ogg_parse_dispose (GObject * object)
265 {
266   GstOggParse *ogg = GST_OGG_PARSE (object);
267
268   GST_LOG_OBJECT (ogg, "Disposing of object %p", ogg);
269
270   ogg_sync_clear (&ogg->sync);
271   gst_ogg_parse_delete_all_streams (ogg);
272
273   if (ogg->caps) {
274     gst_caps_unref (ogg->caps);
275     ogg->caps = NULL;
276   }
277
278   if (G_OBJECT_CLASS (parent_class)->dispose)
279     G_OBJECT_CLASS (parent_class)->dispose (object);
280 }
281
282 /* submit the given buffer to the ogg sync.
283  *
284  * Returns the number of bytes submited.
285  */
286 static gint
287 gst_ogg_parse_submit_buffer (GstOggParse * ogg, GstBuffer * buffer)
288 {
289   guint size;
290   guint8 *data;
291   gchar *oggbuffer;
292
293   size = GST_BUFFER_SIZE (buffer);
294   data = GST_BUFFER_DATA (buffer);
295
296   /* We now have a buffer, submit it to the ogg sync layer */
297   oggbuffer = ogg_sync_buffer (&ogg->sync, size);
298   memcpy (oggbuffer, data, size);
299   ogg_sync_wrote (&ogg->sync, size);
300
301   /* We've copied all the neccesary data, so we're done with the buffer */
302   gst_buffer_unref (buffer);
303
304   return size;
305 }
306
307 static void
308 gst_ogg_parse_append_header (GValue * array, GstBuffer * buf)
309 {
310   GValue value = { 0 };
311   /* We require a copy to avoid circular refcounts */
312   GstBuffer *buffer = gst_buffer_copy (buf);
313
314   GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
315
316   g_value_init (&value, GST_TYPE_BUFFER);
317   gst_value_set_buffer (&value, buffer);
318   gst_value_array_append_value (array, &value);
319   g_value_unset (&value);
320
321 }
322
323 typedef enum
324 {
325   PAGE_HEADER,                  /* Header page */
326   PAGE_DATA,                    /* Data page */
327   PAGE_PENDING,                 /* We don't know yet, we'll have to see some future pages */
328 } page_type;
329
330 static page_type
331 gst_ogg_parse_is_header (GstOggParse * ogg, GstOggStream * stream,
332     ogg_page * page)
333 {
334   ogg_int64_t gpos = ogg_page_granulepos (page);
335
336   if (gpos < 0)
337     return PAGE_PENDING;
338
339   /* This is good enough for now, but technically requires codec-specific
340    * behaviour to be perfect. This is where we need the mooted library for 
341    * this stuff, which nobody has written.
342    */
343   if (gpos > 0)
344     return PAGE_DATA;
345   else
346     return PAGE_HEADER;
347 }
348
349 static GstBuffer *
350 gst_ogg_parse_buffer_from_page (ogg_page * page,
351     guint64 offset, gboolean delta, GstClockTime timestamp)
352 {
353   int size = page->header_len + page->body_len;
354   GstBuffer *buf = gst_buffer_new_and_alloc (size);
355
356   memcpy (GST_BUFFER_DATA (buf), page->header, page->header_len);
357   memcpy (GST_BUFFER_DATA (buf) + page->header_len, page->body, page->body_len);
358
359   GST_BUFFER_TIMESTAMP (buf) = timestamp;
360   GST_BUFFER_OFFSET (buf) = offset;
361   GST_BUFFER_OFFSET_END (buf) = offset + size;
362
363   return buf;
364 }
365
366
367 /* Reads in buffers, parses them, reframes into one-buffer-per-ogg-page, submits
368  * pages to output pad.
369  */
370 static GstFlowReturn
371 gst_ogg_parse_chain (GstPad * pad, GstBuffer * buffer)
372 {
373   GstOggParse *ogg;
374   GstFlowReturn result = GST_FLOW_OK;
375   gint ret = -1;
376   guint32 serialno;
377   GstBuffer *pagebuffer;
378   GstClockTime buffertimestamp = GST_BUFFER_TIMESTAMP (buffer);
379
380   ogg = GST_OGG_PARSE (GST_OBJECT_PARENT (pad));
381
382   GST_LOG_OBJECT (ogg, "Chain function received buffer of size %d",
383       GST_BUFFER_SIZE (buffer));
384
385   gst_ogg_parse_submit_buffer (ogg, buffer);
386
387   while (ret != 0 && result == GST_FLOW_OK) {
388     ogg_page page;
389
390     /* We use ogg_sync_pageseek() rather than ogg_sync_pageout() so that we can
391      * track how many bytes the ogg layer discarded (in the case of sync errors,
392      * etc.); this allows us to accurately track the current stream offset
393      */
394     ret = ogg_sync_pageseek (&ogg->sync, &page);
395     if (ret == 0) {
396       /* need more data, that's fine... */
397       break;
398     } else if (ret < 0) {
399       /* discontinuity; track how many bytes we skipped (-ret) */
400       ogg->offset -= ret;
401     } else {
402       gint64 granule = ogg_page_granulepos (&page);
403 #ifndef GST_DISABLE_GST_DEBUG
404       int bos = ogg_page_bos (&page);
405 #endif
406       guint64 startoffset = ogg->offset;
407       GstOggStream *stream;
408
409       serialno = ogg_page_serialno (&page);
410       stream = gst_ogg_parse_find_stream (ogg, serialno);
411
412       GST_LOG_OBJECT (ogg, "Timestamping outgoing buffer as %" GST_TIME_FORMAT,
413           GST_TIME_ARGS (buffertimestamp));
414
415       buffertimestamp = gst_ogg_stream_get_end_time_for_granulepos (stream,
416           granule);
417       pagebuffer = gst_ogg_parse_buffer_from_page (&page, startoffset, FALSE,
418           buffertimestamp);
419
420       /* We read out 'ret' bytes, so we set the next offset appropriately */
421       ogg->offset += ret;
422
423       GST_LOG_OBJECT (ogg,
424           "processing ogg page (serial %08x, pageno %ld, "
425           "granule pos %" G_GUINT64_FORMAT ", bos %d, offset %"
426           G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT ")",
427           serialno, ogg_page_pageno (&page),
428           granule, bos, startoffset, ogg->offset);
429
430       if (ogg_page_bos (&page)) {
431         /* If we've seen this serialno before, this is technically an error,
432          * we log this case but accept it - this one replaces the previous
433          * stream with this serialno. We can do this since we're streaming, and
434          * not supporting seeking...
435          */
436         GstOggStream *stream = gst_ogg_parse_find_stream (ogg, serialno);
437
438         if (stream != NULL) {
439           GST_LOG_OBJECT (ogg, "Incorrect stream; repeats serial number %u "
440               "at offset %" G_GINT64_FORMAT, serialno, ogg->offset);
441         }
442
443         if (ogg->last_page_not_bos) {
444           GST_LOG_OBJECT (ogg, "Deleting all referenced streams, found a new "
445               "chain starting with serial %u", serialno);
446           gst_ogg_parse_delete_all_streams (ogg);
447         }
448
449         stream = gst_ogg_parse_new_stream (ogg, &page);
450
451         ogg->last_page_not_bos = FALSE;
452
453         gst_buffer_ref (pagebuffer);
454         stream->headers = g_list_append (stream->headers, pagebuffer);
455
456         if (!ogg->in_headers) {
457           GST_LOG_OBJECT (ogg,
458               "Found start of new chain at offset %" G_GUINT64_FORMAT,
459               startoffset);
460           ogg->in_headers = 1;
461         }
462
463         /* For now, we just keep the header buffer in the stream->headers list;
464          * it actually gets output once we've collected the entire set
465          */
466       } else {
467         /* Non-BOS page. Either: we're outside headers, and this isn't a 
468          * header (normal data), outside headers and this is (error!), inside
469          * headers, this is (append header), or inside headers and this isn't 
470          * (we've found the end of headers; flush the lot!)
471          *
472          * Before that, we flag that the last page seen (this one) was not a 
473          * BOS page; that way we know that when we next see a BOS page it's a
474          * new chain, and we can flush all existing streams.
475          */
476         page_type type;
477         GstOggStream *stream = gst_ogg_parse_find_stream (ogg, serialno);
478
479         if (!stream) {
480           GST_LOG_OBJECT (ogg,
481               "Non-BOS page unexpectedly found at %" G_GINT64_FORMAT,
482               ogg->offset);
483           goto failure;
484         }
485
486         ogg->last_page_not_bos = TRUE;
487
488         type = gst_ogg_parse_is_header (ogg, stream, &page);
489
490         if (type == PAGE_PENDING && ogg->in_headers) {
491           gst_buffer_ref (pagebuffer);
492
493           stream->unknown_pages = g_list_append (stream->unknown_pages,
494               pagebuffer);
495         } else if (type == PAGE_HEADER) {
496           if (!ogg->in_headers) {
497             GST_LOG_OBJECT (ogg, "Header page unexpectedly found outside "
498                 "headers at offset %" G_GINT64_FORMAT, ogg->offset);
499             goto failure;
500           } else {
501             /* Append the header to the buffer list, after any unknown previous
502              * pages
503              */
504             stream->headers = g_list_concat (stream->headers,
505                 stream->unknown_pages);
506             g_list_free (stream->unknown_pages);
507             gst_buffer_ref (pagebuffer);
508             stream->headers = g_list_append (stream->headers, pagebuffer);
509           }
510         } else {                /* PAGE_DATA, or PAGE_PENDING but outside headers */
511           if (ogg->in_headers) {
512             /* First non-header page... set caps, flush headers.
513              *
514              * First up, we build a single GValue list of all the pagebuffers
515              * we're using for the headers, in order.
516              * Then we set this on the caps structure. Then we can start pushing
517              * buffers for the headers, and finally we send this non-header
518              * page.
519              */
520             GstCaps *caps;
521             GstStructure *structure;
522             GValue array = { 0 };
523             gint count = 0;
524             gboolean found_pending_headers = FALSE;
525             GSList *l;
526
527             g_value_init (&array, GST_TYPE_ARRAY);
528
529             for (l = ogg->oggstreams; l != NULL; l = l->next) {
530               GstOggStream *stream = (GstOggStream *) l->data;
531
532               if (g_list_length (stream->headers) == 0) {
533                 GST_LOG_OBJECT (ogg, "No primary header found for stream %08lx",
534                     stream->serialno);
535                 goto failure;
536               }
537
538               gst_ogg_parse_append_header (&array,
539                   GST_BUFFER (stream->headers->data));
540               count++;
541             }
542
543             for (l = ogg->oggstreams; l != NULL; l = l->next) {
544               GstOggStream *stream = (GstOggStream *) l->data;
545               int j;
546
547               for (j = 1; j < g_list_length (stream->headers); j++) {
548                 gst_ogg_parse_append_header (&array,
549                     GST_BUFFER (g_list_nth_data (stream->headers, j)));
550                 count++;
551               }
552             }
553
554             caps = gst_pad_get_caps (ogg->srcpad);
555             caps = gst_caps_make_writable (caps);
556
557             structure = gst_caps_get_structure (caps, 0);
558             gst_structure_set_value (structure, "streamheader", &array);
559
560             gst_pad_set_caps (ogg->srcpad, caps);
561
562             g_value_unset (&array);
563
564             if (ogg->caps)
565               gst_caps_unref (ogg->caps);
566             ogg->caps = caps;
567
568             GST_LOG_OBJECT (ogg, "Set \"streamheader\" caps with %d buffers "
569                 "(one per page)", count);
570
571             /* Now, we do the same thing, but push buffers... */
572             for (l = ogg->oggstreams; l != NULL; l = l->next) {
573               GstOggStream *stream = (GstOggStream *) l->data;
574               GstBuffer *buf = GST_BUFFER (stream->headers->data);
575
576               gst_buffer_set_caps (buf, caps);
577
578               result = gst_pad_push (ogg->srcpad, buf);
579               if (result != GST_FLOW_OK)
580                 return result;
581             }
582             for (l = ogg->oggstreams; l != NULL; l = l->next) {
583               GstOggStream *stream = (GstOggStream *) l->data;
584               int j;
585
586               for (j = 1; j < g_list_length (stream->headers); j++) {
587                 GstBuffer *buf =
588                     GST_BUFFER (g_list_nth_data (stream->headers, j));
589                 gst_buffer_set_caps (buf, caps);
590
591                 result = gst_pad_push (ogg->srcpad, buf);
592                 if (result != GST_FLOW_OK)
593                   return result;
594               }
595             }
596
597             ogg->in_headers = 0;
598
599             /* And finally the pending data pages */
600             for (l = ogg->oggstreams; l != NULL; l = l->next) {
601               GstOggStream *stream = (GstOggStream *) l->data;
602               GList *k;
603
604               if (stream->unknown_pages == NULL)
605                 continue;
606
607               if (found_pending_headers) {
608                 GST_WARNING_OBJECT (ogg, "Incorrectly muxed headers found at "
609                     "approximate offset %" G_GINT64_FORMAT, ogg->offset);
610               }
611               found_pending_headers = TRUE;
612
613               GST_LOG_OBJECT (ogg, "Pushing %d pending pages after headers",
614                   g_list_length (stream->unknown_pages) + 1);
615
616               for (k = stream->unknown_pages; k != NULL; k = k->next) {
617                 GstBuffer *buf;
618
619                 buf = GST_BUFFER (k->data);
620                 gst_buffer_set_caps (buf, caps);
621                 result = gst_pad_push (ogg->srcpad, buf);
622                 if (result != GST_FLOW_OK)
623                   return result;
624               }
625               g_list_foreach (stream->unknown_pages,
626                   (GFunc) gst_mini_object_unref, NULL);
627               g_list_free (stream->unknown_pages);
628               stream->unknown_pages = NULL;
629             }
630
631             gst_buffer_set_caps (pagebuffer, caps);
632
633             result = gst_pad_push (ogg->srcpad, GST_BUFFER (pagebuffer));
634             if (result != GST_FLOW_OK)
635               return result;
636           } else {
637             /* Normal data page, submit buffer */
638             gst_buffer_set_caps (pagebuffer, ogg->caps);
639             result = gst_pad_push (ogg->srcpad, GST_BUFFER (pagebuffer));
640             if (result != GST_FLOW_OK)
641               return result;
642           }
643         }
644       }
645     }
646   }
647
648   return result;
649
650 failure:
651   gst_pad_push_event (GST_PAD (ogg->srcpad), gst_event_new_eos ());
652   return GST_FLOW_ERROR;
653 }
654
655 static GstStateChangeReturn
656 gst_ogg_parse_change_state (GstElement * element, GstStateChange transition)
657 {
658   GstOggParse *ogg;
659   GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
660
661   ogg = GST_OGG_PARSE (element);
662
663   switch (transition) {
664     case GST_STATE_CHANGE_NULL_TO_READY:
665       ogg_sync_init (&ogg->sync);
666       break;
667     case GST_STATE_CHANGE_READY_TO_PAUSED:
668       ogg_sync_reset (&ogg->sync);
669       break;
670     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
671       break;
672     default:
673       break;
674   }
675
676   result = parent_class->change_state (element, transition);
677
678   switch (transition) {
679     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
680       break;
681     case GST_STATE_CHANGE_PAUSED_TO_READY:
682       break;
683     case GST_STATE_CHANGE_READY_TO_NULL:
684       ogg_sync_clear (&ogg->sync);
685       break;
686     default:
687       break;
688   }
689   return result;
690 }
691
692 gboolean
693 gst_ogg_parse_plugin_init (GstPlugin * plugin)
694 {
695   GST_DEBUG_CATEGORY_INIT (gst_ogg_parse_debug, "oggparse", 0, "ogg parser");
696
697   return gst_element_register (plugin, "oggparse", GST_RANK_NONE,
698       GST_TYPE_OGG_PARSE);
699 }