66192cc27f667a1329305006cb347e322ca13550
[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
59
60
61 #define SKELETON_FISBONE_MIN_SIZE  52
62
63
64 struct _GstOggMap
65 {
66   const gchar *id;
67   int id_length;
68   int min_packet_size;
69   const gchar *media_type;
70   GstOggMapSetupFunc setup_func;
71   GstOggMapToGranuleFunc granulepos_to_granule_func;
72   GstOggMapToGranuleposFunc granule_to_granulepos_func;
73   GstOggMapIsKeyFrameFunc is_key_frame_func;
74   GstOggMapIsHeaderPacketFunc is_header_func;
75   GstOggMapPacketDurationFunc packet_duration_func;
76 };
77
78 static const GstOggMap mappers[];
79
80 GstClockTime
81 gst_ogg_stream_get_packet_start_time (GstOggStream * pad, ogg_packet * packet)
82 {
83   int duration;
84
85   if (packet->granulepos == -1) {
86     return GST_CLOCK_TIME_NONE;
87   }
88
89   duration = gst_ogg_stream_get_packet_duration (pad, packet);
90   if (duration == -1) {
91     return GST_CLOCK_TIME_NONE;
92   }
93
94   return gst_ogg_stream_granule_to_time (pad,
95       gst_ogg_stream_granulepos_to_granule (pad,
96           packet->granulepos) - duration);
97 }
98
99 GstClockTime
100 gst_ogg_stream_get_start_time_for_granulepos (GstOggStream * pad,
101     gint64 granulepos)
102 {
103   if (pad->frame_size == 0)
104     return GST_CLOCK_TIME_NONE;
105
106   return gst_ogg_stream_granule_to_time (pad,
107       gst_ogg_stream_granulepos_to_granule (pad, granulepos));
108 }
109
110 GstClockTime
111 gst_ogg_stream_get_end_time_for_granulepos (GstOggStream * pad,
112     gint64 granulepos)
113 {
114   return gst_ogg_stream_granule_to_time (pad,
115       gst_ogg_stream_granulepos_to_granule (pad, granulepos));
116 }
117
118 GstClockTime
119 gst_ogg_stream_granule_to_time (GstOggStream * pad, gint64 granule)
120 {
121   if (granule == 0 || pad->granulerate_n == 0 || pad->granulerate_d == 0)
122     return 0;
123
124   return gst_util_uint64_scale (granule, GST_SECOND * pad->granulerate_d,
125       pad->granulerate_n);
126 }
127
128 gint64
129 gst_ogg_stream_granulepos_to_granule (GstOggStream * pad, gint64 granulepos)
130 {
131   if (granulepos == -1 || granulepos == 0) {
132     return granulepos;
133   }
134
135   if (mappers[pad->map].granulepos_to_granule_func == NULL) {
136     GST_WARNING ("Failed to convert granulepos to granule");
137     return -1;
138   }
139
140   return mappers[pad->map].granulepos_to_granule_func (pad, granulepos);
141 }
142
143 gint64
144 gst_ogg_stream_granulepos_to_key_granule (GstOggStream * pad, gint64 granulepos)
145 {
146   if (granulepos == -1 || granulepos == 0) {
147     return granulepos;
148   }
149
150   return granulepos >> pad->granuleshift;
151 }
152
153 gint64
154 gst_ogg_stream_granule_to_granulepos (GstOggStream * pad, gint64 granule,
155     gint64 keyframe_granule)
156 {
157   if (granule == -1 || granule == 0) {
158     return granule;
159   }
160
161   if (mappers[pad->map].granule_to_granulepos_func == NULL) {
162     GST_WARNING ("Failed to convert granule to granulepos");
163     return -1;
164   }
165
166   return mappers[pad->map].granule_to_granulepos_func (pad, granule,
167       keyframe_granule);
168 }
169
170 #if 0
171 gboolean
172 gst_ogg_stream_packet_granulepos_is_key_frame (GstOggStream * pad,
173     gint64 granulepos)
174 {
175   if (granulepos == -1) {
176     return FALSE;
177   }
178
179   if (mappers[pad->map].is_key_frame_func == NULL) {
180     GST_WARNING ("Failed to determine key frame");
181     return FALSE;
182   }
183
184   return mappers[pad->map].is_key_frame_func (pad, granulepos);
185 }
186 #endif
187
188 gboolean
189 gst_ogg_stream_packet_is_header (GstOggStream * pad, ogg_packet * packet)
190 {
191   if (mappers[pad->map].is_header_func == NULL) {
192     GST_WARNING ("Failed to determine header");
193     return FALSE;
194   }
195
196   return mappers[pad->map].is_header_func (pad, packet);
197 }
198
199 gint64
200 gst_ogg_stream_get_packet_duration (GstOggStream * pad, ogg_packet * packet)
201 {
202   if (mappers[pad->map].packet_duration_func == NULL) {
203     GST_WARNING ("Failed to determine packet duration");
204     return -1;
205   }
206
207   return mappers[pad->map].packet_duration_func (pad, packet);
208 }
209
210
211
212
213 /* some generic functions */
214
215 static gboolean
216 is_keyframe_true (GstOggStream * pad, gint64 granulepos)
217 {
218   return TRUE;
219 }
220
221 static gint64
222 granulepos_to_granule_default (GstOggStream * pad, gint64 granulepos)
223 {
224   gint64 keyindex, keyoffset;
225
226   if (pad->granuleshift != 0) {
227     keyindex = granulepos >> pad->granuleshift;
228     keyoffset = granulepos - (keyindex << pad->granuleshift);
229     return keyindex + keyoffset;
230   } else {
231     return granulepos;
232   }
233 }
234
235
236 static gint64
237 granule_to_granulepos_default (GstOggStream * pad, gint64 granule,
238     gint64 keyframe_granule)
239 {
240   gint64 keyoffset;
241
242   if (pad->granuleshift != 0) {
243     keyoffset = granule - keyframe_granule;
244     return (keyframe_granule << pad->granuleshift) | keyoffset;
245   } else {
246     return granule;
247   }
248 }
249
250 #ifdef unused
251 static gboolean
252 is_header_unknown (GstOggStream * pad, ogg_packet * packet)
253 {
254   GST_WARNING ("don't know how to detect header");
255   return FALSE;
256 }
257 #endif
258
259 static gboolean
260 is_header_true (GstOggStream * pad, ogg_packet * packet)
261 {
262   return TRUE;
263 }
264
265 static gboolean
266 is_header_count (GstOggStream * pad, ogg_packet * packet)
267 {
268   if (pad->n_header_packets_seen < pad->n_header_packets) {
269     return TRUE;
270   }
271   return FALSE;
272 }
273
274 static gint64
275 packet_duration_constant (GstOggStream * pad, ogg_packet * packet)
276 {
277   return pad->frame_size;
278 }
279
280 /* theora */
281
282 static gboolean
283 setup_theora_mapper (GstOggStream * pad, ogg_packet * packet)
284 {
285   guint8 *data = packet->packet;
286   guint w, h, par_d, par_n;
287
288   w = GST_READ_UINT24_BE (data + 14) & 0xFFFFF0;
289   h = GST_READ_UINT24_BE (data + 17) & 0xFFFFF0;
290
291   pad->granulerate_n = GST_READ_UINT32_BE (data + 22);
292   pad->granulerate_d = GST_READ_UINT32_BE (data + 26);
293
294   par_n = GST_READ_UINT24_BE (data + 30);
295   par_d = GST_READ_UINT24_BE (data + 33);
296
297   GST_LOG ("fps = %d/%d, PAR = %u/%u, width = %u, height = %u",
298       pad->granulerate_n, pad->granulerate_d, par_n, par_d, w, h);
299
300   /* 2 bits + 3 bits = 5 bits KFGSHIFT */
301   pad->granuleshift = ((GST_READ_UINT8 (data + 40) & 0x03) << 3) +
302       (GST_READ_UINT8 (data + 41) >> 5);
303
304   pad->n_header_packets = 3;
305   pad->frame_size = 1;
306
307   if (pad->granulerate_n == 0 || pad->granulerate_d == 0) {
308     GST_WARNING ("frame rate %d/%d", pad->granulerate_n, pad->granulerate_d);
309     return FALSE;
310   }
311
312   pad->caps = gst_caps_new_simple ("video/x-theora", NULL);
313
314   if (w > 0 && h > 0) {
315     gst_caps_set_simple (pad->caps, "width", G_TYPE_INT, w, "height",
316         G_TYPE_INT, h, NULL);
317   }
318
319   /* PAR of 0:N, N:0 and 0:0 is allowed and maps to 1:1 */
320   if (par_n == 0 || par_d == 0)
321     par_n = par_d = 1;
322
323   /* only add framerate now so caps look prettier, with width/height first */
324   gst_caps_set_simple (pad->caps, "framerate", GST_TYPE_FRACTION,
325       pad->granulerate_n, pad->granulerate_d, "pixel-aspect-ratio",
326       GST_TYPE_FRACTION, par_n, par_d, NULL);
327
328   return TRUE;
329 }
330
331 static gint64
332 granulepos_to_granule_theora (GstOggStream * pad, gint64 granulepos)
333 {
334   gint64 keyindex, keyoffset;
335
336   if (pad->granuleshift != 0) {
337     keyindex = granulepos >> pad->granuleshift;
338     keyoffset = granulepos - (keyindex << pad->granuleshift);
339     if (keyoffset == 0) {
340       pad->theora_has_zero_keyoffset = TRUE;
341     }
342     if (pad->theora_has_zero_keyoffset) {
343       keyoffset++;
344     }
345     return keyindex + keyoffset;
346   } else {
347     return granulepos;
348   }
349 }
350
351 static gboolean
352 is_keyframe_theora (GstOggStream * pad, gint64 granulepos)
353 {
354   gint64 frame_mask;
355
356   if (granulepos == (gint64) - 1)
357     return FALSE;
358
359   frame_mask = (1 << (pad->granuleshift + 1)) - 1;
360
361   return ((granulepos & frame_mask) == 0);
362 }
363
364 static gboolean
365 is_header_theora (GstOggStream * pad, ogg_packet * packet)
366 {
367   return (packet->bytes > 0 && (packet->packet[0] & 0x80) == 0x80);
368 }
369
370 /* dirac */
371
372 static gboolean
373 setup_dirac_mapper (GstOggStream * pad, ogg_packet * packet)
374 {
375   int ret;
376   DiracSequenceHeader header;
377
378   ret = dirac_sequence_header_parse (&header, packet->packet + 13,
379       packet->bytes - 13);
380   if (ret == 0) {
381     GST_DEBUG ("Failed to parse Dirac sequence header");
382     return FALSE;
383   }
384
385   pad->granulerate_n = header.frame_rate_numerator * 2;
386   pad->granulerate_d = header.frame_rate_denominator;
387   pad->granuleshift = 22;
388   pad->n_header_packets = 1;
389   pad->frame_size = 2;
390
391   if (header.interlaced_coding != 0) {
392     GST_DEBUG ("non-progressive Dirac coding not implemented");
393     return FALSE;
394   }
395
396   pad->caps = gst_caps_new_simple ("video/x-dirac",
397       "width", G_TYPE_INT, header.width,
398       "height", G_TYPE_INT, header.height,
399       "interlaced", G_TYPE_BOOLEAN, header.interlaced,
400       "pixel-aspect-ratio", GST_TYPE_FRACTION,
401       header.aspect_ratio_numerator, header.aspect_ratio_denominator,
402       "framerate", GST_TYPE_FRACTION, header.frame_rate_numerator,
403       header.frame_rate_denominator, NULL);
404
405   return TRUE;
406 }
407
408 #define OGG_DIRAC_GRANULE_LOW_MASK ((1<<22) - 1)
409 static gboolean
410 is_keyframe_dirac (GstOggStream * pad, gint64 granulepos)
411 {
412   gint64 pt;
413   int dist_h;
414   int dist_l;
415   int dist;
416   int delay;
417   gint64 dt;
418
419   if (granulepos == -1)
420     return -1;
421
422   pt = ((granulepos >> 22) + (granulepos & OGG_DIRAC_GRANULE_LOW_MASK)) >> 9;
423   dist_h = (granulepos >> 22) & 0xff;
424   dist_l = granulepos & 0xff;
425   dist = (dist_h << 8) | dist_l;
426   delay = (granulepos >> 9) & 0x1fff;
427   dt = pt - delay;
428
429   return (dist == 0);
430 }
431
432 static gint64
433 granulepos_to_granule_dirac (GstOggStream * pad, gint64 gp)
434 {
435   gint64 pt;
436   int dist_h;
437   int dist_l;
438   int dist;
439   int delay;
440   gint64 dt;
441
442   pt = ((gp >> 22) + (gp & OGG_DIRAC_GRANULE_LOW_MASK)) >> 9;
443   dist_h = (gp >> 22) & 0xff;
444   dist_l = gp & 0xff;
445   dist = (dist_h << 8) | dist_l;
446   delay = (gp >> 9) & 0x1fff;
447   dt = pt - delay;
448
449   GST_DEBUG ("pt %" G_GINT64_FORMAT " delay %d", pt, delay);
450
451   return dt + 4;
452 }
453
454 static gint64
455 granule_to_granulepos_dirac (GstOggStream * pad, gint64 granule,
456     gint64 keyframe_granule)
457 {
458   /* This conversion requires knowing more details about the Dirac
459    * stream. */
460   return -1;
461 }
462
463
464 /* vorbis */
465
466 static gboolean
467 setup_vorbis_mapper (GstOggStream * pad, ogg_packet * packet)
468 {
469   guint8 *data = packet->packet;
470   guint chans;
471
472   data += 1 + 6 + 4;
473   chans = GST_READ_UINT8 (data);
474   data += 1;
475   pad->granulerate_n = GST_READ_UINT32_LE (data);
476   pad->granulerate_d = 1;
477   pad->granuleshift = 0;
478   pad->last_size = 0;
479   GST_LOG ("sample rate: %d", pad->granulerate_n);
480
481   pad->n_header_packets = 3;
482
483   if (pad->granulerate_n == 0)
484     return FALSE;
485
486   parse_vorbis_header_packet (pad, packet);
487
488   pad->caps = gst_caps_new_simple ("audio/x-vorbis",
489       "rate", G_TYPE_INT, pad->granulerate_n, "channels", G_TYPE_INT, chans,
490       NULL);
491
492   return TRUE;
493 }
494
495 static gboolean
496 is_header_vorbis (GstOggStream * pad, ogg_packet * packet)
497 {
498   if (packet->bytes > 0 && (packet->packet[0] & 0x01) == 0)
499     return FALSE;
500
501   if (packet->packet[0] == 5) {
502     parse_vorbis_setup_packet (pad, packet);
503   }
504
505   return TRUE;
506 }
507
508 static gint64
509 packet_duration_vorbis (GstOggStream * pad, ogg_packet * packet)
510 {
511   int mode;
512   int size;
513   int duration;
514
515   if (packet->packet[0] & 1)
516     return 0;
517
518   mode = (packet->packet[0] >> 1) & ((1 << pad->vorbis_log2_num_modes) - 1);
519   size = pad->vorbis_mode_sizes[mode] ? pad->long_size : pad->short_size;
520
521   if (pad->last_size == 0) {
522     duration = 0;
523   } else {
524     duration = pad->last_size / 4 + size / 4;
525   }
526   pad->last_size = size;
527
528   GST_DEBUG ("duration %d", (int) duration);
529
530   return duration;
531 }
532
533 /* speex */
534
535
536 static gboolean
537 setup_speex_mapper (GstOggStream * pad, ogg_packet * packet)
538 {
539   guint8 *data = packet->packet;
540   guint chans;
541
542   data += 8 + 20 + 4 + 4;
543   pad->granulerate_n = GST_READ_UINT32_LE (data);
544   pad->granulerate_d = 1;
545   pad->granuleshift = 0;
546
547   data += 4 + 4 + 4;
548   chans = GST_READ_UINT32_LE (data);
549
550   GST_LOG ("sample rate: %d, channels: %u", pad->granulerate_n, chans);
551
552   pad->n_header_packets = GST_READ_UINT32_LE (packet->packet + 68) + 2;
553   pad->frame_size = GST_READ_UINT32_LE (packet->packet + 64) *
554       GST_READ_UINT32_LE (packet->packet + 56);
555
556   if (pad->granulerate_n == 0)
557     return FALSE;
558
559   pad->caps = gst_caps_new_simple ("audio/x-speex", "rate", G_TYPE_INT,
560       pad->granulerate_n, "channels", G_TYPE_INT, chans, NULL);
561
562   return TRUE;
563 }
564
565
566 /* flac */
567
568 static gboolean
569 setup_fLaC_mapper (GstOggStream * pad, ogg_packet * packet)
570 {
571   pad->granulerate_n = 0;
572   pad->granulerate_d = 1;
573   pad->granuleshift = 0;
574
575   pad->n_header_packets = 3;
576
577   pad->caps = gst_caps_new_simple ("audio/x-flac", NULL);
578
579   return TRUE;
580 }
581
582 static gboolean
583 is_header_fLaC (GstOggStream * pad, ogg_packet * packet)
584 {
585   if (pad->n_header_packets_seen == 1) {
586     pad->granulerate_n = (packet->packet[14] << 12) |
587         (packet->packet[15] << 4) | ((packet->packet[16] >> 4) & 0xf);
588   }
589
590   if (pad->n_header_packets_seen < pad->n_header_packets) {
591     return TRUE;
592   }
593
594   return FALSE;
595 }
596
597 static gboolean
598 setup_flac_mapper (GstOggStream * pad, ogg_packet * packet)
599 {
600   guint8 *data = packet->packet;
601   guint chans;
602
603   /* see http://flac.sourceforge.net/ogg_mapping.html */
604
605   pad->granulerate_n = (GST_READ_UINT32_BE (data + 27) & 0xFFFFF000) >> 12;
606   pad->granulerate_d = 1;
607   pad->granuleshift = 0;
608   chans = ((GST_READ_UINT32_BE (data + 27) & 0x00000E00) >> 9) + 1;
609
610   GST_DEBUG ("sample rate: %d, channels: %u", pad->granulerate_n, chans);
611
612   pad->n_header_packets = GST_READ_UINT16_BE (packet->packet + 7);
613
614   if (pad->granulerate_n == 0)
615     return FALSE;
616
617   pad->caps = gst_caps_new_simple ("audio/x-flac", "rate", G_TYPE_INT,
618       pad->granulerate_n, "channels", G_TYPE_INT, chans, NULL);
619
620   return TRUE;
621 }
622
623 static gboolean
624 is_header_flac (GstOggStream * pad, ogg_packet * packet)
625 {
626   return (packet->bytes > 0 && (packet->packet[0] != 0xff));
627 }
628
629 static gint64
630 packet_duration_flac (GstOggStream * pad, ogg_packet * packet)
631 {
632   int block_size_index;
633
634   if (packet->bytes < 4)
635     return -1;
636
637   block_size_index = packet->packet[2] >> 4;
638   if (block_size_index == 1)
639     return 192;
640   if (block_size_index >= 2 && block_size_index <= 5) {
641     return 576 << (block_size_index - 2);
642   }
643   if (block_size_index >= 8) {
644     return 256 << (block_size_index - 8);
645   }
646   if (block_size_index == 6 || block_size_index == 7) {
647     guint len, bytes = (block_size_index - 6) + 1;
648     guint8 tmp;
649
650     if (packet->bytes < 4 + 1 + bytes)
651       return -1;
652     tmp = packet->packet[4];
653     /* utf-8 prefix */
654     len = 0;
655     while (tmp & 0x80) {
656       len++;
657       tmp <<= 1;
658     }
659     if (len == 2)
660       return -1;
661     if (len == 0)
662       len++;
663     if (packet->bytes < 4 + len + bytes)
664       return -1;
665     if (bytes == 1) {
666       return packet->packet[4 + len] + 1;
667     } else {
668       return GST_READ_UINT16_BE (packet->packet + 4 + len) + 1;
669     }
670   }
671   return -1;
672 }
673
674 /* fishead */
675
676 static gboolean
677 setup_fishead_mapper (GstOggStream * pad, ogg_packet * packet)
678 {
679   guint8 *data;
680   gint64 prestime_n, prestime_d;
681   gint64 basetime_n, basetime_d;
682   gint64 basetime;
683
684   data = packet->packet;
685
686   data += 8 + 2 + 2;            /* header + major/minor version */
687
688   prestime_n = (gint64) GST_READ_UINT64_LE (data);
689   data += 8;
690   prestime_d = (gint64) GST_READ_UINT64_LE (data);
691   data += 8;
692   basetime_n = (gint64) GST_READ_UINT64_LE (data);
693   data += 8;
694   basetime_d = (gint64) GST_READ_UINT64_LE (data);
695   data += 8;
696
697   /* FIXME: we don't use basetime anywhere in the demuxer! */
698   if (basetime_d != 0)
699     basetime = gst_util_uint64_scale (GST_SECOND, basetime_n, basetime_d);
700   else
701     basetime = -1;
702
703   GST_INFO ("skeleton fishead parsed (basetime: %" GST_TIME_FORMAT ")",
704       GST_TIME_ARGS (basetime));
705
706   pad->is_skeleton = TRUE;
707
708   return TRUE;
709 }
710
711 /* Do we need these for something?
712  * ogm->hdr.size = GST_READ_UINT32_LE (&data[13]);
713  * ogm->hdr.time_unit = GST_READ_UINT64_LE (&data[17]);
714  * ogm->hdr.samples_per_unit = GST_READ_UINT64_LE (&data[25]);
715  * ogm->hdr.default_len = GST_READ_UINT32_LE (&data[33]);
716  * ogm->hdr.buffersize = GST_READ_UINT32_LE (&data[37]);
717  * ogm->hdr.bits_per_sample = GST_READ_UINT32_LE (&data[41]);
718  */
719
720 static gboolean
721 is_header_ogm (GstOggStream * pad, ogg_packet * packet)
722 {
723   if (packet->bytes >= 1 && (packet->packet[0] & 0x01))
724     return TRUE;
725
726   return FALSE;
727 }
728
729 static gint64
730 packet_duration_ogm (GstOggStream * pad, ogg_packet * packet)
731 {
732   const guint8 *data;
733   int samples;
734   int offset;
735   int n;
736
737   data = packet->packet;
738   offset = 1 + (((data[0] & 0xc0) >> 6) | ((data[0] & 0x02) << 1));
739
740   if (offset > packet->bytes) {
741     GST_ERROR ("buffer too small");
742     return -1;
743   }
744
745   samples = 0;
746   for (n = offset - 1; n > 0; n--) {
747     samples = (samples << 8) | data[n];
748   }
749
750   return samples;
751 }
752
753 static gboolean
754 setup_ogmaudio_mapper (GstOggStream * pad, ogg_packet * packet)
755 {
756   guint8 *data = packet->packet;
757   guint32 fourcc;
758
759   pad->granulerate_n = GST_READ_UINT64_LE (data + 25);
760   pad->granulerate_d = 1;
761
762   fourcc = GST_READ_UINT32_LE (data + 9);
763   GST_DEBUG ("fourcc: %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
764
765   pad->caps = gst_riff_create_audio_caps (fourcc, NULL, NULL, NULL, NULL, NULL);
766
767   GST_LOG ("sample rate: %d", pad->granulerate_n);
768   if (pad->granulerate_n == 0)
769     return FALSE;
770
771   if (pad->caps) {
772     gst_caps_set_simple (pad->caps,
773         "rate", G_TYPE_INT, pad->granulerate_n, NULL);
774   } else {
775     pad->caps = gst_caps_new_simple ("audio/x-ogm-unknown",
776         "fourcc", GST_TYPE_FOURCC, fourcc,
777         "rate", G_TYPE_INT, pad->granulerate_n, NULL);
778   }
779
780   pad->n_header_packets = 1;
781   pad->is_ogm = TRUE;
782
783   return TRUE;
784 }
785
786 static gboolean
787 setup_ogmvideo_mapper (GstOggStream * pad, ogg_packet * packet)
788 {
789   guint8 *data = packet->packet;
790   guint32 fourcc;
791   int width, height;
792   gint64 time_unit;
793
794   GST_DEBUG ("time unit %d", GST_READ_UINT32_LE (data + 16));
795   GST_DEBUG ("samples per unit %d", GST_READ_UINT32_LE (data + 24));
796
797   pad->granulerate_n = 10000000;
798   time_unit = GST_READ_UINT64_LE (data + 17);
799   if (time_unit > G_MAXINT || time_unit < G_MININT) {
800     GST_WARNING ("timeunit is out of range");
801   }
802   pad->granulerate_d = (gint) CLAMP (time_unit, G_MININT, G_MAXINT);
803
804   GST_LOG ("fps = %d/%d = %.3f",
805       pad->granulerate_n, pad->granulerate_d,
806       (double) pad->granulerate_n / pad->granulerate_d);
807
808   fourcc = GST_READ_UINT32_LE (data + 9);
809   width = GST_READ_UINT32_LE (data + 45);
810   height = GST_READ_UINT32_LE (data + 49);
811   GST_DEBUG ("fourcc: %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
812
813   pad->caps = gst_riff_create_video_caps (fourcc, NULL, NULL, NULL, NULL, NULL);
814
815   if (pad->caps == NULL) {
816     pad->caps = gst_caps_new_simple ("video/x-ogm-unknown",
817         "fourcc", GST_TYPE_FOURCC, fourcc,
818         "framerate", GST_TYPE_FRACTION, pad->granulerate_n,
819         pad->granulerate_d, NULL);
820   } else {
821     gst_caps_set_simple (pad->caps,
822         "framerate", GST_TYPE_FRACTION, pad->granulerate_n,
823         pad->granulerate_d,
824         "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
825   }
826   GST_DEBUG ("caps: %" GST_PTR_FORMAT, pad->caps);
827
828   pad->n_header_packets = 1;
829   pad->frame_size = 1;
830   pad->is_ogm = TRUE;
831
832   return TRUE;
833 }
834
835 static gboolean
836 setup_ogmtext_mapper (GstOggStream * pad, ogg_packet * packet)
837 {
838   guint8 *data = packet->packet;
839   gint64 time_unit;
840
841   pad->granulerate_n = 10000000;
842   time_unit = GST_READ_UINT64_LE (data + 17);
843   if (time_unit > G_MAXINT || time_unit < G_MININT) {
844     GST_WARNING ("timeunit is out of range");
845   }
846   pad->granulerate_d = (gint) CLAMP (time_unit, G_MININT, G_MAXINT);
847
848   GST_LOG ("fps = %d/%d = %.3f",
849       pad->granulerate_n, pad->granulerate_d,
850       (double) pad->granulerate_n / pad->granulerate_d);
851
852   if (pad->granulerate_d <= 0)
853     return FALSE;
854
855   pad->caps = gst_caps_new_simple ("text/plain", NULL);
856
857   pad->n_header_packets = 1;
858   pad->is_ogm = TRUE;
859   pad->is_ogm_text = TRUE;
860
861   return TRUE;
862 }
863
864 /* PCM */
865
866 #define OGGPCM_FMT_S8 0x00000000        /* Signed integer 8 bit */
867 #define OGGPCM_FMT_U8 0x00000001        /* Unsigned integer 8 bit */
868 #define OGGPCM_FMT_S16_LE 0x00000002    /* Signed integer 16 bit little endian */
869 #define OGGPCM_FMT_S16_BE 0x00000003    /* Signed integer 16 bit big endian */
870 #define OGGPCM_FMT_S24_LE 0x00000004    /* Signed integer 24 bit little endian */
871 #define OGGPCM_FMT_S24_BE 0x00000005    /* Signed integer 24 bit big endian */
872 #define OGGPCM_FMT_S32_LE 0x00000006    /* Signed integer 32 bit little endian */
873 #define OGGPCM_FMT_S32_BE 0x00000007    /* Signed integer 32 bit big endian */
874
875 #define OGGPCM_FMT_ULAW 0x00000010      /* G.711 u-law encoding (8 bit) */
876 #define OGGPCM_FMT_ALAW 0x00000011      /* G.711 A-law encoding (8 bit) */
877
878 #define OGGPCM_FMT_FLT32_LE 0x00000020  /* IEEE Float [-1,1] 32 bit little endian */
879 #define OGGPCM_FMT_FLT32_BE 0x00000021  /* IEEE Float [-1,1] 32 bit big endian */
880 #define OGGPCM_FMT_FLT64_LE 0x00000022  /* IEEE Float [-1,1] 64 bit little endian */
881 #define OGGPCM_FMT_FLT64_BE 0x00000023  /* IEEE Float [-1,1] 64 bit big endian */
882
883
884 static gboolean
885 setup_pcm_mapper (GstOggStream * pad, ogg_packet * packet)
886 {
887   guint8 *data = packet->packet;
888   int format;
889   int channels;
890   GstCaps *caps;
891
892   pad->granulerate_n = GST_READ_UINT32_LE (data + 16);
893   pad->granulerate_d = 1;
894   GST_LOG ("sample rate: %d", pad->granulerate_n);
895
896   format = GST_READ_UINT32_LE (data + 12);
897   channels = GST_READ_UINT8 (data + 21);
898
899   pad->n_header_packets = 2 + GST_READ_UINT32_LE (data + 24);
900
901   if (pad->granulerate_n == 0)
902     return FALSE;
903
904   switch (format) {
905     case OGGPCM_FMT_S8:
906       caps = gst_caps_new_simple ("audio/x-raw-int",
907           "depth", G_TYPE_INT, 8,
908           "width", G_TYPE_INT, 8, "signed", G_TYPE_BOOLEAN, TRUE, NULL);
909       break;
910     case OGGPCM_FMT_U8:
911       caps = gst_caps_new_simple ("audio/x-raw-int",
912           "depth", G_TYPE_INT, 8,
913           "width", G_TYPE_INT, 8, "signed", G_TYPE_BOOLEAN, FALSE, NULL);
914       break;
915     case OGGPCM_FMT_S16_LE:
916       caps = gst_caps_new_simple ("audio/x-raw-int",
917           "depth", G_TYPE_INT, 16,
918           "width", G_TYPE_INT, 16,
919           "endianness", G_TYPE_INT, G_LITTLE_ENDIAN,
920           "signed", G_TYPE_BOOLEAN, TRUE, NULL);
921       break;
922     case OGGPCM_FMT_S16_BE:
923       caps = gst_caps_new_simple ("audio/x-raw-int",
924           "depth", G_TYPE_INT, 16,
925           "width", G_TYPE_INT, 16,
926           "endianness", G_TYPE_INT, G_BIG_ENDIAN,
927           "signed", G_TYPE_BOOLEAN, TRUE, NULL);
928       break;
929     case OGGPCM_FMT_S24_LE:
930       caps = gst_caps_new_simple ("audio/x-raw-int",
931           "depth", G_TYPE_INT, 24,
932           "width", G_TYPE_INT, 24,
933           "endianness", G_TYPE_INT, G_LITTLE_ENDIAN,
934           "signed", G_TYPE_BOOLEAN, TRUE, NULL);
935       break;
936     case OGGPCM_FMT_S24_BE:
937       caps = gst_caps_new_simple ("audio/x-raw-int",
938           "depth", G_TYPE_INT, 24,
939           "width", G_TYPE_INT, 24,
940           "endianness", G_TYPE_INT, G_BIG_ENDIAN,
941           "signed", G_TYPE_BOOLEAN, TRUE, NULL);
942       break;
943     case OGGPCM_FMT_S32_LE:
944       caps = gst_caps_new_simple ("audio/x-raw-int",
945           "depth", G_TYPE_INT, 32,
946           "width", G_TYPE_INT, 32,
947           "endianness", G_TYPE_INT, G_LITTLE_ENDIAN,
948           "signed", G_TYPE_BOOLEAN, TRUE, NULL);
949       break;
950     case OGGPCM_FMT_S32_BE:
951       caps = gst_caps_new_simple ("audio/x-raw-int",
952           "depth", G_TYPE_INT, 32,
953           "width", G_TYPE_INT, 32,
954           "endianness", G_TYPE_INT, G_BIG_ENDIAN,
955           "signed", G_TYPE_BOOLEAN, TRUE, NULL);
956       break;
957     case OGGPCM_FMT_ULAW:
958       caps = gst_caps_new_simple ("audio/x-mulaw", NULL);
959       break;
960     case OGGPCM_FMT_ALAW:
961       caps = gst_caps_new_simple ("audio/x-alaw", NULL);
962       break;
963     case OGGPCM_FMT_FLT32_LE:
964       caps = gst_caps_new_simple ("audio/x-raw-float",
965           "width", G_TYPE_INT, 32,
966           "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, NULL);
967       break;
968     case OGGPCM_FMT_FLT32_BE:
969       caps = gst_caps_new_simple ("audio/x-raw-float",
970           "width", G_TYPE_INT, 32,
971           "endianness", G_TYPE_INT, G_BIG_ENDIAN, NULL);
972       break;
973     case OGGPCM_FMT_FLT64_LE:
974       caps = gst_caps_new_simple ("audio/x-raw-float",
975           "width", G_TYPE_INT, 64,
976           "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, NULL);
977       break;
978     case OGGPCM_FMT_FLT64_BE:
979       caps = gst_caps_new_simple ("audio/x-raw-float",
980           "width", G_TYPE_INT, 64,
981           "endianness", G_TYPE_INT, G_BIG_ENDIAN, NULL);
982       break;
983     default:
984       return FALSE;
985   }
986
987   gst_caps_set_simple (caps, "audio/x-raw-int",
988       "rate", G_TYPE_INT, pad->granulerate_n,
989       "channels", G_TYPE_INT, channels, NULL);
990   pad->caps = caps;
991
992   return TRUE;
993 }
994
995 /* cmml */
996
997 static gboolean
998 setup_cmml_mapper (GstOggStream * pad, ogg_packet * packet)
999 {
1000   guint8 *data = packet->packet;
1001
1002   pad->granulerate_n = GST_READ_UINT64_LE (data + 12);
1003   pad->granulerate_d = GST_READ_UINT64_LE (data + 20);
1004   pad->granuleshift = data[28];
1005   GST_LOG ("sample rate: %d", pad->granulerate_n);
1006
1007   pad->n_header_packets = 3;
1008
1009   if (pad->granulerate_n == 0)
1010     return FALSE;
1011
1012   data += 4 + (4 + 4 + 4);
1013   GST_DEBUG ("blocksize0: %u", 1 << (data[0] >> 4));
1014   GST_DEBUG ("blocksize1: %u", 1 << (data[0] & 0x0F));
1015
1016   pad->caps = gst_caps_new_simple ("text/x-cmml", NULL);
1017
1018   return TRUE;
1019 }
1020
1021 /* celt */
1022
1023 static gboolean
1024 setup_celt_mapper (GstOggStream * pad, ogg_packet * packet)
1025 {
1026   guint8 *data = packet->packet;
1027
1028   pad->granulerate_n = GST_READ_UINT32_LE (data + 36);
1029   pad->granulerate_d = 1;
1030   pad->granuleshift = 0;
1031   GST_LOG ("sample rate: %d", pad->granulerate_n);
1032
1033   pad->frame_size = GST_READ_UINT32_LE (packet->packet + 44);
1034   pad->n_header_packets = GST_READ_UINT32_LE (packet->packet + 56) + 2;
1035
1036   if (pad->granulerate_n == 0)
1037     return FALSE;
1038
1039   pad->caps = gst_caps_new_simple ("audio/x-celt",
1040       "rate", G_TYPE_INT, pad->granulerate_n, NULL);
1041
1042   return TRUE;
1043 }
1044
1045 /* kate */
1046
1047 static gboolean
1048 setup_kate_mapper (GstOggStream * pad, ogg_packet * packet)
1049 {
1050   guint8 *data = packet->packet;
1051   const char *category;
1052
1053   if (packet->bytes < 64)
1054     return FALSE;
1055
1056   pad->granulerate_n = GST_READ_UINT32_LE (data + 24);
1057   pad->granulerate_d = GST_READ_UINT32_LE (data + 28);
1058   pad->granuleshift = GST_READ_UINT8 (data + 15);
1059   GST_LOG ("sample rate: %d", pad->granulerate_n);
1060
1061   pad->n_header_packets = GST_READ_UINT8 (data + 11);
1062
1063   if (pad->granulerate_n == 0)
1064     return FALSE;
1065
1066   category = (const char *) data + 48;
1067   if (strcmp (category, "subtitles") == 0 || strcmp (category, "SUB") == 0 ||
1068       strcmp (category, "spu-subtitles") == 0 ||
1069       strcmp (category, "K-SPU") == 0) {
1070     pad->caps = gst_caps_new_simple ("subtitle/x-kate", NULL);
1071   } else {
1072     pad->caps = gst_caps_new_simple ("application/x-kate", NULL);
1073   }
1074
1075   return TRUE;
1076 }
1077
1078
1079 /* *INDENT-OFF* */
1080 /* indent hates our freedoms */
1081 static const GstOggMap mappers[] = {
1082   {
1083     "\200theora", 7, 42,
1084     "video/x-theora",
1085     setup_theora_mapper,
1086     granulepos_to_granule_theora,
1087     granule_to_granulepos_default,
1088     is_keyframe_theora,
1089     is_header_theora,
1090     packet_duration_constant
1091   },
1092   {
1093     "\001vorbis", 7, 22,
1094     "audio/x-vorbis",
1095     setup_vorbis_mapper,
1096     granulepos_to_granule_default,
1097     granule_to_granulepos_default,
1098     is_keyframe_true,
1099     is_header_vorbis,
1100     packet_duration_vorbis
1101   },
1102   {
1103     "Speex", 5, 80,
1104     "audio/x-speex",
1105     setup_speex_mapper,
1106     granulepos_to_granule_default,
1107     granule_to_granulepos_default,
1108     is_keyframe_true,
1109     is_header_count,
1110     packet_duration_constant
1111   },
1112   {
1113     "PCM     ", 8, 0,
1114     "audio/x-raw-int",
1115     setup_pcm_mapper,
1116     NULL,
1117     NULL,
1118     NULL,
1119     is_header_count,
1120     NULL
1121   },
1122   {
1123     "CMML\0\0\0\0", 8, 0,
1124     "text/x-cmml",
1125     setup_cmml_mapper,
1126     NULL,
1127     NULL,
1128     NULL,
1129     is_header_count,
1130     NULL
1131   },
1132   {
1133     "Annodex", 7, 0,
1134     "application/x-annodex",
1135     setup_fishead_mapper,
1136     granulepos_to_granule_default,
1137     granule_to_granulepos_default,
1138     NULL,
1139     is_header_count,
1140     NULL
1141   },
1142   {
1143     "fishead", 7, 64,
1144     "application/octet-stream",
1145     setup_fishead_mapper,
1146     NULL,
1147     NULL,
1148     NULL,
1149     is_header_true,
1150     NULL
1151   },
1152   {
1153     "fLaC", 4, 0,
1154     "audio/x-flac",
1155     setup_fLaC_mapper,
1156     granulepos_to_granule_default,
1157     granule_to_granulepos_default,
1158     is_keyframe_true,
1159     is_header_fLaC,
1160     NULL
1161   },
1162   {
1163     "\177FLAC", 5, 36,
1164     "audio/x-flac",
1165     setup_flac_mapper,
1166     granulepos_to_granule_default,
1167     granule_to_granulepos_default,
1168     is_keyframe_true,
1169     is_header_flac,
1170     packet_duration_flac
1171   },
1172   {
1173     "AnxData", 7, 0,
1174     "application/octet-stream",
1175     NULL,
1176     NULL,
1177     NULL,
1178     NULL,
1179     NULL,
1180   },
1181   {
1182     "CELT    ", 8, 0,
1183     "audio/x-celt",
1184     setup_celt_mapper,
1185     granulepos_to_granule_default,
1186     granule_to_granulepos_default,
1187     NULL,
1188     is_header_count,
1189     packet_duration_constant
1190   },
1191   {
1192     "\200kate\0\0\0", 8, 0,
1193     "text/x-kate",
1194     setup_kate_mapper,
1195     granulepos_to_granule_default,
1196     granule_to_granulepos_default,
1197     NULL,
1198     is_header_count,
1199     NULL
1200   },
1201   {
1202     "BBCD\0", 5, 13,
1203     "video/x-dirac",
1204     setup_dirac_mapper,
1205     granulepos_to_granule_dirac,
1206     granule_to_granulepos_dirac,
1207     is_keyframe_dirac,
1208     is_header_count,
1209     packet_duration_constant
1210   },
1211   {
1212     "\001audio\0\0\0", 9, 53,
1213     "application/x-ogm-audio",
1214     setup_ogmaudio_mapper,
1215     granulepos_to_granule_default,
1216     granule_to_granulepos_default,
1217     is_keyframe_true,
1218     is_header_ogm,
1219     packet_duration_ogm
1220   },
1221   {
1222     "\001video\0\0\0", 9, 53,
1223     "application/x-ogm-video",
1224     setup_ogmvideo_mapper,
1225     granulepos_to_granule_default,
1226     granule_to_granulepos_default,
1227     NULL,
1228     is_header_ogm,
1229     packet_duration_constant
1230   },
1231   {
1232     "\001text\0\0\0", 9, 9,
1233     "application/x-ogm-text",
1234     setup_ogmtext_mapper,
1235     granulepos_to_granule_default,
1236     granule_to_granulepos_default,
1237     is_keyframe_true,
1238     is_header_ogm,
1239     packet_duration_ogm
1240   }
1241 };
1242 /* *INDENT-ON* */
1243
1244 gboolean
1245 gst_ogg_stream_setup_map (GstOggStream * pad, ogg_packet * packet)
1246 {
1247   int i;
1248   gboolean ret;
1249
1250   for (i = 0; i < G_N_ELEMENTS (mappers); i++) {
1251     if (packet->bytes >= mappers[i].min_packet_size &&
1252         packet->bytes >= mappers[i].id_length &&
1253         memcmp (packet->packet, mappers[i].id, mappers[i].id_length) == 0) {
1254
1255       GST_DEBUG ("found mapper for '%s'", mappers[i].id);
1256
1257       if (mappers[i].setup_func)
1258         ret = mappers[i].setup_func (pad, packet);
1259       else
1260         continue;
1261
1262       if (ret) {
1263         GST_DEBUG ("got stream type %" GST_PTR_FORMAT, pad->caps);
1264         pad->map = i;
1265         return TRUE;
1266       } else {
1267         GST_WARNING ("mapper '%s' did not accept setup header",
1268             mappers[i].media_type);
1269       }
1270     }
1271   }
1272
1273   return FALSE;
1274 }