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 /* only add framerate now so caps look prettier, with width/height first */
316 gst_caps_set_simple (pad->caps, "framerate", GST_TYPE_FRACTION,
317 pad->granulerate_n, pad->granulerate_d, NULL);
319 if (par_n > 0 && par_d > 0) {
320 gst_caps_set_simple (pad->caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
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 packet_duration_flac (GstOggStream * pad, ogg_packet * packet)
626 int block_size_index;
628 if (packet->bytes < 4)
631 block_size_index = packet->packet[2] >> 4;
632 if (block_size_index == 1)
634 if (block_size_index >= 2 && block_size_index <= 5) {
635 return 576 << (block_size_index - 2);
637 if (block_size_index >= 8) {
638 return 256 << (block_size_index - 8);
640 if (block_size_index == 6 || block_size_index == 7) {
641 guint len, bytes = (block_size_index - 6) + 1;
644 if (packet->bytes < 4 + 1 + bytes)
646 tmp = packet->packet[4];
657 if (packet->bytes < 4 + len + bytes)
660 return packet->packet[4 + len] + 1;
662 return GST_READ_UINT16_BE (packet->packet + 4 + len) + 1;
671 setup_fishead_mapper (GstOggStream * pad, ogg_packet * packet)
674 gint64 prestime_n, prestime_d;
675 gint64 basetime_n, basetime_d;
678 data = packet->packet;
680 data += 8 + 2 + 2; /* header + major/minor version */
682 prestime_n = (gint64) GST_READ_UINT64_LE (data);
684 prestime_d = (gint64) GST_READ_UINT64_LE (data);
686 basetime_n = (gint64) GST_READ_UINT64_LE (data);
688 basetime_d = (gint64) GST_READ_UINT64_LE (data);
691 /* FIXME: we don't use basetime anywhere in the demuxer! */
692 basetime = gst_util_uint64_scale (GST_SECOND, basetime_n, basetime_d);
693 GST_INFO ("skeleton fishead parsed (basetime: %" GST_TIME_FORMAT ")",
694 GST_TIME_ARGS (basetime));
700 gst_ogg_map_add_fisbone (GstOggStream * pad,
701 const guint8 * data, guint size, GstClockTime * p_start_time,
704 GstClockTime start_time;
705 gint64 start_granule;
708 if (size < SKELETON_FISBONE_MIN_SIZE || memcmp (data, "fisbone\0", 8) != 0) {
709 GST_WARNING ("invalid fisbone packet, ignoring");
713 if (pad->have_fisbone) {
714 GST_DEBUG ("already have fisbone, ignoring second one");
718 /* skip "fisbone\0" + headers offset + serialno + num headers */
719 data += 8 + 4 + 4 + 4;
721 pad->have_fisbone = TRUE;
723 /* we just overwrite whatever was set before by the format-specific setup */
724 pad->granulerate_n = GST_READ_UINT64_LE (data);
725 pad->granulerate_d = GST_READ_UINT64_LE (data + 8);
727 start_granule = GST_READ_UINT64_LE (data + 16);
728 preroll = GST_READ_UINT32_LE (data + 24);
729 pad->granuleshift = GST_READ_UINT8 (data + 28);
731 start_time = granulepos_to_granule_default (pad, start_granule);
734 *p_start_time = start_time;
737 *p_preroll = preroll;
742 /* Do we need these for something?
743 * ogm->hdr.size = GST_READ_UINT32_LE (&data[13]);
744 * ogm->hdr.time_unit = GST_READ_UINT64_LE (&data[17]);
745 * ogm->hdr.samples_per_unit = GST_READ_UINT64_LE (&data[25]);
746 * ogm->hdr.default_len = GST_READ_UINT32_LE (&data[33]);
747 * ogm->hdr.buffersize = GST_READ_UINT32_LE (&data[37]);
748 * ogm->hdr.bits_per_sample = GST_READ_UINT32_LE (&data[41]);
752 is_header_ogm (GstOggStream * pad, ogg_packet * packet)
754 if (packet->bytes >= 1 && (packet->packet[0] & 0x01))
761 packet_duration_ogm (GstOggStream * pad, ogg_packet * packet)
768 data = packet->packet;
769 offset = 1 + (((data[0] & 0xc0) >> 6) | ((data[0] & 0x02) << 1));
771 if (offset > packet->bytes) {
772 GST_ERROR ("buffer too small");
777 for (n = offset - 1; n > 0; n--) {
778 samples = (samples << 8) | data[n];
785 setup_ogmaudio_mapper (GstOggStream * pad, ogg_packet * packet)
787 guint8 *data = packet->packet;
790 pad->granulerate_n = GST_READ_UINT64_LE (data + 25);
791 pad->granulerate_d = 1;
793 fourcc = GST_READ_UINT32_LE (data + 9);
794 GST_DEBUG ("fourcc: %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
796 pad->caps = gst_riff_create_audio_caps (fourcc, NULL, NULL, NULL, NULL, NULL);
798 GST_LOG ("sample rate: %d", pad->granulerate_n);
799 if (pad->granulerate_n == 0)
803 gst_caps_set_simple (pad->caps,
804 "rate", G_TYPE_INT, pad->granulerate_n, NULL);
806 pad->caps = gst_caps_new_simple ("audio/x-ogm-unknown",
807 "fourcc", GST_TYPE_FOURCC, fourcc,
808 "rate", G_TYPE_INT, pad->granulerate_n, NULL);
811 pad->n_header_packets = 1;
818 setup_ogmvideo_mapper (GstOggStream * pad, ogg_packet * packet)
820 guint8 *data = packet->packet;
825 GST_DEBUG ("time unit %d", GST_READ_UINT32_LE (data + 16));
826 GST_DEBUG ("samples per unit %d", GST_READ_UINT32_LE (data + 24));
828 pad->granulerate_n = 10000000;
829 time_unit = GST_READ_UINT64_LE (data + 17);
830 if (time_unit > G_MAXINT || time_unit < G_MININT) {
831 GST_WARNING ("timeunit is out of range");
833 pad->granulerate_d = (gint) CLAMP (time_unit, G_MININT, G_MAXINT);
835 GST_LOG ("fps = %d/%d = %.3f",
836 pad->granulerate_n, pad->granulerate_d,
837 (double) pad->granulerate_n / pad->granulerate_d);
839 fourcc = GST_READ_UINT32_LE (data + 9);
840 width = GST_READ_UINT32_LE (data + 45);
841 height = GST_READ_UINT32_LE (data + 49);
842 GST_DEBUG ("fourcc: %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
844 pad->caps = gst_riff_create_video_caps (fourcc, NULL, NULL, NULL, NULL, NULL);
846 if (pad->caps == NULL) {
847 pad->caps = gst_caps_new_simple ("video/x-ogm-unknown",
848 "fourcc", GST_TYPE_FOURCC, fourcc,
849 "framerate", GST_TYPE_FRACTION, pad->granulerate_n,
850 pad->granulerate_d, NULL);
852 gst_caps_set_simple (pad->caps,
853 "framerate", GST_TYPE_FRACTION, pad->granulerate_n,
855 "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
857 GST_DEBUG ("caps: %" GST_PTR_FORMAT, pad->caps);
859 pad->n_header_packets = 1;
867 setup_ogmtext_mapper (GstOggStream * pad, ogg_packet * packet)
869 guint8 *data = packet->packet;
872 pad->granulerate_n = 10000000;
873 time_unit = GST_READ_UINT64_LE (data + 17);
874 if (time_unit > G_MAXINT || time_unit < G_MININT) {
875 GST_WARNING ("timeunit is out of range");
877 pad->granulerate_d = (gint) CLAMP (time_unit, G_MININT, G_MAXINT);
879 GST_LOG ("fps = %d/%d = %.3f",
880 pad->granulerate_n, pad->granulerate_d,
881 (double) pad->granulerate_n / pad->granulerate_d);
883 if (pad->granulerate_d <= 0)
886 pad->caps = gst_caps_new_simple ("text/plain", NULL);
888 pad->n_header_packets = 1;
890 pad->is_ogm_text = TRUE;
897 #define OGGPCM_FMT_S8 0x00000000 /* Signed integer 8 bit */
898 #define OGGPCM_FMT_U8 0x00000001 /* Unsigned integer 8 bit */
899 #define OGGPCM_FMT_S16_LE 0x00000002 /* Signed integer 16 bit little endian */
900 #define OGGPCM_FMT_S16_BE 0x00000003 /* Signed integer 16 bit big endian */
901 #define OGGPCM_FMT_S24_LE 0x00000004 /* Signed integer 24 bit little endian */
902 #define OGGPCM_FMT_S24_BE 0x00000005 /* Signed integer 24 bit big endian */
903 #define OGGPCM_FMT_S32_LE 0x00000006 /* Signed integer 32 bit little endian */
904 #define OGGPCM_FMT_S32_BE 0x00000007 /* Signed integer 32 bit big endian */
906 #define OGGPCM_FMT_ULAW 0x00000010 /* G.711 u-law encoding (8 bit) */
907 #define OGGPCM_FMT_ALAW 0x00000011 /* G.711 A-law encoding (8 bit) */
909 #define OGGPCM_FMT_FLT32_LE 0x00000020 /* IEEE Float [-1,1] 32 bit little endian */
910 #define OGGPCM_FMT_FLT32_BE 0x00000021 /* IEEE Float [-1,1] 32 bit big endian */
911 #define OGGPCM_FMT_FLT64_LE 0x00000022 /* IEEE Float [-1,1] 64 bit little endian */
912 #define OGGPCM_FMT_FLT64_BE 0x00000023 /* IEEE Float [-1,1] 64 bit big endian */
916 setup_pcm_mapper (GstOggStream * pad, ogg_packet * packet)
918 guint8 *data = packet->packet;
923 pad->granulerate_n = GST_READ_UINT32_LE (data + 16);
924 pad->granulerate_d = 1;
925 GST_LOG ("sample rate: %d", pad->granulerate_n);
927 format = GST_READ_UINT32_LE (data + 12);
928 channels = GST_READ_UINT8 (data + 21);
930 pad->n_header_packets = 2 + GST_READ_UINT32_LE (data + 24);
932 if (pad->granulerate_n == 0)
937 caps = gst_caps_new_simple ("audio/x-raw-int",
938 "depth", G_TYPE_INT, 8,
939 "width", G_TYPE_INT, 8, "signed", G_TYPE_BOOLEAN, TRUE, NULL);
942 caps = gst_caps_new_simple ("audio/x-raw-int",
943 "depth", G_TYPE_INT, 8,
944 "width", G_TYPE_INT, 8, "signed", G_TYPE_BOOLEAN, FALSE, NULL);
946 case OGGPCM_FMT_S16_LE:
947 caps = gst_caps_new_simple ("audio/x-raw-int",
948 "depth", G_TYPE_INT, 16,
949 "width", G_TYPE_INT, 16,
950 "endianness", G_TYPE_INT, G_LITTLE_ENDIAN,
951 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
953 case OGGPCM_FMT_S16_BE:
954 caps = gst_caps_new_simple ("audio/x-raw-int",
955 "depth", G_TYPE_INT, 16,
956 "width", G_TYPE_INT, 16,
957 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
958 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
960 case OGGPCM_FMT_S24_LE:
961 caps = gst_caps_new_simple ("audio/x-raw-int",
962 "depth", G_TYPE_INT, 24,
963 "width", G_TYPE_INT, 24,
964 "endianness", G_TYPE_INT, G_LITTLE_ENDIAN,
965 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
967 case OGGPCM_FMT_S24_BE:
968 caps = gst_caps_new_simple ("audio/x-raw-int",
969 "depth", G_TYPE_INT, 24,
970 "width", G_TYPE_INT, 24,
971 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
972 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
974 case OGGPCM_FMT_S32_LE:
975 caps = gst_caps_new_simple ("audio/x-raw-int",
976 "depth", G_TYPE_INT, 32,
977 "width", G_TYPE_INT, 32,
978 "endianness", G_TYPE_INT, G_LITTLE_ENDIAN,
979 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
981 case OGGPCM_FMT_S32_BE:
982 caps = gst_caps_new_simple ("audio/x-raw-int",
983 "depth", G_TYPE_INT, 32,
984 "width", G_TYPE_INT, 32,
985 "endianness", G_TYPE_INT, G_BIG_ENDIAN,
986 "signed", G_TYPE_BOOLEAN, TRUE, NULL);
988 case OGGPCM_FMT_ULAW:
989 caps = gst_caps_new_simple ("audio/x-mulaw", NULL);
991 case OGGPCM_FMT_ALAW:
992 caps = gst_caps_new_simple ("audio/x-alaw", NULL);
994 case OGGPCM_FMT_FLT32_LE:
995 caps = gst_caps_new_simple ("audio/x-raw-float",
996 "width", G_TYPE_INT, 32,
997 "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, NULL);
999 case OGGPCM_FMT_FLT32_BE:
1000 caps = gst_caps_new_simple ("audio/x-raw-float",
1001 "width", G_TYPE_INT, 32,
1002 "endianness", G_TYPE_INT, G_BIG_ENDIAN, NULL);
1004 case OGGPCM_FMT_FLT64_LE:
1005 caps = gst_caps_new_simple ("audio/x-raw-float",
1006 "width", G_TYPE_INT, 64,
1007 "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, NULL);
1009 case OGGPCM_FMT_FLT64_BE:
1010 caps = gst_caps_new_simple ("audio/x-raw-float",
1011 "width", G_TYPE_INT, 64,
1012 "endianness", G_TYPE_INT, G_BIG_ENDIAN, NULL);
1018 gst_caps_set_simple (caps, "audio/x-raw-int",
1019 "rate", G_TYPE_INT, pad->granulerate_n,
1020 "channels", G_TYPE_INT, channels, NULL);
1029 setup_cmml_mapper (GstOggStream * pad, ogg_packet * packet)
1031 guint8 *data = packet->packet;
1033 pad->granulerate_n = GST_READ_UINT64_LE (data + 12);
1034 pad->granulerate_d = GST_READ_UINT64_LE (data + 20);
1035 pad->granuleshift = data[28];
1036 GST_LOG ("sample rate: %d", pad->granulerate_n);
1038 pad->n_header_packets = 3;
1040 if (pad->granulerate_n == 0)
1043 data += 4 + (4 + 4 + 4);
1044 GST_DEBUG ("blocksize0: %u", 1 << (data[0] >> 4));
1045 GST_DEBUG ("blocksize1: %u", 1 << (data[0] & 0x0F));
1047 pad->caps = gst_caps_new_simple ("text/x-cmml", NULL);
1055 setup_celt_mapper (GstOggStream * pad, ogg_packet * packet)
1057 guint8 *data = packet->packet;
1059 pad->granulerate_n = GST_READ_UINT32_LE (data + 36);
1060 pad->granulerate_d = 1;
1061 pad->granuleshift = 0;
1062 GST_LOG ("sample rate: %d", pad->granulerate_n);
1064 pad->frame_size = GST_READ_UINT32_LE (packet->packet + 44);
1065 pad->n_header_packets = GST_READ_UINT32_LE (packet->packet + 56) + 2;
1067 if (pad->granulerate_n == 0)
1070 pad->caps = gst_caps_new_simple ("audio/x-celt",
1071 "rate", G_TYPE_INT, pad->granulerate_n, NULL);
1079 setup_kate_mapper (GstOggStream * pad, ogg_packet * packet)
1081 guint8 *data = packet->packet;
1083 pad->granulerate_n = GST_READ_UINT32_LE (data + 24);
1084 pad->granulerate_d = GST_READ_UINT32_LE (data + 28);
1085 pad->granuleshift = GST_READ_UINT8 (data + 15);
1086 GST_LOG ("sample rate: %d", pad->granulerate_n);
1088 pad->n_header_packets = GST_READ_UINT8 (data + 11);
1090 if (pad->granulerate_n == 0)
1093 pad->caps = gst_caps_new_simple ("audio/x-kate",
1094 "rate", G_TYPE_INT, pad->granulerate_n, NULL);
1101 /* indent hates our freedoms */
1102 static const GstOggMap mappers[] = {
1104 "\200theora", 7, 42,
1106 setup_theora_mapper,
1107 granulepos_to_granule_theora,
1108 granule_to_granulepos_default,
1111 packet_duration_constant
1114 "\001vorbis", 7, 22,
1116 setup_vorbis_mapper,
1117 granulepos_to_granule_default,
1118 granule_to_granulepos_default,
1121 packet_duration_vorbis
1127 granulepos_to_granule_default,
1128 granule_to_granulepos_default,
1131 packet_duration_constant
1144 "CMML\0\0\0\0", 8, 0,
1155 "application/x-annodex",
1156 setup_fishead_mapper,
1157 granulepos_to_granule_default,
1158 granule_to_granulepos_default,
1165 "application/octet-stream",
1166 setup_fishead_mapper,
1177 granulepos_to_granule_default,
1178 granule_to_granulepos_default,
1187 granulepos_to_granule_default,
1188 granule_to_granulepos_default,
1191 packet_duration_flac
1195 "application/octet-stream",
1206 granulepos_to_granule_default,
1207 granule_to_granulepos_default,
1210 packet_duration_constant
1213 "\200kate\0\0\0", 8, 0,
1226 granulepos_to_granule_dirac,
1227 granule_to_granulepos_dirac,
1230 packet_duration_constant
1233 "\001audio\0\0\0", 9, 53,
1234 "application/x-ogm-audio",
1235 setup_ogmaudio_mapper,
1236 granulepos_to_granule_default,
1237 granule_to_granulepos_default,
1243 "\001video\0\0\0", 9, 53,
1244 "application/x-ogm-video",
1245 setup_ogmvideo_mapper,
1246 granulepos_to_granule_default,
1247 granule_to_granulepos_default,
1250 packet_duration_constant
1253 "\001text\0\0\0", 9, 9,
1254 "application/x-ogm-text",
1255 setup_ogmtext_mapper,
1256 granulepos_to_granule_default,
1257 granule_to_granulepos_default,
1266 gst_ogg_stream_setup_map (GstOggStream * pad, ogg_packet * packet)
1271 for (i = 0; i < G_N_ELEMENTS (mappers); i++) {
1272 if (packet->bytes >= mappers[i].min_packet_size &&
1273 packet->bytes >= mappers[i].id_length &&
1274 memcmp (packet->packet, mappers[i].id, mappers[i].id_length) == 0) {
1275 ret = mappers[i].setup_func (pad, packet);
1277 GST_DEBUG ("got stream type %" GST_PTR_FORMAT, pad->caps);
1281 GST_WARNING ("mapper '%s' did not accept setup header",
1282 mappers[i].media_type);