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