Merge branch 'master' into 0.11
[platform/upstream/gstreamer.git] / ext / ogg / gstoggstream.c
1 /* GStreamer Ogg Granulepos Mapping Utility Functions
2  * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
3  * Copyright (C) 2009 David Schleef <ds@schleef.org>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "gstoggstream.h"
26 #include "dirac_parse.h"
27 #include "vorbis_parse.h"
28
29 #include <gst/riff/riff-media.h>
30
31 #include <stdlib.h>
32 #include <string.h>
33
34 GST_DEBUG_CATEGORY_EXTERN (gst_ogg_demux_debug);
35 GST_DEBUG_CATEGORY_EXTERN (gst_ogg_demux_setup_debug);
36 #define GST_CAT_DEFAULT gst_ogg_demux_debug
37
38 typedef struct _GstOggMap GstOggMap;
39
40 typedef gboolean (*GstOggMapSetupFunc) (GstOggStream * pad,
41     ogg_packet * packet);
42 typedef GstClockTime (*GstOggMapToTimeFunc) (GstOggStream * pad,
43     gint64 granulepos);
44 typedef gint64 (*GstOggMapToGranuleFunc) (GstOggStream * pad,
45     gint64 granulepos);
46 typedef gint64 (*GstOggMapToGranuleposFunc) (GstOggStream * pad,
47     gint64 granule, gint64 keyframe_granule);
48
49 /* returns TRUE if the granulepos denotes a key frame */
50 typedef gboolean (*GstOggMapIsKeyFrameFunc) (GstOggStream * pad,
51     gint64 granulepos);
52
53 /* returns TRUE if the given packet is a stream header packet */
54 typedef gboolean (*GstOggMapIsHeaderPacketFunc) (GstOggStream * pad,
55     ogg_packet * packet);
56 typedef gint64 (*GstOggMapPacketDurationFunc) (GstOggStream * pad,
57     ogg_packet * packet);
58 typedef void (*GstOggMapExtractTagsFunc) (GstOggStream * pad,
59     ogg_packet * packet);
60
61 typedef gint64 (*GstOggMapGranuleposToKeyGranuleFunc) (GstOggStream * pad,
62     gint64 granulepos);
63
64 #define SKELETON_FISBONE_MIN_SIZE  52
65 #define SKELETON_FISHEAD_3_3_MIN_SIZE 112
66 #define SKELETON_FISHEAD_4_0_MIN_SIZE 80
67
68 struct _GstOggMap
69 {
70   const gchar *id;
71   int id_length;
72   int min_packet_size;
73   const gchar *media_type;
74   GstOggMapSetupFunc setup_func;
75   GstOggMapToGranuleFunc granulepos_to_granule_func;
76   GstOggMapToGranuleposFunc granule_to_granulepos_func;
77   GstOggMapIsKeyFrameFunc is_key_frame_func;
78   GstOggMapIsHeaderPacketFunc is_header_func;
79   GstOggMapPacketDurationFunc packet_duration_func;
80   GstOggMapGranuleposToKeyGranuleFunc granulepos_to_key_granule_func;
81   GstOggMapExtractTagsFunc extract_tags_func;
82 };
83
84 extern const GstOggMap mappers[];
85
86 GstClockTime
87 gst_ogg_stream_get_packet_start_time (GstOggStream * pad, ogg_packet * packet)
88 {
89   int duration;
90
91   if (packet->granulepos == -1) {
92     return GST_CLOCK_TIME_NONE;
93   }
94
95   duration = gst_ogg_stream_get_packet_duration (pad, packet);
96   if (duration == -1) {
97     return GST_CLOCK_TIME_NONE;
98   }
99
100   return gst_ogg_stream_granule_to_time (pad,
101       gst_ogg_stream_granulepos_to_granule (pad,
102           packet->granulepos) - duration);
103 }
104
105 GstClockTime
106 gst_ogg_stream_get_start_time_for_granulepos (GstOggStream * pad,
107     gint64 granulepos)
108 {
109   if (pad->frame_size == 0)
110     return GST_CLOCK_TIME_NONE;
111
112   return gst_ogg_stream_granule_to_time (pad,
113       gst_ogg_stream_granulepos_to_granule (pad, granulepos));
114 }
115
116 GstClockTime
117 gst_ogg_stream_get_end_time_for_granulepos (GstOggStream * pad,
118     gint64 granulepos)
119 {
120   return gst_ogg_stream_granule_to_time (pad,
121       gst_ogg_stream_granulepos_to_granule (pad, granulepos));
122 }
123
124 GstClockTime
125 gst_ogg_stream_granule_to_time (GstOggStream * pad, gint64 granule)
126 {
127   if (granule == 0 || pad->granulerate_n == 0 || pad->granulerate_d == 0)
128     return 0;
129
130   return gst_util_uint64_scale (granule, GST_SECOND * pad->granulerate_d,
131       pad->granulerate_n);
132 }
133
134 gint64
135 gst_ogg_stream_granulepos_to_granule (GstOggStream * pad, gint64 granulepos)
136 {
137   if (granulepos == -1 || granulepos == 0) {
138     return granulepos;
139   }
140
141   if (mappers[pad->map].granulepos_to_granule_func == NULL) {
142     GST_WARNING ("Failed to convert granulepos to granule");
143     return -1;
144   }
145
146   return mappers[pad->map].granulepos_to_granule_func (pad, granulepos);
147 }
148
149 gint64
150 gst_ogg_stream_granulepos_to_key_granule (GstOggStream * pad, gint64 granulepos)
151 {
152   if (mappers[pad->map].granulepos_to_key_granule_func)
153     return mappers[pad->map].granulepos_to_key_granule_func (pad, granulepos);
154
155   if (granulepos == -1 || granulepos == 0) {
156     return granulepos;
157   }
158
159   return granulepos >> pad->granuleshift;
160 }
161
162 gint64
163 gst_ogg_stream_granule_to_granulepos (GstOggStream * pad, gint64 granule,
164     gint64 keyframe_granule)
165 {
166   if (granule == -1 || granule == 0) {
167     return granule;
168   }
169
170   if (mappers[pad->map].granule_to_granulepos_func == NULL) {
171     GST_WARNING ("Failed to convert granule to granulepos");
172     return -1;
173   }
174
175   return mappers[pad->map].granule_to_granulepos_func (pad, granule,
176       keyframe_granule);
177 }
178
179 gboolean
180 gst_ogg_stream_granulepos_is_key_frame (GstOggStream * pad, gint64 granulepos)
181 {
182   if (granulepos == -1) {
183     return FALSE;
184   }
185
186   if (mappers[pad->map].is_key_frame_func == NULL) {
187     GST_WARNING ("Failed to determine key frame");
188     return FALSE;
189   }
190
191   return mappers[pad->map].is_key_frame_func (pad, granulepos);
192 }
193
194 gboolean
195 gst_ogg_stream_packet_is_header (GstOggStream * pad, ogg_packet * packet)
196 {
197   if (mappers[pad->map].is_header_func == NULL) {
198     GST_WARNING ("Failed to determine header");
199     return FALSE;
200   }
201
202   return mappers[pad->map].is_header_func (pad, packet);
203 }
204
205 gint64
206 gst_ogg_stream_get_packet_duration (GstOggStream * pad, ogg_packet * packet)
207 {
208   if (mappers[pad->map].packet_duration_func == NULL) {
209     GST_WARNING ("Failed to determine packet duration");
210     return -1;
211   }
212
213   return mappers[pad->map].packet_duration_func (pad, packet);
214 }
215
216
217 void
218 gst_ogg_stream_extract_tags (GstOggStream * pad, ogg_packet * packet)
219 {
220   if (mappers[pad->map].extract_tags_func == NULL) {
221     GST_DEBUG ("No tag extraction");
222     return;
223   }
224
225   mappers[pad->map].extract_tags_func (pad, packet);
226 }
227
228 /* some generic functions */
229
230 static gboolean
231 is_keyframe_true (GstOggStream * pad, gint64 granulepos)
232 {
233   return TRUE;
234 }
235
236 static gint64
237 granulepos_to_granule_default (GstOggStream * pad, gint64 granulepos)
238 {
239   gint64 keyindex, keyoffset;
240
241   if (pad->granuleshift != 0) {
242     keyindex = granulepos >> pad->granuleshift;
243     keyoffset = granulepos - (keyindex << pad->granuleshift);
244     return keyindex + keyoffset;
245   } else {
246     return granulepos;
247   }
248 }
249
250
251 static gint64
252 granule_to_granulepos_default (GstOggStream * pad, gint64 granule,
253     gint64 keyframe_granule)
254 {
255   gint64 keyoffset;
256
257   if (pad->granuleshift != 0) {
258     /* If we don't know where the previous keyframe is yet, assume it is
259        at 0 or 1, depending on bitstream version. If nothing else, this
260        avoids getting negative granpos back. */
261     if (keyframe_granule < 0)
262       keyframe_granule = pad->theora_has_zero_keyoffset ? 0 : 1;
263     keyoffset = granule - keyframe_granule;
264     return (keyframe_granule << pad->granuleshift) | keyoffset;
265   } else {
266     return granule;
267   }
268 }
269
270 #ifdef unused
271 static gboolean
272 is_header_unknown (GstOggStream * pad, ogg_packet * packet)
273 {
274   GST_WARNING ("don't know how to detect header");
275   return FALSE;
276 }
277 #endif
278
279 static gboolean
280 is_header_true (GstOggStream * pad, ogg_packet * packet)
281 {
282   return TRUE;
283 }
284
285 static gboolean
286 is_header_count (GstOggStream * pad, ogg_packet * packet)
287 {
288   if (pad->n_header_packets_seen < pad->n_header_packets) {
289     return TRUE;
290   }
291   return FALSE;
292 }
293
294 static gint64
295 packet_duration_constant (GstOggStream * pad, ogg_packet * packet)
296 {
297   return pad->frame_size;
298 }
299
300 /* helper: extracts tags from vorbis comment ogg packet.
301  * Returns result in *tags after free'ing existing *tags (if any) */
302 static gboolean
303 tag_list_from_vorbiscomment_packet (ogg_packet * packet,
304     const guint8 * id_data, const guint id_data_length, GstTagList ** tags)
305 {
306   gchar *encoder = NULL;
307   GstTagList *list;
308   gboolean ret = TRUE;
309
310   g_return_val_if_fail (tags != NULL, FALSE);
311
312   list = gst_tag_list_from_vorbiscomment (packet->packet, packet->bytes,
313       id_data, id_data_length, &encoder);
314
315   if (!list) {
316     GST_WARNING ("failed to decode vorbis comments");
317     ret = FALSE;
318     goto exit;
319   }
320
321   if (encoder) {
322     if (encoder[0])
323       gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER, encoder,
324           NULL);
325     g_free (encoder);
326   }
327
328 exit:
329   if (*tags)
330     gst_tag_list_free (*tags);
331   *tags = list;
332
333   return ret;
334 }
335
336 /* theora */
337
338 static gboolean
339 setup_theora_mapper (GstOggStream * pad, ogg_packet * packet)
340 {
341   guint8 *data = packet->packet;
342   guint w, h, par_d, par_n;
343   guint8 vmaj, vmin, vrev;
344
345   vmaj = data[7];
346   vmin = data[8];
347   vrev = data[9];
348
349   w = GST_READ_UINT24_BE (data + 14) & 0xFFFFFF;
350   h = GST_READ_UINT24_BE (data + 17) & 0xFFFFFF;
351
352   pad->granulerate_n = GST_READ_UINT32_BE (data + 22);
353   pad->granulerate_d = GST_READ_UINT32_BE (data + 26);
354
355   par_n = GST_READ_UINT24_BE (data + 30);
356   par_d = GST_READ_UINT24_BE (data + 33);
357
358   GST_LOG ("fps = %d/%d, PAR = %u/%u, width = %u, height = %u",
359       pad->granulerate_n, pad->granulerate_d, par_n, par_d, w, h);
360
361   /* 2 bits + 3 bits = 5 bits KFGSHIFT */
362   pad->granuleshift = ((GST_READ_UINT8 (data + 40) & 0x03) << 3) +
363       (GST_READ_UINT8 (data + 41) >> 5);
364
365   pad->is_video = TRUE;
366   pad->n_header_packets = 3;
367   pad->frame_size = 1;
368
369   pad->bitrate = GST_READ_UINT24_BE (data + 37);
370   GST_LOG ("bit rate: %d", pad->bitrate);
371
372   if (pad->granulerate_n == 0 || pad->granulerate_d == 0) {
373     GST_WARNING ("frame rate %d/%d", pad->granulerate_n, pad->granulerate_d);
374     return FALSE;
375   }
376
377   /* The interpretation of the granule position has changed with 3.2.1.
378      The granule is now made from the number of frames encoded, rather than
379      the index of the frame being encoded - so there is a difference of 1. */
380   pad->theora_has_zero_keyoffset =
381       ((vmaj << 16) | (vmin << 8) | vrev) < 0x030201;
382
383   pad->caps = gst_caps_new_simple ("video/x-theora", NULL);
384
385   if (w > 0 && h > 0) {
386     gst_caps_set_simple (pad->caps, "width", G_TYPE_INT, w, "height",
387         G_TYPE_INT, h, NULL);
388   }
389
390   /* PAR of 0:N, N:0 and 0:0 is allowed and maps to 1:1 */
391   if (par_n == 0 || par_d == 0)
392     par_n = par_d = 1;
393
394   /* only add framerate now so caps look prettier, with width/height first */
395   gst_caps_set_simple (pad->caps, "framerate", GST_TYPE_FRACTION,
396       pad->granulerate_n, pad->granulerate_d, "pixel-aspect-ratio",
397       GST_TYPE_FRACTION, par_n, par_d, NULL);
398
399   return TRUE;
400 }
401
402 static gint64
403 granulepos_to_granule_theora (GstOggStream * pad, gint64 granulepos)
404 {
405   gint64 keyindex, keyoffset;
406
407   if (pad->granuleshift != 0) {
408     keyindex = granulepos >> pad->granuleshift;
409     keyoffset = granulepos - (keyindex << pad->granuleshift);
410     if (pad->theora_has_zero_keyoffset) {
411       keyoffset++;
412     }
413     return keyindex + keyoffset;
414   } else {
415     return granulepos;
416   }
417 }
418
419 static gboolean
420 is_keyframe_theora (GstOggStream * pad, gint64 granulepos)
421 {
422   gint64 frame_mask;
423
424   if (granulepos == (gint64) - 1)
425     return FALSE;
426
427   frame_mask = (1 << pad->granuleshift) - 1;
428
429   return ((granulepos & frame_mask) == 0);
430 }
431
432 static gboolean
433 is_header_theora (GstOggStream * pad, ogg_packet * packet)
434 {
435   return (packet->bytes > 0 && (packet->packet[0] & 0x80) == 0x80);
436 }
437
438 static void
439 extract_tags_theora (GstOggStream * pad, ogg_packet * packet)
440 {
441   if (packet->bytes > 0 && packet->packet[0] == 0x81) {
442     tag_list_from_vorbiscomment_packet (packet,
443         (const guint8 *) "\201theora", 7, &pad->taglist);
444
445     if (!pad->taglist)
446       pad->taglist = gst_tag_list_new ();
447
448     if (pad->bitrate)
449       gst_tag_list_add (pad->taglist, GST_TAG_MERGE_REPLACE,
450           GST_TAG_BITRATE, (guint) pad->bitrate, NULL);
451   }
452 }
453
454 /* dirac */
455
456 static gboolean
457 setup_dirac_mapper (GstOggStream * pad, ogg_packet * packet)
458 {
459   int ret;
460   DiracSequenceHeader header;
461
462   ret = dirac_sequence_header_parse (&header, packet->packet + 13,
463       packet->bytes - 13);
464   if (ret == 0) {
465     GST_DEBUG ("Failed to parse Dirac sequence header");
466     return FALSE;
467   }
468
469   pad->is_video = TRUE;
470   pad->granulerate_n = header.frame_rate_numerator * 2;
471   pad->granulerate_d = header.frame_rate_denominator;
472   pad->granuleshift = 22;
473   pad->n_header_packets = 1;
474   pad->frame_size = 2;
475
476   if (header.interlaced_coding != 0) {
477     GST_DEBUG ("non-progressive Dirac coding not implemented");
478     return FALSE;
479   }
480
481   pad->caps = gst_caps_new_simple ("video/x-dirac",
482       "width", G_TYPE_INT, header.width,
483       "height", G_TYPE_INT, header.height,
484       "interlaced", G_TYPE_BOOLEAN, header.interlaced,
485       "pixel-aspect-ratio", GST_TYPE_FRACTION,
486       header.aspect_ratio_numerator, header.aspect_ratio_denominator,
487       "framerate", GST_TYPE_FRACTION, header.frame_rate_numerator,
488       header.frame_rate_denominator, NULL);
489
490   return TRUE;
491 }
492
493 #define OGG_DIRAC_GRANULE_LOW_MASK ((1<<22) - 1)
494 static gboolean
495 is_keyframe_dirac (GstOggStream * pad, gint64 granulepos)
496 {
497   int dist_h;
498   int dist_l;
499   int dist;
500
501   if (granulepos == -1)
502     return -1;
503
504   dist_h = (granulepos >> 22) & 0xff;
505   dist_l = granulepos & 0xff;
506   dist = (dist_h << 8) | dist_l;
507
508   return (dist == 0);
509 }
510
511 static gint64
512 granulepos_to_granule_dirac (GstOggStream * pad, gint64 gp)
513 {
514   gint64 pt;
515   int delay;
516   gint64 dt;
517
518   pt = ((gp >> 22) + (gp & OGG_DIRAC_GRANULE_LOW_MASK)) >> 9;
519   delay = (gp >> 9) & 0x1fff;
520   dt = pt - delay;
521
522   GST_DEBUG ("pt %" G_GINT64_FORMAT " delay %d", pt, delay);
523
524   return dt + 4;
525 }
526
527 static gint64
528 granule_to_granulepos_dirac (GstOggStream * pad, gint64 granule,
529     gint64 keyframe_granule)
530 {
531   /* This conversion requires knowing more details about the Dirac
532    * stream. */
533   return -1;
534 }
535
536 static gint64
537 granulepos_to_key_granule_dirac (GstOggStream * pad, gint64 gp)
538 {
539   gint64 pt;
540   int dist_h;
541   int dist_l;
542   int dist;
543   int delay;
544   gint64 dt;
545
546   if (gp == -1 || gp == 0)
547     return gp;
548
549   pt = ((gp >> 22) + (gp & OGG_DIRAC_GRANULE_LOW_MASK)) >> 9;
550   dist_h = (gp >> 22) & 0xff;
551   dist_l = gp & 0xff;
552   dist = (dist_h << 8) | dist_l;
553   delay = (gp >> 9) & 0x1fff;
554   dt = pt - delay;
555
556   return dt - 2 * dist + 4;
557 }
558
559 /* VP8 */
560
561 static gboolean
562 setup_vp8_mapper (GstOggStream * pad, ogg_packet * packet)
563 {
564   gint width, height, par_n, par_d, fps_n, fps_d;
565
566   if (packet->bytes < 26) {
567     GST_DEBUG ("Failed to parse VP8 BOS page");
568     return FALSE;
569   }
570
571   width = GST_READ_UINT16_BE (packet->packet + 8);
572   height = GST_READ_UINT16_BE (packet->packet + 10);
573   par_n = GST_READ_UINT24_BE (packet->packet + 12);
574   par_d = GST_READ_UINT24_BE (packet->packet + 15);
575   fps_n = GST_READ_UINT32_BE (packet->packet + 18);
576   fps_d = GST_READ_UINT32_BE (packet->packet + 22);
577
578   pad->is_video = TRUE;
579   pad->is_vp8 = TRUE;
580   pad->granulerate_n = fps_n;
581   pad->granulerate_d = fps_d;
582   pad->n_header_packets = 2;
583   pad->frame_size = 1;
584
585   pad->caps = gst_caps_new_simple ("video/x-vp8",
586       "width", G_TYPE_INT, width,
587       "height", G_TYPE_INT, height,
588       "pixel-aspect-ratio", GST_TYPE_FRACTION,
589       par_n, par_d, "framerate", GST_TYPE_FRACTION, fps_n, fps_d, NULL);
590
591   return TRUE;
592 }
593
594 static gboolean
595 is_keyframe_vp8 (GstOggStream * pad, gint64 granulepos)
596 {
597   guint64 gpos = granulepos;
598
599   if (granulepos == -1)
600     return FALSE;
601
602   /* Get rid of flags */
603   gpos >>= 3;
604
605   return ((gpos & 0x07ffffff) == 0);
606 }
607
608 static gint64
609 granulepos_to_granule_vp8 (GstOggStream * pad, gint64 gpos)
610 {
611   guint64 gp = (guint64) gpos;
612   guint32 pt;
613   guint32 dist;
614
615   pt = (gp >> 32);
616   dist = (gp >> 3) & 0x07ffffff;
617
618   GST_DEBUG ("pt %u, dist %u", pt, dist);
619
620   return pt;
621 }
622
623 static gint64
624 granule_to_granulepos_vp8 (GstOggStream * pad, gint64 granule,
625     gint64 keyframe_granule)
626 {
627   /* FIXME: This requires to look into the content of the packets
628    * because the simple granule counter doesn't know about invisible
629    * frames...
630    */
631   return -1;
632 }
633
634 /* Check if this packet contains an invisible frame or not */
635 static gint64
636 packet_duration_vp8 (GstOggStream * pad, ogg_packet * packet)
637 {
638   guint32 hdr;
639
640   if (packet->bytes < 3)
641     return 0;
642
643   hdr = GST_READ_UINT24_LE (packet->packet);
644
645   return (((hdr >> 4) & 1) != 0) ? 1 : 0;
646 }
647
648 static gint64
649 granulepos_to_key_granule_vp8 (GstOggStream * pad, gint64 granulepos)
650 {
651   guint64 gp = granulepos;
652   guint64 pts = (gp >> 32);
653   guint32 dist = (gp >> 3) & 0x07ffffff;
654
655   if (granulepos == -1 || granulepos == 0)
656     return granulepos;
657
658   if (dist > pts)
659     return 0;
660
661   return pts - dist;
662 }
663
664 static gboolean
665 is_header_vp8 (GstOggStream * pad, ogg_packet * packet)
666 {
667   if (packet->bytes >= 5 && packet->packet[0] == 0x4F &&
668       packet->packet[1] == 0x56 && packet->packet[2] == 0x50 &&
669       packet->packet[3] == 0x38 && packet->packet[4] == 0x30)
670     return TRUE;
671   return FALSE;
672 }
673
674 static void
675 extract_tags_vp8 (GstOggStream * pad, ogg_packet * packet)
676 {
677   if (packet->bytes >= 7 && memcmp (packet->packet, "OVP80\2 ", 7) == 0) {
678     tag_list_from_vorbiscomment_packet (packet,
679         (const guint8 *) "OVP80\2 ", 7, &pad->taglist);
680   }
681 }
682
683 /* vorbis */
684
685 static gboolean
686 setup_vorbis_mapper (GstOggStream * pad, ogg_packet * packet)
687 {
688   guint8 *data = packet->packet;
689   guint chans;
690
691   data += 1 + 6;
692   pad->version = GST_READ_UINT32_LE (data);
693   data += 4;
694   chans = GST_READ_UINT8 (data);
695   data += 1;
696   pad->granulerate_n = GST_READ_UINT32_LE (data);
697   pad->granulerate_d = 1;
698   pad->granuleshift = 0;
699   pad->last_size = 0;
700   GST_LOG ("sample rate: %d", pad->granulerate_n);
701
702   data += 4;
703   pad->bitrate_upper = GST_READ_UINT32_LE (data);
704   data += 4;
705   pad->bitrate_nominal = GST_READ_UINT32_LE (data);
706   data += 4;
707   pad->bitrate_lower = GST_READ_UINT32_LE (data);
708
709   if (pad->bitrate_nominal > 0)
710     pad->bitrate = pad->bitrate_nominal;
711
712   if (pad->bitrate_upper > 0 && !pad->bitrate)
713     pad->bitrate = pad->bitrate_upper;
714
715   if (pad->bitrate_lower > 0 && !pad->bitrate)
716     pad->bitrate = pad->bitrate_lower;
717
718   GST_LOG ("bit rate: %d", pad->bitrate);
719
720   pad->n_header_packets = 3;
721
722   if (pad->granulerate_n == 0)
723     return FALSE;
724
725   parse_vorbis_header_packet (pad, packet);
726
727   pad->caps = gst_caps_new_simple ("audio/x-vorbis",
728       "rate", G_TYPE_INT, pad->granulerate_n, "channels", G_TYPE_INT, chans,
729       NULL);
730
731   return TRUE;
732 }
733
734 static gboolean
735 is_header_vorbis (GstOggStream * pad, ogg_packet * packet)
736 {
737   if (packet->bytes > 0 && (packet->packet[0] & 0x01) == 0)
738     return FALSE;
739
740   if (packet->packet[0] == 5) {
741     parse_vorbis_setup_packet (pad, packet);
742   }
743
744   return TRUE;
745 }
746
747 static void
748 extract_tags_vorbis (GstOggStream * pad, ogg_packet * packet)
749 {
750   if (packet->bytes == 0 || (packet->packet[0] & 0x01) == 0)
751     return;
752
753   if (((guint8 *) (packet->packet))[0] == 0x03) {
754     tag_list_from_vorbiscomment_packet (packet,
755         (const guint8 *) "\003vorbis", 7, &pad->taglist);
756
757     if (!pad->taglist)
758       pad->taglist = gst_tag_list_new ();
759
760     gst_tag_list_add (pad->taglist, GST_TAG_MERGE_REPLACE,
761         GST_TAG_ENCODER_VERSION, pad->version, NULL);
762
763     if (pad->bitrate_nominal > 0)
764       gst_tag_list_add (pad->taglist, GST_TAG_MERGE_REPLACE,
765           GST_TAG_NOMINAL_BITRATE, (guint) pad->bitrate_nominal, NULL);
766
767     if (pad->bitrate_upper > 0)
768       gst_tag_list_add (pad->taglist, GST_TAG_MERGE_REPLACE,
769           GST_TAG_MAXIMUM_BITRATE, (guint) pad->bitrate_upper, NULL);
770
771     if (pad->bitrate_lower > 0)
772       gst_tag_list_add (pad->taglist, GST_TAG_MERGE_REPLACE,
773           GST_TAG_MINIMUM_BITRATE, (guint) pad->bitrate_lower, NULL);
774
775     if (pad->bitrate)
776       gst_tag_list_add (pad->taglist, GST_TAG_MERGE_REPLACE,
777           GST_TAG_BITRATE, (guint) pad->bitrate, NULL);
778   }
779 }
780
781 static gint64
782 packet_duration_vorbis (GstOggStream * pad, ogg_packet * packet)
783 {
784   int mode;
785   int size;
786   int duration;
787
788   if (packet->packet[0] & 1)
789     return 0;
790
791   mode = (packet->packet[0] >> 1) & ((1 << pad->vorbis_log2_num_modes) - 1);
792   size = pad->vorbis_mode_sizes[mode] ? pad->long_size : pad->short_size;
793
794   if (pad->last_size == 0) {
795     duration = 0;
796   } else {
797     duration = pad->last_size / 4 + size / 4;
798   }
799   pad->last_size = size;
800
801   GST_DEBUG ("duration %d", (int) duration);
802
803   return duration;
804 }
805
806 /* speex */
807
808
809 static gboolean
810 setup_speex_mapper (GstOggStream * pad, ogg_packet * packet)
811 {
812   guint8 *data = packet->packet;
813   guint chans;
814
815   data += 8 + 20 + 4 + 4;
816   pad->granulerate_n = GST_READ_UINT32_LE (data);
817   pad->granulerate_d = 1;
818   pad->granuleshift = 0;
819
820   data += 4 + 4 + 4;
821   chans = GST_READ_UINT32_LE (data);
822   data += 4;
823   pad->bitrate = GST_READ_UINT32_LE (data);
824
825   GST_LOG ("sample rate: %d, channels: %u", pad->granulerate_n, chans);
826   GST_LOG ("bit rate: %d", pad->bitrate);
827
828   pad->n_header_packets = GST_READ_UINT32_LE (packet->packet + 68) + 2;
829   pad->frame_size = GST_READ_UINT32_LE (packet->packet + 64) *
830       GST_READ_UINT32_LE (packet->packet + 56);
831
832   if (pad->granulerate_n == 0)
833     return FALSE;
834
835   pad->caps = gst_caps_new_simple ("audio/x-speex", "rate", G_TYPE_INT,
836       pad->granulerate_n, "channels", G_TYPE_INT, chans, NULL);
837
838   return TRUE;
839 }
840
841 static void
842 extract_tags_count (GstOggStream * pad, ogg_packet * packet)
843 {
844   /* packet 2 must be comment packet */
845   if (packet->bytes > 0 && pad->n_header_packets_seen == 1) {
846     tag_list_from_vorbiscomment_packet (packet, NULL, 0, &pad->taglist);
847
848     if (!pad->taglist)
849       pad->taglist = gst_tag_list_new ();
850
851     if (pad->bitrate)
852       gst_tag_list_add (pad->taglist, GST_TAG_MERGE_REPLACE,
853           GST_TAG_BITRATE, (guint) pad->bitrate, NULL);
854   }
855 }
856
857
858 /* flac */
859
860 static gboolean
861 setup_fLaC_mapper (GstOggStream * pad, ogg_packet * packet)
862 {
863   pad->granulerate_n = 0;
864   pad->granulerate_d = 1;
865   pad->granuleshift = 0;
866
867   pad->n_header_packets = 3;
868
869   pad->caps = gst_caps_new_simple ("audio/x-flac", NULL);
870
871   return TRUE;
872 }
873
874 static gboolean
875 is_header_fLaC (GstOggStream * pad, ogg_packet * packet)
876 {
877   if (pad->n_header_packets_seen == 1) {
878     pad->granulerate_n = (packet->packet[14] << 12) |
879         (packet->packet[15] << 4) | ((packet->packet[16] >> 4) & 0xf);
880   }
881
882   if (pad->n_header_packets_seen < pad->n_header_packets) {
883     return TRUE;
884   }
885
886   return FALSE;
887 }
888
889 static gboolean
890 setup_flac_mapper (GstOggStream * pad, ogg_packet * packet)
891 {
892   guint8 *data = packet->packet;
893   guint chans;
894
895   /* see http://flac.sourceforge.net/ogg_mapping.html */
896
897   pad->granulerate_n = (GST_READ_UINT32_BE (data + 27) & 0xFFFFF000) >> 12;
898   pad->granulerate_d = 1;
899   pad->granuleshift = 0;
900   chans = ((GST_READ_UINT32_BE (data + 27) & 0x00000E00) >> 9) + 1;
901
902   GST_DEBUG ("sample rate: %d, channels: %u", pad->granulerate_n, chans);
903
904   pad->n_header_packets = GST_READ_UINT16_BE (packet->packet + 7);
905
906   if (pad->granulerate_n == 0)
907     return FALSE;
908
909   pad->caps = gst_caps_new_simple ("audio/x-flac", "rate", G_TYPE_INT,
910       pad->granulerate_n, "channels", G_TYPE_INT, chans, NULL);
911
912   return TRUE;
913 }
914
915 static gboolean
916 is_header_flac (GstOggStream * pad, ogg_packet * packet)
917 {
918   return (packet->bytes > 0 && (packet->packet[0] != 0xff));
919 }
920
921 static gint64
922 packet_duration_flac (GstOggStream * pad, ogg_packet * packet)
923 {
924   int block_size_index;
925
926   if (packet->bytes < 4)
927     return -1;
928
929   block_size_index = packet->packet[2] >> 4;
930   if (block_size_index == 1)
931     return 192;
932   if (block_size_index >= 2 && block_size_index <= 5) {
933     return 576 << (block_size_index - 2);
934   }
935   if (block_size_index >= 8) {
936     return 256 << (block_size_index - 8);
937   }
938   if (block_size_index == 6 || block_size_index == 7) {
939     guint len, bytes = (block_size_index - 6) + 1;
940     guint8 tmp;
941
942     if (packet->bytes < 4 + 1 + bytes)
943       return -1;
944     tmp = packet->packet[4];
945     /* utf-8 prefix */
946     len = 0;
947     while (tmp & 0x80) {
948       len++;
949       tmp <<= 1;
950     }
951     if (len == 2)
952       return -1;
953     if (len == 0)
954       len++;
955     if (packet->bytes < 4 + len + bytes)
956       return -1;
957     if (bytes == 1) {
958       return packet->packet[4 + len] + 1;
959     } else {
960       return GST_READ_UINT16_BE (packet->packet + 4 + len) + 1;
961     }
962   }
963   return -1;
964 }
965
966 static void
967 extract_tags_flac (GstOggStream * pad, ogg_packet * packet)
968 {
969   if (packet->bytes > 4 && ((packet->packet[0] & 0x7F) == 0x4)) {
970     tag_list_from_vorbiscomment_packet (packet,
971         packet->packet, 4, &pad->taglist);
972   }
973 }
974
975 /* fishead */
976
977 static gboolean
978 setup_fishead_mapper (GstOggStream * pad, ogg_packet * packet)
979 {
980   guint8 *data;
981   gint64 prestime_n, prestime_d;
982   gint64 basetime_n, basetime_d;
983
984   data = packet->packet;
985
986   data += 8;                    /* header */
987
988   pad->skeleton_major = GST_READ_UINT16_LE (data);
989   data += 2;
990   pad->skeleton_minor = GST_READ_UINT16_LE (data);
991   data += 2;
992
993   prestime_n = (gint64) GST_READ_UINT64_LE (data);
994   data += 8;
995   prestime_d = (gint64) GST_READ_UINT64_LE (data);
996   data += 8;
997   basetime_n = (gint64) GST_READ_UINT64_LE (data);
998   data += 8;
999   basetime_d = (gint64) GST_READ_UINT64_LE (data);
1000   data += 8;
1001
1002   /* FIXME: we don't use basetime anywhere in the demuxer! */
1003   if (basetime_d != 0)
1004     pad->basetime = gst_util_uint64_scale (GST_SECOND, basetime_n, basetime_d);
1005   else
1006     pad->basetime = -1;
1007
1008   if (prestime_d != 0)
1009     pad->prestime = gst_util_uint64_scale (GST_SECOND, prestime_n, prestime_d);
1010   else
1011     pad->prestime = -1;
1012
1013   /* Ogg Skeleton 3.3+ streams provide additional information in the header */
1014   if (packet->bytes >= SKELETON_FISHEAD_3_3_MIN_SIZE && pad->skeleton_major == 3
1015       && pad->skeleton_minor > 0) {
1016     gint64 firstsampletime_n, firstsampletime_d;
1017     gint64 lastsampletime_n, lastsampletime_d;
1018     gint64 firstsampletime, lastsampletime;
1019     guint64 segment_length, content_offset;
1020
1021     firstsampletime_n = GST_READ_UINT64_LE (data + 64);
1022     firstsampletime_d = GST_READ_UINT64_LE (data + 72);
1023     lastsampletime_n = GST_READ_UINT64_LE (data + 80);
1024     lastsampletime_d = GST_READ_UINT64_LE (data + 88);
1025     segment_length = GST_READ_UINT64_LE (data + 96);
1026     content_offset = GST_READ_UINT64_LE (data + 104);
1027
1028     GST_INFO ("firstsampletime %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT,
1029         firstsampletime_n, firstsampletime_d);
1030     GST_INFO ("lastsampletime %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT,
1031         lastsampletime_n, lastsampletime_d);
1032     GST_INFO ("segment length %" G_GUINT64_FORMAT, segment_length);
1033     GST_INFO ("content offset %" G_GUINT64_FORMAT, content_offset);
1034
1035     if (firstsampletime_d > 0)
1036       firstsampletime = gst_util_uint64_scale (GST_SECOND,
1037           firstsampletime_n, firstsampletime_d);
1038     else
1039       firstsampletime = 0;
1040
1041     if (lastsampletime_d > 0)
1042       lastsampletime = gst_util_uint64_scale (GST_SECOND,
1043           lastsampletime_n, lastsampletime_d);
1044     else
1045       lastsampletime = 0;
1046
1047     if (lastsampletime > firstsampletime)
1048       pad->total_time = lastsampletime - firstsampletime;
1049     else
1050       pad->total_time = -1;
1051
1052     GST_INFO ("skeleton fishead parsed total: %" GST_TIME_FORMAT,
1053         GST_TIME_ARGS (pad->total_time));
1054   } else if (packet->bytes >= SKELETON_FISHEAD_4_0_MIN_SIZE
1055       && pad->skeleton_major == 4) {
1056     guint64 segment_length, content_offset;
1057
1058     segment_length = GST_READ_UINT64_LE (data + 64);
1059     content_offset = GST_READ_UINT64_LE (data + 72);
1060
1061     GST_INFO ("segment length %" G_GUINT64_FORMAT, segment_length);
1062     GST_INFO ("content offset %" G_GUINT64_FORMAT, content_offset);
1063   } else {
1064     pad->total_time = -1;
1065   }
1066
1067   GST_INFO ("skeleton fishead %u.%u parsed (basetime: %" GST_TIME_FORMAT
1068       ", prestime: %" GST_TIME_FORMAT ")", pad->skeleton_major,
1069       pad->skeleton_minor, GST_TIME_ARGS (pad->basetime),
1070       GST_TIME_ARGS (pad->prestime));
1071
1072   pad->is_skeleton = TRUE;
1073   pad->is_sparse = TRUE;
1074
1075   pad->caps = gst_caps_new_simple ("none/none", NULL);
1076
1077   return TRUE;
1078 }
1079
1080 gboolean
1081 gst_ogg_map_parse_fisbone (GstOggStream * pad, const guint8 * data, guint size,
1082     guint32 * serialno, GstOggSkeleton * type)
1083 {
1084   GstOggSkeleton stype;
1085   guint serial_offset;
1086
1087   if (size < SKELETON_FISBONE_MIN_SIZE) {
1088     GST_WARNING ("small fisbone packet of size %d, ignoring", size);
1089     return FALSE;
1090   }
1091
1092   if (memcmp (data, "fisbone\0", 8) == 0) {
1093     GST_INFO ("got fisbone packet");
1094     stype = GST_OGG_SKELETON_FISBONE;
1095     serial_offset = 12;
1096   } else if (memcmp (data, "index\0", 6) == 0) {
1097     GST_INFO ("got index packet");
1098     stype = GST_OGG_SKELETON_INDEX;
1099     serial_offset = 6;
1100   } else if (memcmp (data, "fishead\0", 8) == 0) {
1101     return FALSE;
1102   } else {
1103     GST_WARNING ("unknown skeleton packet \"%10.10s\"", data);
1104     return FALSE;
1105   }
1106
1107   if (serialno)
1108     *serialno = GST_READ_UINT32_LE (data + serial_offset);
1109
1110   if (type)
1111     *type = stype;
1112
1113   return TRUE;
1114 }
1115
1116 gboolean
1117 gst_ogg_map_add_fisbone (GstOggStream * pad, GstOggStream * skel_pad,
1118     const guint8 * data, guint size, GstClockTime * p_start_time)
1119 {
1120   GstClockTime start_time;
1121   gint64 start_granule;
1122
1123   if (pad->have_fisbone) {
1124     GST_DEBUG ("already have fisbone, ignoring second one");
1125     return FALSE;
1126   }
1127
1128   /* skip "fisbone\0" + headers offset + serialno + num headers */
1129   data += 8 + 4 + 4 + 4;
1130
1131   pad->have_fisbone = TRUE;
1132
1133   /* we just overwrite whatever was set before by the format-specific setup */
1134   pad->granulerate_n = GST_READ_UINT64_LE (data);
1135   pad->granulerate_d = GST_READ_UINT64_LE (data + 8);
1136
1137   start_granule = GST_READ_UINT64_LE (data + 16);
1138   pad->preroll = GST_READ_UINT32_LE (data + 24);
1139   pad->granuleshift = GST_READ_UINT8 (data + 28);
1140
1141   start_time = granulepos_to_granule_default (pad, start_granule);
1142
1143   GST_INFO ("skeleton fisbone parsed "
1144       "(start time: %" GST_TIME_FORMAT
1145       " granulerate_n: %d granulerate_d: %d "
1146       " preroll: %" G_GUINT32_FORMAT " granuleshift: %d)",
1147       GST_TIME_ARGS (start_time),
1148       pad->granulerate_n, pad->granulerate_d, pad->preroll, pad->granuleshift);
1149
1150   if (p_start_time)
1151     *p_start_time = start_time;
1152
1153   return TRUE;
1154 }
1155
1156 static gboolean
1157 read_vlc (const guint8 ** data, guint * size, guint64 * result)
1158 {
1159   gint shift = 0;
1160   guint8 byte;
1161
1162   *result = 0;
1163
1164   do {
1165     if (G_UNLIKELY (*size < 1))
1166       return FALSE;
1167
1168     byte = **data;
1169     *result |= ((byte & 0x7f) << shift);
1170     shift += 7;
1171
1172     (*data)++;
1173     (*size)--;
1174   } while ((byte & 0x80) != 0x80);
1175
1176   return TRUE;
1177 }
1178
1179 gboolean
1180 gst_ogg_map_add_index (GstOggStream * pad, GstOggStream * skel_pad,
1181     const guint8 * data, guint size)
1182 {
1183   guint64 i, n_keypoints, isize;
1184   guint64 offset, timestamp;
1185   guint64 offset_d, timestamp_d;
1186
1187   if (pad->index) {
1188     GST_DEBUG ("already have index, ignoring second one");
1189     return TRUE;
1190   }
1191
1192   if ((skel_pad->skeleton_major == 3 && size < 26) ||
1193       (skel_pad->skeleton_major == 4 && size < 62)) {
1194     GST_WARNING ("small index packet of size %u, ignoring", size);
1195     return FALSE;
1196   }
1197
1198   /* skip "index\0" + serialno */
1199   data += 6 + 4;
1200   size -= 6 + 4;
1201
1202   n_keypoints = GST_READ_UINT64_LE (data);
1203
1204   data += 8;
1205   size -= 8;
1206
1207   pad->kp_denom = GST_READ_UINT64_LE (data);
1208   if (pad->kp_denom == 0)
1209     pad->kp_denom = 1;
1210
1211   data += 8;
1212   size -= 8;
1213
1214   if (skel_pad->skeleton_major == 4) {
1215     gint64 firstsampletime_n;
1216     gint64 lastsampletime_n;
1217     gint64 firstsampletime, lastsampletime;
1218
1219     firstsampletime_n = GST_READ_UINT64_LE (data + 0);
1220     lastsampletime_n = GST_READ_UINT64_LE (data + 8);
1221
1222     GST_INFO ("firstsampletime %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT,
1223         firstsampletime_n, pad->kp_denom);
1224     GST_INFO ("lastsampletime %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT,
1225         lastsampletime_n, pad->kp_denom);
1226
1227     firstsampletime = gst_util_uint64_scale (GST_SECOND,
1228         firstsampletime_n, pad->kp_denom);
1229     lastsampletime = gst_util_uint64_scale (GST_SECOND,
1230         lastsampletime_n, pad->kp_denom);
1231
1232     if (lastsampletime > firstsampletime)
1233       pad->total_time = lastsampletime - firstsampletime;
1234     else
1235       pad->total_time = -1;
1236
1237     GST_INFO ("skeleton index parsed total: %" GST_TIME_FORMAT,
1238         GST_TIME_ARGS (pad->total_time));
1239
1240     data += 16;
1241     size -= 16;
1242   }
1243
1244   GST_INFO ("skeleton index has %" G_GUINT64_FORMAT " keypoints, denom: %"
1245       G_GINT64_FORMAT, n_keypoints, pad->kp_denom);
1246
1247   pad->index = g_try_new (GstOggIndex, n_keypoints);
1248   if (!pad->index)
1249     return FALSE;
1250
1251   isize = 0;
1252   offset = 0;
1253   timestamp = 0;
1254
1255   for (i = 0; i < n_keypoints; i++) {
1256     /* read deltas */
1257     if (!read_vlc (&data, &size, &offset_d))
1258       break;
1259     if (!read_vlc (&data, &size, &timestamp_d))
1260       break;
1261
1262     offset += offset_d;
1263     timestamp += timestamp_d;
1264
1265     pad->index[i].offset = offset;
1266     pad->index[i].timestamp = timestamp;
1267     isize++;
1268
1269     GST_INFO ("offset %" G_GUINT64_FORMAT " time %" G_GUINT64_FORMAT, offset,
1270         timestamp);
1271   }
1272   if (isize != n_keypoints) {
1273     GST_WARNING ("truncated index, expected %" G_GUINT64_FORMAT ", found %"
1274         G_GUINT64_FORMAT, n_keypoints, isize);
1275   }
1276   pad->n_index = isize;
1277   /* try to use the index to estimate the bitrate */
1278   if (isize > 2) {
1279     guint64 so, eo, st, et, b, t;
1280
1281     /* get start and end offset and timestamps */
1282     so = pad->index[0].offset;
1283     st = pad->index[0].timestamp;
1284     eo = pad->index[isize - 1].offset;
1285     et = pad->index[isize - 1].timestamp;
1286
1287     b = eo - so;
1288     t = et - st;
1289
1290     GST_DEBUG ("bytes/time %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT, b, t);
1291
1292     /* this is the total stream bitrate according to this index */
1293     pad->idx_bitrate = gst_util_uint64_scale (8 * b, pad->kp_denom, t);
1294
1295     GST_DEBUG ("bitrate %" G_GUINT64_FORMAT, pad->idx_bitrate);
1296   }
1297
1298   return TRUE;
1299 }
1300
1301 static gint
1302 gst_ogg_index_compare (const GstOggIndex * index, const guint64 * ts,
1303     gpointer user_data)
1304 {
1305   if (index->timestamp < *ts)
1306     return -1;
1307   else if (index->timestamp > *ts)
1308     return 1;
1309   else
1310     return 0;
1311 }
1312
1313 gboolean
1314 gst_ogg_map_search_index (GstOggStream * pad, gboolean before,
1315     guint64 * timestamp, guint64 * offset)
1316 {
1317   guint64 n_index;
1318   guint64 ts;
1319   GstOggIndex *best;
1320
1321   n_index = pad->n_index;
1322   if (n_index == 0 || pad->index == NULL)
1323     return FALSE;
1324
1325   ts = gst_util_uint64_scale (*timestamp, pad->kp_denom, GST_SECOND);
1326   GST_INFO ("timestamp %" G_GUINT64_FORMAT, ts);
1327
1328   best =
1329       gst_util_array_binary_search (pad->index, n_index, sizeof (GstOggIndex),
1330       (GCompareDataFunc) gst_ogg_index_compare, GST_SEARCH_MODE_BEFORE, &ts,
1331       NULL);
1332
1333   if (best == NULL)
1334     return FALSE;
1335
1336   GST_INFO ("found at index %u", (guint) (best - pad->index));
1337
1338   if (offset)
1339     *offset = best->offset;
1340   if (timestamp)
1341     *timestamp =
1342         gst_util_uint64_scale (best->timestamp, GST_SECOND, pad->kp_denom);
1343
1344   return TRUE;
1345 }
1346
1347 /* Do we need these for something?
1348  * ogm->hdr.size = GST_READ_UINT32_LE (&data[13]);
1349  * ogm->hdr.time_unit = GST_READ_UINT64_LE (&data[17]);
1350  * ogm->hdr.samples_per_unit = GST_READ_UINT64_LE (&data[25]);
1351  * ogm->hdr.default_len = GST_READ_UINT32_LE (&data[33]);
1352  * ogm->hdr.buffersize = GST_READ_UINT32_LE (&data[37]);
1353  * ogm->hdr.bits_per_sample = GST_READ_UINT32_LE (&data[41]);
1354  */
1355
1356 static gboolean
1357 is_header_ogm (GstOggStream * pad, ogg_packet * packet)
1358 {
1359   if (packet->bytes >= 1 && (packet->packet[0] & 0x01))
1360     return TRUE;
1361
1362   return FALSE;
1363 }
1364
1365 static void
1366 extract_tags_ogm (GstOggStream * pad, ogg_packet * packet)
1367 {
1368   if (!(packet->packet[0] & 1) && (packet->packet[0] & 3 && pad->is_ogm_text)) {
1369     tag_list_from_vorbiscomment_packet (packet,
1370         (const guint8 *) "\003vorbis", 7, &pad->taglist);
1371   }
1372 }
1373
1374 static gint64
1375 packet_duration_ogm (GstOggStream * pad, ogg_packet * packet)
1376 {
1377   const guint8 *data;
1378   int samples;
1379   int offset;
1380   int n;
1381
1382   data = packet->packet;
1383   offset = 1 + (((data[0] & 0xc0) >> 6) | ((data[0] & 0x02) << 1));
1384
1385   if (offset > packet->bytes) {
1386     GST_ERROR ("buffer too small");
1387     return -1;
1388   }
1389
1390   samples = 0;
1391   for (n = offset - 1; n > 0; n--) {
1392     samples = (samples << 8) | data[n];
1393   }
1394
1395   return samples;
1396 }
1397
1398 static gboolean
1399 setup_ogmaudio_mapper (GstOggStream * pad, ogg_packet * packet)
1400 {
1401   guint8 *data = packet->packet;
1402   guint32 fourcc;
1403
1404   pad->granulerate_n = GST_READ_UINT64_LE (data + 25);
1405   pad->granulerate_d = 1;
1406
1407   fourcc = GST_READ_UINT32_LE (data + 9);
1408   GST_DEBUG ("fourcc: %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
1409
1410   pad->caps = gst_riff_create_audio_caps (fourcc, NULL, NULL, NULL, NULL, NULL);
1411
1412   GST_LOG ("sample rate: %d", pad->granulerate_n);
1413   if (pad->granulerate_n == 0)
1414     return FALSE;
1415
1416   if (pad->caps) {
1417     gst_caps_set_simple (pad->caps,
1418         "rate", G_TYPE_INT, pad->granulerate_n, NULL);
1419   } else {
1420     pad->caps = gst_caps_new_simple ("audio/x-ogm-unknown",
1421         "fourcc", GST_TYPE_FOURCC, fourcc,
1422         "rate", G_TYPE_INT, pad->granulerate_n, NULL);
1423   }
1424
1425   pad->n_header_packets = 1;
1426   pad->is_ogm = TRUE;
1427
1428   return TRUE;
1429 }
1430
1431 static gboolean
1432 setup_ogmvideo_mapper (GstOggStream * pad, ogg_packet * packet)
1433 {
1434   guint8 *data = packet->packet;
1435   guint32 fourcc;
1436   int width, height;
1437   gint64 time_unit;
1438
1439   GST_DEBUG ("time unit %d", GST_READ_UINT32_LE (data + 16));
1440   GST_DEBUG ("samples per unit %d", GST_READ_UINT32_LE (data + 24));
1441
1442   pad->is_video = TRUE;
1443   pad->granulerate_n = 10000000;
1444   time_unit = GST_READ_UINT64_LE (data + 17);
1445   if (time_unit > G_MAXINT || time_unit < G_MININT) {
1446     GST_WARNING ("timeunit is out of range");
1447   }
1448   pad->granulerate_d = (gint) CLAMP (time_unit, G_MININT, G_MAXINT);
1449
1450   GST_LOG ("fps = %d/%d = %.3f",
1451       pad->granulerate_n, pad->granulerate_d,
1452       (double) pad->granulerate_n / pad->granulerate_d);
1453
1454   fourcc = GST_READ_UINT32_LE (data + 9);
1455   width = GST_READ_UINT32_LE (data + 45);
1456   height = GST_READ_UINT32_LE (data + 49);
1457   GST_DEBUG ("fourcc: %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
1458
1459   pad->caps = gst_riff_create_video_caps (fourcc, NULL, NULL, NULL, NULL, NULL);
1460
1461   if (pad->caps == NULL) {
1462     pad->caps = gst_caps_new_simple ("video/x-ogm-unknown",
1463         "fourcc", GST_TYPE_FOURCC, fourcc,
1464         "framerate", GST_TYPE_FRACTION, pad->granulerate_n,
1465         pad->granulerate_d, NULL);
1466   } else {
1467     gst_caps_set_simple (pad->caps,
1468         "framerate", GST_TYPE_FRACTION, pad->granulerate_n,
1469         pad->granulerate_d,
1470         "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
1471   }
1472   GST_DEBUG ("caps: %" GST_PTR_FORMAT, pad->caps);
1473
1474   pad->n_header_packets = 1;
1475   pad->frame_size = 1;
1476   pad->is_ogm = TRUE;
1477
1478   return TRUE;
1479 }
1480
1481 static gboolean
1482 setup_ogmtext_mapper (GstOggStream * pad, ogg_packet * packet)
1483 {
1484   guint8 *data = packet->packet;
1485   gint64 time_unit;
1486
1487   pad->granulerate_n = 10000000;
1488   time_unit = GST_READ_UINT64_LE (data + 17);
1489   if (time_unit > G_MAXINT || time_unit < G_MININT) {
1490     GST_WARNING ("timeunit is out of range");
1491   }
1492   pad->granulerate_d = (gint) CLAMP (time_unit, G_MININT, G_MAXINT);
1493
1494   GST_LOG ("fps = %d/%d = %.3f",
1495       pad->granulerate_n, pad->granulerate_d,
1496       (double) pad->granulerate_n / pad->granulerate_d);
1497
1498   if (pad->granulerate_d <= 0)
1499     return FALSE;
1500
1501   pad->caps = gst_caps_new_simple ("text/plain", NULL);
1502
1503   pad->n_header_packets = 1;
1504   pad->is_ogm = TRUE;
1505   pad->is_ogm_text = TRUE;
1506   pad->is_sparse = TRUE;
1507
1508   return TRUE;
1509 }
1510
1511 /* PCM */
1512
1513 #define OGGPCM_FMT_S8 0x00000000        /* Signed integer 8 bit */
1514 #define OGGPCM_FMT_U8 0x00000001        /* Unsigned integer 8 bit */
1515 #define OGGPCM_FMT_S16_LE 0x00000002    /* Signed integer 16 bit little endian */
1516 #define OGGPCM_FMT_S16_BE 0x00000003    /* Signed integer 16 bit big endian */
1517 #define OGGPCM_FMT_S24_LE 0x00000004    /* Signed integer 24 bit little endian */
1518 #define OGGPCM_FMT_S24_BE 0x00000005    /* Signed integer 24 bit big endian */
1519 #define OGGPCM_FMT_S32_LE 0x00000006    /* Signed integer 32 bit little endian */
1520 #define OGGPCM_FMT_S32_BE 0x00000007    /* Signed integer 32 bit big endian */
1521
1522 #define OGGPCM_FMT_ULAW 0x00000010      /* G.711 u-law encoding (8 bit) */
1523 #define OGGPCM_FMT_ALAW 0x00000011      /* G.711 A-law encoding (8 bit) */
1524
1525 #define OGGPCM_FMT_FLT32_LE 0x00000020  /* IEEE Float [-1,1] 32 bit little endian */
1526 #define OGGPCM_FMT_FLT32_BE 0x00000021  /* IEEE Float [-1,1] 32 bit big endian */
1527 #define OGGPCM_FMT_FLT64_LE 0x00000022  /* IEEE Float [-1,1] 64 bit little endian */
1528 #define OGGPCM_FMT_FLT64_BE 0x00000023  /* IEEE Float [-1,1] 64 bit big endian */
1529
1530
1531 static gboolean
1532 setup_pcm_mapper (GstOggStream * pad, ogg_packet * packet)
1533 {
1534   guint8 *data = packet->packet;
1535   int format;
1536   int channels;
1537   GstCaps *caps;
1538
1539   pad->granulerate_n = GST_READ_UINT32_LE (data + 16);
1540   pad->granulerate_d = 1;
1541   GST_LOG ("sample rate: %d", pad->granulerate_n);
1542
1543   format = GST_READ_UINT32_LE (data + 12);
1544   channels = GST_READ_UINT8 (data + 21);
1545
1546   pad->n_header_packets = 2 + GST_READ_UINT32_LE (data + 24);
1547
1548   if (pad->granulerate_n == 0)
1549     return FALSE;
1550
1551   switch (format) {
1552     case OGGPCM_FMT_S8:
1553       caps = gst_caps_new_simple ("audio/x-raw-int",
1554           "depth", G_TYPE_INT, 8,
1555           "width", G_TYPE_INT, 8, "signed", G_TYPE_BOOLEAN, TRUE, NULL);
1556       break;
1557     case OGGPCM_FMT_U8:
1558       caps = gst_caps_new_simple ("audio/x-raw-int",
1559           "depth", G_TYPE_INT, 8,
1560           "width", G_TYPE_INT, 8, "signed", G_TYPE_BOOLEAN, FALSE, NULL);
1561       break;
1562     case OGGPCM_FMT_S16_LE:
1563       caps = gst_caps_new_simple ("audio/x-raw-int",
1564           "depth", G_TYPE_INT, 16,
1565           "width", G_TYPE_INT, 16,
1566           "endianness", G_TYPE_INT, G_LITTLE_ENDIAN,
1567           "signed", G_TYPE_BOOLEAN, TRUE, NULL);
1568       break;
1569     case OGGPCM_FMT_S16_BE:
1570       caps = gst_caps_new_simple ("audio/x-raw-int",
1571           "depth", G_TYPE_INT, 16,
1572           "width", G_TYPE_INT, 16,
1573           "endianness", G_TYPE_INT, G_BIG_ENDIAN,
1574           "signed", G_TYPE_BOOLEAN, TRUE, NULL);
1575       break;
1576     case OGGPCM_FMT_S24_LE:
1577       caps = gst_caps_new_simple ("audio/x-raw-int",
1578           "depth", G_TYPE_INT, 24,
1579           "width", G_TYPE_INT, 24,
1580           "endianness", G_TYPE_INT, G_LITTLE_ENDIAN,
1581           "signed", G_TYPE_BOOLEAN, TRUE, NULL);
1582       break;
1583     case OGGPCM_FMT_S24_BE:
1584       caps = gst_caps_new_simple ("audio/x-raw-int",
1585           "depth", G_TYPE_INT, 24,
1586           "width", G_TYPE_INT, 24,
1587           "endianness", G_TYPE_INT, G_BIG_ENDIAN,
1588           "signed", G_TYPE_BOOLEAN, TRUE, NULL);
1589       break;
1590     case OGGPCM_FMT_S32_LE:
1591       caps = gst_caps_new_simple ("audio/x-raw-int",
1592           "depth", G_TYPE_INT, 32,
1593           "width", G_TYPE_INT, 32,
1594           "endianness", G_TYPE_INT, G_LITTLE_ENDIAN,
1595           "signed", G_TYPE_BOOLEAN, TRUE, NULL);
1596       break;
1597     case OGGPCM_FMT_S32_BE:
1598       caps = gst_caps_new_simple ("audio/x-raw-int",
1599           "depth", G_TYPE_INT, 32,
1600           "width", G_TYPE_INT, 32,
1601           "endianness", G_TYPE_INT, G_BIG_ENDIAN,
1602           "signed", G_TYPE_BOOLEAN, TRUE, NULL);
1603       break;
1604     case OGGPCM_FMT_ULAW:
1605       caps = gst_caps_new_simple ("audio/x-mulaw", NULL);
1606       break;
1607     case OGGPCM_FMT_ALAW:
1608       caps = gst_caps_new_simple ("audio/x-alaw", NULL);
1609       break;
1610     case OGGPCM_FMT_FLT32_LE:
1611       caps = gst_caps_new_simple ("audio/x-raw-float",
1612           "width", G_TYPE_INT, 32,
1613           "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, NULL);
1614       break;
1615     case OGGPCM_FMT_FLT32_BE:
1616       caps = gst_caps_new_simple ("audio/x-raw-float",
1617           "width", G_TYPE_INT, 32,
1618           "endianness", G_TYPE_INT, G_BIG_ENDIAN, NULL);
1619       break;
1620     case OGGPCM_FMT_FLT64_LE:
1621       caps = gst_caps_new_simple ("audio/x-raw-float",
1622           "width", G_TYPE_INT, 64,
1623           "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, NULL);
1624       break;
1625     case OGGPCM_FMT_FLT64_BE:
1626       caps = gst_caps_new_simple ("audio/x-raw-float",
1627           "width", G_TYPE_INT, 64,
1628           "endianness", G_TYPE_INT, G_BIG_ENDIAN, NULL);
1629       break;
1630     default:
1631       return FALSE;
1632   }
1633
1634   gst_caps_set_simple (caps, "audio/x-raw-int",
1635       "rate", G_TYPE_INT, pad->granulerate_n,
1636       "channels", G_TYPE_INT, channels, NULL);
1637   pad->caps = caps;
1638
1639   return TRUE;
1640 }
1641
1642 /* cmml */
1643
1644 static gboolean
1645 setup_cmml_mapper (GstOggStream * pad, ogg_packet * packet)
1646 {
1647   guint8 *data = packet->packet;
1648
1649   pad->granulerate_n = GST_READ_UINT64_LE (data + 12);
1650   pad->granulerate_d = GST_READ_UINT64_LE (data + 20);
1651   pad->granuleshift = data[28];
1652   GST_LOG ("sample rate: %d", pad->granulerate_n);
1653
1654   pad->n_header_packets = 3;
1655
1656   if (pad->granulerate_n == 0)
1657     return FALSE;
1658
1659   data += 4 + (4 + 4 + 4);
1660   GST_DEBUG ("blocksize0: %u", 1 << (data[0] >> 4));
1661   GST_DEBUG ("blocksize1: %u", 1 << (data[0] & 0x0F));
1662
1663   pad->caps = gst_caps_new_simple ("text/x-cmml", NULL);
1664   pad->is_sparse = TRUE;
1665
1666   return TRUE;
1667 }
1668
1669 /* celt */
1670
1671 static gboolean
1672 setup_celt_mapper (GstOggStream * pad, ogg_packet * packet)
1673 {
1674   guint8 *data = packet->packet;
1675
1676   pad->granulerate_n = GST_READ_UINT32_LE (data + 36);
1677   pad->granulerate_d = 1;
1678   pad->granuleshift = 0;
1679   GST_LOG ("sample rate: %d", pad->granulerate_n);
1680
1681   pad->frame_size = GST_READ_UINT32_LE (packet->packet + 44);
1682   pad->n_header_packets = GST_READ_UINT32_LE (packet->packet + 56) + 2;
1683
1684   if (pad->granulerate_n == 0)
1685     return FALSE;
1686
1687   pad->caps = gst_caps_new_simple ("audio/x-celt",
1688       "rate", G_TYPE_INT, pad->granulerate_n, NULL);
1689
1690   return TRUE;
1691 }
1692
1693 /* kate */
1694
1695 static gboolean
1696 setup_kate_mapper (GstOggStream * pad, ogg_packet * packet)
1697 {
1698   guint8 *data = packet->packet;
1699   const char *category;
1700
1701   if (packet->bytes < 64)
1702     return FALSE;
1703
1704   pad->granulerate_n = GST_READ_UINT32_LE (data + 24);
1705   pad->granulerate_d = GST_READ_UINT32_LE (data + 28);
1706   pad->granuleshift = GST_READ_UINT8 (data + 15);
1707   GST_LOG ("sample rate: %d", pad->granulerate_n);
1708
1709   pad->n_header_packets = GST_READ_UINT8 (data + 11);
1710   GST_LOG ("kate header packets: %d", pad->n_header_packets);
1711
1712   if (pad->granulerate_n == 0)
1713     return FALSE;
1714
1715   category = (const char *) data + 48;
1716   if (strcmp (category, "subtitles") == 0 || strcmp (category, "SUB") == 0 ||
1717       strcmp (category, "spu-subtitles") == 0 ||
1718       strcmp (category, "K-SPU") == 0) {
1719     pad->caps = gst_caps_new_simple ("subtitle/x-kate", NULL);
1720   } else {
1721     pad->caps = gst_caps_new_simple ("application/x-kate", NULL);
1722   }
1723
1724   pad->is_sparse = TRUE;
1725
1726   return TRUE;
1727 }
1728
1729 static gint64
1730 packet_duration_kate (GstOggStream * pad, ogg_packet * packet)
1731 {
1732   gint64 duration;
1733
1734   if (packet->bytes < 1)
1735     return 0;
1736
1737   switch (packet->packet[0]) {
1738     case 0x00:                 /* text data */
1739       if (packet->bytes < 1 + 8 * 2) {
1740         duration = 0;
1741       } else {
1742         duration = GST_READ_UINT64_LE (packet->packet + 1 + 8);
1743         if (duration < 0)
1744           duration = 0;
1745       }
1746       break;
1747     default:
1748       duration = GST_CLOCK_TIME_NONE;
1749       break;
1750   }
1751
1752   return duration;
1753 }
1754
1755 static void
1756 extract_tags_kate (GstOggStream * pad, ogg_packet * packet)
1757 {
1758   GstTagList *list = NULL;
1759
1760   if (packet->bytes <= 0)
1761     return;
1762
1763   switch (packet->packet[0]) {
1764     case 0x80:{
1765       const gchar *canonical;
1766       char language[16];
1767
1768       if (packet->bytes < 64) {
1769         GST_WARNING ("Kate ID header packet is less than 64 bytes, ignored");
1770         break;
1771       }
1772
1773       /* the language tag is 16 bytes at offset 32, ensure NUL terminator */
1774       memcpy (language, packet->packet + 32, 16);
1775       language[15] = 0;
1776
1777       /* language is an ISO 639-1 code or RFC 3066 language code, we
1778        * truncate to ISO 639-1 */
1779       g_strdelimit (language, NULL, '\0');
1780       canonical = gst_tag_get_language_code_iso_639_1 (language);
1781       if (canonical) {
1782         list = gst_tag_list_new_full (GST_TAG_LANGUAGE_CODE, canonical, NULL);
1783       } else {
1784         GST_WARNING ("Unknown or invalid language code %s, ignored", language);
1785       }
1786       break;
1787     }
1788     case 0x81:
1789       tag_list_from_vorbiscomment_packet (packet,
1790           (const guint8 *) "\201kate\0\0\0\0", 9, &list);
1791       break;
1792     default:
1793       break;
1794   }
1795
1796   if (list) {
1797     if (pad->taglist) {
1798       /* ensure the comment packet cannot override the category/language
1799          from the identification header */
1800       gst_tag_list_insert (pad->taglist, list, GST_TAG_MERGE_KEEP_ALL);
1801     } else
1802       pad->taglist = list;
1803   }
1804 }
1805
1806
1807 /* *INDENT-OFF* */
1808 /* indent hates our freedoms */
1809 const GstOggMap mappers[] = {
1810   {
1811     "\200theora", 7, 42,
1812     "video/x-theora",
1813     setup_theora_mapper,
1814     granulepos_to_granule_theora,
1815     granule_to_granulepos_default,
1816     is_keyframe_theora,
1817     is_header_theora,
1818     packet_duration_constant,
1819     NULL,
1820     extract_tags_theora
1821   },
1822   {
1823     "\001vorbis", 7, 22,
1824     "audio/x-vorbis",
1825     setup_vorbis_mapper,
1826     granulepos_to_granule_default,
1827     granule_to_granulepos_default,
1828     is_keyframe_true,
1829     is_header_vorbis,
1830     packet_duration_vorbis,
1831     NULL,
1832     extract_tags_vorbis
1833   },
1834   {
1835     "Speex", 5, 80,
1836     "audio/x-speex",
1837     setup_speex_mapper,
1838     granulepos_to_granule_default,
1839     granule_to_granulepos_default,
1840     is_keyframe_true,
1841     is_header_count,
1842     packet_duration_constant,
1843     NULL,
1844     extract_tags_count
1845   },
1846   {
1847     "PCM     ", 8, 0,
1848     "audio/x-raw-int",
1849     setup_pcm_mapper,
1850     NULL,
1851     NULL,
1852     NULL,
1853     is_header_count,
1854     NULL,
1855     NULL,
1856     NULL
1857   },
1858   {
1859     "CMML\0\0\0\0", 8, 0,
1860     "text/x-cmml",
1861     setup_cmml_mapper,
1862     NULL,
1863     NULL,
1864     NULL,
1865     is_header_count,
1866     NULL,
1867     NULL,
1868     NULL
1869   },
1870   {
1871     "Annodex", 7, 0,
1872     "application/x-annodex",
1873     setup_fishead_mapper,
1874     granulepos_to_granule_default,
1875     granule_to_granulepos_default,
1876     NULL,
1877     is_header_count,
1878     NULL,
1879     NULL,
1880     NULL
1881   },
1882   {
1883     "fishead", 7, 64,
1884     "application/octet-stream",
1885     setup_fishead_mapper,
1886     NULL,
1887     NULL,
1888     NULL,
1889     is_header_true,
1890     NULL,
1891     NULL,
1892     NULL
1893   },
1894   {
1895     "fLaC", 4, 0,
1896     "audio/x-flac",
1897     setup_fLaC_mapper,
1898     granulepos_to_granule_default,
1899     granule_to_granulepos_default,
1900     is_keyframe_true,
1901     is_header_fLaC,
1902     packet_duration_flac,
1903     NULL,
1904     NULL
1905   },
1906   {
1907     "\177FLAC", 5, 36,
1908     "audio/x-flac",
1909     setup_flac_mapper,
1910     granulepos_to_granule_default,
1911     granule_to_granulepos_default,
1912     is_keyframe_true,
1913     is_header_flac,
1914     packet_duration_flac,
1915     NULL,
1916     extract_tags_flac
1917   },
1918   {
1919     "AnxData", 7, 0,
1920     "application/octet-stream",
1921     NULL,
1922     NULL,
1923     NULL,
1924     NULL,
1925     NULL,
1926     NULL,
1927     NULL
1928   },
1929   {
1930     "CELT    ", 8, 0,
1931     "audio/x-celt",
1932     setup_celt_mapper,
1933     granulepos_to_granule_default,
1934     granule_to_granulepos_default,
1935     NULL,
1936     is_header_count,
1937     packet_duration_constant,
1938     NULL,
1939     extract_tags_count
1940   },
1941   {
1942     "\200kate\0\0\0", 8, 0,
1943     "text/x-kate",
1944     setup_kate_mapper,
1945     granulepos_to_granule_default,
1946     granule_to_granulepos_default,
1947     NULL,
1948     is_header_count,
1949     packet_duration_kate,
1950     NULL,
1951     extract_tags_kate
1952   },
1953   {
1954     "BBCD\0", 5, 13,
1955     "video/x-dirac",
1956     setup_dirac_mapper,
1957     granulepos_to_granule_dirac,
1958     granule_to_granulepos_dirac,
1959     is_keyframe_dirac,
1960     is_header_count,
1961     packet_duration_constant,
1962     granulepos_to_key_granule_dirac,
1963     NULL
1964   },
1965   {
1966     "OVP80\1\1", 7, 4,
1967     "video/x-vp8",
1968     setup_vp8_mapper,
1969     granulepos_to_granule_vp8,
1970     granule_to_granulepos_vp8,
1971     is_keyframe_vp8,
1972     is_header_vp8,
1973     packet_duration_vp8,
1974     granulepos_to_key_granule_vp8,
1975     extract_tags_vp8
1976   },
1977   {
1978     "\001audio\0\0\0", 9, 53,
1979     "application/x-ogm-audio",
1980     setup_ogmaudio_mapper,
1981     granulepos_to_granule_default,
1982     granule_to_granulepos_default,
1983     is_keyframe_true,
1984     is_header_ogm,
1985     packet_duration_ogm,
1986     NULL,
1987     NULL
1988   },
1989   {
1990     "\001video\0\0\0", 9, 53,
1991     "application/x-ogm-video",
1992     setup_ogmvideo_mapper,
1993     granulepos_to_granule_default,
1994     granule_to_granulepos_default,
1995     NULL,
1996     is_header_ogm,
1997     packet_duration_constant,
1998     NULL,
1999     NULL
2000   },
2001   {
2002     "\001text\0\0\0", 9, 9,
2003     "application/x-ogm-text",
2004     setup_ogmtext_mapper,
2005     granulepos_to_granule_default,
2006     granule_to_granulepos_default,
2007     is_keyframe_true,
2008     is_header_ogm,
2009     packet_duration_ogm,
2010     NULL,
2011     extract_tags_ogm
2012   }
2013 };
2014 /* *INDENT-ON* */
2015
2016 gboolean
2017 gst_ogg_stream_setup_map (GstOggStream * pad, ogg_packet * packet)
2018 {
2019   int i;
2020   gboolean ret;
2021
2022   for (i = 0; i < G_N_ELEMENTS (mappers); i++) {
2023     if (packet->bytes >= mappers[i].min_packet_size &&
2024         packet->bytes >= mappers[i].id_length &&
2025         memcmp (packet->packet, mappers[i].id, mappers[i].id_length) == 0) {
2026
2027       GST_DEBUG ("found mapper for '%s'", mappers[i].id);
2028
2029       if (mappers[i].setup_func)
2030         ret = mappers[i].setup_func (pad, packet);
2031       else
2032         continue;
2033
2034       if (ret) {
2035         GST_DEBUG ("got stream type %" GST_PTR_FORMAT, pad->caps);
2036         pad->map = i;
2037         return TRUE;
2038       } else {
2039         GST_WARNING ("mapper '%s' did not accept setup header",
2040             mappers[i].media_type);
2041       }
2042     }
2043   }
2044
2045   return FALSE;
2046 }