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