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