kate: minor cleanup
[platform/upstream/gstreamer.git] / ext / kate / gstkateenc.c
1 /*
2  * GStreamer
3  * Copyright 2005 Thomas Vander Stichele <thomas@apestaart.org>
4  * Copyright 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
5  * Copyright (C) 2007 Fluendo S.A. <info@fluendo.com>
6  * Copyright 2008, 2009 Vincent Penquerc'h <ogg.k.ogg.k@googlemail.com>
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24  * DEALINGS IN THE SOFTWARE.
25  *
26  * Alternatively, the contents of this file may be used under the
27  * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
28  * which case the following provisions apply instead of the ones
29  * mentioned above:
30  *
31  * This library is free software; you can redistribute it and/or
32  * modify it under the terms of the GNU Library General Public
33  * License as published by the Free Software Foundation; either
34  * version 2 of the License, or (at your option) any later version.
35  *
36  * This library is distributed in the hope that it will be useful,
37  * but WITHOUT ANY WARRANTY; without even the implied warranty of
38  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
39  * Library General Public License for more details.
40  *
41  * You should have received a copy of the GNU Library General Public
42  * License along with this library; if not, write to the
43  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
44  * Boston, MA 02110-1301, USA.
45  */
46
47 /**
48  * SECTION:element-kateenc
49  * @see_also: oggmux
50  *
51  * <refsect2>
52  * <para>
53  * This element encodes Kate streams
54  * <ulink url="http://libkate.googlecode.com/">Kate</ulink> is a free codec
55  * for text based data, such as subtitles. Any number of kate streams can be
56  * embedded in an Ogg stream.
57  * </para>
58  * <para>
59  * libkate (see above url) is needed to build this plugin.
60  * </para>
61  * <title>Example pipeline</title>
62  * <para>
63  * This encodes a DVD SPU track to a Kate stream:
64  * <programlisting>
65  * gst-launch dvdreadsrc ! dvddemux ! dvdsubparse ! kateenc category=spu-subtitles ! oggmux ! filesink location=test.ogg
66  * </programlisting>
67  * </para>
68  * </refsect2>
69  */
70
71 /* FIXME:
72  *  - should we automatically pick up the language code from the
73  *    upstream event tags if none was set via the property?
74  *  - turn category property into an enum (freestyle text property in
75  *    combination with supposedly strictly defined known values that
76  *    aren't even particularly human-readable is just not very nice)? */
77
78 #ifdef HAVE_CONFIG_H
79 #include "config.h"
80 #endif
81
82 #include <string.h>
83
84 #include <gst/gst.h>
85 #include <gst/gsttagsetter.h>
86 #include <gst/tag/tag.h>
87
88 #include "gstkate.h"
89 #include "gstkateutil.h"
90 #include "gstkatespu.h"
91 #include "gstkateenc.h"
92
93 GST_DEBUG_CATEGORY_EXTERN (gst_kateenc_debug);
94 #define GST_CAT_DEFAULT gst_kateenc_debug
95
96 /* Filter signals and args */
97 enum
98 {
99   /* FILL ME */
100   LAST_SIGNAL
101 };
102
103 enum
104 {
105   ARG_0,
106   ARG_LANGUAGE,
107   ARG_CATEGORY,
108   ARG_GRANULE_RATE_NUM,
109   ARG_GRANULE_RATE_DEN,
110   ARG_GRANULE_SHIFT,
111   ARG_KEEPALIVE_MIN_TIME,
112   ARG_ORIGINAL_CANVAS_WIDTH,
113   ARG_ORIGINAL_CANVAS_HEIGHT,
114   ARG_DEFAULT_SPU_DURATION,
115 };
116
117 #define DEFAULT_KEEPALIVE_MIN_TIME 2.5f
118 #define DEFAULT_DEFAULT_SPU_DURATION 1.5f
119
120 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
121     GST_PAD_SINK,
122     GST_PAD_ALWAYS,
123     GST_STATIC_CAPS ("text/x-raw, format={ pango-markup, utf8 }; "
124         GST_KATE_SPU_MIME_TYPE)
125     );
126
127 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
128     GST_PAD_SRC,
129     GST_PAD_ALWAYS,
130     GST_STATIC_CAPS ("subtitle/x-kate; application/x-kate")
131     );
132
133 static void gst_kate_enc_set_property (GObject * object, guint prop_id,
134     const GValue * value, GParamSpec * pspec);
135 static void gst_kate_enc_get_property (GObject * object, guint prop_id,
136     GValue * value, GParamSpec * pspec);
137 static void gst_kate_enc_dispose (GObject * object);
138
139 static gboolean gst_kate_enc_setcaps (GstKateEnc * ke, GstCaps * caps);
140 static GstFlowReturn gst_kate_enc_chain (GstPad * pad, GstObject * parent,
141     GstBuffer * buf);
142 static GstStateChangeReturn gst_kate_enc_change_state (GstElement * element,
143     GstStateChange transition);
144 static gboolean gst_kate_enc_sink_event (GstPad * pad, GstObject * parent,
145     GstEvent * event);
146 static gboolean gst_kate_enc_source_query (GstPad * pad, GstObject * parent,
147     GstQuery * query);
148
149 #define gst_kate_enc_parent_class parent_class
150 G_DEFINE_TYPE_WITH_CODE (GstKateEnc, gst_kate_enc, GST_TYPE_ELEMENT,
151     G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL));
152
153 /* initialize the plugin's class */
154 static void
155 gst_kate_enc_class_init (GstKateEncClass * klass)
156 {
157   GObjectClass *gobject_class;
158   GstElementClass *gstelement_class;
159
160   gobject_class = (GObjectClass *) klass;
161   gstelement_class = (GstElementClass *) klass;
162
163   gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_kate_enc_set_property);
164   gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_kate_enc_get_property);
165   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_kate_enc_dispose);
166
167   g_object_class_install_property (gobject_class, ARG_LANGUAGE,
168       g_param_spec_string ("language", "Language",
169           "The language of the stream (e.g. \"fr\" or \"fr_FR\" for French)",
170           "", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
171
172   g_object_class_install_property (gobject_class, ARG_CATEGORY,
173       g_param_spec_string ("category", "Category",
174           "The category of the stream", "",
175           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
176
177   g_object_class_install_property (gobject_class, ARG_GRANULE_RATE_NUM,
178       g_param_spec_int ("granule-rate-numerator", "Granule rate numerator",
179           "The numerator of the granule rate",
180           1, G_MAXINT, 1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
181
182   g_object_class_install_property (gobject_class, ARG_GRANULE_RATE_DEN,
183       g_param_spec_int ("granule-rate-denominator", "Granule rate denominator",
184           "The denominator of the granule rate",
185           1, G_MAXINT, 1000, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
186
187   g_object_class_install_property (gobject_class, ARG_GRANULE_SHIFT,
188       g_param_spec_int ("granule-shift", "Granule shift",
189           "The granule shift", 0, 64, 32,
190           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
191
192   g_object_class_install_property (gobject_class, ARG_ORIGINAL_CANVAS_WIDTH,
193       g_param_spec_int ("original-canvas-width", "Original canvas width",
194           "The width of the canvas this stream was authored for (0 is unspecified)",
195           0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
196
197   g_object_class_install_property (gobject_class, ARG_ORIGINAL_CANVAS_HEIGHT,
198       g_param_spec_int ("original-canvas-height", "Original canvas height",
199           "The height of the canvas this stream was authored for (0 is unspecified)",
200           0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
201
202   g_object_class_install_property (gobject_class, ARG_KEEPALIVE_MIN_TIME,
203       g_param_spec_float ("keepalive-min-time", "Keepalive mimimum time",
204           "Minimum time to emit keepalive packets (0 disables keepalive packets)",
205           0.0f, FLT_MAX, DEFAULT_KEEPALIVE_MIN_TIME,
206           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
207
208   g_object_class_install_property (gobject_class, ARG_DEFAULT_SPU_DURATION,
209       g_param_spec_float ("default-spu-duration", "Default SPU duration",
210           "The assumed max duration (in seconds) of SPUs with no duration specified",
211           0.0f, FLT_MAX, DEFAULT_DEFAULT_SPU_DURATION,
212           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
213
214   gstelement_class->change_state =
215       GST_DEBUG_FUNCPTR (gst_kate_enc_change_state);
216
217   gst_element_class_add_pad_template (gstelement_class,
218       gst_static_pad_template_get (&src_factory));
219   gst_element_class_add_pad_template (gstelement_class,
220       gst_static_pad_template_get (&sink_factory));
221
222   gst_element_class_set_static_metadata (gstelement_class,
223       "Kate stream encoder", "Codec/Encoder/Subtitle",
224       "Encodes Kate streams from text or subpictures",
225       "Vincent Penquerc'h <ogg.k.ogg.k@googlemail.com>");
226 }
227
228 /* initialize the new element
229  * instantiate pads and add them to element
230  * set functions
231  * initialize structure
232  */
233 static void
234 gst_kate_enc_init (GstKateEnc * ke)
235 {
236   GST_DEBUG_OBJECT (ke, "gst_kate_enc_init");
237
238   ke->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
239   gst_pad_set_chain_function (ke->sinkpad,
240       GST_DEBUG_FUNCPTR (gst_kate_enc_chain));
241   gst_pad_set_event_function (ke->sinkpad,
242       GST_DEBUG_FUNCPTR (gst_kate_enc_sink_event));
243   gst_element_add_pad (GST_ELEMENT (ke), ke->sinkpad);
244
245   ke->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
246   gst_pad_set_query_function (ke->srcpad,
247       GST_DEBUG_FUNCPTR (gst_kate_enc_source_query));
248   gst_element_add_pad (GST_ELEMENT (ke), ke->srcpad);
249
250   ke->initialized = FALSE;
251   ke->headers_sent = FALSE;
252   ke->last_timestamp = 0;
253   ke->latest_end_time = 0;
254   ke->language = NULL;
255   ke->category = NULL;
256   ke->format = GST_KATE_FORMAT_UNDEFINED;
257   ke->granule_rate_numerator = 1000;
258   ke->granule_rate_denominator = 1;
259   ke->granule_shift = 32;
260   ke->original_canvas_width = 0;
261   ke->original_canvas_height = 0;
262   ke->keepalive_min_time = DEFAULT_KEEPALIVE_MIN_TIME;
263   ke->default_spu_duration = DEFAULT_DEFAULT_SPU_DURATION;
264   memcpy (ke->spu_clut, gst_kate_spu_default_clut,
265       sizeof (gst_kate_spu_default_clut));
266   ke->delayed_spu = FALSE;
267   ke->delayed_bitmap = NULL;
268   ke->delayed_palette = NULL;
269   ke->delayed_region = NULL;
270 }
271
272 static void
273 gst_kate_enc_dispose (GObject * object)
274 {
275   GstKateEnc *ke = GST_KATE_ENC (object);
276
277   GST_LOG_OBJECT (ke, "disposing");
278
279   if (ke->language) {
280     g_free (ke->language);
281     ke->language = NULL;
282   }
283   if (ke->category) {
284     g_free (ke->category);
285     ke->category = NULL;
286   }
287
288   GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
289 }
290
291 static void
292 gst_kate_enc_set_property (GObject * object, guint prop_id,
293     const GValue * value, GParamSpec * pspec)
294 {
295   GstKateEnc *ke = GST_KATE_ENC (object);
296   const char *str;
297
298   switch (prop_id) {
299     case ARG_LANGUAGE:
300       if (ke->language) {
301         g_free (ke->language);
302         ke->language = NULL;
303       }
304       str = g_value_get_string (value);
305       if (str)
306         ke->language = g_strdup (str);
307       break;
308     case ARG_CATEGORY:
309       if (ke->category) {
310         g_free (ke->category);
311         ke->category = NULL;
312       }
313       str = g_value_get_string (value);
314       if (str)
315         ke->category = g_strdup (str);
316       break;
317     case ARG_GRANULE_RATE_NUM:
318       ke->granule_rate_numerator = g_value_get_int (value);
319       break;
320     case ARG_GRANULE_RATE_DEN:
321       ke->granule_rate_denominator = g_value_get_int (value);
322       break;
323     case ARG_GRANULE_SHIFT:
324       ke->granule_rate_denominator = g_value_get_int (value);
325       break;
326     case ARG_KEEPALIVE_MIN_TIME:
327       ke->keepalive_min_time = g_value_get_float (value);
328       break;
329     case ARG_ORIGINAL_CANVAS_WIDTH:
330       ke->original_canvas_width = g_value_get_int (value);
331       break;
332     case ARG_ORIGINAL_CANVAS_HEIGHT:
333       ke->original_canvas_height = g_value_get_int (value);
334       break;
335     case ARG_DEFAULT_SPU_DURATION:
336       ke->default_spu_duration = g_value_get_float (value);
337       break;
338     default:
339       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
340       break;
341   }
342 }
343
344 static void
345 gst_kate_enc_get_property (GObject * object, guint prop_id,
346     GValue * value, GParamSpec * pspec)
347 {
348   GstKateEnc *ke = GST_KATE_ENC (object);
349
350   switch (prop_id) {
351     case ARG_LANGUAGE:
352       g_value_set_string (value, ke->language ? ke->language : "");
353       break;
354     case ARG_CATEGORY:
355       g_value_set_string (value, ke->category ? ke->category : "");
356       break;
357     case ARG_GRANULE_RATE_NUM:
358       g_value_set_int (value, ke->granule_rate_numerator);
359       break;
360     case ARG_GRANULE_RATE_DEN:
361       g_value_set_int (value, ke->granule_rate_denominator);
362       break;
363     case ARG_GRANULE_SHIFT:
364       g_value_set_int (value, ke->granule_shift);
365       break;
366     case ARG_KEEPALIVE_MIN_TIME:
367       g_value_set_float (value, ke->keepalive_min_time);
368       break;
369     case ARG_ORIGINAL_CANVAS_WIDTH:
370       g_value_set_int (value, ke->original_canvas_width);
371       break;
372     case ARG_ORIGINAL_CANVAS_HEIGHT:
373       g_value_set_int (value, ke->original_canvas_height);
374       break;
375     case ARG_DEFAULT_SPU_DURATION:
376       g_value_set_float (value, ke->default_spu_duration);
377       break;
378     default:
379       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
380       break;
381   }
382 }
383
384 /* GstElement vmethod implementations */
385
386 static GstBuffer *
387 gst_kate_enc_create_buffer (GstKateEnc * ke, kate_packet * kp,
388     kate_int64_t granpos, GstClockTime timestamp, GstClockTime duration,
389     gboolean header)
390 {
391   GstBuffer *buffer;
392
393   g_return_val_if_fail (kp != NULL, NULL);
394   g_return_val_if_fail (kp->data != NULL, NULL);
395
396   buffer = gst_buffer_new_allocate (NULL, kp->nbytes, NULL);
397   if (G_UNLIKELY (!buffer)) {
398     GST_WARNING_OBJECT (ke, "Failed to allocate buffer for %u bytes",
399         (guint) kp->nbytes);
400     return NULL;
401   }
402
403   gst_buffer_fill (buffer, 0, kp->data, kp->nbytes);
404
405   /* same system as other Ogg codecs, as per ext/ogg/README:
406      OFFSET_END is the granulepos
407      OFFSET is its time representation
408    */
409   GST_BUFFER_OFFSET_END (buffer) = granpos;
410   GST_BUFFER_OFFSET (buffer) = timestamp;
411   GST_BUFFER_TIMESTAMP (buffer) = timestamp;
412   GST_BUFFER_DURATION (buffer) = duration;
413
414   return buffer;
415 }
416
417 static GstFlowReturn
418 gst_kate_enc_push_buffer (GstKateEnc * ke, GstBuffer * buffer)
419 {
420   GstFlowReturn flow;
421
422   ke->last_timestamp = GST_BUFFER_TIMESTAMP (buffer);
423   if (GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer) >
424       ke->latest_end_time) {
425     ke->latest_end_time =
426         GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer);
427   }
428
429   flow = gst_pad_push (ke->srcpad, buffer);
430   if (G_UNLIKELY (flow != GST_FLOW_OK)) {
431     GST_WARNING_OBJECT (ke->srcpad, "push flow: %s", gst_flow_get_name (flow));
432   }
433
434   return flow;
435 }
436
437 static GstFlowReturn
438 gst_kate_enc_push_and_free_kate_packet (GstKateEnc * ke, kate_packet * kp,
439     kate_int64_t granpos, GstClockTime timestamp, GstClockTime duration,
440     gboolean header)
441 {
442   GstBuffer *buffer;
443
444   GST_LOG_OBJECT (ke, "Creating buffer, %u bytes", (guint) kp->nbytes);
445   buffer =
446       gst_kate_enc_create_buffer (ke, kp, granpos, timestamp, duration, header);
447   if (G_UNLIKELY (!buffer)) {
448     GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
449         ("Failed to create buffer, %u bytes", (guint) kp->nbytes));
450     kate_packet_clear (kp);
451     return GST_FLOW_ERROR;
452   }
453
454   kate_packet_clear (kp);
455
456   return gst_kate_enc_push_buffer (ke, buffer);
457 }
458
459 static void
460 gst_kate_enc_metadata_set1 (const GstTagList * list, const gchar * tag,
461     gpointer kateenc)
462 {
463   GstKateEnc *ke = GST_KATE_ENC (kateenc);
464   GList *vc_list, *l;
465
466   vc_list = gst_tag_to_vorbis_comments (list, tag);
467
468   for (l = vc_list; l != NULL; l = l->next) {
469     const gchar *vc_string = (const gchar *) l->data;
470     gchar *key = NULL, *val = NULL;
471
472     GST_LOG_OBJECT (ke, "Kate comment: %s", vc_string);
473     if (gst_tag_parse_extended_comment (vc_string, &key, NULL, &val, TRUE)) {
474       kate_comment_add_tag (&ke->kc, key, val);
475       g_free (key);
476       g_free (val);
477     }
478   }
479
480   g_list_foreach (vc_list, (GFunc) g_free, NULL);
481   g_list_free (vc_list);
482 }
483
484 static void
485 gst_kate_enc_set_metadata (GstKateEnc * ke)
486 {
487   GstTagList *merged_tags;
488   const GstTagList *user_tags;
489
490   user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (ke));
491
492   GST_DEBUG_OBJECT (ke, "upstream tags = %" GST_PTR_FORMAT, ke->tags);
493   GST_DEBUG_OBJECT (ke, "user-set tags = %" GST_PTR_FORMAT, user_tags);
494
495   /* gst_tag_list_merge() will handle NULL for either or both lists fine */
496   merged_tags = gst_tag_list_merge (user_tags, ke->tags,
497       gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (ke)));
498
499   if (merged_tags) {
500     GST_DEBUG_OBJECT (ke, "merged   tags = %" GST_PTR_FORMAT, merged_tags);
501     gst_tag_list_foreach (merged_tags, gst_kate_enc_metadata_set1, ke);
502     gst_tag_list_unref (merged_tags);
503   }
504 }
505
506 static gboolean
507 gst_kate_enc_setcaps (GstKateEnc * ke, GstCaps * caps)
508 {
509   GST_LOG_OBJECT (ke, "input caps: %" GST_PTR_FORMAT, caps);
510
511   /* One day we could try to automatically set the category based on the
512    * input format, assuming that the input is subtitles. Currently that
513    * doesn't work yet though, because we send the header packets already from
514    * the sink event handler when receiving the newsegment event, so before
515    * the first buffer (might be tricky to change too, given that there could
516    * be no data at the beginning for a long time). So for now we just try to
517    * make sure people didn't set the category to something obviously wrong. */
518   if (ke->category != NULL) {
519     GstStructure *s = gst_caps_get_structure (caps, 0);
520
521     if (gst_structure_has_name (s, "text/x-raw")) {
522       const gchar *format;
523
524       format = gst_structure_get_string (s, "format");
525       if (strcmp (format, "utf8") == 0) {
526         ke->format = GST_KATE_FORMAT_TEXT_UTF8;
527       } else if (strcmp (format, "pango-markup") == 0) {
528         ke->format = GST_KATE_FORMAT_TEXT_PANGO_MARKUP;
529       }
530
531       if (strcmp (ke->category, "K-SPU") == 0 ||
532           strcmp (ke->category, "spu-subtitles") == 0) {
533         GST_ELEMENT_WARNING (ke, LIBRARY, SETTINGS, (NULL),
534             ("Category set to '%s', but input is text-based.", ke->category));
535       }
536     } else if (gst_structure_has_name (s, "subpicture/x-dvd")) {
537       ke->format = GST_KATE_FORMAT_SPU;
538       if (strcmp (ke->category, "SUB") == 0 ||
539           strcmp (ke->category, "subtitles") == 0) {
540         GST_ELEMENT_WARNING (ke, LIBRARY, SETTINGS, (NULL),
541             ("Category set to '%s', but input is subpictures.", ke->category));
542       }
543     } else {
544       GST_ERROR_OBJECT (ke, "unexpected input caps %" GST_PTR_FORMAT, caps);
545       return FALSE;
546     }
547   }
548
549   return TRUE;
550 }
551
552 static gboolean
553 gst_kate_enc_is_simple_subtitle_category (GstKateEnc * ke, const char *category)
554 {
555   static const char *const simple[] = {
556     "subtitles",
557     "SUB",
558     "spu-subtitles",
559     "K-SPU",
560   };
561   int n;
562
563   if (!category)
564     return FALSE;
565   for (n = 0; n < G_N_ELEMENTS (simple); ++n) {
566     if (!strcmp (category, simple[n]))
567       return TRUE;
568   }
569   return FALSE;
570 }
571
572 static GstFlowReturn
573 gst_kate_enc_send_headers (GstKateEnc * ke)
574 {
575   GstFlowReturn rflow = GST_FLOW_OK;
576   GstCaps *caps;
577   GList *headers = NULL, *item;
578
579   if (G_UNLIKELY (ke->category == NULL || *ke->category == '\0')) {
580     /* The error code is a bit of a lie, but seems most appropriate. */
581     GST_ELEMENT_ERROR (ke, LIBRARY, SETTINGS, (NULL),
582         ("The 'category' property must be set. For subtitles, set it to "
583             "either 'SUB' (text subtitles) or 'K-SPU' (dvd-style subtitles)"));
584     return GST_FLOW_ERROR;
585   }
586
587   gst_kate_enc_set_metadata (ke);
588
589   /* encode headers and store them in a list */
590   while (1) {
591     kate_packet kp;
592     int ret = kate_encode_headers (&ke->k, &ke->kc, &kp);
593     if (ret == 0) {
594       GstBuffer *buffer;
595
596       buffer = gst_kate_enc_create_buffer (ke, &kp, 0, 0, 0, TRUE);
597       if (!buffer) {
598         GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
599             ("Failed to create buffer, %u bytes", (guint) kp.nbytes));
600         rflow = GST_FLOW_ERROR;
601         break;
602       }
603       kate_packet_clear (&kp);
604
605       GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_HEADER);
606       headers = g_list_append (headers, buffer);
607     } else if (ret > 0) {
608       GST_LOG_OBJECT (ke, "Last header encoded");
609       break;
610     } else {
611       GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
612           ("Failed encoding headers: %s",
613               gst_kate_util_get_error_message (ret)));
614       rflow = GST_FLOW_ERROR;
615       break;
616     }
617   }
618
619   if (rflow == GST_FLOW_OK) {
620     if (gst_kate_enc_is_simple_subtitle_category (ke, ke->category)) {
621       caps = gst_kate_util_set_header_on_caps (&ke->element,
622           gst_caps_from_string ("subtitle/x-kate"), headers);
623     } else {
624       caps = gst_kate_util_set_header_on_caps (&ke->element,
625           gst_caps_from_string ("application/x-kate"), headers);
626     }
627     if (caps) {
628       GST_DEBUG_OBJECT (ke, "here are the caps: %" GST_PTR_FORMAT, caps);
629       gst_pad_set_caps (ke->srcpad, caps);
630       gst_caps_unref (caps);
631
632       GST_LOG_OBJECT (ke, "pushing headers");
633       item = headers;
634       while (item) {
635         GstBuffer *buffer = item->data;
636         GST_LOG_OBJECT (ke, "pushing header %p", buffer);
637         gst_kate_enc_push_buffer (ke, buffer);
638         item = item->next;
639       }
640     } else {
641       GST_ERROR_OBJECT (ke, "Failed to set headers on caps");
642     }
643   }
644
645   g_list_free (headers);
646
647   return rflow;
648 }
649
650 static GstFlowReturn
651 gst_kate_enc_flush_headers (GstKateEnc * ke)
652 {
653   GstFlowReturn rflow = GST_FLOW_OK;
654   if (!ke->headers_sent) {
655     GST_INFO_OBJECT (ke, "headers not yet sent, flushing");
656     rflow = gst_kate_enc_send_headers (ke);
657     if (rflow == GST_FLOW_OK) {
658       ke->headers_sent = TRUE;
659       GST_INFO_OBJECT (ke, "headers flushed");
660     } else {
661       GST_WARNING_OBJECT (ke, "Failed to flush headers: %s",
662           gst_flow_get_name (rflow));
663     }
664   }
665   return rflow;
666 }
667
668 static GstFlowReturn
669 gst_kate_enc_chain_push_packet (GstKateEnc * ke, kate_packet * kp,
670     GstClockTime start, GstClockTime duration)
671 {
672   kate_int64_t granpos;
673   GstFlowReturn rflow;
674
675   granpos = kate_encode_get_granule (&ke->k);
676   if (G_UNLIKELY (granpos < 0)) {
677     GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
678         ("Negative granpos for packet"));
679     kate_packet_clear (kp);
680     return GST_FLOW_ERROR;
681   }
682   rflow =
683       gst_kate_enc_push_and_free_kate_packet (ke, kp, granpos, start, duration,
684       FALSE);
685   if (G_UNLIKELY (rflow != GST_FLOW_OK)) {
686     GST_WARNING_OBJECT (ke, "Failed to push Kate packet");
687   }
688   return rflow;
689 }
690
691 static void
692 gst_kate_enc_generate_keepalive (GstKateEnc * ke, GstClockTime timestamp)
693 {
694   kate_packet kp;
695   int ret;
696   kate_float t = timestamp / (double) GST_SECOND;
697   GST_DEBUG_OBJECT (ke, "keepalive at %f", t);
698   ret = kate_encode_keepalive (&ke->k, t, &kp);
699   if (ret < 0) {
700     GST_WARNING_OBJECT (ke, "Failed to encode keepalive packet: %s",
701         gst_kate_util_get_error_message (ret));
702   } else {
703     kate_int64_t granpos = kate_encode_get_granule (&ke->k);
704     GST_LOG_OBJECT (ke, "Keepalive packet encoded");
705     if (gst_kate_enc_push_and_free_kate_packet (ke, &kp, granpos, timestamp, 0,
706             FALSE)) {
707       GST_WARNING_OBJECT (ke, "Failed to push keepalive packet");
708     }
709   }
710 }
711
712 static GstFlowReturn
713 gst_kate_enc_flush_waiting (GstKateEnc * ke, GstClockTime now)
714 {
715   GstFlowReturn rflow = GST_FLOW_OK;
716   if (ke->delayed_spu) {
717     int ret;
718     kate_packet kp;
719     GstClockTime keepalive_time;
720
721     kate_float t0 = ke->delayed_start / (double) GST_SECOND;
722     kate_float t1 = now / (double) GST_SECOND;
723
724     GST_INFO_OBJECT (ke,
725         "We had a delayed SPU packet starting at %f, flushing at %f (assumed duration %f)",
726         t0, t1, t1 - t0);
727
728     ret = kate_encode_text (&ke->k, t0, t1, "", 0, &kp);
729     if (G_UNLIKELY (ret < 0)) {
730       GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
731           ("Failed to encode text packet: %s",
732               gst_kate_util_get_error_message (ret)));
733       rflow = GST_FLOW_ERROR;
734     } else {
735       rflow =
736           gst_kate_enc_chain_push_packet (ke, &kp, ke->delayed_start,
737           now - ke->delayed_start + 1);
738     }
739
740     if (rflow == GST_FLOW_OK) {
741       GST_DEBUG_OBJECT (ke, "delayed SPU packet flushed");
742     } else {
743       GST_WARNING_OBJECT (ke, "Failed to flush delayed SPU packet: %s",
744           gst_flow_get_name (rflow));
745     }
746
747     /* forget it even if we couldn't flush it */
748     ke->delayed_spu = FALSE;
749
750     /* free the delayed data */
751     g_free (ke->delayed_bitmap->pixels);
752     g_free (ke->delayed_bitmap);
753     ke->delayed_bitmap = NULL;
754     g_free (ke->delayed_palette->colors);
755     g_free (ke->delayed_palette);
756     ke->delayed_palette = NULL;
757     g_free (ke->delayed_region);
758     ke->delayed_region = NULL;
759
760     /* now that we've flushed the packet, we want to insert keepalives as requested */
761     if (ke->keepalive_min_time > 0.0f && t1 > t0) {
762       GST_INFO_OBJECT (ke, "generating keepalives at %f from %f to %f",
763           ke->keepalive_min_time, t0, t1);
764       for (keepalive_time = ke->delayed_start;
765           (keepalive_time += ke->keepalive_min_time * GST_SECOND) < now;) {
766         GST_INFO_OBJECT (ke, "generating keepalive at %f",
767             keepalive_time / (double) GST_SECOND);
768         gst_kate_enc_generate_keepalive (ke, keepalive_time);
769       }
770     }
771   }
772   return rflow;
773 }
774
775 static GstFlowReturn
776 gst_kate_enc_chain_spu (GstKateEnc * ke, GstBuffer * buf)
777 {
778   kate_packet kp;
779   kate_region *kregion;
780   kate_bitmap *kbitmap;
781   kate_palette *kpalette;
782   GstFlowReturn rflow;
783   int ret = 0;
784
785   /* allocate region, bitmap, and palette, in case we have to delay encoding them */
786   kregion = (kate_region *) g_malloc (sizeof (kate_region));
787   kbitmap = (kate_bitmap *) g_malloc (sizeof (kate_bitmap));
788   kpalette = (kate_palette *) g_malloc (sizeof (kate_palette));
789   if (!kregion || !kpalette || !kbitmap) {
790     if (kregion)
791       g_free (kregion);
792     if (kbitmap)
793       g_free (kbitmap);
794     if (kpalette)
795       g_free (kpalette);
796     GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL), ("Out of memory"));
797     return GST_FLOW_ERROR;
798   }
799
800   rflow = gst_kate_spu_decode_spu (ke, buf, kregion, kbitmap, kpalette);
801   if (G_UNLIKELY (rflow != GST_FLOW_OK)) {
802     GST_ERROR_OBJECT (ke, "Failed to decode incoming SPU");
803 #if 0
804     {
805       static int spu_count = 0;
806       FILE *f;
807       char name[32];
808       snprintf (name, sizeof (name), "/tmp/bad_spu_%04d", spu_count++);
809       name[sizeof (name) - 1] = 0;
810       f = fopen (name, "w");
811       if (f) {
812         fwrite (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf), 1, f);
813         fclose (f);
814       }
815     }
816 #endif
817   } else if (G_UNLIKELY (kbitmap->width == 0 || kbitmap->height == 0)) {
818     /* there are some DVDs (well, at least one) where some dimwits put in a wholly transparent full screen 720x576 SPU !!!!?! */
819     GST_WARNING_OBJECT (ke, "SPU is totally invisible - dimwits");
820     rflow = GST_FLOW_OK;
821   } else {
822     /* timestamp offsets are hidden in the SPU packets */
823     GstClockTime start =
824         GST_BUFFER_TIMESTAMP (buf) + GST_KATE_STM_TO_GST (ke->show_time);
825     GstClockTime stop =
826         GST_BUFFER_TIMESTAMP (buf) + GST_KATE_STM_TO_GST (ke->hide_time);
827     kate_float t0 = start / (double) GST_SECOND;
828     kate_float t1 = stop / (double) GST_SECOND;
829     GST_DEBUG_OBJECT (ke, "buf ts %f, start/show %hu/%hu",
830         GST_BUFFER_TIMESTAMP (buf) / (double) GST_SECOND, ke->show_time,
831         ke->hide_time);
832
833 #if 0
834     {
835       static int spu_count = 0;
836       FILE *f;
837       char name[32];
838       snprintf (name, sizeof (name), "/tmp/spu_%04d", spu_count++);
839       name[sizeof (name) - 1] = 0;
840       f = fopen (name, "w");
841       if (f) {
842         fwrite (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf), 1, f);
843         fclose (f);
844       }
845     }
846 #endif
847     GST_DEBUG_OBJECT (ke, "Encoding %zux%zu SPU: (%zu bytes) from %f to %f",
848         kbitmap->width, kbitmap->height, gst_buffer_get_size (buf), t0, t1);
849
850     ret = kate_encode_set_region (&ke->k, kregion);
851     if (G_UNLIKELY (ret < 0)) {
852       GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
853           ("Failed to set region: %s", gst_kate_util_get_error_message (ret)));
854       rflow = GST_FLOW_ERROR;
855     } else {
856       ret = kate_encode_set_palette (&ke->k, kpalette);
857       if (G_UNLIKELY (ret < 0)) {
858         GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
859             ("Failed to set palette: %s",
860                 gst_kate_util_get_error_message (ret)));
861         rflow = GST_FLOW_ERROR;
862       } else {
863         ret = kate_encode_set_bitmap (&ke->k, kbitmap);
864         if (G_UNLIKELY (ret < 0)) {
865           GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
866               ("Failed to set bitmap: %s",
867                   gst_kate_util_get_error_message (ret)));
868           rflow = GST_FLOW_ERROR;
869         } else {
870           /* Some SPUs have no hide time - so I'm going to delay the encoding of the packet
871              till either a suitable event happens, and the time of this event will be used
872              as the end time of this SPU, which will then be encoded and sent off. Suitable
873              events are the arrival of a subsequent SPU (eg, this SPU will replace the one
874              with no end), EOS, a new segment event, or a time threshold being reached */
875           if (ke->hide_time <= ke->show_time) {
876             GST_INFO_OBJECT (ke,
877                 "Cannot encode SPU packet now, hide time is now known (starting at %f) - delaying",
878                 t0);
879             ke->delayed_spu = TRUE;
880             ke->delayed_start = start;
881             ke->delayed_bitmap = kbitmap;
882             ke->delayed_palette = kpalette;
883             ke->delayed_region = kregion;
884             rflow = GST_FLOW_OK;
885           } else {
886             ret = kate_encode_text (&ke->k, t0, t1, "", 0, &kp);
887             if (G_UNLIKELY (ret < 0)) {
888               GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
889                   ("Failed to encode empty text for SPU buffer: %s",
890                       gst_kate_util_get_error_message (ret)));
891               rflow = GST_FLOW_ERROR;
892             } else {
893               rflow =
894                   gst_kate_enc_chain_push_packet (ke, &kp, start,
895                   stop - start + 1);
896             }
897           }
898         }
899       }
900     }
901
902     if (!ke->delayed_spu) {
903       g_free (kpalette->colors);
904       g_free (kpalette);
905       g_free (kbitmap->pixels);
906       g_free (kbitmap);
907       g_free (kregion);
908     }
909   }
910
911   return rflow;
912 }
913
914 static GstFlowReturn
915 gst_kate_enc_chain_text (GstKateEnc * ke, GstBuffer * buf)
916 {
917   kate_packet kp = { 0 };
918   int ret = 0;
919   GstFlowReturn rflow;
920   GstClockTime start = GST_BUFFER_TIMESTAMP (buf);
921   GstClockTime stop = GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf);
922
923   if (ke->format == GST_KATE_FORMAT_TEXT_PANGO_MARKUP) {
924     ret = kate_encode_set_markup_type (&ke->k, kate_markup_simple);
925   } else if (ke->format == GST_KATE_FORMAT_TEXT_UTF8) {
926     ret = kate_encode_set_markup_type (&ke->k, kate_markup_none);
927   } else {
928     return GST_FLOW_ERROR;
929   }
930
931   if (G_UNLIKELY (ret < 0)) {
932     GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
933         ("Failed to set markup type: %s",
934             gst_kate_util_get_error_message (ret)));
935     rflow = GST_FLOW_ERROR;
936   } else {
937     GstMapInfo info;
938     gboolean need_unmap = TRUE;
939     kate_float t0 = start / (double) GST_SECOND;
940     kate_float t1 = stop / (double) GST_SECOND;
941
942     if (!gst_buffer_map (buf, &info, GST_MAP_READ)) {
943       info.data = NULL;
944       info.size = 0;
945       need_unmap = FALSE;
946       GST_WARNING_OBJECT (buf, "Failed to map buffer");
947     }
948
949     GST_LOG_OBJECT (ke, "Encoding text: %*.*s (%u bytes) from %f to %f",
950         (int) info.size, (int) info.size, info.data, (int) info.size, t0, t1);
951     ret = kate_encode_text (&ke->k, t0, t1, (const char *) info.data, info.size,
952         &kp);
953     if (G_UNLIKELY (ret < 0)) {
954       GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
955           ("Failed to encode text: %s", gst_kate_util_get_error_message (ret)));
956       rflow = GST_FLOW_ERROR;
957     } else {
958       rflow = gst_kate_enc_chain_push_packet (ke, &kp, start, stop - start + 1);
959     }
960     if (need_unmap)
961       gst_buffer_unmap (buf, &info);
962   }
963
964   return rflow;
965 }
966
967 /* chain function
968  * this function does the actual processing
969  */
970 static GstFlowReturn
971 gst_kate_enc_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
972 {
973   GstKateEnc *ke = GST_KATE_ENC (parent);
974   GstFlowReturn rflow;
975
976   GST_DEBUG_OBJECT (ke, "got packet, %zu bytes", gst_buffer_get_size (buf));
977
978   /* first push headers if we haven't done that yet */
979   rflow = gst_kate_enc_flush_headers (ke);
980
981   if (G_LIKELY (rflow == GST_FLOW_OK)) {
982     /* flush any packet we had waiting */
983     rflow = gst_kate_enc_flush_waiting (ke, GST_BUFFER_TIMESTAMP (buf));
984
985     if (G_LIKELY (rflow == GST_FLOW_OK)) {
986       if (ke->format == GST_KATE_FORMAT_SPU) {
987         /* encode a kate_bitmap */
988         rflow = gst_kate_enc_chain_spu (ke, buf);
989       } else {
990         /* encode text */
991         rflow = gst_kate_enc_chain_text (ke, buf);
992       }
993     }
994   }
995
996   gst_buffer_unref (buf);
997
998   return rflow;
999 }
1000
1001 static GstStateChangeReturn
1002 gst_kate_enc_change_state (GstElement * element, GstStateChange transition)
1003 {
1004   GstKateEnc *ke = GST_KATE_ENC (element);
1005   GstStateChangeReturn res;
1006   int ret;
1007
1008   GST_INFO_OBJECT (ke, "gst_kate_enc_change_state");
1009
1010   switch (transition) {
1011     case GST_STATE_CHANGE_NULL_TO_READY:
1012       ke->tags = gst_tag_list_new_empty ();
1013       break;
1014     case GST_STATE_CHANGE_READY_TO_PAUSED:
1015       GST_DEBUG_OBJECT (ke, "READY -> PAUSED, initializing kate state");
1016       ret = kate_info_init (&ke->ki);
1017       if (ret < 0) {
1018         GST_WARNING_OBJECT (ke, "failed to initialize kate info structure: %s",
1019             gst_kate_util_get_error_message (ret));
1020         break;
1021       }
1022       if (ke->language) {
1023         ret = kate_info_set_language (&ke->ki, ke->language);
1024         if (ret < 0) {
1025           GST_WARNING_OBJECT (ke, "failed to set stream language: %s",
1026               gst_kate_util_get_error_message (ret));
1027           break;
1028         }
1029       }
1030       if (ke->category) {
1031         ret = kate_info_set_category (&ke->ki, ke->category);
1032         if (ret < 0) {
1033           GST_WARNING_OBJECT (ke, "failed to set stream category: %s",
1034               gst_kate_util_get_error_message (ret));
1035           break;
1036         }
1037       }
1038       ret =
1039           kate_info_set_original_canvas_size (&ke->ki,
1040           ke->original_canvas_width, ke->original_canvas_height);
1041       if (ret < 0) {
1042         GST_WARNING_OBJECT (ke, "failed to set original canvas size: %s",
1043             gst_kate_util_get_error_message (ret));
1044         break;
1045       }
1046       ret = kate_comment_init (&ke->kc);
1047       if (ret < 0) {
1048         GST_WARNING_OBJECT (ke,
1049             "failed to initialize kate comment structure: %s",
1050             gst_kate_util_get_error_message (ret));
1051         break;
1052       }
1053       ret = kate_encode_init (&ke->k, &ke->ki);
1054       if (ret < 0) {
1055         GST_WARNING_OBJECT (ke, "failed to initialize kate state: %s",
1056             gst_kate_util_get_error_message (ret));
1057         break;
1058       }
1059       ke->headers_sent = FALSE;
1060       ke->initialized = TRUE;
1061       ke->last_timestamp = 0;
1062       ke->latest_end_time = 0;
1063       ke->format = GST_KATE_FORMAT_UNDEFINED;
1064       break;
1065     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1066       break;
1067     case GST_STATE_CHANGE_READY_TO_NULL:
1068       gst_tag_list_unref (ke->tags);
1069       ke->tags = NULL;
1070       break;
1071     default:
1072       break;
1073   }
1074
1075   res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1076   if (res == GST_STATE_CHANGE_FAILURE) {
1077     GST_WARNING_OBJECT (ke, "Parent failed to change state");
1078     return res;
1079   }
1080
1081   switch (transition) {
1082     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1083       break;
1084     case GST_STATE_CHANGE_PAUSED_TO_READY:
1085       GST_DEBUG_OBJECT (ke, "PAUSED -> READY, clearing kate state");
1086       if (ke->initialized) {
1087         kate_clear (&ke->k);
1088         kate_info_clear (&ke->ki);
1089         kate_comment_clear (&ke->kc);
1090         ke->initialized = FALSE;
1091         ke->last_timestamp = 0;
1092         ke->latest_end_time = 0;
1093       }
1094       break;
1095     case GST_STATE_CHANGE_READY_TO_NULL:
1096       break;
1097     default:
1098       break;
1099   }
1100
1101   GST_DEBUG_OBJECT (ke, "State change done");
1102
1103   return res;
1104 }
1105
1106 static GstClockTime
1107 gst_kate_enc_granule_time (kate_state * k, gint64 granulepos)
1108 {
1109   float t;
1110
1111   if (granulepos == -1)
1112     return -1;
1113
1114   t = kate_granule_time (k->ki, granulepos);
1115   return t * GST_SECOND;
1116 }
1117
1118 /*
1119 conversions on the sink:
1120   - nothing
1121 conversions on the source:
1122   - default is granules at num/den rate
1123   - default -> time is possible
1124   - bytes do not mean anything, packets can be any number of bytes, and we
1125     have no way to know the number of bytes emitted without decoding
1126 */
1127
1128 static gboolean
1129 gst_kate_enc_convert (GstPad * pad, GstFormat src_fmt, gint64 src_val,
1130     GstFormat * dest_fmt, gint64 * dest_val)
1131 {
1132   GstKateEnc *ke;
1133   gboolean res = FALSE;
1134
1135   if (src_fmt == *dest_fmt) {
1136     *dest_val = src_val;
1137     return TRUE;
1138   }
1139
1140   ke = GST_KATE_ENC (gst_pad_get_parent (pad));
1141
1142   if (!ke->initialized) {
1143     GST_WARNING_OBJECT (ke, "not initialized yet");
1144     gst_object_unref (ke);
1145     return FALSE;
1146   }
1147
1148   if (src_fmt == GST_FORMAT_BYTES || *dest_fmt == GST_FORMAT_BYTES) {
1149     GST_WARNING_OBJECT (ke, "unsupported format");
1150     gst_object_unref (ke);
1151     return FALSE;
1152   }
1153
1154   switch (src_fmt) {
1155     case GST_FORMAT_DEFAULT:
1156       switch (*dest_fmt) {
1157         case GST_FORMAT_TIME:
1158           *dest_val = gst_kate_enc_granule_time (&ke->k, src_val);
1159           res = TRUE;
1160           break;
1161         default:
1162           res = FALSE;
1163           break;
1164       }
1165       break;
1166     default:
1167       res = FALSE;
1168       break;
1169   }
1170
1171   if (!res) {
1172     GST_WARNING_OBJECT (ke, "unsupported format");
1173   }
1174
1175   gst_object_unref (ke);
1176   return res;
1177 }
1178
1179 static gboolean
1180 gst_kate_enc_source_query (GstPad * pad, GstObject * parent, GstQuery * query)
1181 {
1182   gboolean res = FALSE;
1183
1184   GST_DEBUG ("source query %d", GST_QUERY_TYPE (query));
1185
1186   switch (GST_QUERY_TYPE (query)) {
1187     case GST_QUERY_CONVERT:
1188     {
1189       GstFormat src_fmt, dest_fmt;
1190       gint64 src_val, dest_val;
1191
1192       gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
1193       if (!gst_kate_enc_convert (pad, src_fmt, src_val, &dest_fmt, &dest_val)) {
1194         return gst_pad_query_default (pad, parent, query);
1195       }
1196       gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
1197       res = TRUE;
1198     }
1199       break;
1200     default:
1201       res = gst_pad_query_default (pad, parent, query);
1202       break;
1203   }
1204
1205   return res;
1206 }
1207
1208 static gboolean
1209 gst_kate_enc_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
1210 {
1211   GstKateEnc *ke = GST_KATE_ENC (parent);
1212   const GstStructure *structure;
1213   gboolean ret;
1214
1215   switch (GST_EVENT_TYPE (event)) {
1216     case GST_EVENT_CAPS:
1217     {
1218       GstCaps *caps;
1219
1220       gst_event_parse_caps (event, &caps);
1221       ret = gst_kate_enc_setcaps (ke, caps);
1222       gst_event_unref (event);
1223       break;
1224     }
1225     case GST_EVENT_SEGMENT:
1226       GST_LOG_OBJECT (ke, "Got newsegment event");
1227       if (ke->initialized) {
1228         GST_LOG_OBJECT (ke, "ensuring all headers are in");
1229         if (gst_kate_enc_flush_headers (ke) != GST_FLOW_OK) {
1230           GST_WARNING_OBJECT (ke, "Failed to flush headers");
1231         } else {
1232           GstSegment seg;
1233
1234           gst_event_copy_segment (event, &seg);
1235           if (seg.format != GST_FORMAT_TIME
1236               || !GST_CLOCK_TIME_IS_VALID (seg.start)) {
1237             GST_WARNING_OBJECT (ke,
1238                 "No time in newsegment event %p, format %d, timestamp %"
1239                 G_GINT64_FORMAT, event, (int) seg.format, seg.start);
1240             /* to be safe, we'd need to generate a keepalive anyway, but we'd have to guess at the timestamp to use; a
1241                good guess would be the last known timestamp plus the keepalive time, but if we then get a packet with a
1242                timestamp less than this, it would fail to encode, which would be Bad. If we don't encode a keepalive, we
1243                run the risk of stalling the pipeline and hanging, which is Very Bad. Oh dear. We can't exit(-1), can we ? */
1244           } else {
1245             float t = seg.start / (double) GST_SECOND;
1246
1247             if (ke->delayed_spu
1248                 && t - ke->delayed_start / (double) GST_SECOND >=
1249                 ke->default_spu_duration) {
1250               if (G_UNLIKELY (gst_kate_enc_flush_waiting (ke,
1251                           seg.start) != GST_FLOW_OK)) {
1252                 GST_WARNING_OBJECT (ke, "Failed to encode delayed packet");
1253                 /* continue with new segment handling anyway */
1254               }
1255             }
1256
1257             GST_LOG_OBJECT (ke, "ts %f, last %f (min %f)", t,
1258                 ke->last_timestamp / (double) GST_SECOND,
1259                 ke->keepalive_min_time);
1260             if (ke->keepalive_min_time > 0.0f
1261                 && t - ke->last_timestamp / (double) GST_SECOND >=
1262                 ke->keepalive_min_time) {
1263               /* we only generate a keepalive if there is no SPU waiting, as it would
1264                  mean out of sequence start times - and granulepos */
1265               if (!ke->delayed_spu) {
1266                 gst_kate_enc_generate_keepalive (ke, seg.start);
1267               }
1268             }
1269           }
1270         }
1271       }
1272       ret = gst_pad_push_event (ke->srcpad, event);
1273       break;
1274
1275     case GST_EVENT_CUSTOM_DOWNSTREAM:
1276       GST_LOG_OBJECT (ke, "Got custom downstream event");
1277       /* adapted from the dvdsubdec element */
1278       structure = gst_event_get_structure (event);
1279       if (structure != NULL
1280           && gst_structure_has_name (structure, "application/x-gst-dvd")) {
1281         if (ke->initialized) {
1282           GST_LOG_OBJECT (ke, "ensuring all headers are in");
1283           if (gst_kate_enc_flush_headers (ke) != GST_FLOW_OK) {
1284             GST_WARNING_OBJECT (ke, "Failed to flush headers");
1285           } else {
1286             const gchar *event_name =
1287                 gst_structure_get_string (structure, "event");
1288             if (event_name) {
1289               if (!strcmp (event_name, "dvd-spu-clut-change")) {
1290                 gchar name[16];
1291                 int idx;
1292                 gboolean found;
1293                 gint value;
1294                 GST_INFO_OBJECT (ke, "New CLUT received");
1295                 for (idx = 0; idx < 16; ++idx) {
1296                   g_snprintf (name, sizeof (name), "clut%02d", idx);
1297                   found = gst_structure_get_int (structure, name, &value);
1298                   if (found) {
1299                     ke->spu_clut[idx] = value;
1300                   } else {
1301                     GST_WARNING_OBJECT (ke,
1302                         "DVD CLUT event did not contain %s field", name);
1303                   }
1304                 }
1305               } else if (!strcmp (event_name, "dvd-lang-codes")) {
1306                 /* we can't know which stream corresponds to us */
1307               }
1308             } else {
1309               GST_WARNING_OBJECT (ke, "custom downstream event with no name");
1310             }
1311           }
1312         }
1313       }
1314       ret = gst_pad_push_event (ke->srcpad, event);
1315       break;
1316
1317     case GST_EVENT_TAG:
1318       GST_LOG_OBJECT (ke, "Got tag event");
1319       if (ke->tags) {
1320         GstTagList *list;
1321
1322         gst_event_parse_tag (event, &list);
1323         gst_tag_list_insert (ke->tags, list,
1324             gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (ke)));
1325       } else {
1326         g_assert_not_reached ();
1327       }
1328       ret = gst_pad_event_default (pad, parent, event);
1329       break;
1330
1331     case GST_EVENT_EOS:
1332       GST_INFO_OBJECT (ke, "Got EOS event");
1333       if (ke->initialized) {
1334         GST_LOG_OBJECT (ke, "ensuring all headers are in");
1335         if (gst_kate_enc_flush_headers (ke) != GST_FLOW_OK) {
1336           GST_WARNING_OBJECT (ke, "Failed to flush headers");
1337         } else {
1338           kate_packet kp;
1339           int ret;
1340           GstClockTime delayed_end =
1341               ke->delayed_start + ke->default_spu_duration * GST_SECOND;
1342
1343           if (G_UNLIKELY (gst_kate_enc_flush_waiting (ke,
1344                       delayed_end) != GST_FLOW_OK)) {
1345             GST_WARNING_OBJECT (ke, "Failed to encode delayed packet");
1346             /* continue with EOS handling anyway */
1347           }
1348
1349           ret = kate_encode_finish (&ke->k, -1, &kp);
1350           if (ret < 0) {
1351             GST_WARNING_OBJECT (ke, "Failed to encode EOS packet: %s",
1352                 gst_kate_util_get_error_message (ret));
1353           } else {
1354             kate_int64_t granpos = kate_encode_get_granule (&ke->k);
1355             GST_LOG_OBJECT (ke, "EOS packet encoded");
1356             if (gst_kate_enc_push_and_free_kate_packet (ke, &kp, granpos,
1357                     ke->latest_end_time, 0, FALSE)) {
1358               GST_WARNING_OBJECT (ke, "Failed to push EOS packet");
1359             }
1360           }
1361         }
1362       }
1363       ret = gst_pad_event_default (pad, parent, event);
1364       break;
1365
1366     default:
1367       GST_LOG_OBJECT (ke, "Got unhandled event");
1368       ret = gst_pad_event_default (pad, parent, event);
1369       break;
1370   }
1371
1372   return ret;
1373 }