ext/ogg/gstogmparse.c: don't pass random values to ogmparse convert function.
[platform/upstream/gstreamer.git] / ext / ogg / gstogmparse.c
1 /* GStreamer
2  * Copyright (C) 2004 Ronald Bultje <rbultje@ronald.bitfreak.net>
3  *
4  * gstogmparse.c: OGM stream header parsing (and data passthrough)
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 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <string.h>
27
28 #include <gst/gst.h>
29 #include <gst/riff/riff-media.h>
30
31 GST_DEBUG_CATEGORY_STATIC (gst_ogm_parse_debug);
32 #define GST_CAT_DEFAULT gst_ogm_parse_debug
33
34 #define GST_TYPE_OGM_VIDEO_PARSE (gst_ogm_video_parse_get_type())
35 #define GST_IS_OGM_VIDEO_PARSE(obj) \
36   (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_OGM_VIDEO_PARSE))
37
38 #define GST_TYPE_OGM_AUDIO_PARSE (gst_ogm_audio_parse_get_type())
39 #define GST_IS_OGM_AUDIO_PARSE(obj) \
40   (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_OGM_AUDIO_PARSE))
41
42 #define GST_TYPE_OGM_TEXT_PARSE (gst_ogm_text_parse_get_type())
43 #define GST_IS_OGM_TEXT_PARSE(obj) \
44   (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_OGM_TEXT_PARSE))
45
46 #define GST_TYPE_OGM_PARSE (gst_ogm_parse_get_type())
47 #define GST_OGM_PARSE(obj) \
48   (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_OGM_PARSE, GstOgmParse))
49 #define GST_OGM_PARSE_CLASS(klass) \
50   (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_OGM_PARSE, GstOgmParse))
51 #define GST_IS_OGM_PARSE(obj) \
52   (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_OGM_PARSE))
53 #define GST_IS_OGM_PARSE_CLASS(obj) \
54   (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_OGM_PARSE))
55 #define GST_OGM_PARSE_GET_CLASS(obj) \
56   (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_OGM_PARSE, GstOgmParseClass))
57
58 typedef struct _stream_header_video
59 {
60   gint32 width;
61   gint32 height;
62 } stream_header_video;
63
64 typedef struct _stream_header_audio
65 {
66   gint16 channels;
67   gint16 blockalign;
68   gint32 avgbytespersec;
69 } stream_header_audio;
70
71 typedef struct _stream_header
72 {
73   gchar streamtype[8];
74   gchar subtype[4];
75
76   /* size of the structure */
77   gint32 size;
78
79   /* in reference time */
80   gint64 time_unit;
81
82   gint64 samples_per_unit;
83
84   /* in media time */
85   gint32 default_len;
86
87   gint32 buffersize;
88   gint32 bits_per_sample;
89
90   union
91   {
92     stream_header_video video;
93     stream_header_audio audio;
94     /* text has no additional data */
95   } s;
96 } stream_header;
97
98 typedef struct _GstOgmParse
99 {
100   GstElement element;
101
102   /* pads */
103   GstPad *srcpad, *sinkpad;
104   GstPadTemplate *srcpadtempl;
105
106   /* audio or video */
107   stream_header hdr;
108
109   /* expected next granulepos (used for timestamp guessing) */
110   guint64 next_granulepos;
111 } GstOgmParse;
112
113 typedef struct _GstOgmParseClass
114 {
115   GstElementClass parent_class;
116 } GstOgmParseClass;
117
118 static GstStaticPadTemplate ogm_video_parse_sink_template_factory =
119 GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
120     GST_STATIC_CAPS ("application/x-ogm-video"));
121 static GstStaticPadTemplate ogm_audio_parse_sink_template_factory =
122 GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
123     GST_STATIC_CAPS ("application/x-ogm-audio"));
124 static GstStaticPadTemplate ogm_text_parse_sink_template_factory =
125 GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
126     GST_STATIC_CAPS ("application/x-ogm-text"));
127 static GstPadTemplate *video_src_templ, *audio_src_templ, *text_src_templ;
128
129 static GType gst_ogm_audio_parse_get_type (void);
130 static GType gst_ogm_video_parse_get_type (void);
131 static GType gst_ogm_text_parse_get_type (void);
132 static GType gst_ogm_parse_get_type (void);
133
134 static void gst_ogm_audio_parse_base_init (GstOgmParseClass * klass);
135 static void gst_ogm_video_parse_base_init (GstOgmParseClass * klass);
136 static void gst_ogm_text_parse_base_init (GstOgmParseClass * klass);
137 static void gst_ogm_parse_class_init (GstOgmParseClass * klass);
138 static void gst_ogm_parse_init (GstOgmParse * ogm);
139 static void gst_ogm_video_parse_init (GstOgmParse * ogm);
140 static void gst_ogm_audio_parse_init (GstOgmParse * ogm);
141 static void gst_ogm_text_parse_init (GstOgmParse * ogm);
142
143 #if 0
144 static const GstFormat *gst_ogm_parse_get_sink_formats (GstPad * pad);
145 #endif
146
147 static const GstQueryType *gst_ogm_parse_get_sink_querytypes (GstPad * pad);
148 static gboolean gst_ogm_parse_sink_query (GstPad * pad, GstQuery * query);
149 static gboolean gst_ogm_parse_sink_convert (GstPad * pad, GstFormat src_format,
150     gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
151
152 static GstFlowReturn gst_ogm_parse_chain (GstPad * pad, GstBuffer * buffer);
153
154 static GstStateChangeReturn gst_ogm_parse_change_state (GstElement * element,
155     GstStateChange transition);
156
157 static GstElementClass *parent_class = NULL;
158
159 static GType
160 gst_ogm_parse_get_type (void)
161 {
162   static GType ogm_parse_type = 0;
163
164   if (!ogm_parse_type) {
165     static const GTypeInfo ogm_parse_info = {
166       sizeof (GstOgmParseClass),
167       NULL,
168       NULL,
169       (GClassInitFunc) gst_ogm_parse_class_init,
170       NULL,
171       NULL,
172       sizeof (GstOgmParse),
173       0,
174       (GInstanceInitFunc) gst_ogm_parse_init,
175     };
176
177     ogm_parse_type =
178         g_type_register_static (GST_TYPE_ELEMENT,
179         "GstOgmParse", &ogm_parse_info, 0);
180   }
181
182   return ogm_parse_type;
183 }
184
185 static GType
186 gst_ogm_audio_parse_get_type (void)
187 {
188   static GType ogm_audio_parse_type = 0;
189
190   if (!ogm_audio_parse_type) {
191     static const GTypeInfo ogm_audio_parse_info = {
192       sizeof (GstOgmParseClass),
193       (GBaseInitFunc) gst_ogm_audio_parse_base_init,
194       NULL,
195       NULL,
196       NULL,
197       NULL,
198       sizeof (GstOgmParse),
199       0,
200       (GInstanceInitFunc) gst_ogm_audio_parse_init,
201     };
202
203     ogm_audio_parse_type =
204         g_type_register_static (GST_TYPE_OGM_PARSE,
205         "GstOgmAudioParse", &ogm_audio_parse_info, 0);
206   }
207
208   return ogm_audio_parse_type;
209 }
210
211 GType
212 gst_ogm_video_parse_get_type (void)
213 {
214   static GType ogm_video_parse_type = 0;
215
216   if (!ogm_video_parse_type) {
217     static const GTypeInfo ogm_video_parse_info = {
218       sizeof (GstOgmParseClass),
219       (GBaseInitFunc) gst_ogm_video_parse_base_init,
220       NULL,
221       NULL,
222       NULL,
223       NULL,
224       sizeof (GstOgmParse),
225       0,
226       (GInstanceInitFunc) gst_ogm_video_parse_init,
227     };
228
229     ogm_video_parse_type =
230         g_type_register_static (GST_TYPE_OGM_PARSE,
231         "GstOgmVideoParse", &ogm_video_parse_info, 0);
232   }
233
234   return ogm_video_parse_type;
235 }
236
237 GType
238 gst_ogm_text_parse_get_type (void)
239 {
240   static GType ogm_text_parse_type = 0;
241
242   if (!ogm_text_parse_type) {
243     static const GTypeInfo ogm_text_parse_info = {
244       sizeof (GstOgmParseClass),
245       (GBaseInitFunc) gst_ogm_text_parse_base_init,
246       NULL,
247       NULL,
248       NULL,
249       NULL,
250       sizeof (GstOgmParse),
251       0,
252       (GInstanceInitFunc) gst_ogm_text_parse_init,
253     };
254
255     ogm_text_parse_type =
256         g_type_register_static (GST_TYPE_OGM_PARSE,
257         "GstOgmTextParse", &ogm_text_parse_info, 0);
258   }
259
260   return ogm_text_parse_type;
261 }
262
263 static void
264 gst_ogm_audio_parse_base_init (GstOgmParseClass * klass)
265 {
266   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
267   static GstElementDetails gst_ogm_audio_parse_details =
268       GST_ELEMENT_DETAILS ("OGM audio stream parser",
269       "Codec/Decoder/Audio",
270       "parse an OGM audio header and stream",
271       "Ronald Bultje <rbultje@ronald.bitfreak.net>");
272   GstCaps *caps = gst_riff_create_audio_template_caps ();
273
274   gst_element_class_set_details (element_class, &gst_ogm_audio_parse_details);
275
276   gst_element_class_add_pad_template (element_class,
277       gst_static_pad_template_get (&ogm_audio_parse_sink_template_factory));
278   audio_src_templ = gst_pad_template_new ("src",
279       GST_PAD_SRC, GST_PAD_SOMETIMES, caps);
280   gst_element_class_add_pad_template (element_class, audio_src_templ);
281 }
282
283 static void
284 gst_ogm_video_parse_base_init (GstOgmParseClass * klass)
285 {
286   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
287   static GstElementDetails gst_ogm_video_parse_details =
288       GST_ELEMENT_DETAILS ("OGM video stream parser",
289       "Codec/Decoder/Video",
290       "parse an OGM video header and stream",
291       "Ronald Bultje <rbultje@ronald.bitfreak.net>");
292   GstCaps *caps = gst_riff_create_video_template_caps ();
293
294   gst_element_class_set_details (element_class, &gst_ogm_video_parse_details);
295
296   gst_element_class_add_pad_template (element_class,
297       gst_static_pad_template_get (&ogm_video_parse_sink_template_factory));
298   video_src_templ = gst_pad_template_new ("src",
299       GST_PAD_SRC, GST_PAD_SOMETIMES, caps);
300   gst_element_class_add_pad_template (element_class, video_src_templ);
301 }
302
303 static void
304 gst_ogm_text_parse_base_init (GstOgmParseClass * klass)
305 {
306   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
307   static GstElementDetails gst_ogm_text_parse_details =
308       GST_ELEMENT_DETAILS ("OGM text stream parser",
309       "Codec/Decoder/Subtitle",
310       "parse an OGM text header and stream",
311       "Ronald Bultje <rbultje@ronald.bitfreak.net>");
312   GstCaps *caps = gst_caps_new_simple ("text/plain", NULL);
313
314   gst_element_class_set_details (element_class, &gst_ogm_text_parse_details);
315
316   gst_element_class_add_pad_template (element_class,
317       gst_static_pad_template_get (&ogm_text_parse_sink_template_factory));
318   text_src_templ = gst_pad_template_new ("src",
319       GST_PAD_SRC, GST_PAD_SOMETIMES, caps);
320   gst_element_class_add_pad_template (element_class, text_src_templ);
321 }
322
323 static void
324 gst_ogm_parse_class_init (GstOgmParseClass * klass)
325 {
326   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
327
328   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
329
330   gstelement_class->change_state = gst_ogm_parse_change_state;
331 }
332
333 static void
334 gst_ogm_parse_init (GstOgmParse * ogm)
335 {
336   /* initalize */
337   memset (&ogm->hdr, 0, sizeof (ogm->hdr));
338   ogm->next_granulepos = 0;
339 }
340
341 static void
342 gst_ogm_audio_parse_init (GstOgmParse * ogm)
343 {
344   /* create the pads */
345   ogm->sinkpad =
346       gst_pad_new_from_static_template (&ogm_audio_parse_sink_template_factory,
347       "sink");
348   gst_pad_set_query_function (ogm->sinkpad, gst_ogm_parse_sink_query);
349   gst_pad_set_chain_function (ogm->sinkpad, gst_ogm_parse_chain);
350   gst_element_add_pad (GST_ELEMENT (ogm), ogm->sinkpad);
351
352 #if 0
353   ogm->srcpad = gst_pad_new_from_template (audio_src_templ, "src");
354   gst_pad_use_explicit_caps (ogm->srcpad);
355   gst_element_add_pad (GST_ELEMENT (ogm), ogm->srcpad);
356 #endif
357   ogm->srcpadtempl = audio_src_templ;
358 }
359
360 static void
361 gst_ogm_video_parse_init (GstOgmParse * ogm)
362 {
363   /* create the pads */
364   ogm->sinkpad =
365       gst_pad_new_from_static_template (&ogm_video_parse_sink_template_factory,
366       "sink");
367   gst_pad_set_query_function (ogm->sinkpad, gst_ogm_parse_sink_query);
368   gst_pad_set_chain_function (ogm->sinkpad, gst_ogm_parse_chain);
369   gst_element_add_pad (GST_ELEMENT (ogm), ogm->sinkpad);
370
371 #if 0
372   ogm->srcpad = gst_pad_new_from_template (video_src_templ, "src");
373   gst_pad_use_explicit_caps (ogm->srcpad);
374   gst_element_add_pad (GST_ELEMENT (ogm), ogm->srcpad);
375 #endif
376   ogm->srcpadtempl = video_src_templ;
377 }
378
379 static void
380 gst_ogm_text_parse_init (GstOgmParse * ogm)
381 {
382   /* create the pads */
383   ogm->sinkpad =
384       gst_pad_new_from_static_template (&ogm_text_parse_sink_template_factory,
385       "sink");
386   gst_pad_set_query_type_function (ogm->sinkpad,
387       gst_ogm_parse_get_sink_querytypes);
388   gst_pad_set_query_function (ogm->sinkpad, gst_ogm_parse_sink_query);
389   gst_pad_set_chain_function (ogm->sinkpad, gst_ogm_parse_chain);
390   gst_element_add_pad (GST_ELEMENT (ogm), ogm->sinkpad);
391
392 #if 0
393   ogm->srcpad = gst_pad_new_from_template (text_src_templ, "src");
394   gst_pad_use_explicit_caps (ogm->srcpad);
395   gst_element_add_pad (GST_ELEMENT (ogm), ogm->srcpad);
396 #endif
397   ogm->srcpadtempl = text_src_templ;
398 }
399
400 #if 0
401 static const GstFormat *
402 gst_ogm_parse_get_sink_formats (GstPad * pad)
403 {
404   static GstFormat formats[] = {
405     GST_FORMAT_DEFAULT,
406     GST_FORMAT_TIME,
407     0
408   };
409
410   return formats;
411 }
412 #endif
413
414 static const GstQueryType *
415 gst_ogm_parse_get_sink_querytypes (GstPad * pad)
416 {
417   static const GstQueryType types[] = {
418     GST_QUERY_POSITION,
419     0
420   };
421
422   return types;
423 }
424
425 static gboolean
426 gst_ogm_parse_sink_convert (GstPad * pad,
427     GstFormat src_format, gint64 src_value,
428     GstFormat * dest_format, gint64 * dest_value)
429 {
430   gboolean res = FALSE;
431   GstOgmParse *ogm = GST_OGM_PARSE (gst_pad_get_parent (pad));
432
433   switch (src_format) {
434     case GST_FORMAT_DEFAULT:
435       switch (*dest_format) {
436         case GST_FORMAT_TIME:
437           switch (ogm->hdr.streamtype[0]) {
438             case 'a':
439               *dest_value = GST_SECOND * src_value / ogm->hdr.samples_per_unit;
440               res = TRUE;
441               break;
442             case 'v':
443             case 't':
444               *dest_value = (GST_SECOND / 10000000) *
445                   ogm->hdr.time_unit * src_value;
446               res = TRUE;
447               break;
448             default:
449               break;
450           }
451           break;
452         default:
453           break;
454       }
455       break;
456     case GST_FORMAT_TIME:
457       switch (*dest_format) {
458         case GST_FORMAT_DEFAULT:
459           switch (ogm->hdr.streamtype[0]) {
460             case 'a':
461               *dest_value = ogm->hdr.samples_per_unit * src_value / GST_SECOND;
462               res = TRUE;
463               break;
464             case 'v':
465             case 't':
466               *dest_value = src_value /
467                   ((GST_SECOND / 10000000) * ogm->hdr.time_unit);
468               res = TRUE;
469               break;
470             default:
471               break;
472           }
473           break;
474         default:
475           break;
476       }
477       break;
478     default:
479       break;
480   }
481
482   return res;
483 }
484
485 static gboolean
486 gst_ogm_parse_sink_query (GstPad * pad, GstQuery * query)
487 {
488   GstOgmParse *ogm = GST_OGM_PARSE (GST_PAD_PARENT (pad));
489   GstFormat format;
490   gboolean res;
491
492   switch (GST_QUERY_TYPE (query)) {
493     case GST_QUERY_POSITION:
494     {
495       gint64 val;
496
497       gst_query_parse_position (query, &format, NULL);
498
499       if (format != GST_FORMAT_DEFAULT && format != GST_FORMAT_TIME)
500         return FALSE;
501
502       if ((res = gst_ogm_parse_sink_convert (pad,
503                   GST_FORMAT_DEFAULT, ogm->next_granulepos, &format, &val))) {
504         /* don't know the total length here.. */
505         gst_query_set_position (query, format, val);
506       }
507       break;
508     }
509     case GST_QUERY_CONVERT:
510     {
511       GstFormat src_fmt, dest_fmt;
512       gint64 src_val, dest_val;
513
514       /* peel off input */
515       gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
516       if ((res = gst_ogm_parse_sink_convert (pad, src_fmt, src_val,
517                   &dest_fmt, &dest_val))) {
518         gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
519       }
520       break;
521     }
522     default:
523       res = FALSE;
524       break;
525   }
526   return res;
527 }
528
529 static GstFlowReturn
530 gst_ogm_parse_chain (GstPad * pad, GstBuffer * buffer)
531 {
532   GstOgmParse *ogm = GST_OGM_PARSE (gst_pad_get_parent (pad));
533   GstBuffer *buf = GST_BUFFER (buffer);
534   guint8 *data = GST_BUFFER_DATA (buf);
535   guint size = GST_BUFFER_SIZE (buf);
536
537   GST_DEBUG_OBJECT (ogm, "New packet with packet start code 0x%02x", data[0]);
538
539   switch (data[0]) {
540     case 0x01:{
541       GstCaps *caps = NULL;
542
543       /* stream header */
544       if (size < sizeof (stream_header) + 1) {
545         GST_ELEMENT_ERROR (ogm, STREAM, WRONG_TYPE,
546             ("Buffer too small"), (NULL));
547         break;
548       }
549
550       if (!memcmp (&data[1], "video\000\000\000", 8)) {
551         ogm->hdr.s.video.width = GST_READ_UINT32_LE (&data[45]);
552         ogm->hdr.s.video.height = GST_READ_UINT32_LE (&data[49]);
553       } else if (!memcmp (&data[1], "audio\000\000\000", 8)) {
554         ogm->hdr.s.audio.channels = GST_READ_UINT32_LE (&data[45]);
555         ogm->hdr.s.audio.blockalign = GST_READ_UINT32_LE (&data[47]);
556         ogm->hdr.s.audio.avgbytespersec = GST_READ_UINT32_LE (&data[49]);
557       } else if (!memcmp (&data[1], "text\000\000\000\000", 8)) {
558         /* nothing here */
559       } else {
560         GST_ELEMENT_ERROR (ogm, STREAM, WRONG_TYPE,
561             ("Unknown stream type"), (NULL));
562         break;
563       }
564       memcpy (ogm->hdr.streamtype, &data[1], 8);
565       memcpy (ogm->hdr.subtype, &data[9], 4);
566       ogm->hdr.size = GST_READ_UINT32_LE (&data[13]);
567       ogm->hdr.time_unit = GST_READ_UINT64_LE (&data[17]);
568       ogm->hdr.samples_per_unit = GST_READ_UINT64_LE (&data[25]);
569       ogm->hdr.default_len = GST_READ_UINT32_LE (&data[33]);
570       ogm->hdr.buffersize = GST_READ_UINT32_LE (&data[37]);
571       ogm->hdr.bits_per_sample = GST_READ_UINT32_LE (&data[41]);
572
573       switch (ogm->hdr.streamtype[0]) {
574         case 'a':{
575           guint codec_id;
576
577           if (!sscanf (ogm->hdr.subtype, "%04x", &codec_id)) {
578             caps = NULL;
579             break;
580           }
581           caps = gst_riff_create_audio_caps (codec_id,
582               NULL, NULL, NULL, NULL, NULL);
583           gst_caps_set_simple (caps,
584               "channels", G_TYPE_INT, ogm->hdr.s.audio.channels,
585               "rate", G_TYPE_INT, ogm->hdr.samples_per_unit, NULL);
586           GST_LOG_OBJECT (ogm, "Type: %s, subtype: 0x%04x, "
587               "channels: %d, samplerate: %d, blockalign: %d, bps: %d",
588               ogm->hdr.streamtype, codec_id, ogm->hdr.s.audio.channels,
589               ogm->hdr.samples_per_unit,
590               ogm->hdr.s.audio.blockalign, ogm->hdr.s.audio.avgbytespersec);
591           break;
592         }
593         case 'v':{
594           guint32 fcc;
595
596           fcc = GST_MAKE_FOURCC (ogm->hdr.subtype[0],
597               ogm->hdr.subtype[1], ogm->hdr.subtype[2], ogm->hdr.subtype[3]);
598           GST_LOG_OBJECT (ogm, "Type: %s, subtype: %" GST_FOURCC_FORMAT
599               ", size: %dx%d, timeunit: %" G_GINT64_FORMAT
600               " (fps: %lf), s/u: %" G_GINT64_FORMAT ", "
601               "def.len: %d, bufsize: %d, bps: %d",
602               ogm->hdr.streamtype, GST_FOURCC_ARGS (fcc),
603               ogm->hdr.s.video.width, ogm->hdr.s.video.height,
604               ogm->hdr.time_unit, 10000000. / ogm->hdr.time_unit,
605               ogm->hdr.samples_per_unit, ogm->hdr.default_len,
606               ogm->hdr.buffersize, ogm->hdr.bits_per_sample);
607           caps = gst_riff_create_video_caps (fcc, NULL, NULL, NULL, NULL, NULL);
608           gst_caps_set_simple (caps,
609               "width", G_TYPE_INT, ogm->hdr.s.video.width,
610               "height", G_TYPE_INT, ogm->hdr.s.video.height,
611               "framerate", GST_TYPE_FRACTION, 10000000, ogm->hdr.time_unit,
612               NULL);
613           break;
614         }
615         case 't':
616           GST_LOG_OBJECT (ogm, "Type: %s, s/u: %" G_GINT64_FORMAT
617               ", timeunit=%" G_GINT64_FORMAT,
618               ogm->hdr.streamtype, ogm->hdr.samples_per_unit,
619               ogm->hdr.time_unit);
620           caps = gst_caps_new_simple ("text/plain", NULL);
621           break;
622         default:
623           g_assert_not_reached ();
624       }
625
626       if (caps) {
627         ogm->srcpad = gst_pad_new ("src", GST_PAD_SRC);
628         gst_pad_set_caps (ogm->srcpad, caps);
629       } else {
630         GST_WARNING_OBJECT (ogm,
631             "No fixed caps were found, carrying on with template");
632         ogm->srcpad = gst_pad_new_from_template (ogm->srcpadtempl, "src");
633       }
634       gst_element_add_pad (GST_ELEMENT (ogm), ogm->srcpad);
635       break;
636     }
637     case 0x03:
638       /* comment - unused */
639       break;
640     default:
641       if ((data[0] & 0x01) == 0) {
642         /* data - push on */
643         guint len = ((data[0] & 0xc0) >> 6) | ((data[0] & 0x02) << 1);
644         guint xsize = 0, n;
645         GstBuffer *sbuf;
646         gboolean keyframe = (data[0] & 0x08) >> 3;
647
648         if (size < len + 1) {
649           GST_ELEMENT_ERROR (ogm, STREAM, WRONG_TYPE,
650               ("Buffer too small"), (NULL));
651           break;
652         }
653         for (n = len; n > 0; n--) {
654           xsize = (xsize << 8) | data[n];
655         }
656
657         GST_DEBUG_OBJECT (ogm,
658             "[0x%02x] samples: %d, hdrbytes: %d, datasize: %d",
659             data[0], xsize, len, size - len - 1);
660         sbuf = gst_buffer_create_sub (buf, len + 1, size - len - 1);
661         if (GST_BUFFER_OFFSET_END_IS_VALID (buf)) {
662           ogm->next_granulepos = GST_BUFFER_OFFSET_END (buf);
663         }
664         switch (ogm->hdr.streamtype[0]) {
665           case 't':
666           case 'v':{
667             gint samples = (ogm->hdr.streamtype[0] == 'v') ? 1 : xsize;
668
669             if (!keyframe)
670               GST_BUFFER_FLAG_SET (sbuf, GST_BUFFER_FLAG_DELTA_UNIT);
671
672             GST_BUFFER_TIMESTAMP (sbuf) = (GST_SECOND / 10000000) *
673                 ogm->next_granulepos * ogm->hdr.time_unit;
674             GST_BUFFER_DURATION (sbuf) = (GST_SECOND / 10000000) *
675                 ogm->hdr.time_unit * samples;
676             ogm->next_granulepos += samples;
677             break;
678           }
679           case 'a':
680             GST_BUFFER_TIMESTAMP (sbuf) = GST_SECOND *
681                 ogm->next_granulepos / ogm->hdr.samples_per_unit;
682             GST_BUFFER_DURATION (sbuf) = GST_SECOND * xsize /
683                 ogm->hdr.samples_per_unit;
684             ogm->next_granulepos += xsize;
685             break;
686           default:
687             gst_buffer_unref (sbuf);
688             sbuf = NULL;
689             GST_ELEMENT_ERROR (ogm, RESOURCE, SYNC, (NULL), (NULL));
690             break;
691         }
692         gst_buffer_set_caps (sbuf, GST_PAD_CAPS (ogm->srcpad));
693         gst_pad_push (ogm->srcpad, sbuf);
694       } else {
695         GST_ELEMENT_ERROR (ogm, STREAM, WRONG_TYPE,
696             ("Wrong packet startcode 0x%02x", data[0]), (NULL));
697       }
698       break;
699   }
700
701   gst_buffer_unref (buf);
702
703   return GST_FLOW_OK;
704 }
705
706 static GstStateChangeReturn
707 gst_ogm_parse_change_state (GstElement * element, GstStateChange transition)
708 {
709   GstOgmParse *ogm = GST_OGM_PARSE (element);
710
711   switch (transition) {
712     case GST_STATE_CHANGE_PAUSED_TO_READY:
713       if (ogm->srcpad) {
714         gst_element_remove_pad (element, ogm->srcpad);
715         ogm->srcpad = NULL;
716       }
717       memset (&ogm->hdr, 0, sizeof (ogm->hdr));
718       ogm->next_granulepos = 0;
719       break;
720     default:
721       break;
722   }
723
724   return parent_class->change_state (element, transition);
725 }
726
727 gboolean
728 gst_ogm_parse_plugin_init (GstPlugin * plugin)
729 {
730   GST_DEBUG_CATEGORY_INIT (gst_ogm_parse_debug, "ogmparse", 0, "ogm parser");
731
732   return gst_element_register (plugin, "ogmaudioparse", GST_RANK_PRIMARY,
733       GST_TYPE_OGM_AUDIO_PARSE) &&
734       gst_element_register (plugin, "ogmvideoparse", GST_RANK_PRIMARY,
735       GST_TYPE_OGM_VIDEO_PARSE) &&
736       gst_element_register (plugin, "ogmtextparse", GST_RANK_PRIMARY,
737       GST_TYPE_OGM_TEXT_PARSE);
738 }