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