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>
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:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
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.
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
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.
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.
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.
48 * SECTION:element-kateenc
53 * This element encodes Kate streams
54 * <ulink url="http://libkate.googlecode.com/">Kate</ulink> is a free codec
55 * for text based data, such as subtitles. Any number of kate streams can be
56 * embedded in an Ogg stream.
59 * libkate (see above url) is needed to build this plugin.
61 * <title>Example pipeline</title>
63 * This encodes a DVD SPU track to a Kate stream:
65 * gst-launch dvdreadsrc ! dvddemux ! dvdsubparse ! kateenc category=spu-subtitles ! oggmux ! filesink location=test.ogg
72 * - should we automatically pick up the language code from the
73 * upstream event tags if none was set via the property?
74 * - turn category property into an enum (freestyle text property in
75 * combination with supposedly strictly defined known values that
76 * aren't even particularly human-readable is just not very nice)? */
85 #include <gst/gsttagsetter.h>
86 #include <gst/tag/tag.h>
89 #include "gstkateutil.h"
90 #include "gstkatespu.h"
91 #include "gstkateenc.h"
93 GST_DEBUG_CATEGORY_EXTERN (gst_kateenc_debug);
94 #define GST_CAT_DEFAULT gst_kateenc_debug
96 /* Filter signals and args */
108 ARG_GRANULE_RATE_NUM,
109 ARG_GRANULE_RATE_DEN,
111 ARG_KEEPALIVE_MIN_TIME,
112 ARG_ORIGINAL_CANVAS_WIDTH,
113 ARG_ORIGINAL_CANVAS_HEIGHT,
114 ARG_DEFAULT_SPU_DURATION,
117 #define DEFAULT_KEEPALIVE_MIN_TIME 2.5f
118 #define DEFAULT_DEFAULT_SPU_DURATION 1.5f
120 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
123 GST_STATIC_CAPS ("text/x-raw, format={ pango-markup, utf8 }; "
124 GST_KATE_SPU_MIME_TYPE)
127 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
130 GST_STATIC_CAPS ("subtitle/x-kate; application/x-kate")
133 static void gst_kate_enc_set_property (GObject * object, guint prop_id,
134 const GValue * value, GParamSpec * pspec);
135 static void gst_kate_enc_get_property (GObject * object, guint prop_id,
136 GValue * value, GParamSpec * pspec);
137 static void gst_kate_enc_dispose (GObject * object);
139 static gboolean gst_kate_enc_setcaps (GstKateEnc * ke, GstCaps * caps);
140 static GstFlowReturn gst_kate_enc_chain (GstPad * pad, GstObject * parent,
142 static GstStateChangeReturn gst_kate_enc_change_state (GstElement * element,
143 GstStateChange transition);
144 static gboolean gst_kate_enc_sink_event (GstPad * pad, GstObject * parent,
146 static gboolean gst_kate_enc_source_query (GstPad * pad, GstObject * parent,
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));
153 /* initialize the plugin's class */
155 gst_kate_enc_class_init (GstKateEncClass * klass)
157 GObjectClass *gobject_class;
158 GstElementClass *gstelement_class;
160 gobject_class = (GObjectClass *) klass;
161 gstelement_class = (GstElementClass *) klass;
163 gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_kate_enc_set_property);
164 gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_kate_enc_get_property);
165 gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_kate_enc_dispose);
167 g_object_class_install_property (gobject_class, ARG_LANGUAGE,
168 g_param_spec_string ("language", "Language",
169 "The language of the stream (e.g. \"fr\" or \"fr_FR\" for French)",
170 "", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
172 g_object_class_install_property (gobject_class, ARG_CATEGORY,
173 g_param_spec_string ("category", "Category",
174 "The category of the stream", "",
175 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
177 g_object_class_install_property (gobject_class, ARG_GRANULE_RATE_NUM,
178 g_param_spec_int ("granule-rate-numerator", "Granule rate numerator",
179 "The numerator of the granule rate",
180 1, G_MAXINT, 1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
182 g_object_class_install_property (gobject_class, ARG_GRANULE_RATE_DEN,
183 g_param_spec_int ("granule-rate-denominator", "Granule rate denominator",
184 "The denominator of the granule rate",
185 1, G_MAXINT, 1000, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
187 g_object_class_install_property (gobject_class, ARG_GRANULE_SHIFT,
188 g_param_spec_int ("granule-shift", "Granule shift",
189 "The granule shift", 0, 64, 32,
190 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
192 g_object_class_install_property (gobject_class, ARG_ORIGINAL_CANVAS_WIDTH,
193 g_param_spec_int ("original-canvas-width", "Original canvas width",
194 "The width of the canvas this stream was authored for (0 is unspecified)",
195 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
197 g_object_class_install_property (gobject_class, ARG_ORIGINAL_CANVAS_HEIGHT,
198 g_param_spec_int ("original-canvas-height", "Original canvas height",
199 "The height of the canvas this stream was authored for (0 is unspecified)",
200 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
202 g_object_class_install_property (gobject_class, ARG_KEEPALIVE_MIN_TIME,
203 g_param_spec_float ("keepalive-min-time", "Keepalive mimimum time",
204 "Minimum time to emit keepalive packets (0 disables keepalive packets)",
205 0.0f, FLT_MAX, DEFAULT_KEEPALIVE_MIN_TIME,
206 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
208 g_object_class_install_property (gobject_class, ARG_DEFAULT_SPU_DURATION,
209 g_param_spec_float ("default-spu-duration", "Default SPU duration",
210 "The assumed max duration (in seconds) of SPUs with no duration specified",
211 0.0f, FLT_MAX, DEFAULT_DEFAULT_SPU_DURATION,
212 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
214 gstelement_class->change_state =
215 GST_DEBUG_FUNCPTR (gst_kate_enc_change_state);
217 gst_element_class_add_pad_template (gstelement_class,
218 gst_static_pad_template_get (&src_factory));
219 gst_element_class_add_pad_template (gstelement_class,
220 gst_static_pad_template_get (&sink_factory));
222 gst_element_class_set_static_metadata (gstelement_class,
223 "Kate stream encoder", "Codec/Encoder/Subtitle",
224 "Encodes Kate streams from text or subpictures",
225 "Vincent Penquerc'h <ogg.k.ogg.k@googlemail.com>");
228 /* initialize the new element
229 * instantiate pads and add them to element
231 * initialize structure
234 gst_kate_enc_init (GstKateEnc * ke)
236 GST_DEBUG_OBJECT (ke, "gst_kate_enc_init");
238 ke->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
239 gst_pad_set_chain_function (ke->sinkpad,
240 GST_DEBUG_FUNCPTR (gst_kate_enc_chain));
241 gst_pad_set_event_function (ke->sinkpad,
242 GST_DEBUG_FUNCPTR (gst_kate_enc_sink_event));
243 gst_element_add_pad (GST_ELEMENT (ke), ke->sinkpad);
245 ke->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
246 gst_pad_set_query_function (ke->srcpad,
247 GST_DEBUG_FUNCPTR (gst_kate_enc_source_query));
248 gst_element_add_pad (GST_ELEMENT (ke), ke->srcpad);
250 ke->initialized = FALSE;
251 ke->headers_sent = FALSE;
252 ke->last_timestamp = 0;
253 ke->latest_end_time = 0;
256 ke->format = GST_KATE_FORMAT_UNDEFINED;
257 ke->granule_rate_numerator = 1000;
258 ke->granule_rate_denominator = 1;
259 ke->granule_shift = 32;
260 ke->original_canvas_width = 0;
261 ke->original_canvas_height = 0;
262 ke->keepalive_min_time = DEFAULT_KEEPALIVE_MIN_TIME;
263 ke->default_spu_duration = DEFAULT_DEFAULT_SPU_DURATION;
264 memcpy (ke->spu_clut, gst_kate_spu_default_clut,
265 sizeof (gst_kate_spu_default_clut));
266 ke->delayed_spu = FALSE;
267 ke->delayed_bitmap = NULL;
268 ke->delayed_palette = NULL;
269 ke->delayed_region = NULL;
273 gst_kate_enc_dispose (GObject * object)
275 GstKateEnc *ke = GST_KATE_ENC (object);
277 GST_LOG_OBJECT (ke, "disposing");
280 g_free (ke->language);
284 g_free (ke->category);
288 GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
292 gst_kate_enc_set_property (GObject * object, guint prop_id,
293 const GValue * value, GParamSpec * pspec)
295 GstKateEnc *ke = GST_KATE_ENC (object);
301 g_free (ke->language);
304 str = g_value_get_string (value);
306 ke->language = g_strdup (str);
310 g_free (ke->category);
313 str = g_value_get_string (value);
315 ke->category = g_strdup (str);
317 case ARG_GRANULE_RATE_NUM:
318 ke->granule_rate_numerator = g_value_get_int (value);
320 case ARG_GRANULE_RATE_DEN:
321 ke->granule_rate_denominator = g_value_get_int (value);
323 case ARG_GRANULE_SHIFT:
324 ke->granule_rate_denominator = g_value_get_int (value);
326 case ARG_KEEPALIVE_MIN_TIME:
327 ke->keepalive_min_time = g_value_get_float (value);
329 case ARG_ORIGINAL_CANVAS_WIDTH:
330 ke->original_canvas_width = g_value_get_int (value);
332 case ARG_ORIGINAL_CANVAS_HEIGHT:
333 ke->original_canvas_height = g_value_get_int (value);
335 case ARG_DEFAULT_SPU_DURATION:
336 ke->default_spu_duration = g_value_get_float (value);
339 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
345 gst_kate_enc_get_property (GObject * object, guint prop_id,
346 GValue * value, GParamSpec * pspec)
348 GstKateEnc *ke = GST_KATE_ENC (object);
352 g_value_set_string (value, ke->language ? ke->language : "");
355 g_value_set_string (value, ke->category ? ke->category : "");
357 case ARG_GRANULE_RATE_NUM:
358 g_value_set_int (value, ke->granule_rate_numerator);
360 case ARG_GRANULE_RATE_DEN:
361 g_value_set_int (value, ke->granule_rate_denominator);
363 case ARG_GRANULE_SHIFT:
364 g_value_set_int (value, ke->granule_shift);
366 case ARG_KEEPALIVE_MIN_TIME:
367 g_value_set_float (value, ke->keepalive_min_time);
369 case ARG_ORIGINAL_CANVAS_WIDTH:
370 g_value_set_int (value, ke->original_canvas_width);
372 case ARG_ORIGINAL_CANVAS_HEIGHT:
373 g_value_set_int (value, ke->original_canvas_height);
375 case ARG_DEFAULT_SPU_DURATION:
376 g_value_set_float (value, ke->default_spu_duration);
379 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
384 /* GstElement vmethod implementations */
387 gst_kate_enc_create_buffer (GstKateEnc * ke, kate_packet * kp,
388 kate_int64_t granpos, GstClockTime timestamp, GstClockTime duration,
393 g_return_val_if_fail (kp != NULL, NULL);
394 g_return_val_if_fail (kp->data != NULL, NULL);
396 buffer = gst_buffer_new_allocate (NULL, kp->nbytes, NULL);
397 if (G_UNLIKELY (!buffer)) {
398 GST_WARNING_OBJECT (ke, "Failed to allocate buffer for %u bytes",
403 gst_buffer_fill (buffer, 0, kp->data, kp->nbytes);
405 /* same system as other Ogg codecs, as per ext/ogg/README:
406 OFFSET_END is the granulepos
407 OFFSET is its time representation
409 GST_BUFFER_OFFSET_END (buffer) = granpos;
410 GST_BUFFER_OFFSET (buffer) = timestamp;
411 GST_BUFFER_TIMESTAMP (buffer) = timestamp;
412 GST_BUFFER_DURATION (buffer) = duration;
418 gst_kate_enc_push_buffer (GstKateEnc * ke, GstBuffer * buffer)
422 ke->last_timestamp = GST_BUFFER_TIMESTAMP (buffer);
423 if (GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer) >
424 ke->latest_end_time) {
425 ke->latest_end_time =
426 GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer);
429 flow = gst_pad_push (ke->srcpad, buffer);
430 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
431 GST_WARNING_OBJECT (ke->srcpad, "push flow: %s", gst_flow_get_name (flow));
438 gst_kate_enc_push_and_free_kate_packet (GstKateEnc * ke, kate_packet * kp,
439 kate_int64_t granpos, GstClockTime timestamp, GstClockTime duration,
444 GST_LOG_OBJECT (ke, "Creating buffer, %u bytes", (guint) kp->nbytes);
446 gst_kate_enc_create_buffer (ke, kp, granpos, timestamp, duration, header);
447 if (G_UNLIKELY (!buffer)) {
448 GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
449 ("Failed to create buffer, %u bytes", (guint) kp->nbytes));
450 kate_packet_clear (kp);
451 return GST_FLOW_ERROR;
454 kate_packet_clear (kp);
456 return gst_kate_enc_push_buffer (ke, buffer);
460 gst_kate_enc_metadata_set1 (const GstTagList * list, const gchar * tag,
463 GstKateEnc *ke = GST_KATE_ENC (kateenc);
466 vc_list = gst_tag_to_vorbis_comments (list, tag);
468 for (l = vc_list; l != NULL; l = l->next) {
469 const gchar *vc_string = (const gchar *) l->data;
470 gchar *key = NULL, *val = NULL;
472 GST_LOG_OBJECT (ke, "Kate comment: %s", vc_string);
473 if (gst_tag_parse_extended_comment (vc_string, &key, NULL, &val, TRUE)) {
474 kate_comment_add_tag (&ke->kc, key, val);
480 g_list_foreach (vc_list, (GFunc) g_free, NULL);
481 g_list_free (vc_list);
485 gst_kate_enc_set_metadata (GstKateEnc * ke)
487 GstTagList *merged_tags;
488 const GstTagList *user_tags;
490 user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (ke));
492 GST_DEBUG_OBJECT (ke, "upstream tags = %" GST_PTR_FORMAT, ke->tags);
493 GST_DEBUG_OBJECT (ke, "user-set tags = %" GST_PTR_FORMAT, user_tags);
495 /* gst_tag_list_merge() will handle NULL for either or both lists fine */
496 merged_tags = gst_tag_list_merge (user_tags, ke->tags,
497 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (ke)));
500 GST_DEBUG_OBJECT (ke, "merged tags = %" GST_PTR_FORMAT, merged_tags);
501 gst_tag_list_foreach (merged_tags, gst_kate_enc_metadata_set1, ke);
502 gst_tag_list_unref (merged_tags);
507 gst_kate_enc_setcaps (GstKateEnc * ke, GstCaps * caps)
509 GST_LOG_OBJECT (ke, "input caps: %" GST_PTR_FORMAT, caps);
511 /* One day we could try to automatically set the category based on the
512 * input format, assuming that the input is subtitles. Currently that
513 * doesn't work yet though, because we send the header packets already from
514 * the sink event handler when receiving the newsegment event, so before
515 * the first buffer (might be tricky to change too, given that there could
516 * be no data at the beginning for a long time). So for now we just try to
517 * make sure people didn't set the category to something obviously wrong. */
518 if (ke->category != NULL) {
519 GstStructure *s = gst_caps_get_structure (caps, 0);
521 if (gst_structure_has_name (s, "text/x-raw")) {
524 format = gst_structure_get_string (s, "format");
525 if (strcmp (format, "utf8") == 0) {
526 ke->format = GST_KATE_FORMAT_TEXT_UTF8;
527 } else if (strcmp (format, "pango-markup") == 0) {
528 ke->format = GST_KATE_FORMAT_TEXT_PANGO_MARKUP;
531 if (strcmp (ke->category, "K-SPU") == 0 ||
532 strcmp (ke->category, "spu-subtitles") == 0) {
533 GST_ELEMENT_WARNING (ke, LIBRARY, SETTINGS, (NULL),
534 ("Category set to '%s', but input is text-based.", ke->category));
536 } else if (gst_structure_has_name (s, "subpicture/x-dvd")) {
537 ke->format = GST_KATE_FORMAT_SPU;
538 if (strcmp (ke->category, "SUB") == 0 ||
539 strcmp (ke->category, "subtitles") == 0) {
540 GST_ELEMENT_WARNING (ke, LIBRARY, SETTINGS, (NULL),
541 ("Category set to '%s', but input is subpictures.", ke->category));
544 GST_ERROR_OBJECT (ke, "unexpected input caps %" GST_PTR_FORMAT, caps);
553 gst_kate_enc_is_simple_subtitle_category (GstKateEnc * ke, const char *category)
555 static const char *const simple[] = {
565 for (n = 0; n < G_N_ELEMENTS (simple); ++n) {
566 if (!strcmp (category, simple[n]))
573 gst_kate_enc_send_headers (GstKateEnc * ke)
575 GstFlowReturn rflow = GST_FLOW_OK;
577 GList *headers = NULL, *item;
579 if (G_UNLIKELY (ke->category == NULL || *ke->category == '\0')) {
580 /* The error code is a bit of a lie, but seems most appropriate. */
581 GST_ELEMENT_ERROR (ke, LIBRARY, SETTINGS, (NULL),
582 ("The 'category' property must be set. For subtitles, set it to "
583 "either 'SUB' (text subtitles) or 'K-SPU' (dvd-style subtitles)"));
584 return GST_FLOW_ERROR;
587 gst_kate_enc_set_metadata (ke);
589 /* encode headers and store them in a list */
592 int ret = kate_encode_headers (&ke->k, &ke->kc, &kp);
596 buffer = gst_kate_enc_create_buffer (ke, &kp, 0, 0, 0, TRUE);
598 GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
599 ("Failed to create buffer, %u bytes", (guint) kp.nbytes));
600 rflow = GST_FLOW_ERROR;
603 kate_packet_clear (&kp);
605 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_HEADER);
606 headers = g_list_append (headers, buffer);
607 } else if (ret > 0) {
608 GST_LOG_OBJECT (ke, "Last header encoded");
611 GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
612 ("Failed encoding headers: %s",
613 gst_kate_util_get_error_message (ret)));
614 rflow = GST_FLOW_ERROR;
619 if (rflow == GST_FLOW_OK) {
620 if (gst_kate_enc_is_simple_subtitle_category (ke, ke->category)) {
621 caps = gst_kate_util_set_header_on_caps (&ke->element,
622 gst_caps_from_string ("subtitle/x-kate"), headers);
624 caps = gst_kate_util_set_header_on_caps (&ke->element,
625 gst_caps_from_string ("application/x-kate"), headers);
628 GST_DEBUG_OBJECT (ke, "here are the caps: %" GST_PTR_FORMAT, caps);
629 gst_pad_set_caps (ke->srcpad, caps);
630 gst_caps_unref (caps);
632 GST_LOG_OBJECT (ke, "pushing headers");
635 GstBuffer *buffer = item->data;
636 GST_LOG_OBJECT (ke, "pushing header %p", buffer);
637 gst_kate_enc_push_buffer (ke, buffer);
641 GST_ERROR_OBJECT (ke, "Failed to set headers on caps");
645 g_list_free (headers);
651 gst_kate_enc_flush_headers (GstKateEnc * ke)
653 GstFlowReturn rflow = GST_FLOW_OK;
654 if (!ke->headers_sent) {
655 GST_INFO_OBJECT (ke, "headers not yet sent, flushing");
656 rflow = gst_kate_enc_send_headers (ke);
657 if (rflow == GST_FLOW_OK) {
658 ke->headers_sent = TRUE;
659 GST_INFO_OBJECT (ke, "headers flushed");
661 GST_WARNING_OBJECT (ke, "Failed to flush headers: %s",
662 gst_flow_get_name (rflow));
669 gst_kate_enc_chain_push_packet (GstKateEnc * ke, kate_packet * kp,
670 GstClockTime start, GstClockTime duration)
672 kate_int64_t granpos;
675 granpos = kate_encode_get_granule (&ke->k);
676 if (G_UNLIKELY (granpos < 0)) {
677 GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
678 ("Negative granpos for packet"));
679 kate_packet_clear (kp);
680 return GST_FLOW_ERROR;
683 gst_kate_enc_push_and_free_kate_packet (ke, kp, granpos, start, duration,
685 if (G_UNLIKELY (rflow != GST_FLOW_OK)) {
686 GST_WARNING_OBJECT (ke, "Failed to push Kate packet");
692 gst_kate_enc_generate_keepalive (GstKateEnc * ke, GstClockTime timestamp)
696 kate_float t = timestamp / (double) GST_SECOND;
697 GST_DEBUG_OBJECT (ke, "keepalive at %f", t);
698 ret = kate_encode_keepalive (&ke->k, t, &kp);
700 GST_WARNING_OBJECT (ke, "Failed to encode keepalive packet: %s",
701 gst_kate_util_get_error_message (ret));
703 kate_int64_t granpos = kate_encode_get_granule (&ke->k);
704 GST_LOG_OBJECT (ke, "Keepalive packet encoded");
705 if (gst_kate_enc_push_and_free_kate_packet (ke, &kp, granpos, timestamp, 0,
707 GST_WARNING_OBJECT (ke, "Failed to push keepalive packet");
713 gst_kate_enc_flush_waiting (GstKateEnc * ke, GstClockTime now)
715 GstFlowReturn rflow = GST_FLOW_OK;
716 if (ke->delayed_spu) {
719 GstClockTime keepalive_time;
721 kate_float t0 = ke->delayed_start / (double) GST_SECOND;
722 kate_float t1 = now / (double) GST_SECOND;
725 "We had a delayed SPU packet starting at %f, flushing at %f (assumed duration %f)",
728 ret = kate_encode_text (&ke->k, t0, t1, "", 0, &kp);
729 if (G_UNLIKELY (ret < 0)) {
730 GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
731 ("Failed to encode text packet: %s",
732 gst_kate_util_get_error_message (ret)));
733 rflow = GST_FLOW_ERROR;
736 gst_kate_enc_chain_push_packet (ke, &kp, ke->delayed_start,
737 now - ke->delayed_start + 1);
740 if (rflow == GST_FLOW_OK) {
741 GST_DEBUG_OBJECT (ke, "delayed SPU packet flushed");
743 GST_WARNING_OBJECT (ke, "Failed to flush delayed SPU packet: %s",
744 gst_flow_get_name (rflow));
747 /* forget it even if we couldn't flush it */
748 ke->delayed_spu = FALSE;
750 /* free the delayed data */
751 g_free (ke->delayed_bitmap->pixels);
752 g_free (ke->delayed_bitmap);
753 ke->delayed_bitmap = NULL;
754 g_free (ke->delayed_palette->colors);
755 g_free (ke->delayed_palette);
756 ke->delayed_palette = NULL;
757 g_free (ke->delayed_region);
758 ke->delayed_region = NULL;
760 /* now that we've flushed the packet, we want to insert keepalives as requested */
761 if (ke->keepalive_min_time > 0.0f && t1 > t0) {
762 GST_INFO_OBJECT (ke, "generating keepalives at %f from %f to %f",
763 ke->keepalive_min_time, t0, t1);
764 for (keepalive_time = ke->delayed_start;
765 (keepalive_time += ke->keepalive_min_time * GST_SECOND) < now;) {
766 GST_INFO_OBJECT (ke, "generating keepalive at %f",
767 keepalive_time / (double) GST_SECOND);
768 gst_kate_enc_generate_keepalive (ke, keepalive_time);
776 gst_kate_enc_chain_spu (GstKateEnc * ke, GstBuffer * buf)
779 kate_region *kregion;
780 kate_bitmap *kbitmap;
781 kate_palette *kpalette;
785 /* allocate region, bitmap, and palette, in case we have to delay encoding them */
786 kregion = (kate_region *) g_malloc (sizeof (kate_region));
787 kbitmap = (kate_bitmap *) g_malloc (sizeof (kate_bitmap));
788 kpalette = (kate_palette *) g_malloc (sizeof (kate_palette));
789 if (!kregion || !kpalette || !kbitmap) {
796 GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL), ("Out of memory"));
797 return GST_FLOW_ERROR;
800 rflow = gst_kate_spu_decode_spu (ke, buf, kregion, kbitmap, kpalette);
801 if (G_UNLIKELY (rflow != GST_FLOW_OK)) {
802 GST_ERROR_OBJECT (ke, "Failed to decode incoming SPU");
805 static int spu_count = 0;
808 snprintf (name, sizeof (name), "/tmp/bad_spu_%04d", spu_count++);
809 name[sizeof (name) - 1] = 0;
810 f = fopen (name, "w");
812 fwrite (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf), 1, f);
817 } else if (G_UNLIKELY (kbitmap->width == 0 || kbitmap->height == 0)) {
818 /* there are some DVDs (well, at least one) where some dimwits put in a wholly transparent full screen 720x576 SPU !!!!?! */
819 GST_WARNING_OBJECT (ke, "SPU is totally invisible - dimwits");
822 /* timestamp offsets are hidden in the SPU packets */
824 GST_BUFFER_TIMESTAMP (buf) + GST_KATE_STM_TO_GST (ke->show_time);
826 GST_BUFFER_TIMESTAMP (buf) + GST_KATE_STM_TO_GST (ke->hide_time);
827 kate_float t0 = start / (double) GST_SECOND;
828 kate_float t1 = stop / (double) GST_SECOND;
829 GST_DEBUG_OBJECT (ke, "buf ts %f, start/show %hu/%hu",
830 GST_BUFFER_TIMESTAMP (buf) / (double) GST_SECOND, ke->show_time,
835 static int spu_count = 0;
838 snprintf (name, sizeof (name), "/tmp/spu_%04d", spu_count++);
839 name[sizeof (name) - 1] = 0;
840 f = fopen (name, "w");
842 fwrite (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf), 1, f);
847 GST_DEBUG_OBJECT (ke, "Encoding %zux%zu SPU: (%zu bytes) from %f to %f",
848 kbitmap->width, kbitmap->height, gst_buffer_get_size (buf), t0, t1);
850 ret = kate_encode_set_region (&ke->k, kregion);
851 if (G_UNLIKELY (ret < 0)) {
852 GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
853 ("Failed to set region: %s", gst_kate_util_get_error_message (ret)));
854 rflow = GST_FLOW_ERROR;
856 ret = kate_encode_set_palette (&ke->k, kpalette);
857 if (G_UNLIKELY (ret < 0)) {
858 GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
859 ("Failed to set palette: %s",
860 gst_kate_util_get_error_message (ret)));
861 rflow = GST_FLOW_ERROR;
863 ret = kate_encode_set_bitmap (&ke->k, kbitmap);
864 if (G_UNLIKELY (ret < 0)) {
865 GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
866 ("Failed to set bitmap: %s",
867 gst_kate_util_get_error_message (ret)));
868 rflow = GST_FLOW_ERROR;
870 /* Some SPUs have no hide time - so I'm going to delay the encoding of the packet
871 till either a suitable event happens, and the time of this event will be used
872 as the end time of this SPU, which will then be encoded and sent off. Suitable
873 events are the arrival of a subsequent SPU (eg, this SPU will replace the one
874 with no end), EOS, a new segment event, or a time threshold being reached */
875 if (ke->hide_time <= ke->show_time) {
877 "Cannot encode SPU packet now, hide time is now known (starting at %f) - delaying",
879 ke->delayed_spu = TRUE;
880 ke->delayed_start = start;
881 ke->delayed_bitmap = kbitmap;
882 ke->delayed_palette = kpalette;
883 ke->delayed_region = kregion;
886 ret = kate_encode_text (&ke->k, t0, t1, "", 0, &kp);
887 if (G_UNLIKELY (ret < 0)) {
888 GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
889 ("Failed to encode empty text for SPU buffer: %s",
890 gst_kate_util_get_error_message (ret)));
891 rflow = GST_FLOW_ERROR;
894 gst_kate_enc_chain_push_packet (ke, &kp, start,
902 if (!ke->delayed_spu) {
903 g_free (kpalette->colors);
905 g_free (kbitmap->pixels);
915 gst_kate_enc_chain_text (GstKateEnc * ke, GstBuffer * buf)
917 kate_packet kp = { 0 };
920 GstClockTime start = GST_BUFFER_TIMESTAMP (buf);
921 GstClockTime stop = GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf);
923 if (ke->format == GST_KATE_FORMAT_TEXT_PANGO_MARKUP) {
924 ret = kate_encode_set_markup_type (&ke->k, kate_markup_simple);
925 } else if (ke->format == GST_KATE_FORMAT_TEXT_UTF8) {
926 ret = kate_encode_set_markup_type (&ke->k, kate_markup_none);
928 return GST_FLOW_ERROR;
931 if (G_UNLIKELY (ret < 0)) {
932 GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
933 ("Failed to set markup type: %s",
934 gst_kate_util_get_error_message (ret)));
935 rflow = GST_FLOW_ERROR;
938 gboolean need_unmap = TRUE;
939 kate_float t0 = start / (double) GST_SECOND;
940 kate_float t1 = stop / (double) GST_SECOND;
942 if (!gst_buffer_map (buf, &info, GST_MAP_READ)) {
946 GST_WARNING_OBJECT (buf, "Failed to map buffer");
949 GST_LOG_OBJECT (ke, "Encoding text: %*.*s (%u bytes) from %f to %f",
950 (int) info.size, (int) info.size, info.data, (int) info.size, t0, t1);
951 ret = kate_encode_text (&ke->k, t0, t1, (const char *) info.data, info.size,
953 if (G_UNLIKELY (ret < 0)) {
954 GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
955 ("Failed to encode text: %s", gst_kate_util_get_error_message (ret)));
956 rflow = GST_FLOW_ERROR;
958 rflow = gst_kate_enc_chain_push_packet (ke, &kp, start, stop - start + 1);
961 gst_buffer_unmap (buf, &info);
968 * this function does the actual processing
971 gst_kate_enc_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
973 GstKateEnc *ke = GST_KATE_ENC (parent);
976 GST_DEBUG_OBJECT (ke, "got packet, %zu bytes", gst_buffer_get_size (buf));
978 /* first push headers if we haven't done that yet */
979 rflow = gst_kate_enc_flush_headers (ke);
981 if (G_LIKELY (rflow == GST_FLOW_OK)) {
982 /* flush any packet we had waiting */
983 rflow = gst_kate_enc_flush_waiting (ke, GST_BUFFER_TIMESTAMP (buf));
985 if (G_LIKELY (rflow == GST_FLOW_OK)) {
986 if (ke->format == GST_KATE_FORMAT_SPU) {
987 /* encode a kate_bitmap */
988 rflow = gst_kate_enc_chain_spu (ke, buf);
991 rflow = gst_kate_enc_chain_text (ke, buf);
996 gst_buffer_unref (buf);
1001 static GstStateChangeReturn
1002 gst_kate_enc_change_state (GstElement * element, GstStateChange transition)
1004 GstKateEnc *ke = GST_KATE_ENC (element);
1005 GstStateChangeReturn res;
1008 GST_INFO_OBJECT (ke, "gst_kate_enc_change_state");
1010 switch (transition) {
1011 case GST_STATE_CHANGE_NULL_TO_READY:
1012 ke->tags = gst_tag_list_new_empty ();
1014 case GST_STATE_CHANGE_READY_TO_PAUSED:
1015 GST_DEBUG_OBJECT (ke, "READY -> PAUSED, initializing kate state");
1016 ret = kate_info_init (&ke->ki);
1018 GST_WARNING_OBJECT (ke, "failed to initialize kate info structure: %s",
1019 gst_kate_util_get_error_message (ret));
1023 ret = kate_info_set_language (&ke->ki, ke->language);
1025 GST_WARNING_OBJECT (ke, "failed to set stream language: %s",
1026 gst_kate_util_get_error_message (ret));
1031 ret = kate_info_set_category (&ke->ki, ke->category);
1033 GST_WARNING_OBJECT (ke, "failed to set stream category: %s",
1034 gst_kate_util_get_error_message (ret));
1039 kate_info_set_original_canvas_size (&ke->ki,
1040 ke->original_canvas_width, ke->original_canvas_height);
1042 GST_WARNING_OBJECT (ke, "failed to set original canvas size: %s",
1043 gst_kate_util_get_error_message (ret));
1046 ret = kate_comment_init (&ke->kc);
1048 GST_WARNING_OBJECT (ke,
1049 "failed to initialize kate comment structure: %s",
1050 gst_kate_util_get_error_message (ret));
1053 ret = kate_encode_init (&ke->k, &ke->ki);
1055 GST_WARNING_OBJECT (ke, "failed to initialize kate state: %s",
1056 gst_kate_util_get_error_message (ret));
1059 ke->headers_sent = FALSE;
1060 ke->initialized = TRUE;
1061 ke->last_timestamp = 0;
1062 ke->latest_end_time = 0;
1063 ke->format = GST_KATE_FORMAT_UNDEFINED;
1065 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1067 case GST_STATE_CHANGE_READY_TO_NULL:
1068 gst_tag_list_unref (ke->tags);
1075 res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1076 if (res == GST_STATE_CHANGE_FAILURE) {
1077 GST_WARNING_OBJECT (ke, "Parent failed to change state");
1081 switch (transition) {
1082 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1084 case GST_STATE_CHANGE_PAUSED_TO_READY:
1085 GST_DEBUG_OBJECT (ke, "PAUSED -> READY, clearing kate state");
1086 if (ke->initialized) {
1087 kate_clear (&ke->k);
1088 kate_info_clear (&ke->ki);
1089 kate_comment_clear (&ke->kc);
1090 ke->initialized = FALSE;
1091 ke->last_timestamp = 0;
1092 ke->latest_end_time = 0;
1095 case GST_STATE_CHANGE_READY_TO_NULL:
1101 GST_DEBUG_OBJECT (ke, "State change done");
1107 gst_kate_enc_granule_time (kate_state * k, gint64 granulepos)
1111 if (granulepos == -1)
1114 t = kate_granule_time (k->ki, granulepos);
1115 return t * GST_SECOND;
1119 conversions on the sink:
1121 conversions on the source:
1122 - default is granules at num/den rate
1123 - default -> time is possible
1124 - bytes do not mean anything, packets can be any number of bytes, and we
1125 have no way to know the number of bytes emitted without decoding
1129 gst_kate_enc_convert (GstPad * pad, GstFormat src_fmt, gint64 src_val,
1130 GstFormat * dest_fmt, gint64 * dest_val)
1133 gboolean res = FALSE;
1135 if (src_fmt == *dest_fmt) {
1136 *dest_val = src_val;
1140 ke = GST_KATE_ENC (gst_pad_get_parent (pad));
1142 if (!ke->initialized) {
1143 GST_WARNING_OBJECT (ke, "not initialized yet");
1144 gst_object_unref (ke);
1148 if (src_fmt == GST_FORMAT_BYTES || *dest_fmt == GST_FORMAT_BYTES) {
1149 GST_WARNING_OBJECT (ke, "unsupported format");
1150 gst_object_unref (ke);
1155 case GST_FORMAT_DEFAULT:
1156 switch (*dest_fmt) {
1157 case GST_FORMAT_TIME:
1158 *dest_val = gst_kate_enc_granule_time (&ke->k, src_val);
1172 GST_WARNING_OBJECT (ke, "unsupported format");
1175 gst_object_unref (ke);
1180 gst_kate_enc_source_query (GstPad * pad, GstObject * parent, GstQuery * query)
1182 gboolean res = FALSE;
1184 GST_DEBUG ("source query %d", GST_QUERY_TYPE (query));
1186 switch (GST_QUERY_TYPE (query)) {
1187 case GST_QUERY_CONVERT:
1189 GstFormat src_fmt, dest_fmt;
1190 gint64 src_val, dest_val;
1192 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
1193 if (!gst_kate_enc_convert (pad, src_fmt, src_val, &dest_fmt, &dest_val)) {
1194 return gst_pad_query_default (pad, parent, query);
1196 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
1201 res = gst_pad_query_default (pad, parent, query);
1209 gst_kate_enc_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
1211 GstKateEnc *ke = GST_KATE_ENC (parent);
1212 const GstStructure *structure;
1215 switch (GST_EVENT_TYPE (event)) {
1216 case GST_EVENT_CAPS:
1220 gst_event_parse_caps (event, &caps);
1221 ret = gst_kate_enc_setcaps (ke, caps);
1222 gst_event_unref (event);
1225 case GST_EVENT_SEGMENT:
1226 GST_LOG_OBJECT (ke, "Got newsegment event");
1227 if (ke->initialized) {
1228 GST_LOG_OBJECT (ke, "ensuring all headers are in");
1229 if (gst_kate_enc_flush_headers (ke) != GST_FLOW_OK) {
1230 GST_WARNING_OBJECT (ke, "Failed to flush headers");
1234 gst_event_copy_segment (event, &seg);
1235 if (seg.format != GST_FORMAT_TIME
1236 || !GST_CLOCK_TIME_IS_VALID (seg.start)) {
1237 GST_WARNING_OBJECT (ke,
1238 "No time in newsegment event %p, format %d, timestamp %"
1239 G_GINT64_FORMAT, event, (int) seg.format, seg.start);
1240 /* to be safe, we'd need to generate a keepalive anyway, but we'd have to guess at the timestamp to use; a
1241 good guess would be the last known timestamp plus the keepalive time, but if we then get a packet with a
1242 timestamp less than this, it would fail to encode, which would be Bad. If we don't encode a keepalive, we
1243 run the risk of stalling the pipeline and hanging, which is Very Bad. Oh dear. We can't exit(-1), can we ? */
1245 float t = seg.start / (double) GST_SECOND;
1248 && t - ke->delayed_start / (double) GST_SECOND >=
1249 ke->default_spu_duration) {
1250 if (G_UNLIKELY (gst_kate_enc_flush_waiting (ke,
1251 seg.start) != GST_FLOW_OK)) {
1252 GST_WARNING_OBJECT (ke, "Failed to encode delayed packet");
1253 /* continue with new segment handling anyway */
1257 GST_LOG_OBJECT (ke, "ts %f, last %f (min %f)", t,
1258 ke->last_timestamp / (double) GST_SECOND,
1259 ke->keepalive_min_time);
1260 if (ke->keepalive_min_time > 0.0f
1261 && t - ke->last_timestamp / (double) GST_SECOND >=
1262 ke->keepalive_min_time) {
1263 /* we only generate a keepalive if there is no SPU waiting, as it would
1264 mean out of sequence start times - and granulepos */
1265 if (!ke->delayed_spu) {
1266 gst_kate_enc_generate_keepalive (ke, seg.start);
1272 ret = gst_pad_push_event (ke->srcpad, event);
1275 case GST_EVENT_CUSTOM_DOWNSTREAM:
1276 GST_LOG_OBJECT (ke, "Got custom downstream event");
1277 /* adapted from the dvdsubdec element */
1278 structure = gst_event_get_structure (event);
1279 if (structure != NULL
1280 && gst_structure_has_name (structure, "application/x-gst-dvd")) {
1281 if (ke->initialized) {
1282 GST_LOG_OBJECT (ke, "ensuring all headers are in");
1283 if (gst_kate_enc_flush_headers (ke) != GST_FLOW_OK) {
1284 GST_WARNING_OBJECT (ke, "Failed to flush headers");
1286 const gchar *event_name =
1287 gst_structure_get_string (structure, "event");
1289 if (!strcmp (event_name, "dvd-spu-clut-change")) {
1294 GST_INFO_OBJECT (ke, "New CLUT received");
1295 for (idx = 0; idx < 16; ++idx) {
1296 g_snprintf (name, sizeof (name), "clut%02d", idx);
1297 found = gst_structure_get_int (structure, name, &value);
1299 ke->spu_clut[idx] = value;
1301 GST_WARNING_OBJECT (ke,
1302 "DVD CLUT event did not contain %s field", name);
1305 } else if (!strcmp (event_name, "dvd-lang-codes")) {
1306 /* we can't know which stream corresponds to us */
1309 GST_WARNING_OBJECT (ke, "custom downstream event with no name");
1314 ret = gst_pad_push_event (ke->srcpad, event);
1318 GST_LOG_OBJECT (ke, "Got tag event");
1322 gst_event_parse_tag (event, &list);
1323 gst_tag_list_insert (ke->tags, list,
1324 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (ke)));
1326 g_assert_not_reached ();
1328 ret = gst_pad_event_default (pad, parent, event);
1332 GST_INFO_OBJECT (ke, "Got EOS event");
1333 if (ke->initialized) {
1334 GST_LOG_OBJECT (ke, "ensuring all headers are in");
1335 if (gst_kate_enc_flush_headers (ke) != GST_FLOW_OK) {
1336 GST_WARNING_OBJECT (ke, "Failed to flush headers");
1340 GstClockTime delayed_end =
1341 ke->delayed_start + ke->default_spu_duration * GST_SECOND;
1343 if (G_UNLIKELY (gst_kate_enc_flush_waiting (ke,
1344 delayed_end) != GST_FLOW_OK)) {
1345 GST_WARNING_OBJECT (ke, "Failed to encode delayed packet");
1346 /* continue with EOS handling anyway */
1349 ret = kate_encode_finish (&ke->k, -1, &kp);
1351 GST_WARNING_OBJECT (ke, "Failed to encode EOS packet: %s",
1352 gst_kate_util_get_error_message (ret));
1354 kate_int64_t granpos = kate_encode_get_granule (&ke->k);
1355 GST_LOG_OBJECT (ke, "EOS packet encoded");
1356 if (gst_kate_enc_push_and_free_kate_packet (ke, &kp, granpos,
1357 ke->latest_end_time, 0, FALSE)) {
1358 GST_WARNING_OBJECT (ke, "Failed to push EOS packet");
1363 ret = gst_pad_event_default (pad, parent, event);
1367 GST_LOG_OBJECT (ke, "Got unhandled event");
1368 ret = gst_pad_event_default (pad, parent, event);