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"
28 #include <gst/riff/riff-media.h>
32 GST_DEBUG_CATEGORY_EXTERN (gst_ogg_demux_debug);
33 GST_DEBUG_CATEGORY_EXTERN (gst_ogg_demux_setup_debug);
34 #define GST_CAT_DEFAULT gst_ogg_demux_debug
36 typedef struct _GstOggMap GstOggMap;
38 typedef gboolean (*GstOggMapSetupFunc) (GstOggStream * pad,
40 typedef GstClockTime (*GstOggMapToTimeFunc) (GstOggStream * pad,
42 typedef gint64 (*GstOggMapToGranuleFunc) (GstOggStream * pad,
44 typedef gint64 (*GstOggMapToGranuleposFunc) (GstOggStream * pad,
45 gint64 granule, gint64 keyframe_granule);
47 /* returns TRUE if the granulepos denotes a key frame */
48 typedef gboolean (*GstOggMapIsKeyFrameFunc) (GstOggStream * pad,
51 /* returns TRUE if the given packet is a stream header packet */
52 typedef gboolean (*GstOggMapIsHeaderPacketFunc) (GstOggStream * pad,
54 typedef gint64 (*GstOggMapPacketDurationFunc) (GstOggStream * pad,
59 #define SKELETON_FISBONE_MIN_SIZE 52
67 const gchar *media_type;
68 GstOggMapSetupFunc setup_func;
69 GstOggMapToGranuleFunc granulepos_to_granule_func;
70 GstOggMapToGranuleposFunc granule_to_granulepos_func;
71 GstOggMapIsKeyFrameFunc is_key_frame_func;
72 GstOggMapIsHeaderPacketFunc is_header_func;
73 GstOggMapPacketDurationFunc packet_duration_func;
76 static const GstOggMap mappers[];
79 gst_ogg_stream_get_packet_start_time (GstOggStream * pad, ogg_packet * packet)
83 if (packet->granulepos == -1) {
84 return GST_CLOCK_TIME_NONE;
87 duration = gst_ogg_stream_get_packet_duration (pad, packet);
89 return GST_CLOCK_TIME_NONE;
92 return gst_ogg_stream_granule_to_time (pad,
93 gst_ogg_stream_granulepos_to_granule (pad,
94 packet->granulepos) - duration);
98 gst_ogg_stream_get_start_time_for_granulepos (GstOggStream * pad,
101 if (pad->frame_size == 0)
102 return GST_CLOCK_TIME_NONE;
104 return gst_ogg_stream_granule_to_time (pad,
105 gst_ogg_stream_granulepos_to_granule (pad, granulepos));
109 gst_ogg_stream_get_end_time_for_granulepos (GstOggStream * pad,
112 return gst_ogg_stream_granule_to_time (pad,
113 gst_ogg_stream_granulepos_to_granule (pad, granulepos));
117 gst_ogg_stream_granule_to_time (GstOggStream * pad, gint64 granule)
119 if (granule == 0 || pad->granulerate_n == 0 || pad->granulerate_d == 0)
122 return gst_util_uint64_scale (granule, GST_SECOND * pad->granulerate_d,
127 gst_ogg_stream_granulepos_to_granule (GstOggStream * pad, gint64 granulepos)
129 if (granulepos == -1 || granulepos == 0) {
133 if (mappers[pad->map].granulepos_to_granule_func == NULL) {
134 GST_WARNING ("Failed to convert granulepos to granule");
138 return mappers[pad->map].granulepos_to_granule_func (pad, granulepos);
142 gst_ogg_stream_granulepos_to_key_granule (GstOggStream * pad, gint64 granulepos)
144 if (granulepos == -1 || granulepos == 0) {
148 return granulepos >> pad->granuleshift;
152 gst_ogg_stream_granule_to_granulepos (GstOggStream * pad, gint64 granule,
153 gint64 keyframe_granule)
155 if (granule == -1 || granule == 0) {
159 if (mappers[pad->map].granule_to_granulepos_func == NULL) {
160 GST_WARNING ("Failed to convert granule to granulepos");
164 return mappers[pad->map].granule_to_granulepos_func (pad, granule,
169 gst_ogg_stream_packet_granulepos_is_key_frame (GstOggStream * pad,
172 if (granulepos == -1) {
176 if (mappers[pad->map].is_key_frame_func == NULL) {
177 GST_WARNING ("Failed to determine key frame");
181 return mappers[pad->map].is_key_frame_func (pad, granulepos);
185 gst_ogg_stream_packet_is_header (GstOggStream * pad, ogg_packet * packet)
187 if (mappers[pad->map].is_header_func == NULL) {
188 GST_WARNING ("Failed to determine header");
192 return mappers[pad->map].is_header_func (pad, packet);
196 gst_ogg_stream_get_packet_duration (GstOggStream * pad, ogg_packet * packet)
198 if (mappers[pad->map].packet_duration_func == NULL) {
199 GST_WARNING ("Failed to determine packet duration");
203 return mappers[pad->map].packet_duration_func (pad, packet);
209 /* some generic functions */
212 is_keyframe_true (GstOggStream * pad, gint64 granulepos)
218 granulepos_to_granule_default (GstOggStream * pad, gint64 granulepos)
220 gint64 keyindex, keyoffset;
222 if (pad->granuleshift != 0) {
223 keyindex = granulepos >> pad->granuleshift;
224 keyoffset = granulepos - (keyindex << pad->granuleshift);
225 return keyindex + keyoffset;
233 granule_to_granulepos_default (GstOggStream * pad, gint64 granule,
234 gint64 keyframe_granule)
238 if (pad->granuleshift != 0) {
239 keyoffset = granule - keyframe_granule;
240 return (keyframe_granule << pad->granuleshift) | keyoffset;
248 is_header_unknown (GstOggStream * pad, ogg_packet * packet)
250 GST_WARNING ("don't know how to detect header");
256 is_header_true (GstOggStream * pad, ogg_packet * packet)
262 is_header_count (GstOggStream * pad, ogg_packet * packet)
264 if (pad->n_header_packets_seen < pad->n_header_packets) {
271 packet_duration_constant (GstOggStream * pad, ogg_packet * packet)
273 return pad->frame_size;
279 setup_theora_mapper (GstOggStream * pad, ogg_packet * packet)
281 guint8 *data = packet->packet;
282 guint w, h, par_d, par_n;
284 w = GST_READ_UINT24_BE (data + 14) & 0xFFFFF0;
285 h = GST_READ_UINT24_BE (data + 17) & 0xFFFFF0;
287 pad->granulerate_n = GST_READ_UINT32_BE (data + 22);
288 pad->granulerate_d = GST_READ_UINT32_BE (data + 26);
290 par_n = GST_READ_UINT24_BE (data + 30);
291 par_d = GST_READ_UINT24_BE (data + 33);
293 GST_LOG ("fps = %d/%d, PAR = %u/%u, width = %u, height = %u",
294 pad->granulerate_n, pad->granulerate_d, par_n, par_d, w, h);
296 /* 2 bits + 3 bits = 5 bits KFGSHIFT */
297 pad->granuleshift = ((GST_READ_UINT8 (data + 40) & 0x03) << 3) +
298 (GST_READ_UINT8 (data + 41) >> 5);
300 pad->n_header_packets = 3;
303 if (pad->granulerate_n == 0 || pad->granulerate_d == 0) {
304 GST_WARNING ("frame rate %d/%d", pad->granulerate_n, pad->granulerate_d);
308 pad->caps = gst_caps_new_simple ("video/x-theora", NULL);
310 if (w > 0 && h > 0) {
311 gst_caps_set_simple (pad->caps, "width", G_TYPE_INT, w, "height",
312 G_TYPE_INT, h, NULL);
315 /* PAR of 0:N, N:0 and 0:0 is allowed and maps to 1:1 */
316 if (par_n == 0 || par_d == 0)
319 /* only add framerate now so caps look prettier, with width/height first */
320 gst_caps_set_simple (pad->caps, "framerate", GST_TYPE_FRACTION,
321 pad->granulerate_n, pad->granulerate_d, "pixel-aspect-ratio",
322 GST_TYPE_FRACTION, par_n, par_d, NULL);
328 granulepos_to_granule_theora (GstOggStream * pad, gint64 granulepos)
330 gint64 keyindex, keyoffset;
332 if (pad->granuleshift != 0) {
333 keyindex = granulepos >> pad->granuleshift;
334 keyoffset = granulepos - (keyindex << pad->granuleshift);
335 if (keyoffset == 0) {
336 pad->theora_has_zero_keyoffset = TRUE;
338 if (pad->theora_has_zero_keyoffset) {
341 return keyindex + keyoffset;
348 is_keyframe_theora (GstOggStream * pad, gint64 granulepos)
352 if (granulepos == (gint64) - 1)
355 frame_mask = (1 << (pad->granuleshift + 1)) - 1;
357 return ((granulepos & frame_mask) == 0);
361 is_header_theora (GstOggStream * pad, ogg_packet * packet)
363 return (packet->bytes > 0 && (packet->packet[0] & 0x80) == 0x80);
369 setup_dirac_mapper (GstOggStream * pad, ogg_packet * packet)
372 DiracSequenceHeader header;
374 ret = dirac_sequence_header_parse (&header, packet->packet + 13,
377 GST_DEBUG ("Failed to parse Dirac sequence header");
381 pad->granulerate_n = header.frame_rate_numerator * 2;
382 pad->granulerate_d = header.frame_rate_denominator;
383 pad->granuleshift = 22;
384 pad->n_header_packets = 1;
387 if (header.interlaced_coding != 0) {
388 GST_DEBUG ("non-progressive Dirac coding not implemented");
392 pad->caps = gst_caps_new_simple ("video/x-dirac",
393 "width", G_TYPE_INT, header.width,
394 "height", G_TYPE_INT, header.height,
395 "interlaced", G_TYPE_BOOLEAN, header.interlaced,
396 "pixel-aspect-ratio", GST_TYPE_FRACTION,
397 header.aspect_ratio_numerator, header.aspect_ratio_denominator,
398 "framerate", GST_TYPE_FRACTION, header.frame_rate_numerator,
399 header.frame_rate_denominator, NULL);
404 #define OGG_DIRAC_GRANULE_LOW_MASK ((1<<22) - 1)
406 is_keyframe_dirac (GstOggStream * pad, gint64 granulepos)
415 if (granulepos == -1)
418 pt = ((granulepos >> 22) + (granulepos & OGG_DIRAC_GRANULE_LOW_MASK)) >> 9;
419 dist_h = (granulepos >> 22) & 0xff;
420 dist_l = granulepos & 0xff;
421 dist = (dist_h << 8) | dist_l;
422 delay = (granulepos >> 9) & 0x1fff;
429 granulepos_to_granule_dirac (GstOggStream * pad, gint64 gp)
438 pt = ((gp >> 22) + (gp & OGG_DIRAC_GRANULE_LOW_MASK)) >> 9;
439 dist_h = (gp >> 22) & 0xff;
441 dist = (dist_h << 8) | dist_l;
442 delay = (gp >> 9) & 0x1fff;
445 GST_DEBUG ("pt %" G_GINT64_FORMAT " delay %d", pt, delay);
451 granule_to_granulepos_dirac (GstOggStream * pad, gint64 granule,
452 gint64 keyframe_granule)
454 /* This conversion requires knowing more details about the Dirac
462 void parse_vorbis_header_packet (GstOggStream * pad, ogg_packet * op);
463 void parse_vorbis_setup_packet (GstOggStream * pad, ogg_packet * op);
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;
712 gst_ogg_map_add_fisbone (GstOggStream * pad,
713 const guint8 * data, guint size, GstClockTime * p_start_time,
716 GstClockTime start_time;
717 gint64 start_granule;
720 if (size < SKELETON_FISBONE_MIN_SIZE || memcmp (data, "fisbone\0", 8) != 0) {
721 GST_WARNING ("invalid fisbone packet, ignoring");
725 if (pad->have_fisbone) {
726 GST_DEBUG ("already have fisbone, ignoring second one");
730 /* skip "fisbone\0" + headers offset + serialno + num headers */
731 data += 8 + 4 + 4 + 4;
733 pad->have_fisbone = TRUE;
735 /* we just overwrite whatever was set before by the format-specific setup */
736 pad->granulerate_n = GST_READ_UINT64_LE (data);
737 pad->granulerate_d = GST_READ_UINT64_LE (data + 8);
739 start_granule = GST_READ_UINT64_LE (data + 16);
740 preroll = GST_READ_UINT32_LE (data + 24);
741 pad->granuleshift = GST_READ_UINT8 (data + 28);
743 start_time = granulepos_to_granule_default (pad, start_granule);
746 *p_start_time = start_time;
749 *p_preroll = preroll;
754 /* Do we need these for something?
755 * ogm->hdr.size = GST_READ_UINT32_LE (&data[13]);
756 * ogm->hdr.time_unit = GST_READ_UINT64_LE (&data[17]);
757 * ogm->hdr.samples_per_unit = GST_READ_UINT64_LE (&data[25]);
758 * ogm->hdr.default_len = GST_READ_UINT32_LE (&data[33]);
759 * ogm->hdr.buffersize = GST_READ_UINT32_LE (&data[37]);
760 * ogm->hdr.bits_per_sample = GST_READ_UINT32_LE (&data[41]);
764 is_header_ogm (GstOggStream * pad, ogg_packet * packet)
766 if (packet->bytes >= 1 && (packet->packet[0] & 0x01))
773 packet_duration_ogm (GstOggStream * pad, ogg_packet * packet)
780 data = packet->packet;
781 offset = 1 + (((data[0] & 0xc0) >> 6) | ((data[0] & 0x02) << 1));
783 if (offset > packet->bytes) {
784 GST_ERROR ("buffer too small");
789 for (n = offset - 1; n > 0; n--) {
790 samples = (samples << 8) | data[n];
797 setup_ogmaudio_mapper (GstOggStream * pad, ogg_packet * packet)
799 guint8 *data = packet->packet;
802 pad->granulerate_n = GST_READ_UINT64_LE (data + 25);
803 pad->granulerate_d = 1;
805 fourcc = GST_READ_UINT32_LE (data + 9);
806 GST_DEBUG ("fourcc: %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
808 pad->caps = gst_riff_create_audio_caps (fourcc, NULL, NULL, NULL, NULL, NULL);
810 GST_LOG ("sample rate: %d", pad->granulerate_n);
811 if (pad->granulerate_n == 0)
815 gst_caps_set_simple (pad->caps,
816 "rate", G_TYPE_INT, pad->granulerate_n, NULL);
818 pad->caps = gst_caps_new_simple ("audio/x-ogm-unknown",
819 "fourcc", GST_TYPE_FOURCC, fourcc,
820 "rate", G_TYPE_INT, pad->granulerate_n, NULL);
823 pad->n_header_packets = 1;
830 setup_ogmvideo_mapper (GstOggStream * pad, ogg_packet * packet)
832 guint8 *data = packet->packet;
837 GST_DEBUG ("time unit %d", GST_READ_UINT32_LE (data + 16));
838 GST_DEBUG ("samples per unit %d", GST_READ_UINT32_LE (data + 24));
840 pad->granulerate_n = 10000000;
841 time_unit = GST_READ_UINT64_LE (data + 17);
842 if (time_unit > G_MAXINT || time_unit < G_MININT) {
843 GST_WARNING ("timeunit is out of range");
845 pad->granulerate_d = (gint) CLAMP (time_unit, G_MININT, G_MAXINT);
847 GST_LOG ("fps = %d/%d = %.3f",
848 pad->granulerate_n, pad->granulerate_d,
849 (double) pad->granulerate_n / pad->granulerate_d);
851 fourcc = GST_READ_UINT32_LE (data + 9);
852 width = GST_READ_UINT32_LE (data + 45);
853 height = GST_READ_UINT32_LE (data + 49);
854 GST_DEBUG ("fourcc: %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
856 pad->caps = gst_riff_create_video_caps (fourcc, NULL, NULL, NULL, NULL, NULL);
858 if (pad->caps == NULL) {
859 pad->caps = gst_caps_new_simple ("video/x-ogm-unknown",
860 "fourcc", GST_TYPE_FOURCC, fourcc,
861 "framerate", GST_TYPE_FRACTION, pad->granulerate_n,
862 pad->granulerate_d, NULL);
864 gst_caps_set_simple (pad->caps,
865 "framerate", GST_TYPE_FRACTION, pad->granulerate_n,
867 "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
869 GST_DEBUG ("caps: %" GST_PTR_FORMAT, pad->caps);
871 pad->n_header_packets = 1;
879 setup_ogmtext_mapper (GstOggStream * pad, ogg_packet * packet)
881 guint8 *data = packet->packet;
884 pad->granulerate_n = 10000000;
885 time_unit = GST_READ_UINT64_LE (data + 17);
886 if (time_unit > G_MAXINT || time_unit < G_MININT) {
887 GST_WARNING ("timeunit is out of range");
889 pad->granulerate_d = (gint) CLAMP (time_unit, G_MININT, G_MAXINT);
891 GST_LOG ("fps = %d/%d = %.3f",
892 pad->granulerate_n, pad->granulerate_d,
893 (double) pad->granulerate_n / pad->granulerate_d);
895 if (pad->granulerate_d <= 0)
898 pad->caps = gst_caps_new_simple ("text/plain", NULL);
900 pad->n_header_packets = 1;
902 pad->is_ogm_text = TRUE;
909 #define OGGPCM_FMT_S8 0x00000000 /* Signed integer 8 bit */
910 #define OGGPCM_FMT_U8 0x00000001 /* Unsigned integer 8 bit */
911 #define OGGPCM_FMT_S16_LE 0x00000002 /* Signed integer 16 bit little endian */
912 #define OGGPCM_FMT_S16_BE 0x00000003 /* Signed integer 16 bit big endian */
913 #define OGGPCM_FMT_S24_LE 0x00000004 /* Signed integer 24 bit little endian */
914 #define OGGPCM_FMT_S24_BE 0x00000005 /* Signed integer 24 bit big endian */
915 #define OGGPCM_FMT_S32_LE 0x00000006 /* Signed integer 32 bit little endian */
916 #define OGGPCM_FMT_S32_BE 0x00000007 /* Signed integer 32 bit big endian */
918 #define OGGPCM_FMT_ULAW 0x00000010 /* G.711 u-law encoding (8 bit) */
919 #define OGGPCM_FMT_ALAW 0x00000011 /* G.711 A-law encoding (8 bit) */
921 #define OGGPCM_FMT_FLT32_LE 0x00000020 /* IEEE Float [-1,1] 32 bit little endian */
922 #define OGGPCM_FMT_FLT32_BE 0x00000021 /* IEEE Float [-1,1] 32 bit big endian */
923 #define OGGPCM_FMT_FLT64_LE 0x00000022 /* IEEE Float [-1,1] 64 bit little endian */
924 #define OGGPCM_FMT_FLT64_BE 0x00000023 /* IEEE Float [-1,1] 64 bit big endian */
928 setup_pcm_mapper (GstOggStream * pad, ogg_packet * packet)
930 guint8 *data = packet->packet;
935 pad->granulerate_n = GST_READ_UINT32_LE (data + 16);
936 pad->granulerate_d = 1;
937 GST_LOG ("sample rate: %d", pad->granulerate_n);
939 format = GST_READ_UINT32_LE (data + 12);
940 channels = GST_READ_UINT8 (data + 21);
942 pad->n_header_packets = 2 + GST_READ_UINT32_LE (data + 24);
944 if (pad->granulerate_n == 0)
949 caps = gst_caps_new_simple ("audio/x-raw-int",
950 "depth", G_TYPE_INT, 8,
951 "width", G_TYPE_INT, 8, "signed", G_TYPE_BOOLEAN, TRUE, NULL);
954 caps = gst_caps_new_simple ("audio/x-raw-int",
955 "depth", G_TYPE_INT, 8,
956 "width", G_TYPE_INT, 8, "signed", G_TYPE_BOOLEAN, FALSE, NULL);
958 case OGGPCM_FMT_S16_LE:
959 caps = gst_caps_new_simple ("audio/x-raw-int",
960 "depth", G_TYPE_INT, 16,
961 "width", G_TYPE_INT, 16,
962 "endianness", G_TYPE_INT, G_LITTLE_ENDIAN,
963 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
965 case OGGPCM_FMT_S16_BE:
966 caps = gst_caps_new_simple ("audio/x-raw-int",
967 "depth", G_TYPE_INT, 16,
968 "width", G_TYPE_INT, 16,
969 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
970 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
972 case OGGPCM_FMT_S24_LE:
973 caps = gst_caps_new_simple ("audio/x-raw-int",
974 "depth", G_TYPE_INT, 24,
975 "width", G_TYPE_INT, 24,
976 "endianness", G_TYPE_INT, G_LITTLE_ENDIAN,
977 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
979 case OGGPCM_FMT_S24_BE:
980 caps = gst_caps_new_simple ("audio/x-raw-int",
981 "depth", G_TYPE_INT, 24,
982 "width", G_TYPE_INT, 24,
983 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
984 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
986 case OGGPCM_FMT_S32_LE:
987 caps = gst_caps_new_simple ("audio/x-raw-int",
988 "depth", G_TYPE_INT, 32,
989 "width", G_TYPE_INT, 32,
990 "endianness", G_TYPE_INT, G_LITTLE_ENDIAN,
991 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
993 case OGGPCM_FMT_S32_BE:
994 caps = gst_caps_new_simple ("audio/x-raw-int",
995 "depth", G_TYPE_INT, 32,
996 "width", G_TYPE_INT, 32,
997 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
998 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
1000 case OGGPCM_FMT_ULAW:
1001 caps = gst_caps_new_simple ("audio/x-mulaw", NULL);
1003 case OGGPCM_FMT_ALAW:
1004 caps = gst_caps_new_simple ("audio/x-alaw", NULL);
1006 case OGGPCM_FMT_FLT32_LE:
1007 caps = gst_caps_new_simple ("audio/x-raw-float",
1008 "width", G_TYPE_INT, 32,
1009 "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, NULL);
1011 case OGGPCM_FMT_FLT32_BE:
1012 caps = gst_caps_new_simple ("audio/x-raw-float",
1013 "width", G_TYPE_INT, 32,
1014 "endianness", G_TYPE_INT, G_BIG_ENDIAN, NULL);
1016 case OGGPCM_FMT_FLT64_LE:
1017 caps = gst_caps_new_simple ("audio/x-raw-float",
1018 "width", G_TYPE_INT, 64,
1019 "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, NULL);
1021 case OGGPCM_FMT_FLT64_BE:
1022 caps = gst_caps_new_simple ("audio/x-raw-float",
1023 "width", G_TYPE_INT, 64,
1024 "endianness", G_TYPE_INT, G_BIG_ENDIAN, NULL);
1030 gst_caps_set_simple (caps, "audio/x-raw-int",
1031 "rate", G_TYPE_INT, pad->granulerate_n,
1032 "channels", G_TYPE_INT, channels, NULL);
1041 setup_cmml_mapper (GstOggStream * pad, ogg_packet * packet)
1043 guint8 *data = packet->packet;
1045 pad->granulerate_n = GST_READ_UINT64_LE (data + 12);
1046 pad->granulerate_d = GST_READ_UINT64_LE (data + 20);
1047 pad->granuleshift = data[28];
1048 GST_LOG ("sample rate: %d", pad->granulerate_n);
1050 pad->n_header_packets = 3;
1052 if (pad->granulerate_n == 0)
1055 data += 4 + (4 + 4 + 4);
1056 GST_DEBUG ("blocksize0: %u", 1 << (data[0] >> 4));
1057 GST_DEBUG ("blocksize1: %u", 1 << (data[0] & 0x0F));
1059 pad->caps = gst_caps_new_simple ("text/x-cmml", NULL);
1067 setup_celt_mapper (GstOggStream * pad, ogg_packet * packet)
1069 guint8 *data = packet->packet;
1071 pad->granulerate_n = GST_READ_UINT32_LE (data + 36);
1072 pad->granulerate_d = 1;
1073 pad->granuleshift = 0;
1074 GST_LOG ("sample rate: %d", pad->granulerate_n);
1076 pad->frame_size = GST_READ_UINT32_LE (packet->packet + 44);
1077 pad->n_header_packets = GST_READ_UINT32_LE (packet->packet + 56) + 2;
1079 if (pad->granulerate_n == 0)
1082 pad->caps = gst_caps_new_simple ("audio/x-celt",
1083 "rate", G_TYPE_INT, pad->granulerate_n, NULL);
1091 setup_kate_mapper (GstOggStream * pad, ogg_packet * packet)
1093 guint8 *data = packet->packet;
1094 const char *category;
1096 if (packet->bytes < 64)
1099 pad->granulerate_n = GST_READ_UINT32_LE (data + 24);
1100 pad->granulerate_d = GST_READ_UINT32_LE (data + 28);
1101 pad->granuleshift = GST_READ_UINT8 (data + 15);
1102 GST_LOG ("sample rate: %d", pad->granulerate_n);
1104 pad->n_header_packets = GST_READ_UINT8 (data + 11);
1106 if (pad->granulerate_n == 0)
1109 category = (const char *) data + 48;
1110 if (strcmp (category, "subtitles") == 0 || strcmp (category, "SUB") == 0 ||
1111 strcmp (category, "spu-subtitles") == 0 ||
1112 strcmp (category, "K-SPU") == 0) {
1113 pad->caps = gst_caps_new_simple ("subtitle/x-kate", NULL);
1115 pad->caps = gst_caps_new_simple ("application/x-kate", NULL);
1123 /* indent hates our freedoms */
1124 static const GstOggMap mappers[] = {
1126 "\200theora", 7, 42,
1128 setup_theora_mapper,
1129 granulepos_to_granule_theora,
1130 granule_to_granulepos_default,
1133 packet_duration_constant
1136 "\001vorbis", 7, 22,
1138 setup_vorbis_mapper,
1139 granulepos_to_granule_default,
1140 granule_to_granulepos_default,
1143 packet_duration_vorbis
1149 granulepos_to_granule_default,
1150 granule_to_granulepos_default,
1153 packet_duration_constant
1166 "CMML\0\0\0\0", 8, 0,
1177 "application/x-annodex",
1178 setup_fishead_mapper,
1179 granulepos_to_granule_default,
1180 granule_to_granulepos_default,
1187 "application/octet-stream",
1188 setup_fishead_mapper,
1199 granulepos_to_granule_default,
1200 granule_to_granulepos_default,
1209 granulepos_to_granule_default,
1210 granule_to_granulepos_default,
1213 packet_duration_flac
1217 "application/octet-stream",
1228 granulepos_to_granule_default,
1229 granule_to_granulepos_default,
1232 packet_duration_constant
1235 "\200kate\0\0\0", 8, 0,
1238 granulepos_to_granule_default,
1239 granule_to_granulepos_default,
1248 granulepos_to_granule_dirac,
1249 granule_to_granulepos_dirac,
1252 packet_duration_constant
1255 "\001audio\0\0\0", 9, 53,
1256 "application/x-ogm-audio",
1257 setup_ogmaudio_mapper,
1258 granulepos_to_granule_default,
1259 granule_to_granulepos_default,
1265 "\001video\0\0\0", 9, 53,
1266 "application/x-ogm-video",
1267 setup_ogmvideo_mapper,
1268 granulepos_to_granule_default,
1269 granule_to_granulepos_default,
1272 packet_duration_constant
1275 "\001text\0\0\0", 9, 9,
1276 "application/x-ogm-text",
1277 setup_ogmtext_mapper,
1278 granulepos_to_granule_default,
1279 granule_to_granulepos_default,
1288 gst_ogg_stream_setup_map (GstOggStream * pad, ogg_packet * packet)
1293 for (i = 0; i < G_N_ELEMENTS (mappers); i++) {
1294 if (packet->bytes >= mappers[i].min_packet_size &&
1295 packet->bytes >= mappers[i].id_length &&
1296 memcmp (packet->packet, mappers[i].id, mappers[i].id_length) == 0) {
1298 GST_DEBUG ("found mapper for '%s'", mappers[i].id);
1300 if (mappers[i].setup_func)
1301 ret = mappers[i].setup_func (pad, packet);
1306 GST_DEBUG ("got stream type %" GST_PTR_FORMAT, pad->caps);
1310 GST_WARNING ("mapper '%s' did not accept setup header",
1311 mappers[i].media_type);