Tizen 2.0 Release
[framework/multimedia/gst-plugins-bad0.10.git] / ext / kate / gstkateutil.c
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., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, 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 *
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     GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_IN_CAPS);
64     g_value_init (&value, GST_TYPE_BUFFER);
65     /* as in theoraenc, we need to copy to avoid circular references */
66     buffer = gst_buffer_copy (buffer);
67     gst_value_set_buffer (&value, buffer);
68     gst_buffer_unref (buffer);
69     gst_value_array_append_value (&array, &value);
70     g_value_unset (&value);
71     headers = headers->next;
72   }
73
74   gst_structure_set_value (structure, "streamheader", &array);
75   g_value_unset (&array);
76   GST_LOG_OBJECT (element, "here are the newly set caps: %" GST_PTR_FORMAT,
77       caps);
78
79   return caps;
80 }
81
82 void
83 gst_kate_util_install_decoder_base_properties (GObjectClass * gobject_class)
84 {
85   g_object_class_install_property (gobject_class, ARG_DEC_BASE_LANGUAGE,
86       g_param_spec_string ("language", "Language", "The language of the stream",
87           "", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
88
89   g_object_class_install_property (gobject_class, ARG_DEC_BASE_CATEGORY,
90       g_param_spec_string ("category", "Category", "The category of the stream",
91           "", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
92
93   g_object_class_install_property (gobject_class,
94       ARG_DEC_BASE_ORIGINAL_CANVAS_WIDTH,
95       g_param_spec_int ("original-canvas-width",
96           "Original canvas width (0 is unspecified)",
97           "The canvas width this stream was authored for", 0, G_MAXINT, 0,
98           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
99
100   g_object_class_install_property (gobject_class,
101       ARG_DEC_BASE_ORIGINAL_CANVAS_HEIGHT,
102       g_param_spec_int ("original-canvas-height", "Original canvas height",
103           "The canvas height this stream was authored for (0 is unspecified)",
104           0, G_MAXINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
105 }
106
107 void
108 gst_kate_util_decode_base_init (GstKateDecoderBase * decoder,
109     gboolean delay_events)
110 {
111   if (G_UNLIKELY (!decoder))
112     return;
113
114   decoder->language = NULL;
115   decoder->category = NULL;
116   decoder->original_canvas_width = 0;
117   decoder->original_canvas_height = 0;
118   decoder->tags = NULL;
119   decoder->initialized = FALSE;
120   decoder->delay_events = delay_events;
121   decoder->event_queue = NULL;
122 }
123
124 static void
125 gst_kate_util_decode_base_reset (GstKateDecoderBase * decoder)
126 {
127   g_free (decoder->language);
128   decoder->language = NULL;
129   g_free (decoder->category);
130   decoder->category = NULL;
131   if (decoder->tags) {
132     gst_tag_list_free (decoder->tags);
133     decoder->tags = NULL;
134   }
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
144 gst_kate_util_decoder_base_queue_event (GstKateDecoderBase * decoder,
145     GstEvent * event, gboolean (*handler) (GstPad *, GstEvent *), GstPad * pad)
146 {
147   gboolean can_be_queued;
148
149   switch (GST_EVENT_TYPE (event)) {
150     case GST_EVENT_FLUSH_START:
151     case GST_EVENT_FLUSH_STOP:
152     case GST_EVENT_EOS:
153       can_be_queued = FALSE;
154       break;
155     default:
156       can_be_queued = TRUE;
157       break;
158   }
159
160   if (decoder->delay_events && can_be_queued) {
161     GstKateDecoderBaseQueuedEvent *item;
162     GST_DEBUG_OBJECT (decoder, "We have to delay the event");
163     item = g_slice_new (GstKateDecoderBaseQueuedEvent);
164     if (item) {
165       item->event = event;
166       item->pad = pad;
167       item->handler = handler;
168       g_queue_push_tail (decoder->event_queue, item);
169       return TRUE;
170     } else {
171       return FALSE;
172     }
173   } else {
174     return FALSE;
175   }
176 }
177
178 static void
179 gst_kate_util_decoder_base_free_event_queue (GstKateDecoderBase * decoder)
180 {
181   while (decoder->event_queue->length) {
182     GstKateDecoderBaseQueuedEvent *item = (GstKateDecoderBaseQueuedEvent *)
183         g_queue_pop_head (decoder->event_queue);
184     g_slice_free (GstKateDecoderBaseQueuedEvent, item);
185   }
186   g_queue_free (decoder->event_queue);
187   decoder->event_queue = NULL;
188 }
189
190 static void
191 gst_kate_util_decoder_base_drain_event_queue (GstKateDecoderBase * decoder)
192 {
193   decoder->delay_events = FALSE;
194
195   if (decoder->event_queue->length == 0)
196     return;
197
198   GST_DEBUG_OBJECT (decoder, "We can now drain all events!");
199   while (decoder->event_queue->length) {
200     GstKateDecoderBaseQueuedEvent *item = (GstKateDecoderBaseQueuedEvent *)
201         g_queue_pop_head (decoder->event_queue);
202     (*item->handler) (item->pad, item->event);
203     g_slice_free (GstKateDecoderBaseQueuedEvent, item);
204   }
205 }
206
207 gboolean
208 gst_kate_util_decoder_base_get_property (GstKateDecoderBase * decoder,
209     GObject * object, guint prop_id, GValue * value, GParamSpec * pspec)
210 {
211   gboolean res = TRUE;
212   switch (prop_id) {
213     case ARG_DEC_BASE_LANGUAGE:
214       g_value_set_string (value, decoder->language);
215       break;
216     case ARG_DEC_BASE_CATEGORY:
217       g_value_set_string (value, decoder->category);
218       break;
219     case ARG_DEC_BASE_ORIGINAL_CANVAS_WIDTH:
220       g_value_set_int (value, decoder->original_canvas_width);
221       break;
222     case ARG_DEC_BASE_ORIGINAL_CANVAS_HEIGHT:
223       g_value_set_int (value, decoder->original_canvas_height);
224       break;
225     default:
226       res = FALSE;
227       break;
228   }
229   return res;
230 }
231
232 static inline gboolean
233 gst_kate_util_is_utf8_string (const char *value, size_t len)
234 {
235   if (len == 0)
236     return FALSE;
237   if (memchr (value, 0, len - 1))
238     return FALSE;
239   if (value[len - 1])
240     return FALSE;
241   return (kate_text_validate (kate_utf8, value, len) >= 0);
242 }
243
244 GstFlowReturn
245 gst_kate_util_decoder_base_chain_kate_packet (GstKateDecoderBase * decoder,
246     GstElement * element, GstPad * pad, GstBuffer * buf, GstPad * srcpad,
247     GstPad * tagpad, GstCaps ** src_caps, const kate_event ** ev)
248 {
249   kate_packet kp;
250   int ret;
251   GstFlowReturn rflow = GST_FLOW_OK;
252   gboolean is_header;
253
254   GST_DEBUG_OBJECT (element, "got kate packet, %u bytes, type %02x",
255       GST_BUFFER_SIZE (buf),
256       GST_BUFFER_SIZE (buf) == 0 ? -1 : GST_BUFFER_DATA (buf)[0]);
257
258   is_header = GST_BUFFER_SIZE (buf) > 0 && (GST_BUFFER_DATA (buf)[0] & 0x80);
259
260   if (!is_header && decoder->tags) {
261     /* after we've processed headers, send any tags before processing the data packet */
262     GST_DEBUG_OBJECT (element, "Not a header, sending tags for pad %s:%s",
263         GST_DEBUG_PAD_NAME (tagpad));
264     gst_element_found_tags_for_pad (element, tagpad, decoder->tags);
265     decoder->tags = NULL;
266   }
267
268   kate_packet_wrap (&kp, GST_BUFFER_SIZE (buf), GST_BUFFER_DATA (buf));
269   ret = kate_high_decode_packetin (&decoder->k, &kp, ev);
270   if (G_UNLIKELY (ret < 0)) {
271     GST_ELEMENT_ERROR (element, STREAM, DECODE, (NULL),
272         ("Failed to decode Kate packet: %s",
273             gst_kate_util_get_error_message (ret)));
274     return GST_FLOW_ERROR;
275   }
276
277   if (G_UNLIKELY (ret > 0)) {
278     GST_DEBUG_OBJECT (element,
279         "kate_high_decode_packetin has received EOS packet");
280   }
281
282   /* headers may be interesting to retrieve information from */
283   if (G_UNLIKELY (is_header)) {
284     switch (GST_BUFFER_DATA (buf)[0]) {
285       case 0x80:               /* ID header */
286         GST_INFO_OBJECT (element, "Parsed ID header: language %s, category %s",
287             decoder->k.ki->language, decoder->k.ki->category);
288         if (src_caps) {
289           if (*src_caps) {
290             gst_caps_unref (*src_caps);
291             *src_caps = NULL;
292           }
293           if (strcmp (decoder->k.ki->category, "K-SPU") == 0 ||
294               strcmp (decoder->k.ki->category, "spu-subtitles") == 0) {
295             *src_caps = gst_caps_new_simple ("video/x-dvd-subpicture", NULL);
296           } else if (decoder->k.ki->text_markup_type == kate_markup_none) {
297             *src_caps = gst_caps_new_simple ("text/plain", NULL);
298           } else {
299             *src_caps = gst_caps_new_simple ("text/x-pango-markup", NULL);
300           }
301           GST_INFO_OBJECT (srcpad, "Setting caps: %" GST_PTR_FORMAT, *src_caps);
302           if (!gst_pad_set_caps (srcpad, *src_caps)) {
303             GST_ERROR_OBJECT (srcpad, "Failed to set caps %" GST_PTR_FORMAT,
304                 *src_caps);
305           }
306         }
307         if (decoder->k.ki->language && *decoder->k.ki->language) {
308           GstTagList *old = decoder->tags, *tags = gst_tag_list_new ();
309           if (tags) {
310             gchar *lang_code;
311
312             /* en_GB -> en */
313             lang_code = g_ascii_strdown (decoder->k.ki->language, -1);
314             g_strdelimit (lang_code, NULL, '\0');
315             gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_LANGUAGE_CODE,
316                 lang_code, NULL);
317             g_free (lang_code);
318             /* TODO: category - where should it go ? */
319             decoder->tags =
320                 gst_tag_list_merge (decoder->tags, tags, GST_TAG_MERGE_REPLACE);
321             gst_tag_list_free (tags);
322             if (old)
323               gst_tag_list_free (old);
324           }
325         }
326
327         /* update properties */
328         if (decoder->language)
329           g_free (decoder->language);
330         decoder->language = g_strdup (decoder->k.ki->language);
331         if (decoder->category)
332           g_free (decoder->category);
333         decoder->category = g_strdup (decoder->k.ki->category);
334         decoder->original_canvas_width = decoder->k.ki->original_canvas_width;
335         decoder->original_canvas_height = decoder->k.ki->original_canvas_height;
336
337         /* we can now send away any event we've delayed, as the src pad now has caps */
338         gst_kate_util_decoder_base_drain_event_queue (decoder);
339
340         break;
341
342       case 0x81:               /* Vorbis comments header */
343         GST_INFO_OBJECT (element, "Parsed comments header");
344         {
345           gchar *encoder = NULL;
346           GstTagList *old = decoder->tags, *list =
347               gst_tag_list_from_vorbiscomment_buffer (buf,
348               (const guint8 *) "\201kate\0\0\0\0", 9, &encoder);
349           if (list) {
350             decoder->tags =
351                 gst_tag_list_merge (decoder->tags, list, GST_TAG_MERGE_REPLACE);
352             gst_tag_list_free (list);
353           }
354
355           if (!decoder->tags) {
356             GST_ERROR_OBJECT (element, "failed to decode comment header");
357             decoder->tags = gst_tag_list_new ();
358           }
359           if (encoder) {
360             gst_tag_list_add (decoder->tags, GST_TAG_MERGE_REPLACE,
361                 GST_TAG_ENCODER, encoder, NULL);
362             g_free (encoder);
363           }
364           gst_tag_list_add (decoder->tags, GST_TAG_MERGE_REPLACE,
365               GST_TAG_SUBTITLE_CODEC, "Kate", NULL);
366           gst_tag_list_add (decoder->tags, GST_TAG_MERGE_REPLACE,
367               GST_TAG_ENCODER_VERSION, decoder->k.ki->bitstream_version_major,
368               NULL);
369
370           if (old)
371             gst_tag_list_free (old);
372
373           if (decoder->initialized) {
374             gst_element_found_tags_for_pad (element, tagpad, decoder->tags);
375             decoder->tags = NULL;
376           } else {
377             /* Only push them as messages for the time being. *
378              * They will be pushed on the pad once the decoder is initialized */
379             gst_element_post_message (element,
380                 gst_message_new_tag (GST_OBJECT (element),
381                     gst_tag_list_copy (decoder->tags)));
382           }
383         }
384         break;
385
386       default:
387         break;
388     }
389   }
390 #if ((KATE_VERSION_MAJOR<<16)|(KATE_VERSION_MINOR<<8)|KATE_VERSION_PATCH) >= 0x000400
391   else if (*ev && (*ev)->meta) {
392     int count = kate_meta_query_count ((*ev)->meta);
393     if (count > 0) {
394       GstTagList *evtags = gst_tag_list_new ();
395       int idx;
396       GST_DEBUG_OBJECT (decoder, "Kate event has %d attached metadata", count);
397       for (idx = 0; idx < count; ++idx) {
398         const char *tag, *value;
399         size_t len;
400         if (kate_meta_query ((*ev)->meta, idx, &tag, &value, &len) < 0) {
401           GST_WARNING_OBJECT (decoder, "Failed to retrieve metadata %d", idx);
402         } else {
403           if (gst_kate_util_is_utf8_string (value, len)) {
404             gchar *compound = g_strdup_printf ("%s=%s", tag, value);
405             GST_DEBUG_OBJECT (decoder, "Metadata %d: %s=%s (%zu bytes)", idx,
406                 tag, value, len);
407             gst_tag_list_add (evtags, GST_TAG_MERGE_APPEND,
408                 GST_TAG_EXTENDED_COMMENT, compound, NULL);
409             g_free (compound);
410           } else {
411             GST_INFO_OBJECT (decoder,
412                 "Metadata %d, (%s, %zu bytes) is binary, ignored", idx, tag,
413                 len);
414           }
415         }
416       }
417       if (gst_tag_list_is_empty (evtags))
418         gst_tag_list_free (evtags);
419       else
420         gst_element_found_tags_for_pad (element, tagpad, evtags);
421     }
422   }
423 #endif
424
425   return rflow;
426 }
427
428 GstStateChangeReturn
429 gst_kate_decoder_base_change_state (GstKateDecoderBase * decoder,
430     GstElement * element, GstElementClass * parent_class,
431     GstStateChange transition)
432 {
433   GstStateChangeReturn res;
434   int ret;
435
436   switch (transition) {
437     case GST_STATE_CHANGE_NULL_TO_READY:
438       break;
439     case GST_STATE_CHANGE_READY_TO_PAUSED:
440       GST_DEBUG_OBJECT (element, "READY -> PAUSED, initializing kate state");
441       ret = kate_high_decode_init (&decoder->k);
442       if (ret < 0) {
443         GST_WARNING_OBJECT (element, "failed to initialize kate state: %s",
444             gst_kate_util_get_error_message (ret));
445       }
446       gst_segment_init (&decoder->kate_segment, GST_FORMAT_UNDEFINED);
447       decoder->kate_flushing = FALSE;
448       decoder->initialized = TRUE;
449       decoder->event_queue = g_queue_new ();
450       break;
451     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
452       break;
453     default:
454       break;
455   }
456
457   res = parent_class->change_state (element, transition);
458
459   switch (transition) {
460     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
461       break;
462     case GST_STATE_CHANGE_PAUSED_TO_READY:
463       GST_DEBUG_OBJECT (element, "PAUSED -> READY, clearing kate state");
464       if (decoder->initialized) {
465         kate_high_decode_clear (&decoder->k);
466         decoder->initialized = FALSE;
467       }
468       gst_segment_init (&decoder->kate_segment, GST_FORMAT_UNDEFINED);
469       decoder->kate_flushing = TRUE;
470       gst_kate_util_decode_base_reset (decoder);
471       break;
472     case GST_STATE_CHANGE_READY_TO_NULL:
473       gst_kate_util_decode_base_reset (decoder);
474       break;
475     default:
476       break;
477   }
478
479   return res;
480 }
481
482 void
483 gst_kate_util_decoder_base_set_flushing (GstKateDecoderBase * decoder,
484     gboolean flushing)
485 {
486   decoder->kate_flushing = flushing;
487   gst_segment_init (&decoder->kate_segment, GST_FORMAT_UNDEFINED);
488 }
489
490 void
491 gst_kate_util_decoder_base_new_segment_event (GstKateDecoderBase * decoder,
492     GstEvent * event)
493 {
494   gboolean update;
495   gdouble rate;
496   GstFormat format;
497   gint64 start, stop, time;
498   gdouble arate;
499
500   gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
501       &start, &stop, &time);
502   GST_DEBUG_OBJECT (decoder, "kate pad segment:"
503       " Update %d, rate %g arate %g format %d start %" GST_TIME_FORMAT
504       " %" GST_TIME_FORMAT " position %" GST_TIME_FORMAT,
505       update, rate, arate, format, GST_TIME_ARGS (start),
506       GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
507   if (!update) {
508     /* Tiger uses this segment is used to remap the video running time to the
509        Kate running time. The sending of segment updates to keep streams in sync
510        does kinda rain on our parade though, and since we don't need these,
511        we just ignore those here */
512     gst_segment_set_newsegment_full (&decoder->kate_segment, update, rate,
513         arate, format, start, stop, time);
514   }
515 }
516
517 gboolean
518 gst_kate_util_decoder_base_update_segment (GstKateDecoderBase * decoder,
519     GstElement * element, GstBuffer * buf)
520 {
521   gint64 clip_start = 0, clip_stop = 0;
522   gboolean in_seg;
523
524   if (decoder->kate_flushing) {
525     GST_LOG_OBJECT (element, "Kate pad flushing, buffer ignored");
526     return FALSE;
527   }
528
529   if (G_LIKELY (GST_BUFFER_TIMESTAMP_IS_VALID (buf))) {
530     GstClockTime stop;
531
532     if (G_LIKELY (GST_BUFFER_DURATION_IS_VALID (buf)))
533       stop = GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf);
534     else
535       stop = GST_CLOCK_TIME_NONE;
536
537     in_seg = gst_segment_clip (&decoder->kate_segment, GST_FORMAT_TIME,
538         GST_BUFFER_TIMESTAMP (buf), stop, &clip_start, &clip_stop);
539   } else {
540     in_seg = TRUE;
541   }
542
543   if (in_seg) {
544     if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
545       gst_segment_set_last_stop (&decoder->kate_segment, GST_FORMAT_TIME,
546           clip_start);
547     }
548   } else {
549     GST_INFO_OBJECT (element, "Kate buffer not in segment, ignored");
550   }
551
552   return in_seg;
553 }
554
555 static GstClockTime
556 gst_kate_util_granule_time (kate_state * k, gint64 granulepos)
557 {
558   if (G_UNLIKELY (granulepos == -1))
559     return -1;
560
561   return kate_granule_time (k->ki, granulepos) * GST_SECOND;
562 }
563
564 /*
565 conversions on the sink:
566   - default is granules at num/den rate (subject to the granule shift)
567   - default -> time is possible
568   - bytes do not mean anything, packets can be any number of bytes, and we
569     have no way to know the number of bytes emitted without decoding
570 conversions on the source:
571   - nothing
572 */
573
574 gboolean
575 gst_kate_decoder_base_convert (GstKateDecoderBase * decoder,
576     GstElement * element, GstPad * pad, GstFormat src_fmt, gint64 src_val,
577     GstFormat * dest_fmt, gint64 * dest_val)
578 {
579   gboolean res = FALSE;
580
581   if (src_fmt == *dest_fmt) {
582     *dest_val = src_val;
583     return TRUE;
584   }
585
586   if (!decoder->initialized) {
587     GST_WARNING_OBJECT (element, "not initialized yet");
588     return FALSE;
589   }
590
591   if (src_fmt == GST_FORMAT_BYTES || *dest_fmt == GST_FORMAT_BYTES) {
592     GST_WARNING_OBJECT (element, "unsupported format");
593     return FALSE;
594   }
595
596   switch (src_fmt) {
597     case GST_FORMAT_DEFAULT:
598       switch (*dest_fmt) {
599         case GST_FORMAT_TIME:
600           *dest_val = gst_kate_util_granule_time (&decoder->k, src_val);
601           res = TRUE;
602           break;
603         default:
604           res = FALSE;
605           break;
606       }
607       break;
608     default:
609       res = FALSE;
610       break;
611   }
612
613   if (!res) {
614     GST_WARNING_OBJECT (element, "unsupported format");
615   }
616
617   return res;
618 }
619
620 gboolean
621 gst_kate_decoder_base_sink_query (GstKateDecoderBase * decoder,
622     GstElement * element, GstPad * pad, GstQuery * query)
623 {
624   switch (GST_QUERY_TYPE (query)) {
625     case GST_QUERY_CONVERT:
626     {
627       GstFormat src_fmt, dest_fmt;
628       gint64 src_val, dest_val;
629
630       gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
631       if (!gst_kate_decoder_base_convert (decoder, element, pad, src_fmt,
632               src_val, &dest_fmt, &dest_val)) {
633         return gst_pad_query_default (pad, query);
634       }
635       gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
636       return TRUE;
637     }
638     default:
639       return gst_pad_query_default (pad, query);
640   }
641 }
642
643 const char *
644 gst_kate_util_get_error_message (int ret)
645 {
646   switch (ret) {
647     case KATE_E_NOT_FOUND:
648       return "value not found";
649     case KATE_E_INVALID_PARAMETER:
650       return "invalid parameter";
651     case KATE_E_OUT_OF_MEMORY:
652       return "out of memory";
653     case KATE_E_BAD_GRANULE:
654       return "bad granule";
655     case KATE_E_INIT:
656       return "initialization error";
657     case KATE_E_BAD_PACKET:
658       return "bad packet";
659     case KATE_E_TEXT:
660       return "invalid/truncated text";
661     case KATE_E_LIMIT:
662       return "a limit was exceeded";
663     case KATE_E_VERSION:
664       return "unsupported bitstream version";
665     case KATE_E_NOT_KATE:
666       return "not a kate bitstream";
667     case KATE_E_BAD_TAG:
668       return "bad tag";
669     case KATE_E_IMPL:
670       return "not implemented";
671
672 #ifdef HAVE_TIGER
673     case TIGER_E_NOT_FOUND:
674       return "value not found";
675     case TIGER_E_INVALID_PARAMETER:
676       return "invalid parameter";
677     case TIGER_E_OUT_OF_MEMORY:
678       return "out of memory";
679     case TIGER_E_CAIRO_ERROR:
680       return "Cairo error";
681     case TIGER_E_BAD_SURFACE_TYPE:
682       return "bad surface type";
683 #endif
684
685     default:
686       return "unknown error";
687   }
688 }