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,
58 typedef void (*GstOggMapExtractTagsFunc) (GstOggStream * pad,
61 typedef gint64 (*GstOggMapGranuleposToKeyGranuleFunc) (GstOggStream * pad,
64 #define SKELETON_FISBONE_MIN_SIZE 52
65 #define SKELETON_FISHEAD_3_3_MIN_SIZE 112
66 #define SKELETON_FISHEAD_4_0_MIN_SIZE 80
73 const gchar *media_type;
74 GstOggMapSetupFunc setup_func;
75 GstOggMapToGranuleFunc granulepos_to_granule_func;
76 GstOggMapToGranuleposFunc granule_to_granulepos_func;
77 GstOggMapIsKeyFrameFunc is_key_frame_func;
78 GstOggMapIsHeaderPacketFunc is_header_func;
79 GstOggMapPacketDurationFunc packet_duration_func;
80 GstOggMapGranuleposToKeyGranuleFunc granulepos_to_key_granule_func;
81 GstOggMapExtractTagsFunc extract_tags_func;
84 extern const GstOggMap mappers[];
87 gst_ogg_stream_get_packet_start_time (GstOggStream * pad, ogg_packet * packet)
91 if (packet->granulepos == -1) {
92 return GST_CLOCK_TIME_NONE;
95 duration = gst_ogg_stream_get_packet_duration (pad, packet);
97 return GST_CLOCK_TIME_NONE;
100 return gst_ogg_stream_granule_to_time (pad,
101 gst_ogg_stream_granulepos_to_granule (pad,
102 packet->granulepos) - duration);
106 gst_ogg_stream_get_start_time_for_granulepos (GstOggStream * pad,
109 if (pad->frame_size == 0)
110 return GST_CLOCK_TIME_NONE;
112 return gst_ogg_stream_granule_to_time (pad,
113 gst_ogg_stream_granulepos_to_granule (pad, granulepos));
117 gst_ogg_stream_get_end_time_for_granulepos (GstOggStream * pad,
120 return gst_ogg_stream_granule_to_time (pad,
121 gst_ogg_stream_granulepos_to_granule (pad, granulepos));
125 gst_ogg_stream_granule_to_time (GstOggStream * pad, gint64 granule)
127 if (granule == 0 || pad->granulerate_n == 0 || pad->granulerate_d == 0)
130 return gst_util_uint64_scale (granule, GST_SECOND * pad->granulerate_d,
135 gst_ogg_stream_granulepos_to_granule (GstOggStream * pad, gint64 granulepos)
137 if (granulepos == -1 || granulepos == 0) {
141 if (mappers[pad->map].granulepos_to_granule_func == NULL) {
142 GST_WARNING ("Failed to convert granulepos to granule");
146 return mappers[pad->map].granulepos_to_granule_func (pad, granulepos);
150 gst_ogg_stream_granulepos_to_key_granule (GstOggStream * pad, gint64 granulepos)
152 if (mappers[pad->map].granulepos_to_key_granule_func)
153 return mappers[pad->map].granulepos_to_key_granule_func (pad, granulepos);
155 if (granulepos == -1 || granulepos == 0) {
159 return granulepos >> pad->granuleshift;
163 gst_ogg_stream_granule_to_granulepos (GstOggStream * pad, gint64 granule,
164 gint64 keyframe_granule)
166 if (granule == -1 || granule == 0) {
170 if (mappers[pad->map].granule_to_granulepos_func == NULL) {
171 GST_WARNING ("Failed to convert granule to granulepos");
175 return mappers[pad->map].granule_to_granulepos_func (pad, granule,
180 gst_ogg_stream_granulepos_is_key_frame (GstOggStream * pad, gint64 granulepos)
182 if (granulepos == -1) {
186 if (mappers[pad->map].is_key_frame_func == NULL) {
187 GST_WARNING ("Failed to determine key frame");
191 return mappers[pad->map].is_key_frame_func (pad, granulepos);
195 gst_ogg_stream_packet_is_header (GstOggStream * pad, ogg_packet * packet)
197 if (mappers[pad->map].is_header_func == NULL) {
198 GST_WARNING ("Failed to determine header");
202 return mappers[pad->map].is_header_func (pad, packet);
206 gst_ogg_stream_get_packet_duration (GstOggStream * pad, ogg_packet * packet)
208 if (mappers[pad->map].packet_duration_func == NULL) {
209 GST_WARNING ("Failed to determine packet duration");
213 return mappers[pad->map].packet_duration_func (pad, packet);
218 gst_ogg_stream_extract_tags (GstOggStream * pad, ogg_packet * packet)
220 if (mappers[pad->map].extract_tags_func == NULL) {
221 GST_DEBUG ("No tag extraction");
225 mappers[pad->map].extract_tags_func (pad, packet);
229 gst_ogg_stream_get_media_type (GstOggStream * pad)
231 const GstCaps *caps = pad->caps;
232 const GstStructure *structure;
235 structure = gst_caps_get_structure (caps, 0);
238 return gst_structure_get_name (structure);
241 /* some generic functions */
244 is_keyframe_true (GstOggStream * pad, gint64 granulepos)
250 granulepos_to_granule_default (GstOggStream * pad, gint64 granulepos)
252 gint64 keyindex, keyoffset;
254 if (pad->granuleshift != 0) {
255 keyindex = granulepos >> pad->granuleshift;
256 keyoffset = granulepos - (keyindex << pad->granuleshift);
257 return keyindex + keyoffset;
265 granule_to_granulepos_default (GstOggStream * pad, gint64 granule,
266 gint64 keyframe_granule)
270 if (pad->granuleshift != 0) {
271 /* If we don't know where the previous keyframe is yet, assume it is
272 at 0 or 1, depending on bitstream version. If nothing else, this
273 avoids getting negative granpos back. */
274 if (keyframe_granule < 0)
275 keyframe_granule = pad->theora_has_zero_keyoffset ? 0 : 1;
276 keyoffset = granule - keyframe_granule;
277 return (keyframe_granule << pad->granuleshift) | keyoffset;
285 is_header_unknown (GstOggStream * pad, ogg_packet * packet)
287 GST_WARNING ("don't know how to detect header");
293 is_header_true (GstOggStream * pad, ogg_packet * packet)
299 is_header_count (GstOggStream * pad, ogg_packet * packet)
301 if (pad->n_header_packets_seen < pad->n_header_packets) {
308 packet_duration_constant (GstOggStream * pad, ogg_packet * packet)
310 return pad->frame_size;
313 /* helper: extracts tags from vorbis comment ogg packet.
314 * Returns result in *tags after free'ing existing *tags (if any) */
316 tag_list_from_vorbiscomment_packet (ogg_packet * packet,
317 const guint8 * id_data, const guint id_data_length, GstTagList ** tags)
319 gchar *encoder = NULL;
323 g_return_val_if_fail (tags != NULL, FALSE);
325 list = gst_tag_list_from_vorbiscomment (packet->packet, packet->bytes,
326 id_data, id_data_length, &encoder);
329 GST_WARNING ("failed to decode vorbis comments");
336 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER, encoder,
343 gst_tag_list_free (*tags);
352 setup_theora_mapper (GstOggStream * pad, ogg_packet * packet)
354 guint8 *data = packet->packet;
355 guint w, h, par_d, par_n;
356 guint8 vmaj, vmin, vrev;
362 w = GST_READ_UINT24_BE (data + 14) & 0xFFFFFF;
363 h = GST_READ_UINT24_BE (data + 17) & 0xFFFFFF;
365 pad->granulerate_n = GST_READ_UINT32_BE (data + 22);
366 pad->granulerate_d = GST_READ_UINT32_BE (data + 26);
368 par_n = GST_READ_UINT24_BE (data + 30);
369 par_d = GST_READ_UINT24_BE (data + 33);
371 GST_LOG ("fps = %d/%d, PAR = %u/%u, width = %u, height = %u",
372 pad->granulerate_n, pad->granulerate_d, par_n, par_d, w, h);
374 /* 2 bits + 3 bits = 5 bits KFGSHIFT */
375 pad->granuleshift = ((GST_READ_UINT8 (data + 40) & 0x03) << 3) +
376 (GST_READ_UINT8 (data + 41) >> 5);
378 pad->is_video = TRUE;
379 pad->n_header_packets = 3;
382 pad->bitrate = GST_READ_UINT24_BE (data + 37);
383 GST_LOG ("bit rate: %d", pad->bitrate);
385 if (pad->granulerate_n == 0 || pad->granulerate_d == 0) {
386 GST_WARNING ("frame rate %d/%d", pad->granulerate_n, pad->granulerate_d);
390 /* The interpretation of the granule position has changed with 3.2.1.
391 The granule is now made from the number of frames encoded, rather than
392 the index of the frame being encoded - so there is a difference of 1. */
393 pad->theora_has_zero_keyoffset =
394 ((vmaj << 16) | (vmin << 8) | vrev) < 0x030201;
396 pad->caps = gst_caps_new_simple ("video/x-theora", NULL);
398 if (w > 0 && h > 0) {
399 gst_caps_set_simple (pad->caps, "width", G_TYPE_INT, w, "height",
400 G_TYPE_INT, h, NULL);
403 /* PAR of 0:N, N:0 and 0:0 is allowed and maps to 1:1 */
404 if (par_n == 0 || par_d == 0)
407 /* only add framerate now so caps look prettier, with width/height first */
408 gst_caps_set_simple (pad->caps, "framerate", GST_TYPE_FRACTION,
409 pad->granulerate_n, pad->granulerate_d, "pixel-aspect-ratio",
410 GST_TYPE_FRACTION, par_n, par_d, NULL);
416 granulepos_to_granule_theora (GstOggStream * pad, gint64 granulepos)
418 gint64 keyindex, keyoffset;
420 if (pad->granuleshift != 0) {
421 keyindex = granulepos >> pad->granuleshift;
422 keyoffset = granulepos - (keyindex << pad->granuleshift);
423 if (pad->theora_has_zero_keyoffset) {
426 return keyindex + keyoffset;
433 is_keyframe_theora (GstOggStream * pad, gint64 granulepos)
437 if (granulepos == (gint64) - 1)
440 frame_mask = (1 << pad->granuleshift) - 1;
442 return ((granulepos & frame_mask) == 0);
446 is_header_theora (GstOggStream * pad, ogg_packet * packet)
448 return (packet->bytes > 0 && (packet->packet[0] & 0x80) == 0x80);
452 extract_tags_theora (GstOggStream * pad, ogg_packet * packet)
454 if (packet->bytes > 0 && packet->packet[0] == 0x81) {
455 tag_list_from_vorbiscomment_packet (packet,
456 (const guint8 *) "\201theora", 7, &pad->taglist);
459 pad->taglist = gst_tag_list_new ();
462 gst_tag_list_add (pad->taglist, GST_TAG_MERGE_REPLACE,
463 GST_TAG_BITRATE, (guint) pad->bitrate, NULL);
470 setup_dirac_mapper (GstOggStream * pad, ogg_packet * packet)
473 DiracSequenceHeader header;
475 ret = dirac_sequence_header_parse (&header, packet->packet + 13,
478 GST_DEBUG ("Failed to parse Dirac sequence header");
482 pad->is_video = TRUE;
483 pad->always_flush_page = TRUE;
484 pad->granulerate_n = header.frame_rate_numerator * 2;
485 pad->granulerate_d = header.frame_rate_denominator;
486 pad->granuleshift = 22;
487 pad->n_header_packets = 1;
490 if (header.interlaced_coding != 0) {
491 GST_DEBUG ("non-progressive Dirac coding not implemented");
495 pad->caps = gst_caps_new_simple ("video/x-dirac",
496 "width", G_TYPE_INT, header.width,
497 "height", G_TYPE_INT, header.height,
498 "interlaced", G_TYPE_BOOLEAN, header.interlaced,
499 "pixel-aspect-ratio", GST_TYPE_FRACTION,
500 header.aspect_ratio_numerator, header.aspect_ratio_denominator,
501 "framerate", GST_TYPE_FRACTION, header.frame_rate_numerator,
502 header.frame_rate_denominator, NULL);
507 #define OGG_DIRAC_GRANULE_LOW_MASK ((1<<22) - 1)
509 is_keyframe_dirac (GstOggStream * pad, gint64 granulepos)
515 if (granulepos == -1)
518 dist_h = (granulepos >> 22) & 0xff;
519 dist_l = granulepos & 0xff;
520 dist = (dist_h << 8) | dist_l;
526 granulepos_to_granule_dirac (GstOggStream * pad, gint64 gp)
532 pt = ((gp >> 22) + (gp & OGG_DIRAC_GRANULE_LOW_MASK)) >> 9;
533 delay = (gp >> 9) & 0x1fff;
536 GST_DEBUG ("pt %" G_GINT64_FORMAT " delay %d", pt, delay);
542 granule_to_granulepos_dirac (GstOggStream * pad, gint64 granule,
543 gint64 keyframe_granule)
545 /* This conversion requires knowing more details about the Dirac
551 granulepos_to_key_granule_dirac (GstOggStream * pad, gint64 gp)
560 if (gp == -1 || gp == 0)
563 pt = ((gp >> 22) + (gp & OGG_DIRAC_GRANULE_LOW_MASK)) >> 9;
564 dist_h = (gp >> 22) & 0xff;
566 dist = (dist_h << 8) | dist_l;
567 delay = (gp >> 9) & 0x1fff;
570 return dt - 2 * dist + 4;
576 setup_vp8_mapper (GstOggStream * pad, ogg_packet * packet)
578 gint width, height, par_n, par_d, fps_n, fps_d;
580 if (packet->bytes < 26) {
581 GST_DEBUG ("Failed to parse VP8 BOS page");
585 width = GST_READ_UINT16_BE (packet->packet + 8);
586 height = GST_READ_UINT16_BE (packet->packet + 10);
587 par_n = GST_READ_UINT24_BE (packet->packet + 12);
588 par_d = GST_READ_UINT24_BE (packet->packet + 15);
589 fps_n = GST_READ_UINT32_BE (packet->packet + 18);
590 fps_d = GST_READ_UINT32_BE (packet->packet + 22);
592 pad->is_video = TRUE;
594 pad->granulerate_n = fps_n;
595 pad->granulerate_d = fps_d;
596 pad->n_header_packets = 2;
599 pad->caps = gst_caps_new_simple ("video/x-vp8",
600 "width", G_TYPE_INT, width,
601 "height", G_TYPE_INT, height,
602 "pixel-aspect-ratio", GST_TYPE_FRACTION,
603 par_n, par_d, "framerate", GST_TYPE_FRACTION, fps_n, fps_d, NULL);
609 is_keyframe_vp8 (GstOggStream * pad, gint64 granulepos)
611 guint64 gpos = granulepos;
613 if (granulepos == -1)
616 /* Get rid of flags */
619 return ((gpos & 0x07ffffff) == 0);
623 granulepos_to_granule_vp8 (GstOggStream * pad, gint64 gpos)
625 guint64 gp = (guint64) gpos;
630 dist = (gp >> 3) & 0x07ffffff;
632 GST_DEBUG ("pt %u, dist %u", pt, dist);
638 granule_to_granulepos_vp8 (GstOggStream * pad, gint64 granule,
639 gint64 keyframe_granule)
641 /* FIXME: This requires to look into the content of the packets
642 * because the simple granule counter doesn't know about invisible
648 /* Check if this packet contains an invisible frame or not */
650 packet_duration_vp8 (GstOggStream * pad, ogg_packet * packet)
654 if (packet->bytes < 3)
657 hdr = GST_READ_UINT24_LE (packet->packet);
659 return (((hdr >> 4) & 1) != 0) ? 1 : 0;
663 granulepos_to_key_granule_vp8 (GstOggStream * pad, gint64 granulepos)
665 guint64 gp = granulepos;
666 guint64 pts = (gp >> 32);
667 guint32 dist = (gp >> 3) & 0x07ffffff;
669 if (granulepos == -1 || granulepos == 0)
679 is_header_vp8 (GstOggStream * pad, ogg_packet * packet)
681 if (packet->bytes >= 5 && packet->packet[0] == 0x4F &&
682 packet->packet[1] == 0x56 && packet->packet[2] == 0x50 &&
683 packet->packet[3] == 0x38 && packet->packet[4] == 0x30)
689 extract_tags_vp8 (GstOggStream * pad, ogg_packet * packet)
691 if (packet->bytes >= 7 && memcmp (packet->packet, "OVP80\2 ", 7) == 0) {
692 tag_list_from_vorbiscomment_packet (packet,
693 (const guint8 *) "OVP80\2 ", 7, &pad->taglist);
700 setup_vorbis_mapper (GstOggStream * pad, ogg_packet * packet)
702 guint8 *data = packet->packet;
706 pad->version = GST_READ_UINT32_LE (data);
708 chans = GST_READ_UINT8 (data);
710 pad->granulerate_n = GST_READ_UINT32_LE (data);
711 pad->granulerate_d = 1;
712 pad->granuleshift = 0;
715 GST_LOG ("sample rate: %d", pad->granulerate_n);
718 pad->bitrate_upper = GST_READ_UINT32_LE (data);
720 pad->bitrate_nominal = GST_READ_UINT32_LE (data);
722 pad->bitrate_lower = GST_READ_UINT32_LE (data);
724 if (pad->bitrate_nominal > 0)
725 pad->bitrate = pad->bitrate_nominal;
727 if (pad->bitrate_upper > 0 && !pad->bitrate)
728 pad->bitrate = pad->bitrate_upper;
730 if (pad->bitrate_lower > 0 && !pad->bitrate)
731 pad->bitrate = pad->bitrate_lower;
733 GST_LOG ("bit rate: %d", pad->bitrate);
735 pad->n_header_packets = 3;
737 if (pad->granulerate_n == 0)
740 parse_vorbis_header_packet (pad, packet);
742 pad->caps = gst_caps_new_simple ("audio/x-vorbis",
743 "rate", G_TYPE_INT, pad->granulerate_n, "channels", G_TYPE_INT, chans,
750 is_header_vorbis (GstOggStream * pad, ogg_packet * packet)
752 if (packet->bytes > 0 && (packet->packet[0] & 0x01) == 0)
755 if (packet->packet[0] == 5) {
756 parse_vorbis_setup_packet (pad, packet);
763 extract_tags_vorbis (GstOggStream * pad, ogg_packet * packet)
765 if (packet->bytes == 0 || (packet->packet[0] & 0x01) == 0)
768 if (((guint8 *) (packet->packet))[0] == 0x03) {
769 tag_list_from_vorbiscomment_packet (packet,
770 (const guint8 *) "\003vorbis", 7, &pad->taglist);
773 pad->taglist = gst_tag_list_new ();
775 gst_tag_list_add (pad->taglist, GST_TAG_MERGE_REPLACE,
776 GST_TAG_ENCODER_VERSION, pad->version, NULL);
778 if (pad->bitrate_nominal > 0)
779 gst_tag_list_add (pad->taglist, GST_TAG_MERGE_REPLACE,
780 GST_TAG_NOMINAL_BITRATE, (guint) pad->bitrate_nominal, NULL);
782 if (pad->bitrate_upper > 0)
783 gst_tag_list_add (pad->taglist, GST_TAG_MERGE_REPLACE,
784 GST_TAG_MAXIMUM_BITRATE, (guint) pad->bitrate_upper, NULL);
786 if (pad->bitrate_lower > 0)
787 gst_tag_list_add (pad->taglist, GST_TAG_MERGE_REPLACE,
788 GST_TAG_MINIMUM_BITRATE, (guint) pad->bitrate_lower, NULL);
791 gst_tag_list_add (pad->taglist, GST_TAG_MERGE_REPLACE,
792 GST_TAG_BITRATE, (guint) pad->bitrate, NULL);
797 packet_duration_vorbis (GstOggStream * pad, ogg_packet * packet)
803 if (packet->bytes == 0 || packet->packet[0] & 1)
806 mode = (packet->packet[0] >> 1) & ((1 << pad->vorbis_log2_num_modes) - 1);
807 size = pad->vorbis_mode_sizes[mode] ? pad->long_size : pad->short_size;
809 if (pad->last_size == 0) {
812 duration = pad->last_size / 4 + size / 4;
814 pad->last_size = size;
816 GST_DEBUG ("duration %d", (int) duration);
825 setup_speex_mapper (GstOggStream * pad, ogg_packet * packet)
827 guint8 *data = packet->packet;
830 data += 8 + 20 + 4 + 4;
831 pad->granulerate_n = GST_READ_UINT32_LE (data);
832 pad->granulerate_d = 1;
833 pad->granuleshift = 0;
836 chans = GST_READ_UINT32_LE (data);
838 pad->bitrate = GST_READ_UINT32_LE (data);
840 GST_LOG ("sample rate: %d, channels: %u", pad->granulerate_n, chans);
841 GST_LOG ("bit rate: %d", pad->bitrate);
843 pad->n_header_packets = GST_READ_UINT32_LE (packet->packet + 68) + 2;
844 pad->frame_size = GST_READ_UINT32_LE (packet->packet + 64) *
845 GST_READ_UINT32_LE (packet->packet + 56);
847 if (pad->granulerate_n == 0)
850 pad->caps = gst_caps_new_simple ("audio/x-speex", "rate", G_TYPE_INT,
851 pad->granulerate_n, "channels", G_TYPE_INT, chans, NULL);
857 extract_tags_count (GstOggStream * pad, ogg_packet * packet)
859 /* packet 2 must be comment packet */
860 if (packet->bytes > 0 && pad->n_header_packets_seen == 1) {
861 tag_list_from_vorbiscomment_packet (packet, NULL, 0, &pad->taglist);
864 pad->taglist = gst_tag_list_new ();
867 gst_tag_list_add (pad->taglist, GST_TAG_MERGE_REPLACE,
868 GST_TAG_BITRATE, (guint) pad->bitrate, NULL);
876 setup_fLaC_mapper (GstOggStream * pad, ogg_packet * packet)
878 pad->granulerate_n = 0;
879 pad->granulerate_d = 1;
880 pad->granuleshift = 0;
882 pad->n_header_packets = 3;
884 pad->caps = gst_caps_new_simple ("audio/x-flac", NULL);
890 is_header_fLaC (GstOggStream * pad, ogg_packet * packet)
892 if (pad->n_header_packets_seen == 1) {
893 pad->granulerate_n = (packet->packet[14] << 12) |
894 (packet->packet[15] << 4) | ((packet->packet[16] >> 4) & 0xf);
897 if (pad->n_header_packets_seen < pad->n_header_packets) {
905 setup_flac_mapper (GstOggStream * pad, ogg_packet * packet)
907 guint8 *data = packet->packet;
910 /* see http://flac.sourceforge.net/ogg_mapping.html */
912 pad->granulerate_n = (GST_READ_UINT32_BE (data + 27) & 0xFFFFF000) >> 12;
913 pad->granulerate_d = 1;
914 pad->granuleshift = 0;
915 chans = ((GST_READ_UINT32_BE (data + 27) & 0x00000E00) >> 9) + 1;
917 GST_DEBUG ("sample rate: %d, channels: %u", pad->granulerate_n, chans);
919 pad->n_header_packets = GST_READ_UINT16_BE (packet->packet + 7);
921 if (pad->granulerate_n == 0)
924 pad->caps = gst_caps_new_simple ("audio/x-flac", "rate", G_TYPE_INT,
925 pad->granulerate_n, "channels", G_TYPE_INT, chans, NULL);
931 is_header_flac (GstOggStream * pad, ogg_packet * packet)
933 return (packet->bytes > 0 && (packet->packet[0] != 0xff));
937 packet_duration_flac (GstOggStream * pad, ogg_packet * packet)
939 int block_size_index;
941 if (packet->bytes < 4)
944 block_size_index = packet->packet[2] >> 4;
945 if (block_size_index == 1)
947 if (block_size_index >= 2 && block_size_index <= 5) {
948 return 576 << (block_size_index - 2);
950 if (block_size_index >= 8) {
951 return 256 << (block_size_index - 8);
953 if (block_size_index == 6 || block_size_index == 7) {
954 guint len, bytes = (block_size_index - 6) + 1;
957 if (packet->bytes < 4 + 1 + bytes)
959 tmp = packet->packet[4];
970 if (packet->bytes < 4 + len + bytes)
973 return packet->packet[4 + len] + 1;
975 return GST_READ_UINT16_BE (packet->packet + 4 + len) + 1;
982 extract_tags_flac (GstOggStream * pad, ogg_packet * packet)
984 if (packet->bytes > 4 && ((packet->packet[0] & 0x7F) == 0x4)) {
985 tag_list_from_vorbiscomment_packet (packet,
986 packet->packet, 4, &pad->taglist);
993 setup_fishead_mapper (GstOggStream * pad, ogg_packet * packet)
996 gint64 prestime_n, prestime_d;
997 gint64 basetime_n, basetime_d;
999 data = packet->packet;
1001 data += 8; /* header */
1003 pad->skeleton_major = GST_READ_UINT16_LE (data);
1005 pad->skeleton_minor = GST_READ_UINT16_LE (data);
1008 prestime_n = (gint64) GST_READ_UINT64_LE (data);
1010 prestime_d = (gint64) GST_READ_UINT64_LE (data);
1012 basetime_n = (gint64) GST_READ_UINT64_LE (data);
1014 basetime_d = (gint64) GST_READ_UINT64_LE (data);
1017 /* FIXME: we don't use basetime anywhere in the demuxer! */
1018 if (basetime_d != 0)
1019 pad->basetime = gst_util_uint64_scale (GST_SECOND, basetime_n, basetime_d);
1023 if (prestime_d != 0)
1024 pad->prestime = gst_util_uint64_scale (GST_SECOND, prestime_n, prestime_d);
1028 /* Ogg Skeleton 3.3+ streams provide additional information in the header */
1029 if (packet->bytes >= SKELETON_FISHEAD_3_3_MIN_SIZE && pad->skeleton_major == 3
1030 && pad->skeleton_minor > 0) {
1031 gint64 firstsampletime_n, firstsampletime_d;
1032 gint64 lastsampletime_n, lastsampletime_d;
1033 gint64 firstsampletime, lastsampletime;
1034 guint64 segment_length, content_offset;
1036 firstsampletime_n = GST_READ_UINT64_LE (data + 64);
1037 firstsampletime_d = GST_READ_UINT64_LE (data + 72);
1038 lastsampletime_n = GST_READ_UINT64_LE (data + 80);
1039 lastsampletime_d = GST_READ_UINT64_LE (data + 88);
1040 segment_length = GST_READ_UINT64_LE (data + 96);
1041 content_offset = GST_READ_UINT64_LE (data + 104);
1043 GST_INFO ("firstsampletime %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT,
1044 firstsampletime_n, firstsampletime_d);
1045 GST_INFO ("lastsampletime %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT,
1046 lastsampletime_n, lastsampletime_d);
1047 GST_INFO ("segment length %" G_GUINT64_FORMAT, segment_length);
1048 GST_INFO ("content offset %" G_GUINT64_FORMAT, content_offset);
1050 if (firstsampletime_d > 0)
1051 firstsampletime = gst_util_uint64_scale (GST_SECOND,
1052 firstsampletime_n, firstsampletime_d);
1054 firstsampletime = 0;
1056 if (lastsampletime_d > 0)
1057 lastsampletime = gst_util_uint64_scale (GST_SECOND,
1058 lastsampletime_n, lastsampletime_d);
1062 if (lastsampletime > firstsampletime)
1063 pad->total_time = lastsampletime - firstsampletime;
1065 pad->total_time = -1;
1067 GST_INFO ("skeleton fishead parsed total: %" GST_TIME_FORMAT,
1068 GST_TIME_ARGS (pad->total_time));
1069 } else if (packet->bytes >= SKELETON_FISHEAD_4_0_MIN_SIZE
1070 && pad->skeleton_major == 4) {
1071 guint64 segment_length, content_offset;
1073 segment_length = GST_READ_UINT64_LE (data + 64);
1074 content_offset = GST_READ_UINT64_LE (data + 72);
1076 GST_INFO ("segment length %" G_GUINT64_FORMAT, segment_length);
1077 GST_INFO ("content offset %" G_GUINT64_FORMAT, content_offset);
1079 pad->total_time = -1;
1082 GST_INFO ("skeleton fishead %u.%u parsed (basetime: %" GST_TIME_FORMAT
1083 ", prestime: %" GST_TIME_FORMAT ")", pad->skeleton_major,
1084 pad->skeleton_minor, GST_TIME_ARGS (pad->basetime),
1085 GST_TIME_ARGS (pad->prestime));
1087 pad->is_skeleton = TRUE;
1088 pad->is_sparse = TRUE;
1090 pad->caps = gst_caps_new_simple ("none/none", NULL);
1096 gst_ogg_map_parse_fisbone (GstOggStream * pad, const guint8 * data, guint size,
1097 guint32 * serialno, GstOggSkeleton * type)
1099 GstOggSkeleton stype;
1100 guint serial_offset;
1102 if (size < SKELETON_FISBONE_MIN_SIZE) {
1103 GST_WARNING ("small fisbone packet of size %d, ignoring", size);
1107 if (memcmp (data, "fisbone\0", 8) == 0) {
1108 GST_INFO ("got fisbone packet");
1109 stype = GST_OGG_SKELETON_FISBONE;
1111 } else if (memcmp (data, "index\0", 6) == 0) {
1112 GST_INFO ("got index packet");
1113 stype = GST_OGG_SKELETON_INDEX;
1115 } else if (memcmp (data, "fishead\0", 8) == 0) {
1118 GST_WARNING ("unknown skeleton packet \"%10.10s\"", data);
1123 *serialno = GST_READ_UINT32_LE (data + serial_offset);
1132 gst_ogg_map_add_fisbone (GstOggStream * pad, GstOggStream * skel_pad,
1133 const guint8 * data, guint size, GstClockTime * p_start_time)
1135 GstClockTime start_time;
1136 gint64 start_granule;
1138 if (pad->have_fisbone) {
1139 GST_DEBUG ("already have fisbone, ignoring second one");
1143 /* skip "fisbone\0" + headers offset + serialno + num headers */
1144 data += 8 + 4 + 4 + 4;
1146 pad->have_fisbone = TRUE;
1148 /* we just overwrite whatever was set before by the format-specific setup */
1149 pad->granulerate_n = GST_READ_UINT64_LE (data);
1150 pad->granulerate_d = GST_READ_UINT64_LE (data + 8);
1152 start_granule = GST_READ_UINT64_LE (data + 16);
1153 pad->preroll = GST_READ_UINT32_LE (data + 24);
1154 pad->granuleshift = GST_READ_UINT8 (data + 28);
1156 start_time = granulepos_to_granule_default (pad, start_granule);
1158 GST_INFO ("skeleton fisbone parsed "
1159 "(start time: %" GST_TIME_FORMAT
1160 " granulerate_n: %d granulerate_d: %d "
1161 " preroll: %" G_GUINT32_FORMAT " granuleshift: %d)",
1162 GST_TIME_ARGS (start_time),
1163 pad->granulerate_n, pad->granulerate_d, pad->preroll, pad->granuleshift);
1166 *p_start_time = start_time;
1172 read_vlc (const guint8 ** data, guint * size, guint64 * result)
1180 if (G_UNLIKELY (*size < 1))
1184 *result |= ((byte & 0x7f) << shift);
1189 } while ((byte & 0x80) != 0x80);
1195 gst_ogg_map_add_index (GstOggStream * pad, GstOggStream * skel_pad,
1196 const guint8 * data, guint size)
1198 guint64 i, n_keypoints, isize;
1199 guint64 offset, timestamp;
1200 guint64 offset_d, timestamp_d;
1203 GST_DEBUG ("already have index, ignoring second one");
1207 if ((skel_pad->skeleton_major == 3 && size < 26) ||
1208 (skel_pad->skeleton_major == 4 && size < 62)) {
1209 GST_WARNING ("small index packet of size %u, ignoring", size);
1213 /* skip "index\0" + serialno */
1217 n_keypoints = GST_READ_UINT64_LE (data);
1222 pad->kp_denom = GST_READ_UINT64_LE (data);
1223 if (pad->kp_denom == 0)
1229 if (skel_pad->skeleton_major == 4) {
1230 gint64 firstsampletime_n;
1231 gint64 lastsampletime_n;
1232 gint64 firstsampletime, lastsampletime;
1234 firstsampletime_n = GST_READ_UINT64_LE (data + 0);
1235 lastsampletime_n = GST_READ_UINT64_LE (data + 8);
1237 GST_INFO ("firstsampletime %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT,
1238 firstsampletime_n, pad->kp_denom);
1239 GST_INFO ("lastsampletime %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT,
1240 lastsampletime_n, pad->kp_denom);
1242 firstsampletime = gst_util_uint64_scale (GST_SECOND,
1243 firstsampletime_n, pad->kp_denom);
1244 lastsampletime = gst_util_uint64_scale (GST_SECOND,
1245 lastsampletime_n, pad->kp_denom);
1247 if (lastsampletime > firstsampletime)
1248 pad->total_time = lastsampletime - firstsampletime;
1250 pad->total_time = -1;
1252 GST_INFO ("skeleton index parsed total: %" GST_TIME_FORMAT,
1253 GST_TIME_ARGS (pad->total_time));
1259 GST_INFO ("skeleton index has %" G_GUINT64_FORMAT " keypoints, denom: %"
1260 G_GINT64_FORMAT, n_keypoints, pad->kp_denom);
1262 pad->index = g_try_new (GstOggIndex, n_keypoints);
1270 for (i = 0; i < n_keypoints; i++) {
1272 if (!read_vlc (&data, &size, &offset_d))
1274 if (!read_vlc (&data, &size, ×tamp_d))
1278 timestamp += timestamp_d;
1280 pad->index[i].offset = offset;
1281 pad->index[i].timestamp = timestamp;
1284 GST_INFO ("offset %" G_GUINT64_FORMAT " time %" G_GUINT64_FORMAT, offset,
1287 if (isize != n_keypoints) {
1288 GST_WARNING ("truncated index, expected %" G_GUINT64_FORMAT ", found %"
1289 G_GUINT64_FORMAT, n_keypoints, isize);
1291 pad->n_index = isize;
1292 /* try to use the index to estimate the bitrate */
1294 guint64 so, eo, st, et, b, t;
1296 /* get start and end offset and timestamps */
1297 so = pad->index[0].offset;
1298 st = pad->index[0].timestamp;
1299 eo = pad->index[isize - 1].offset;
1300 et = pad->index[isize - 1].timestamp;
1305 GST_DEBUG ("bytes/time %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT, b, t);
1307 /* this is the total stream bitrate according to this index */
1308 pad->idx_bitrate = gst_util_uint64_scale (8 * b, pad->kp_denom, t);
1310 GST_DEBUG ("bitrate %" G_GUINT64_FORMAT, pad->idx_bitrate);
1317 gst_ogg_index_compare (const GstOggIndex * index, const guint64 * ts,
1320 if (index->timestamp < *ts)
1322 else if (index->timestamp > *ts)
1329 gst_ogg_map_search_index (GstOggStream * pad, gboolean before,
1330 guint64 * timestamp, guint64 * offset)
1336 n_index = pad->n_index;
1337 if (n_index == 0 || pad->index == NULL)
1340 ts = gst_util_uint64_scale (*timestamp, pad->kp_denom, GST_SECOND);
1341 GST_INFO ("timestamp %" G_GUINT64_FORMAT, ts);
1344 gst_util_array_binary_search (pad->index, n_index, sizeof (GstOggIndex),
1345 (GCompareDataFunc) gst_ogg_index_compare, GST_SEARCH_MODE_BEFORE, &ts,
1351 GST_INFO ("found at index %u", (guint) (best - pad->index));
1354 *offset = best->offset;
1357 gst_util_uint64_scale (best->timestamp, GST_SECOND, pad->kp_denom);
1362 /* Do we need these for something?
1363 * ogm->hdr.size = GST_READ_UINT32_LE (&data[13]);
1364 * ogm->hdr.time_unit = GST_READ_UINT64_LE (&data[17]);
1365 * ogm->hdr.samples_per_unit = GST_READ_UINT64_LE (&data[25]);
1366 * ogm->hdr.default_len = GST_READ_UINT32_LE (&data[33]);
1367 * ogm->hdr.buffersize = GST_READ_UINT32_LE (&data[37]);
1368 * ogm->hdr.bits_per_sample = GST_READ_UINT32_LE (&data[41]);
1372 is_header_ogm (GstOggStream * pad, ogg_packet * packet)
1374 if (packet->bytes >= 1 && (packet->packet[0] & 0x01))
1381 extract_tags_ogm (GstOggStream * pad, ogg_packet * packet)
1383 if (!(packet->packet[0] & 1) && (packet->packet[0] & 3 && pad->is_ogm_text)) {
1384 tag_list_from_vorbiscomment_packet (packet,
1385 (const guint8 *) "\003vorbis", 7, &pad->taglist);
1390 packet_duration_ogm (GstOggStream * pad, ogg_packet * packet)
1397 data = packet->packet;
1398 offset = 1 + (((data[0] & 0xc0) >> 6) | ((data[0] & 0x02) << 1));
1400 if (offset > packet->bytes) {
1401 GST_ERROR ("buffer too small");
1406 for (n = offset - 1; n > 0; n--) {
1407 samples = (samples << 8) | data[n];
1414 setup_ogmaudio_mapper (GstOggStream * pad, ogg_packet * packet)
1416 guint8 *data = packet->packet;
1420 pad->granulerate_n = GST_READ_UINT64_LE (data + 25);
1421 pad->granulerate_d = 1;
1423 fourcc = GST_READ_UINT32_LE (data + 9);
1424 fstr = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
1425 GST_DEBUG ("fourcc: %s", fstr);
1427 pad->caps = gst_riff_create_audio_caps (fourcc, NULL, NULL, NULL, NULL, NULL);
1429 GST_LOG ("sample rate: %d", pad->granulerate_n);
1430 if (pad->granulerate_n == 0)
1434 gst_caps_set_simple (pad->caps,
1435 "rate", G_TYPE_INT, pad->granulerate_n, NULL);
1437 pad->caps = gst_caps_new_simple ("audio/x-ogm-unknown",
1438 "fourcc", G_TYPE_STRING, fstr,
1439 "rate", G_TYPE_INT, pad->granulerate_n, NULL);
1443 pad->n_header_packets = 1;
1450 setup_ogmvideo_mapper (GstOggStream * pad, ogg_packet * packet)
1452 guint8 *data = packet->packet;
1458 GST_DEBUG ("time unit %d", GST_READ_UINT32_LE (data + 16));
1459 GST_DEBUG ("samples per unit %d", GST_READ_UINT32_LE (data + 24));
1461 pad->is_video = TRUE;
1462 pad->granulerate_n = 10000000;
1463 time_unit = GST_READ_UINT64_LE (data + 17);
1464 if (time_unit > G_MAXINT || time_unit < G_MININT) {
1465 GST_WARNING ("timeunit is out of range");
1467 pad->granulerate_d = (gint) CLAMP (time_unit, G_MININT, G_MAXINT);
1469 GST_LOG ("fps = %d/%d = %.3f",
1470 pad->granulerate_n, pad->granulerate_d,
1471 (double) pad->granulerate_n / pad->granulerate_d);
1473 fourcc = GST_READ_UINT32_LE (data + 9);
1474 width = GST_READ_UINT32_LE (data + 45);
1475 height = GST_READ_UINT32_LE (data + 49);
1476 fstr = g_strdup_printf ("%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
1477 GST_DEBUG ("fourcc: %s", fstr);
1479 pad->caps = gst_riff_create_video_caps (fourcc, NULL, NULL, NULL, NULL, NULL);
1481 if (pad->caps == NULL) {
1482 pad->caps = gst_caps_new_simple ("video/x-ogm-unknown",
1483 "fourcc", G_TYPE_STRING, fstr,
1484 "framerate", GST_TYPE_FRACTION, pad->granulerate_n,
1485 pad->granulerate_d, NULL);
1487 gst_caps_set_simple (pad->caps,
1488 "framerate", GST_TYPE_FRACTION, pad->granulerate_n,
1490 "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
1492 GST_DEBUG ("caps: %" GST_PTR_FORMAT, pad->caps);
1495 pad->n_header_packets = 1;
1496 pad->frame_size = 1;
1503 setup_ogmtext_mapper (GstOggStream * pad, ogg_packet * packet)
1505 guint8 *data = packet->packet;
1508 pad->granulerate_n = 10000000;
1509 time_unit = GST_READ_UINT64_LE (data + 17);
1510 if (time_unit > G_MAXINT || time_unit < G_MININT) {
1511 GST_WARNING ("timeunit is out of range");
1513 pad->granulerate_d = (gint) CLAMP (time_unit, G_MININT, G_MAXINT);
1515 GST_LOG ("fps = %d/%d = %.3f",
1516 pad->granulerate_n, pad->granulerate_d,
1517 (double) pad->granulerate_n / pad->granulerate_d);
1519 if (pad->granulerate_d <= 0)
1522 pad->caps = gst_caps_new_simple ("text/plain", NULL);
1524 pad->n_header_packets = 1;
1526 pad->is_ogm_text = TRUE;
1527 pad->is_sparse = TRUE;
1534 #define OGGPCM_FMT_S8 0x00000000 /* Signed integer 8 bit */
1535 #define OGGPCM_FMT_U8 0x00000001 /* Unsigned integer 8 bit */
1536 #define OGGPCM_FMT_S16_LE 0x00000002 /* Signed integer 16 bit little endian */
1537 #define OGGPCM_FMT_S16_BE 0x00000003 /* Signed integer 16 bit big endian */
1538 #define OGGPCM_FMT_S24_LE 0x00000004 /* Signed integer 24 bit little endian */
1539 #define OGGPCM_FMT_S24_BE 0x00000005 /* Signed integer 24 bit big endian */
1540 #define OGGPCM_FMT_S32_LE 0x00000006 /* Signed integer 32 bit little endian */
1541 #define OGGPCM_FMT_S32_BE 0x00000007 /* Signed integer 32 bit big endian */
1543 #define OGGPCM_FMT_ULAW 0x00000010 /* G.711 u-law encoding (8 bit) */
1544 #define OGGPCM_FMT_ALAW 0x00000011 /* G.711 A-law encoding (8 bit) */
1546 #define OGGPCM_FMT_FLT32_LE 0x00000020 /* IEEE Float [-1,1] 32 bit little endian */
1547 #define OGGPCM_FMT_FLT32_BE 0x00000021 /* IEEE Float [-1,1] 32 bit big endian */
1548 #define OGGPCM_FMT_FLT64_LE 0x00000022 /* IEEE Float [-1,1] 64 bit little endian */
1549 #define OGGPCM_FMT_FLT64_BE 0x00000023 /* IEEE Float [-1,1] 64 bit big endian */
1553 setup_pcm_mapper (GstOggStream * pad, ogg_packet * packet)
1555 guint8 *data = packet->packet;
1560 pad->granulerate_n = GST_READ_UINT32_LE (data + 16);
1561 pad->granulerate_d = 1;
1562 GST_LOG ("sample rate: %d", pad->granulerate_n);
1564 format = GST_READ_UINT32_LE (data + 12);
1565 channels = GST_READ_UINT8 (data + 21);
1567 pad->n_header_packets = 2 + GST_READ_UINT32_LE (data + 24);
1569 if (pad->granulerate_n == 0)
1574 caps = gst_caps_new_simple ("audio/x-raw",
1575 "format", G_TYPE_STRING, "S8", NULL);
1578 caps = gst_caps_new_simple ("audio/x-raw",
1579 "format", G_TYPE_STRING, "U8", NULL);
1581 case OGGPCM_FMT_S16_LE:
1582 caps = gst_caps_new_simple ("audio/x-raw",
1583 "format", G_TYPE_STRING, "S16_LE", NULL);
1585 case OGGPCM_FMT_S16_BE:
1586 caps = gst_caps_new_simple ("audio/x-raw",
1587 "format", G_TYPE_STRING, "S16_BE", NULL);
1589 case OGGPCM_FMT_S24_LE:
1590 caps = gst_caps_new_simple ("audio/x-raw",
1591 "format", G_TYPE_STRING, "S24_3LE", NULL);
1593 case OGGPCM_FMT_S24_BE:
1594 caps = gst_caps_new_simple ("audio/x-raw",
1595 "format", G_TYPE_STRING, "S24_3BE", NULL);
1597 case OGGPCM_FMT_S32_LE:
1598 caps = gst_caps_new_simple ("audio/x-raw",
1599 "format", G_TYPE_STRING, "S32_LE", NULL);
1601 case OGGPCM_FMT_S32_BE:
1602 caps = gst_caps_new_simple ("audio/x-raw",
1603 "format", G_TYPE_STRING, "S32_BE", NULL);
1605 case OGGPCM_FMT_ULAW:
1606 caps = gst_caps_new_simple ("audio/x-mulaw", NULL);
1608 case OGGPCM_FMT_ALAW:
1609 caps = gst_caps_new_simple ("audio/x-alaw", NULL);
1611 case OGGPCM_FMT_FLT32_LE:
1612 caps = gst_caps_new_simple ("audio/x-raw",
1613 "format", G_TYPE_STRING, "F32_LE", NULL);
1615 case OGGPCM_FMT_FLT32_BE:
1616 caps = gst_caps_new_simple ("audio/x-raw",
1617 "format", G_TYPE_STRING, "F32_BE", NULL);
1619 case OGGPCM_FMT_FLT64_LE:
1620 caps = gst_caps_new_simple ("audio/x-raw",
1621 "format", G_TYPE_STRING, "F64_LE", NULL);
1623 case OGGPCM_FMT_FLT64_BE:
1624 caps = gst_caps_new_simple ("audio/x-raw",
1625 "format", G_TYPE_STRING, "F64_BE", NULL);
1631 gst_caps_set_simple (caps,
1632 "rate", G_TYPE_INT, pad->granulerate_n,
1633 "channels", G_TYPE_INT, channels, NULL);
1642 setup_cmml_mapper (GstOggStream * pad, ogg_packet * packet)
1644 guint8 *data = packet->packet;
1646 pad->granulerate_n = GST_READ_UINT64_LE (data + 12);
1647 pad->granulerate_d = GST_READ_UINT64_LE (data + 20);
1648 pad->granuleshift = data[28];
1649 GST_LOG ("sample rate: %d", pad->granulerate_n);
1651 pad->n_header_packets = 3;
1653 if (pad->granulerate_n == 0)
1656 data += 4 + (4 + 4 + 4);
1657 GST_DEBUG ("blocksize0: %u", 1 << (data[0] >> 4));
1658 GST_DEBUG ("blocksize1: %u", 1 << (data[0] & 0x0F));
1660 pad->caps = gst_caps_new_simple ("text/x-cmml", NULL);
1661 pad->always_flush_page = TRUE;
1662 pad->is_sparse = TRUE;
1670 setup_celt_mapper (GstOggStream * pad, ogg_packet * packet)
1672 guint8 *data = packet->packet;
1674 pad->granulerate_n = GST_READ_UINT32_LE (data + 36);
1675 pad->granulerate_d = 1;
1676 pad->granuleshift = 0;
1677 GST_LOG ("sample rate: %d", pad->granulerate_n);
1679 pad->frame_size = GST_READ_UINT32_LE (packet->packet + 44);
1680 pad->n_header_packets = GST_READ_UINT32_LE (packet->packet + 56) + 2;
1682 if (pad->granulerate_n == 0)
1685 pad->caps = gst_caps_new_simple ("audio/x-celt",
1686 "rate", G_TYPE_INT, pad->granulerate_n, NULL);
1694 setup_kate_mapper (GstOggStream * pad, ogg_packet * packet)
1696 guint8 *data = packet->packet;
1697 const char *category;
1699 if (packet->bytes < 64)
1702 pad->granulerate_n = GST_READ_UINT32_LE (data + 24);
1703 pad->granulerate_d = GST_READ_UINT32_LE (data + 28);
1704 pad->granuleshift = GST_READ_UINT8 (data + 15);
1705 GST_LOG ("sample rate: %d", pad->granulerate_n);
1707 pad->n_header_packets = GST_READ_UINT8 (data + 11);
1708 GST_LOG ("kate header packets: %d", pad->n_header_packets);
1710 if (pad->granulerate_n == 0)
1713 category = (const char *) data + 48;
1714 if (strcmp (category, "subtitles") == 0 || strcmp (category, "SUB") == 0 ||
1715 strcmp (category, "spu-subtitles") == 0 ||
1716 strcmp (category, "K-SPU") == 0) {
1717 pad->caps = gst_caps_new_simple ("subtitle/x-kate", NULL);
1719 pad->caps = gst_caps_new_simple ("application/x-kate", NULL);
1722 pad->is_sparse = TRUE;
1723 pad->always_flush_page = TRUE;
1729 packet_duration_kate (GstOggStream * pad, ogg_packet * packet)
1733 if (packet->bytes < 1)
1736 switch (packet->packet[0]) {
1737 case 0x00: /* text data */
1738 if (packet->bytes < 1 + 8 * 2) {
1741 duration = GST_READ_UINT64_LE (packet->packet + 1 + 8);
1747 duration = GST_CLOCK_TIME_NONE;
1755 extract_tags_kate (GstOggStream * pad, ogg_packet * packet)
1757 GstTagList *list = NULL;
1759 if (packet->bytes <= 0)
1762 switch (packet->packet[0]) {
1764 const gchar *canonical;
1767 if (packet->bytes < 64) {
1768 GST_WARNING ("Kate ID header packet is less than 64 bytes, ignored");
1772 /* the language tag is 16 bytes at offset 32, ensure NUL terminator */
1773 memcpy (language, packet->packet + 32, 16);
1776 /* language is an ISO 639-1 code or RFC 3066 language code, we
1777 * truncate to ISO 639-1 */
1778 g_strdelimit (language, NULL, '\0');
1779 canonical = gst_tag_get_language_code_iso_639_1 (language);
1781 list = gst_tag_list_new_full (GST_TAG_LANGUAGE_CODE, canonical, NULL);
1783 GST_WARNING ("Unknown or invalid language code %s, ignored", language);
1788 tag_list_from_vorbiscomment_packet (packet,
1789 (const guint8 *) "\201kate\0\0\0\0", 9, &list);
1797 /* ensure the comment packet cannot override the category/language
1798 from the identification header */
1799 gst_tag_list_insert (pad->taglist, list, GST_TAG_MERGE_KEEP_ALL);
1801 pad->taglist = list;
1807 /* indent hates our freedoms */
1808 const GstOggMap mappers[] = {
1810 "\200theora", 7, 42,
1812 setup_theora_mapper,
1813 granulepos_to_granule_theora,
1814 granule_to_granulepos_default,
1817 packet_duration_constant,
1822 "\001vorbis", 7, 22,
1824 setup_vorbis_mapper,
1825 granulepos_to_granule_default,
1826 granule_to_granulepos_default,
1829 packet_duration_vorbis,
1837 granulepos_to_granule_default,
1838 granule_to_granulepos_default,
1841 packet_duration_constant,
1858 "CMML\0\0\0\0", 8, 0,
1871 "application/x-annodex",
1872 setup_fishead_mapper,
1873 granulepos_to_granule_default,
1874 granule_to_granulepos_default,
1883 "application/octet-stream",
1884 setup_fishead_mapper,
1897 granulepos_to_granule_default,
1898 granule_to_granulepos_default,
1901 packet_duration_flac,
1909 granulepos_to_granule_default,
1910 granule_to_granulepos_default,
1913 packet_duration_flac,
1919 "application/octet-stream",
1932 granulepos_to_granule_default,
1933 granule_to_granulepos_default,
1936 packet_duration_constant,
1941 "\200kate\0\0\0", 8, 0,
1944 granulepos_to_granule_default,
1945 granule_to_granulepos_default,
1948 packet_duration_kate,
1956 granulepos_to_granule_dirac,
1957 granule_to_granulepos_dirac,
1960 packet_duration_constant,
1961 granulepos_to_key_granule_dirac,
1968 granulepos_to_granule_vp8,
1969 granule_to_granulepos_vp8,
1972 packet_duration_vp8,
1973 granulepos_to_key_granule_vp8,
1977 "\001audio\0\0\0", 9, 53,
1978 "application/x-ogm-audio",
1979 setup_ogmaudio_mapper,
1980 granulepos_to_granule_default,
1981 granule_to_granulepos_default,
1984 packet_duration_ogm,
1989 "\001video\0\0\0", 9, 53,
1990 "application/x-ogm-video",
1991 setup_ogmvideo_mapper,
1992 granulepos_to_granule_default,
1993 granule_to_granulepos_default,
1996 packet_duration_constant,
2001 "\001text\0\0\0", 9, 9,
2002 "application/x-ogm-text",
2003 setup_ogmtext_mapper,
2004 granulepos_to_granule_default,
2005 granule_to_granulepos_default,
2008 packet_duration_ogm,
2016 gst_ogg_stream_setup_map (GstOggStream * pad, ogg_packet * packet)
2021 for (i = 0; i < G_N_ELEMENTS (mappers); i++) {
2022 if (packet->bytes >= mappers[i].min_packet_size &&
2023 packet->bytes >= mappers[i].id_length &&
2024 memcmp (packet->packet, mappers[i].id, mappers[i].id_length) == 0) {
2026 GST_DEBUG ("found mapper for '%s'", mappers[i].id);
2028 if (mappers[i].setup_func)
2029 ret = mappers[i].setup_func (pad, packet);
2034 GST_DEBUG ("got stream type %" GST_PTR_FORMAT, pad->caps);
2038 GST_WARNING ("mapper '%s' did not accept setup header",
2039 mappers[i].media_type);
2048 gst_ogg_stream_setup_map_from_caps_headers (GstOggStream * pad,
2049 const GstCaps * caps)
2052 const GstStructure *structure;
2053 const GValue *streamheader;
2054 const GValue *first_element;
2060 GST_INFO ("Checking streamheader on caps %" GST_PTR_FORMAT, caps);
2065 structure = gst_caps_get_structure (caps, 0);
2066 streamheader = gst_structure_get_value (structure, "streamheader");
2068 if (streamheader == NULL) {
2069 GST_LOG ("no streamheader field in caps %" GST_PTR_FORMAT, caps);
2073 if (!GST_VALUE_HOLDS_ARRAY (streamheader)) {
2074 GST_ERROR ("streamheader field not an array, caps: %" GST_PTR_FORMAT, caps);
2078 if (gst_value_array_get_size (streamheader) == 0) {
2079 GST_ERROR ("empty streamheader field in caps %" GST_PTR_FORMAT, caps);
2083 first_element = gst_value_array_get_value (streamheader, 0);
2085 if (!GST_VALUE_HOLDS_BUFFER (first_element)) {
2086 GST_ERROR ("first streamheader not a buffer, caps: %" GST_PTR_FORMAT, caps);
2090 buf = gst_value_get_buffer (first_element);
2092 GST_ERROR ("no first streamheader buffer");
2096 data = gst_buffer_map (buf, &size, 0, GST_MAP_READ);
2097 if (data == NULL || size == 0) {
2098 GST_ERROR ("invalid first streamheader buffer");
2102 GST_MEMDUMP ("streamheader", data, size);
2104 packet.packet = data;
2105 packet.bytes = size;
2107 GST_INFO ("Found headers on caps, using those to determine type");
2108 ret = gst_ogg_stream_setup_map (pad, &packet);
2110 gst_buffer_unmap (buf, data, size);