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