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>
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.
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.
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.
25 #include "gstoggstream.h"
26 #include "dirac_parse.h"
27 #include "vorbis_parse.h"
29 #include <gst/riff/riff-media.h>
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
38 typedef struct _GstOggMap GstOggMap;
40 typedef gboolean (*GstOggMapSetupFunc) (GstOggStream * pad,
42 typedef GstClockTime (*GstOggMapToTimeFunc) (GstOggStream * pad,
44 typedef gint64 (*GstOggMapToGranuleFunc) (GstOggStream * pad,
46 typedef gint64 (*GstOggMapToGranuleposFunc) (GstOggStream * pad,
47 gint64 granule, gint64 keyframe_granule);
49 /* returns TRUE if the granulepos denotes a key frame */
50 typedef gboolean (*GstOggMapIsKeyFrameFunc) (GstOggStream * pad,
53 /* returns TRUE if the given packet is a stream header packet */
54 typedef gboolean (*GstOggMapIsHeaderPacketFunc) (GstOggStream * pad,
56 typedef gint64 (*GstOggMapPacketDurationFunc) (GstOggStream * pad,
61 #define SKELETON_FISBONE_MIN_SIZE 52
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;
78 static const GstOggMap mappers[];
81 gst_ogg_stream_get_packet_start_time (GstOggStream * pad, ogg_packet * packet)
85 if (packet->granulepos == -1) {
86 return GST_CLOCK_TIME_NONE;
89 duration = gst_ogg_stream_get_packet_duration (pad, packet);
91 return GST_CLOCK_TIME_NONE;
94 return gst_ogg_stream_granule_to_time (pad,
95 gst_ogg_stream_granulepos_to_granule (pad,
96 packet->granulepos) - duration);
100 gst_ogg_stream_get_start_time_for_granulepos (GstOggStream * pad,
103 if (pad->frame_size == 0)
104 return GST_CLOCK_TIME_NONE;
106 return gst_ogg_stream_granule_to_time (pad,
107 gst_ogg_stream_granulepos_to_granule (pad, granulepos));
111 gst_ogg_stream_get_end_time_for_granulepos (GstOggStream * pad,
114 return gst_ogg_stream_granule_to_time (pad,
115 gst_ogg_stream_granulepos_to_granule (pad, granulepos));
119 gst_ogg_stream_granule_to_time (GstOggStream * pad, gint64 granule)
121 if (granule == 0 || pad->granulerate_n == 0 || pad->granulerate_d == 0)
124 return gst_util_uint64_scale (granule, GST_SECOND * pad->granulerate_d,
129 gst_ogg_stream_granulepos_to_granule (GstOggStream * pad, gint64 granulepos)
131 if (granulepos == -1 || granulepos == 0) {
135 if (mappers[pad->map].granulepos_to_granule_func == NULL) {
136 GST_WARNING ("Failed to convert granulepos to granule");
140 return mappers[pad->map].granulepos_to_granule_func (pad, granulepos);
144 gst_ogg_stream_granulepos_to_key_granule (GstOggStream * pad, gint64 granulepos)
146 if (granulepos == -1 || granulepos == 0) {
150 return granulepos >> pad->granuleshift;
154 gst_ogg_stream_granule_to_granulepos (GstOggStream * pad, gint64 granule,
155 gint64 keyframe_granule)
157 if (granule == -1 || granule == 0) {
161 if (mappers[pad->map].granule_to_granulepos_func == NULL) {
162 GST_WARNING ("Failed to convert granule to granulepos");
166 return mappers[pad->map].granule_to_granulepos_func (pad, granule,
172 gst_ogg_stream_packet_granulepos_is_key_frame (GstOggStream * pad,
175 if (granulepos == -1) {
179 if (mappers[pad->map].is_key_frame_func == NULL) {
180 GST_WARNING ("Failed to determine key frame");
184 return mappers[pad->map].is_key_frame_func (pad, granulepos);
189 gst_ogg_stream_packet_is_header (GstOggStream * pad, ogg_packet * packet)
191 if (mappers[pad->map].is_header_func == NULL) {
192 GST_WARNING ("Failed to determine header");
196 return mappers[pad->map].is_header_func (pad, packet);
200 gst_ogg_stream_get_packet_duration (GstOggStream * pad, ogg_packet * packet)
202 if (mappers[pad->map].packet_duration_func == NULL) {
203 GST_WARNING ("Failed to determine packet duration");
207 return mappers[pad->map].packet_duration_func (pad, packet);
213 /* some generic functions */
216 is_keyframe_true (GstOggStream * pad, gint64 granulepos)
222 granulepos_to_granule_default (GstOggStream * pad, gint64 granulepos)
224 gint64 keyindex, keyoffset;
226 if (pad->granuleshift != 0) {
227 keyindex = granulepos >> pad->granuleshift;
228 keyoffset = granulepos - (keyindex << pad->granuleshift);
229 return keyindex + keyoffset;
237 granule_to_granulepos_default (GstOggStream * pad, gint64 granule,
238 gint64 keyframe_granule)
242 if (pad->granuleshift != 0) {
243 keyoffset = granule - keyframe_granule;
244 return (keyframe_granule << pad->granuleshift) | keyoffset;
252 is_header_unknown (GstOggStream * pad, ogg_packet * packet)
254 GST_WARNING ("don't know how to detect header");
260 is_header_true (GstOggStream * pad, ogg_packet * packet)
266 is_header_count (GstOggStream * pad, ogg_packet * packet)
268 if (pad->n_header_packets_seen < pad->n_header_packets) {
275 packet_duration_constant (GstOggStream * pad, ogg_packet * packet)
277 return pad->frame_size;
283 setup_theora_mapper (GstOggStream * pad, ogg_packet * packet)
285 guint8 *data = packet->packet;
286 guint w, h, par_d, par_n;
288 w = GST_READ_UINT24_BE (data + 14) & 0xFFFFF0;
289 h = GST_READ_UINT24_BE (data + 17) & 0xFFFFF0;
291 pad->granulerate_n = GST_READ_UINT32_BE (data + 22);
292 pad->granulerate_d = GST_READ_UINT32_BE (data + 26);
294 par_n = GST_READ_UINT24_BE (data + 30);
295 par_d = GST_READ_UINT24_BE (data + 33);
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);
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);
304 pad->n_header_packets = 3;
307 if (pad->granulerate_n == 0 || pad->granulerate_d == 0) {
308 GST_WARNING ("frame rate %d/%d", pad->granulerate_n, pad->granulerate_d);
312 pad->caps = gst_caps_new_simple ("video/x-theora", NULL);
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);
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)
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);
332 granulepos_to_granule_theora (GstOggStream * pad, gint64 granulepos)
334 gint64 keyindex, keyoffset;
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;
342 if (pad->theora_has_zero_keyoffset) {
345 return keyindex + keyoffset;
352 is_keyframe_theora (GstOggStream * pad, gint64 granulepos)
356 if (granulepos == (gint64) - 1)
359 frame_mask = (1 << (pad->granuleshift + 1)) - 1;
361 return ((granulepos & frame_mask) == 0);
365 is_header_theora (GstOggStream * pad, ogg_packet * packet)
367 return (packet->bytes > 0 && (packet->packet[0] & 0x80) == 0x80);
373 setup_dirac_mapper (GstOggStream * pad, ogg_packet * packet)
376 DiracSequenceHeader header;
378 ret = dirac_sequence_header_parse (&header, packet->packet + 13,
381 GST_DEBUG ("Failed to parse Dirac sequence header");
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;
391 if (header.interlaced_coding != 0) {
392 GST_DEBUG ("non-progressive Dirac coding not implemented");
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);
408 #define OGG_DIRAC_GRANULE_LOW_MASK ((1<<22) - 1)
410 is_keyframe_dirac (GstOggStream * pad, gint64 granulepos)
419 if (granulepos == -1)
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;
433 granulepos_to_granule_dirac (GstOggStream * pad, gint64 gp)
442 pt = ((gp >> 22) + (gp & OGG_DIRAC_GRANULE_LOW_MASK)) >> 9;
443 dist_h = (gp >> 22) & 0xff;
445 dist = (dist_h << 8) | dist_l;
446 delay = (gp >> 9) & 0x1fff;
449 GST_DEBUG ("pt %" G_GINT64_FORMAT " delay %d", pt, delay);
455 granule_to_granulepos_dirac (GstOggStream * pad, gint64 granule,
456 gint64 keyframe_granule)
458 /* This conversion requires knowing more details about the Dirac
467 setup_vorbis_mapper (GstOggStream * pad, ogg_packet * packet)
469 guint8 *data = packet->packet;
473 chans = GST_READ_UINT8 (data);
475 pad->granulerate_n = GST_READ_UINT32_LE (data);
476 pad->granulerate_d = 1;
477 pad->granuleshift = 0;
479 GST_LOG ("sample rate: %d", pad->granulerate_n);
481 pad->n_header_packets = 3;
483 if (pad->granulerate_n == 0)
486 parse_vorbis_header_packet (pad, packet);
488 pad->caps = gst_caps_new_simple ("audio/x-vorbis",
489 "rate", G_TYPE_INT, pad->granulerate_n, "channels", G_TYPE_INT, chans,
496 is_header_vorbis (GstOggStream * pad, ogg_packet * packet)
498 if (packet->bytes > 0 && (packet->packet[0] & 0x01) == 0)
501 if (packet->packet[0] == 5) {
502 parse_vorbis_setup_packet (pad, packet);
509 packet_duration_vorbis (GstOggStream * pad, ogg_packet * packet)
515 if (packet->packet[0] & 1)
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;
521 if (pad->last_size == 0) {
524 duration = pad->last_size / 4 + size / 4;
526 pad->last_size = size;
528 GST_DEBUG ("duration %d", (int) duration);
537 setup_speex_mapper (GstOggStream * pad, ogg_packet * packet)
539 guint8 *data = packet->packet;
542 data += 8 + 20 + 4 + 4;
543 pad->granulerate_n = GST_READ_UINT32_LE (data);
544 pad->granulerate_d = 1;
545 pad->granuleshift = 0;
548 chans = GST_READ_UINT32_LE (data);
550 GST_LOG ("sample rate: %d, channels: %u", pad->granulerate_n, chans);
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);
556 if (pad->granulerate_n == 0)
559 pad->caps = gst_caps_new_simple ("audio/x-speex", "rate", G_TYPE_INT,
560 pad->granulerate_n, "channels", G_TYPE_INT, chans, NULL);
569 setup_fLaC_mapper (GstOggStream * pad, ogg_packet * packet)
571 pad->granulerate_n = 0;
572 pad->granulerate_d = 1;
573 pad->granuleshift = 0;
575 pad->n_header_packets = 3;
577 pad->caps = gst_caps_new_simple ("audio/x-flac", NULL);
583 is_header_fLaC (GstOggStream * pad, ogg_packet * packet)
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);
590 if (pad->n_header_packets_seen < pad->n_header_packets) {
598 setup_flac_mapper (GstOggStream * pad, ogg_packet * packet)
600 guint8 *data = packet->packet;
603 /* see http://flac.sourceforge.net/ogg_mapping.html */
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;
610 GST_DEBUG ("sample rate: %d, channels: %u", pad->granulerate_n, chans);
612 pad->n_header_packets = GST_READ_UINT16_BE (packet->packet + 7);
614 if (pad->granulerate_n == 0)
617 pad->caps = gst_caps_new_simple ("audio/x-flac", "rate", G_TYPE_INT,
618 pad->granulerate_n, "channels", G_TYPE_INT, chans, NULL);
624 is_header_flac (GstOggStream * pad, ogg_packet * packet)
626 return (packet->bytes > 0 && (packet->packet[0] != 0xff));
630 packet_duration_flac (GstOggStream * pad, ogg_packet * packet)
632 int block_size_index;
634 if (packet->bytes < 4)
637 block_size_index = packet->packet[2] >> 4;
638 if (block_size_index == 1)
640 if (block_size_index >= 2 && block_size_index <= 5) {
641 return 576 << (block_size_index - 2);
643 if (block_size_index >= 8) {
644 return 256 << (block_size_index - 8);
646 if (block_size_index == 6 || block_size_index == 7) {
647 guint len, bytes = (block_size_index - 6) + 1;
650 if (packet->bytes < 4 + 1 + bytes)
652 tmp = packet->packet[4];
663 if (packet->bytes < 4 + len + bytes)
666 return packet->packet[4 + len] + 1;
668 return GST_READ_UINT16_BE (packet->packet + 4 + len) + 1;
677 setup_fishead_mapper (GstOggStream * pad, ogg_packet * packet)
680 gint64 prestime_n, prestime_d;
681 gint64 basetime_n, basetime_d;
684 data = packet->packet;
686 data += 8 + 2 + 2; /* header + major/minor version */
688 prestime_n = (gint64) GST_READ_UINT64_LE (data);
690 prestime_d = (gint64) GST_READ_UINT64_LE (data);
692 basetime_n = (gint64) GST_READ_UINT64_LE (data);
694 basetime_d = (gint64) GST_READ_UINT64_LE (data);
697 /* FIXME: we don't use basetime anywhere in the demuxer! */
699 basetime = gst_util_uint64_scale (GST_SECOND, basetime_n, basetime_d);
703 GST_INFO ("skeleton fishead parsed (basetime: %" GST_TIME_FORMAT ")",
704 GST_TIME_ARGS (basetime));
706 pad->is_skeleton = TRUE;
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]);
721 is_header_ogm (GstOggStream * pad, ogg_packet * packet)
723 if (packet->bytes >= 1 && (packet->packet[0] & 0x01))
730 packet_duration_ogm (GstOggStream * pad, ogg_packet * packet)
737 data = packet->packet;
738 offset = 1 + (((data[0] & 0xc0) >> 6) | ((data[0] & 0x02) << 1));
740 if (offset > packet->bytes) {
741 GST_ERROR ("buffer too small");
746 for (n = offset - 1; n > 0; n--) {
747 samples = (samples << 8) | data[n];
754 setup_ogmaudio_mapper (GstOggStream * pad, ogg_packet * packet)
756 guint8 *data = packet->packet;
759 pad->granulerate_n = GST_READ_UINT64_LE (data + 25);
760 pad->granulerate_d = 1;
762 fourcc = GST_READ_UINT32_LE (data + 9);
763 GST_DEBUG ("fourcc: %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
765 pad->caps = gst_riff_create_audio_caps (fourcc, NULL, NULL, NULL, NULL, NULL);
767 GST_LOG ("sample rate: %d", pad->granulerate_n);
768 if (pad->granulerate_n == 0)
772 gst_caps_set_simple (pad->caps,
773 "rate", G_TYPE_INT, pad->granulerate_n, NULL);
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);
780 pad->n_header_packets = 1;
787 setup_ogmvideo_mapper (GstOggStream * pad, ogg_packet * packet)
789 guint8 *data = packet->packet;
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));
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");
802 pad->granulerate_d = (gint) CLAMP (time_unit, G_MININT, G_MAXINT);
804 GST_LOG ("fps = %d/%d = %.3f",
805 pad->granulerate_n, pad->granulerate_d,
806 (double) pad->granulerate_n / pad->granulerate_d);
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));
813 pad->caps = gst_riff_create_video_caps (fourcc, NULL, NULL, NULL, NULL, NULL);
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);
821 gst_caps_set_simple (pad->caps,
822 "framerate", GST_TYPE_FRACTION, pad->granulerate_n,
824 "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
826 GST_DEBUG ("caps: %" GST_PTR_FORMAT, pad->caps);
828 pad->n_header_packets = 1;
836 setup_ogmtext_mapper (GstOggStream * pad, ogg_packet * packet)
838 guint8 *data = packet->packet;
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");
846 pad->granulerate_d = (gint) CLAMP (time_unit, G_MININT, G_MAXINT);
848 GST_LOG ("fps = %d/%d = %.3f",
849 pad->granulerate_n, pad->granulerate_d,
850 (double) pad->granulerate_n / pad->granulerate_d);
852 if (pad->granulerate_d <= 0)
855 pad->caps = gst_caps_new_simple ("text/plain", NULL);
857 pad->n_header_packets = 1;
859 pad->is_ogm_text = TRUE;
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 */
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) */
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 */
885 setup_pcm_mapper (GstOggStream * pad, ogg_packet * packet)
887 guint8 *data = packet->packet;
892 pad->granulerate_n = GST_READ_UINT32_LE (data + 16);
893 pad->granulerate_d = 1;
894 GST_LOG ("sample rate: %d", pad->granulerate_n);
896 format = GST_READ_UINT32_LE (data + 12);
897 channels = GST_READ_UINT8 (data + 21);
899 pad->n_header_packets = 2 + GST_READ_UINT32_LE (data + 24);
901 if (pad->granulerate_n == 0)
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);
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);
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);
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);
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);
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);
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);
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);
957 case OGGPCM_FMT_ULAW:
958 caps = gst_caps_new_simple ("audio/x-mulaw", NULL);
960 case OGGPCM_FMT_ALAW:
961 caps = gst_caps_new_simple ("audio/x-alaw", NULL);
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);
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);
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);
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);
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);
998 setup_cmml_mapper (GstOggStream * pad, ogg_packet * packet)
1000 guint8 *data = packet->packet;
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);
1007 pad->n_header_packets = 3;
1009 if (pad->granulerate_n == 0)
1012 data += 4 + (4 + 4 + 4);
1013 GST_DEBUG ("blocksize0: %u", 1 << (data[0] >> 4));
1014 GST_DEBUG ("blocksize1: %u", 1 << (data[0] & 0x0F));
1016 pad->caps = gst_caps_new_simple ("text/x-cmml", NULL);
1024 setup_celt_mapper (GstOggStream * pad, ogg_packet * packet)
1026 guint8 *data = packet->packet;
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);
1033 pad->frame_size = GST_READ_UINT32_LE (packet->packet + 44);
1034 pad->n_header_packets = GST_READ_UINT32_LE (packet->packet + 56) + 2;
1036 if (pad->granulerate_n == 0)
1039 pad->caps = gst_caps_new_simple ("audio/x-celt",
1040 "rate", G_TYPE_INT, pad->granulerate_n, NULL);
1048 setup_kate_mapper (GstOggStream * pad, ogg_packet * packet)
1050 guint8 *data = packet->packet;
1051 const char *category;
1053 if (packet->bytes < 64)
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);
1061 pad->n_header_packets = GST_READ_UINT8 (data + 11);
1063 if (pad->granulerate_n == 0)
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);
1072 pad->caps = gst_caps_new_simple ("application/x-kate", NULL);
1080 /* indent hates our freedoms */
1081 static const GstOggMap mappers[] = {
1083 "\200theora", 7, 42,
1085 setup_theora_mapper,
1086 granulepos_to_granule_theora,
1087 granule_to_granulepos_default,
1090 packet_duration_constant
1093 "\001vorbis", 7, 22,
1095 setup_vorbis_mapper,
1096 granulepos_to_granule_default,
1097 granule_to_granulepos_default,
1100 packet_duration_vorbis
1106 granulepos_to_granule_default,
1107 granule_to_granulepos_default,
1110 packet_duration_constant
1123 "CMML\0\0\0\0", 8, 0,
1134 "application/x-annodex",
1135 setup_fishead_mapper,
1136 granulepos_to_granule_default,
1137 granule_to_granulepos_default,
1144 "application/octet-stream",
1145 setup_fishead_mapper,
1156 granulepos_to_granule_default,
1157 granule_to_granulepos_default,
1166 granulepos_to_granule_default,
1167 granule_to_granulepos_default,
1170 packet_duration_flac
1174 "application/octet-stream",
1185 granulepos_to_granule_default,
1186 granule_to_granulepos_default,
1189 packet_duration_constant
1192 "\200kate\0\0\0", 8, 0,
1195 granulepos_to_granule_default,
1196 granule_to_granulepos_default,
1205 granulepos_to_granule_dirac,
1206 granule_to_granulepos_dirac,
1209 packet_duration_constant
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,
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,
1229 packet_duration_constant
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,
1245 gst_ogg_stream_setup_map (GstOggStream * pad, ogg_packet * packet)
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) {
1255 GST_DEBUG ("found mapper for '%s'", mappers[i].id);
1257 if (mappers[i].setup_func)
1258 ret = mappers[i].setup_func (pad, packet);
1263 GST_DEBUG ("got stream type %" GST_PTR_FORMAT, pad->caps);
1267 GST_WARNING ("mapper '%s' did not accept setup header",
1268 mappers[i].media_type);