1 /* GStreamer
2  * Copyright (C) 2008 Vincent Penquerc'h <ogg.k.ogg.k@googlemail.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 /* FIXME: shouldn't all this GstKateDecoderBase stuff really be a base class? */
21 
22 #ifdef HAVE_CONFIG_H
23 #  include "config.h"
24 #endif
25 
26 #include <string.h>
27 #ifdef HAVE_TIGER
28 #include <tiger/tiger.h>
29 #endif
30 #include <gst/tag/tag.h>
31 #include "gstkate.h"
32 #include "gstkateutil.h"
33 
34 GST_DEBUG_CATEGORY_EXTERN (gst_kateutil_debug);
35 #define GST_CAT_DEFAULT gst_kateutil_debug
36 
37 static void gst_kate_util_decoder_base_free_event_queue (GstKateDecoderBase *
38     decoder);
39 
40 GstCaps *
gst_kate_util_set_header_on_caps(GstElement * element,GstCaps * caps,GList * headers)41 gst_kate_util_set_header_on_caps (GstElement * element, GstCaps * caps,
42     GList * headers)
43 {
44   GstStructure *structure;
45   GValue array = { 0 };
46 
47   GST_LOG_OBJECT (element, "caps: %" GST_PTR_FORMAT, caps);
48 
49   if (G_UNLIKELY (!caps))
50     return NULL;
51   if (G_UNLIKELY (!headers))
52     return NULL;
53 
54   caps = gst_caps_make_writable (caps);
55   structure = gst_caps_get_structure (caps, 0);
56 
57   g_value_init (&array, GST_TYPE_ARRAY);
58 
59   while (headers) {
60     GValue value = { 0 };
61     GstBuffer *buffer = headers->data;
62     g_assert (buffer);
63     g_value_init (&value, GST_TYPE_BUFFER);
64     buffer = gst_buffer_copy (buffer);
65     GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_HEADER);
66     gst_value_take_buffer (&value, buffer);
67     gst_value_array_append_value (&array, &value);
68     g_value_unset (&value);
69     headers = headers->next;
70   }
71 
72   gst_structure_take_value (structure, "streamheader", &array);
73 
74   GST_LOG_OBJECT (element, "here are the newly set caps: %" GST_PTR_FORMAT,
75       caps);
76 
77   return caps;
78 }
79 
80 void
gst_kate_util_install_decoder_base_properties(GObjectClass * gobject_class)81 gst_kate_util_install_decoder_base_properties (GObjectClass * gobject_class)
82 {
83   g_object_class_install_property (gobject_class, ARG_DEC_BASE_LANGUAGE,
84       g_param_spec_string ("language", "Language", "The language of the stream",
85           "", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
86 
87   g_object_class_install_property (gobject_class, ARG_DEC_BASE_CATEGORY,
88       g_param_spec_string ("category", "Category", "The category of the stream",
89           "", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
90 
91   g_object_class_install_property (gobject_class,
92       ARG_DEC_BASE_ORIGINAL_CANVAS_WIDTH,
93       g_param_spec_int ("original-canvas-width",
94           "Original canvas width (0 is unspecified)",
95           "The canvas width this stream was authored for", 0, G_MAXINT, 0,
96           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
97 
98   g_object_class_install_property (gobject_class,
99       ARG_DEC_BASE_ORIGINAL_CANVAS_HEIGHT,
100       g_param_spec_int ("original-canvas-height", "Original canvas height",
101           "The canvas height this stream was authored for (0 is unspecified)",
102           0, G_MAXINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
103 }
104 
105 void
gst_kate_util_decode_base_init(GstKateDecoderBase * decoder,gboolean delay_events)106 gst_kate_util_decode_base_init (GstKateDecoderBase * decoder,
107     gboolean delay_events)
108 {
109   if (G_UNLIKELY (!decoder))
110     return;
111 
112   decoder->language = NULL;
113   decoder->category = NULL;
114   decoder->original_canvas_width = 0;
115   decoder->original_canvas_height = 0;
116   decoder->tags = NULL;
117   decoder->tags_changed = FALSE;
118   decoder->initialized = FALSE;
119   decoder->delay_events = delay_events;
120   decoder->event_queue = NULL;
121 }
122 
123 static void
gst_kate_util_decode_base_reset(GstKateDecoderBase * decoder)124 gst_kate_util_decode_base_reset (GstKateDecoderBase * decoder)
125 {
126   g_free (decoder->language);
127   decoder->language = NULL;
128   g_free (decoder->category);
129   decoder->category = NULL;
130   if (decoder->tags) {
131     gst_tag_list_unref (decoder->tags);
132     decoder->tags = NULL;
133   }
134   decoder->tags_changed = FALSE;
135   decoder->original_canvas_width = 0;
136   decoder->original_canvas_height = 0;
137   if (decoder->event_queue) {
138     gst_kate_util_decoder_base_free_event_queue (decoder);
139   }
140   decoder->initialized = FALSE;
141 }
142 
143 gboolean
gst_kate_util_decoder_base_queue_event(GstKateDecoderBase * decoder,GstEvent * event,gboolean (* handler)(GstPad *,GstObject *,GstEvent *),GstObject * parent,GstPad * pad)144 gst_kate_util_decoder_base_queue_event (GstKateDecoderBase * decoder,
145     GstEvent * event, gboolean (*handler) (GstPad *, GstObject *, GstEvent *),
146     GstObject * parent, GstPad * pad)
147 {
148   gboolean can_be_queued;
149 
150   switch (GST_EVENT_TYPE (event)) {
151     case GST_EVENT_FLUSH_START:
152     case GST_EVENT_FLUSH_STOP:
153     case GST_EVENT_EOS:
154       can_be_queued = FALSE;
155       break;
156     case GST_EVENT_SEGMENT:
157       gst_kate_util_decoder_base_segment_event (decoder, event);
158       can_be_queued = TRUE;
159       break;
160     default:
161       can_be_queued = TRUE;
162       break;
163   }
164 
165   if (GST_EVENT_IS_STICKY (event) && GST_EVENT_TYPE (event) < GST_EVENT_CAPS)
166     can_be_queued = FALSE;
167 
168   if (decoder->delay_events && can_be_queued) {
169     GstKateDecoderBaseQueuedEvent *item;
170     GST_DEBUG_OBJECT (decoder, "We have to delay the event");
171     item = g_slice_new (GstKateDecoderBaseQueuedEvent);
172     if (item) {
173       item->event = event;
174       item->parent = parent;
175       item->pad = pad;
176       item->handler = handler;
177       g_queue_push_tail (decoder->event_queue, item);
178       return TRUE;
179     } else {
180       return FALSE;
181     }
182   } else {
183     return FALSE;
184   }
185 }
186 
187 static void
gst_kate_util_decoder_base_free_event_queue(GstKateDecoderBase * decoder)188 gst_kate_util_decoder_base_free_event_queue (GstKateDecoderBase * decoder)
189 {
190   while (decoder->event_queue->length) {
191     GstKateDecoderBaseQueuedEvent *item = (GstKateDecoderBaseQueuedEvent *)
192         g_queue_pop_head (decoder->event_queue);
193     gst_event_unref (item->event);
194     g_slice_free (GstKateDecoderBaseQueuedEvent, item);
195   }
196   g_queue_free (decoder->event_queue);
197   decoder->event_queue = NULL;
198 }
199 
200 static void
gst_kate_util_decoder_base_drain_event_queue(GstKateDecoderBase * decoder)201 gst_kate_util_decoder_base_drain_event_queue (GstKateDecoderBase * decoder)
202 {
203   decoder->delay_events = FALSE;
204 
205   if (decoder->event_queue->length == 0)
206     return;
207 
208   GST_DEBUG_OBJECT (decoder, "We can now drain all events!");
209   while (decoder->event_queue->length) {
210     GstKateDecoderBaseQueuedEvent *item = (GstKateDecoderBaseQueuedEvent *)
211         g_queue_pop_head (decoder->event_queue);
212     (*item->handler) (item->pad, item->parent, item->event);
213     g_slice_free (GstKateDecoderBaseQueuedEvent, item);
214   }
215 }
216 
217 void
gst_kate_util_decoder_base_add_tags(GstKateDecoderBase * decoder,GstTagList * tags,gboolean take_ownership_of_tags)218 gst_kate_util_decoder_base_add_tags (GstKateDecoderBase * decoder,
219     GstTagList * tags, gboolean take_ownership_of_tags)
220 {
221   if (!decoder->tags) {
222     if (!take_ownership_of_tags)
223       tags = gst_tag_list_ref (tags);
224     decoder->tags = tags;
225   } else {
226     GstTagList *old = decoder->tags;
227     decoder->tags = gst_tag_list_merge (old, tags, GST_TAG_MERGE_REPLACE);
228     gst_tag_list_unref (old);
229     if (take_ownership_of_tags)
230       gst_tag_list_unref (tags);
231   }
232   decoder->tags_changed = TRUE;
233 }
234 
235 GstEvent *
gst_kate_util_decoder_base_get_tag_event(GstKateDecoderBase * decoder)236 gst_kate_util_decoder_base_get_tag_event (GstKateDecoderBase * decoder)
237 {
238   if (!decoder->tags)
239     return NULL;
240   decoder->tags_changed = FALSE;
241   return gst_event_new_tag (gst_tag_list_ref (decoder->tags));
242 }
243 
244 gboolean
gst_kate_util_decoder_base_get_property(GstKateDecoderBase * decoder,GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)245 gst_kate_util_decoder_base_get_property (GstKateDecoderBase * decoder,
246     GObject * object, guint prop_id, GValue * value, GParamSpec * pspec)
247 {
248   gboolean res = TRUE;
249   switch (prop_id) {
250     case ARG_DEC_BASE_LANGUAGE:
251       g_value_set_string (value, decoder->language);
252       break;
253     case ARG_DEC_BASE_CATEGORY:
254       g_value_set_string (value, decoder->category);
255       break;
256     case ARG_DEC_BASE_ORIGINAL_CANVAS_WIDTH:
257       g_value_set_int (value, decoder->original_canvas_width);
258       break;
259     case ARG_DEC_BASE_ORIGINAL_CANVAS_HEIGHT:
260       g_value_set_int (value, decoder->original_canvas_height);
261       break;
262     default:
263       res = FALSE;
264       break;
265   }
266   return res;
267 }
268 
269 static inline gboolean
gst_kate_util_is_utf8_string(const char * value,size_t len)270 gst_kate_util_is_utf8_string (const char *value, size_t len)
271 {
272   if (len == 0)
273     return FALSE;
274   if (memchr (value, 0, len - 1))
275     return FALSE;
276   if (value[len - 1])
277     return FALSE;
278   return (kate_text_validate (kate_utf8, value, len) >= 0);
279 }
280 
281 GstFlowReturn
gst_kate_util_decoder_base_chain_kate_packet(GstKateDecoderBase * decoder,GstElement * element,GstPad * pad,GstBuffer * buf,GstPad * srcpad,GstPad * tagpad,GstCaps ** src_caps,const kate_event ** ev)282 gst_kate_util_decoder_base_chain_kate_packet (GstKateDecoderBase * decoder,
283     GstElement * element, GstPad * pad, GstBuffer * buf, GstPad * srcpad,
284     GstPad * tagpad, GstCaps ** src_caps, const kate_event ** ev)
285 {
286   kate_packet kp;
287   int ret;
288   GstFlowReturn rflow = GST_FLOW_OK;
289   gboolean is_header;
290   GstMapInfo info;
291   gsize header_size;
292   guint8 header[1];
293 
294   header_size = gst_buffer_extract (buf, 0, header, 1);
295 
296   GST_DEBUG_OBJECT (element,
297       "got kate packet, %" G_GSIZE_FORMAT " bytes, type %02x",
298       gst_buffer_get_size (buf), header_size == 0 ? -1 : header[0]);
299 
300   is_header = header_size > 0 && (header[0] & 0x80);
301 
302   if (!is_header && decoder->tags_changed) {
303     /* after we've processed headers, send any tags before processing the data packet */
304     GST_DEBUG_OBJECT (element, "Not a header, sending tags for pad %s:%s",
305         GST_DEBUG_PAD_NAME (tagpad));
306     gst_pad_push_event (tagpad,
307         gst_kate_util_decoder_base_get_tag_event (decoder));
308   }
309 
310   if (gst_buffer_map (buf, &info, GST_MAP_READ)) {
311     kate_packet_wrap (&kp, info.size, info.data);
312     ret = kate_high_decode_packetin (&decoder->k, &kp, ev);
313     gst_buffer_unmap (buf, &info);
314   } else {
315     GST_ELEMENT_ERROR (element, STREAM, DECODE, (NULL),
316         ("Failed to map buffer"));
317     return GST_FLOW_ERROR;
318   }
319 
320   if (G_UNLIKELY (ret < 0)) {
321     GST_ELEMENT_ERROR (element, STREAM, DECODE, (NULL),
322         ("Failed to decode Kate packet: %s",
323             gst_kate_util_get_error_message (ret)));
324     return GST_FLOW_ERROR;
325   }
326 
327   if (G_UNLIKELY (ret > 0)) {
328     GST_DEBUG_OBJECT (element,
329         "kate_high_decode_packetin has received EOS packet");
330   }
331 
332   /* headers may be interesting to retrieve information from */
333   if (G_UNLIKELY (is_header)) {
334     switch (header[0]) {
335       case 0x80:               /* ID header */
336         GST_INFO_OBJECT (element, "Parsed ID header: language %s, category %s",
337             decoder->k.ki->language, decoder->k.ki->category);
338         if (src_caps) {
339           if (*src_caps) {
340             gst_caps_unref (*src_caps);
341             *src_caps = NULL;
342           }
343           if (strcmp (decoder->k.ki->category, "K-SPU") == 0 ||
344               strcmp (decoder->k.ki->category, "spu-subtitles") == 0) {
345             *src_caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
346           } else if (decoder->k.ki->text_markup_type == kate_markup_none) {
347             *src_caps = gst_caps_new_simple ("text/x-raw", "format",
348                 G_TYPE_STRING, "utf8", NULL);
349           } else {
350             *src_caps = gst_caps_new_simple ("text/x-raw", "format",
351                 G_TYPE_STRING, "pango-markup", NULL);
352           }
353           GST_INFO_OBJECT (srcpad, "Setting caps: %" GST_PTR_FORMAT, *src_caps);
354           if (!gst_pad_set_caps (srcpad, *src_caps)) {
355             GST_ERROR_OBJECT (srcpad, "Failed to set caps %" GST_PTR_FORMAT,
356                 *src_caps);
357           }
358         }
359         if (decoder->k.ki->language && *decoder->k.ki->language) {
360           GstTagList *tags = gst_tag_list_new_empty ();
361           gchar *lang_code;
362 
363           /* en_GB -> en */
364           lang_code = g_ascii_strdown (decoder->k.ki->language, -1);
365           g_strdelimit (lang_code, NULL, '\0');
366           gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_LANGUAGE_CODE,
367               lang_code, NULL);
368           g_free (lang_code);
369           /* TODO: category - where should it go ? */
370           gst_kate_util_decoder_base_add_tags (decoder, tags, TRUE);
371         }
372 
373         /* update properties */
374         g_free (decoder->language);
375         decoder->language = g_strdup (decoder->k.ki->language);
376         g_free (decoder->category);
377         decoder->category = g_strdup (decoder->k.ki->category);
378         decoder->original_canvas_width = decoder->k.ki->original_canvas_width;
379         decoder->original_canvas_height = decoder->k.ki->original_canvas_height;
380 
381         /* we can now send away any event we've delayed, as the src pad now has caps */
382         gst_kate_util_decoder_base_drain_event_queue (decoder);
383 
384         break;
385 
386       case 0x81:               /* Vorbis comments header */
387         GST_INFO_OBJECT (element, "Parsed comments header");
388         {
389           gchar *encoder = NULL;
390           GstTagList *list = gst_tag_list_from_vorbiscomment_buffer (buf,
391               (const guint8 *) "\201kate\0\0\0\0", 9, &encoder);
392           if (!list) {
393             GST_ERROR_OBJECT (element, "failed to decode comment header");
394             list = gst_tag_list_new_empty ();
395           }
396           if (encoder) {
397             gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
398                 GST_TAG_ENCODER, encoder, NULL);
399             g_free (encoder);
400           }
401           gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
402               GST_TAG_SUBTITLE_CODEC, "Kate", NULL);
403           gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
404               GST_TAG_ENCODER_VERSION, decoder->k.ki->bitstream_version_major,
405               NULL);
406 
407           gst_kate_util_decoder_base_add_tags (decoder, list, TRUE);
408 
409           if (decoder->initialized) {
410             gst_pad_push_event (tagpad,
411                 gst_event_new_tag (gst_tag_list_ref (decoder->tags)));
412           }
413         }
414         break;
415 
416       default:
417         break;
418     }
419   }
420 #if ((KATE_VERSION_MAJOR<<16)|(KATE_VERSION_MINOR<<8)|KATE_VERSION_PATCH) >= 0x000400
421   else if (*ev && (*ev)->meta) {
422     int count = kate_meta_query_count ((*ev)->meta);
423     if (count > 0) {
424       GstTagList *evtags = gst_tag_list_new_empty ();
425       int idx;
426       GST_DEBUG_OBJECT (decoder, "Kate event has %d attached metadata", count);
427       for (idx = 0; idx < count; ++idx) {
428         const char *tag, *value;
429         size_t len;
430         if (kate_meta_query ((*ev)->meta, idx, &tag, &value, &len) < 0) {
431           GST_WARNING_OBJECT (decoder, "Failed to retrieve metadata %d", idx);
432         } else {
433           if (gst_kate_util_is_utf8_string (value, len)) {
434             gchar *compound = g_strdup_printf ("%s=%s", tag, value);
435             GST_DEBUG_OBJECT (decoder,
436                 "Metadata %d: %s=%s (%" G_GSIZE_FORMAT " bytes)", idx, tag,
437                 value, len);
438             gst_tag_list_add (evtags, GST_TAG_MERGE_APPEND,
439                 GST_TAG_EXTENDED_COMMENT, compound, NULL);
440             g_free (compound);
441           } else {
442             GST_INFO_OBJECT (decoder,
443                 "Metadata %d, (%s, %" G_GSIZE_FORMAT
444                 " bytes) is binary, ignored", idx, tag, len);
445           }
446         }
447       }
448       gst_kate_util_decoder_base_add_tags (decoder, evtags, TRUE);
449       gst_pad_push_event (tagpad,
450           gst_kate_util_decoder_base_get_tag_event (decoder));
451     }
452   }
453 #endif
454 
455   return rflow;
456 }
457 
458 GstStateChangeReturn
gst_kate_decoder_base_change_state(GstKateDecoderBase * decoder,GstElement * element,GstElementClass * parent_class,GstStateChange transition)459 gst_kate_decoder_base_change_state (GstKateDecoderBase * decoder,
460     GstElement * element, GstElementClass * parent_class,
461     GstStateChange transition)
462 {
463   GstStateChangeReturn res;
464   int ret;
465 
466   switch (transition) {
467     case GST_STATE_CHANGE_NULL_TO_READY:
468       break;
469     case GST_STATE_CHANGE_READY_TO_PAUSED:
470       GST_DEBUG_OBJECT (element, "READY -> PAUSED, initializing kate state");
471       ret = kate_high_decode_init (&decoder->k);
472       if (ret < 0) {
473         GST_WARNING_OBJECT (element, "failed to initialize kate state: %s",
474             gst_kate_util_get_error_message (ret));
475       }
476       gst_segment_init (&decoder->kate_segment, GST_FORMAT_UNDEFINED);
477       decoder->kate_flushing = FALSE;
478       decoder->initialized = TRUE;
479       decoder->event_queue = g_queue_new ();
480       break;
481     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
482       break;
483     default:
484       break;
485   }
486 
487   res = parent_class->change_state (element, transition);
488 
489   switch (transition) {
490     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
491       break;
492     case GST_STATE_CHANGE_PAUSED_TO_READY:
493       GST_DEBUG_OBJECT (element, "PAUSED -> READY, clearing kate state");
494       if (decoder->initialized) {
495         kate_high_decode_clear (&decoder->k);
496         decoder->initialized = FALSE;
497       }
498       gst_segment_init (&decoder->kate_segment, GST_FORMAT_UNDEFINED);
499       decoder->kate_flushing = TRUE;
500       gst_kate_util_decode_base_reset (decoder);
501       break;
502     case GST_STATE_CHANGE_READY_TO_NULL:
503       gst_kate_util_decode_base_reset (decoder);
504       break;
505     default:
506       break;
507   }
508 
509   return res;
510 }
511 
512 void
gst_kate_util_decoder_base_set_flushing(GstKateDecoderBase * decoder,gboolean flushing)513 gst_kate_util_decoder_base_set_flushing (GstKateDecoderBase * decoder,
514     gboolean flushing)
515 {
516   decoder->kate_flushing = flushing;
517   gst_segment_init (&decoder->kate_segment, GST_FORMAT_UNDEFINED);
518 }
519 
520 void
gst_kate_util_decoder_base_segment_event(GstKateDecoderBase * decoder,GstEvent * event)521 gst_kate_util_decoder_base_segment_event (GstKateDecoderBase * decoder,
522     GstEvent * event)
523 {
524   GstSegment seg;
525 
526   gst_event_copy_segment (event, &seg);
527 
528   GST_DEBUG_OBJECT (decoder, "kate pad segment: %" GST_SEGMENT_FORMAT, &seg);
529 
530   decoder->kate_segment = seg;
531 }
532 
533 gboolean
gst_kate_util_decoder_base_update_segment(GstKateDecoderBase * decoder,GstElement * element,GstBuffer * buf)534 gst_kate_util_decoder_base_update_segment (GstKateDecoderBase * decoder,
535     GstElement * element, GstBuffer * buf)
536 {
537   guint64 clip_start = 0, clip_stop = 0;
538   gboolean in_seg;
539 
540   if (decoder->kate_flushing) {
541     GST_LOG_OBJECT (element, "Kate pad flushing, buffer ignored");
542     return FALSE;
543   }
544 
545   if (G_LIKELY (GST_BUFFER_TIMESTAMP_IS_VALID (buf))) {
546     GstClockTime stop;
547 
548     if (G_LIKELY (GST_BUFFER_DURATION_IS_VALID (buf)))
549       stop = GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf);
550     else
551       stop = GST_CLOCK_TIME_NONE;
552 
553     in_seg = gst_segment_clip (&decoder->kate_segment, GST_FORMAT_TIME,
554         GST_BUFFER_TIMESTAMP (buf), stop, &clip_start, &clip_stop);
555   } else {
556     in_seg = TRUE;
557   }
558 
559   if (in_seg) {
560     if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
561       decoder->kate_segment.position = clip_start;
562     }
563   } else {
564     GST_INFO_OBJECT (element, "Kate buffer not in segment, ignored");
565   }
566 
567   return in_seg;
568 }
569 
570 static GstClockTime
gst_kate_util_granule_time(kate_state * k,gint64 granulepos)571 gst_kate_util_granule_time (kate_state * k, gint64 granulepos)
572 {
573   if (G_UNLIKELY (granulepos == -1))
574     return -1;
575 
576   return kate_granule_time (k->ki, granulepos) * GST_SECOND;
577 }
578 
579 /*
580 conversions on the sink:
581   - default is granules at num/den rate (subject to the granule shift)
582   - default -> time is possible
583   - bytes do not mean anything, packets can be any number of bytes, and we
584     have no way to know the number of bytes emitted without decoding
585 conversions on the source:
586   - nothing
587 */
588 
589 gboolean
gst_kate_decoder_base_convert(GstKateDecoderBase * decoder,GstElement * element,GstPad * pad,GstFormat src_fmt,gint64 src_val,GstFormat * dest_fmt,gint64 * dest_val)590 gst_kate_decoder_base_convert (GstKateDecoderBase * decoder,
591     GstElement * element, GstPad * pad, GstFormat src_fmt, gint64 src_val,
592     GstFormat * dest_fmt, gint64 * dest_val)
593 {
594   gboolean res = FALSE;
595 
596   if (src_fmt == *dest_fmt) {
597     *dest_val = src_val;
598     return TRUE;
599   }
600 
601   if (!decoder->initialized) {
602     GST_WARNING_OBJECT (element, "not initialized yet");
603     return FALSE;
604   }
605 
606   if (src_fmt == GST_FORMAT_BYTES || *dest_fmt == GST_FORMAT_BYTES) {
607     GST_WARNING_OBJECT (element, "unsupported format");
608     return FALSE;
609   }
610 
611   switch (src_fmt) {
612     case GST_FORMAT_DEFAULT:
613       switch (*dest_fmt) {
614         case GST_FORMAT_TIME:
615           *dest_val = gst_kate_util_granule_time (&decoder->k, src_val);
616           res = TRUE;
617           break;
618         default:
619           res = FALSE;
620           break;
621       }
622       break;
623     default:
624       res = FALSE;
625       break;
626   }
627 
628   if (!res) {
629     GST_WARNING_OBJECT (element, "unsupported format");
630   }
631 
632   return res;
633 }
634 
635 gboolean
gst_kate_decoder_base_sink_query(GstKateDecoderBase * decoder,GstElement * element,GstPad * pad,GstObject * parent,GstQuery * query)636 gst_kate_decoder_base_sink_query (GstKateDecoderBase * decoder,
637     GstElement * element, GstPad * pad, GstObject * parent, GstQuery * query)
638 {
639   switch (GST_QUERY_TYPE (query)) {
640     case GST_QUERY_CONVERT:
641     {
642       GstFormat src_fmt, dest_fmt;
643       gint64 src_val, dest_val;
644 
645       gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
646       if (!gst_kate_decoder_base_convert (decoder, element, pad, src_fmt,
647               src_val, &dest_fmt, &dest_val)) {
648         return gst_pad_query_default (pad, parent, query);
649       }
650       gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
651       return TRUE;
652     }
653     default:
654       return gst_pad_query_default (pad, parent, query);
655   }
656 }
657 
658 const char *
gst_kate_util_get_error_message(int ret)659 gst_kate_util_get_error_message (int ret)
660 {
661   switch (ret) {
662     case KATE_E_NOT_FOUND:
663       return "value not found";
664     case KATE_E_INVALID_PARAMETER:
665       return "invalid parameter";
666     case KATE_E_OUT_OF_MEMORY:
667       return "out of memory";
668     case KATE_E_BAD_GRANULE:
669       return "bad granule";
670     case KATE_E_INIT:
671       return "initialization error";
672     case KATE_E_BAD_PACKET:
673       return "bad packet";
674     case KATE_E_TEXT:
675       return "invalid/truncated text";
676     case KATE_E_LIMIT:
677       return "a limit was exceeded";
678     case KATE_E_VERSION:
679       return "unsupported bitstream version";
680     case KATE_E_NOT_KATE:
681       return "not a kate bitstream";
682     case KATE_E_BAD_TAG:
683       return "bad tag";
684     case KATE_E_IMPL:
685       return "not implemented";
686 
687 #ifdef HAVE_TIGER
688     case TIGER_E_NOT_FOUND:
689       return "value not found";
690     case TIGER_E_INVALID_PARAMETER:
691       return "invalid parameter";
692     case TIGER_E_OUT_OF_MEMORY:
693       return "out of memory";
694     case TIGER_E_CAIRO_ERROR:
695       return "Cairo error";
696     case TIGER_E_BAD_SURFACE_TYPE:
697       return "bad surface type";
698 #endif
699 
700     default:
701       return "unknown error";
702   }
703 }
704