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