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
52 * This element encodes Kate streams.
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
58 * libkate (see above url) is needed to build this plugin.
62 * This encodes a DVD SPU track to a Kate stream:
64 * gst-launch-1.0 dvdreadsrc ! dvddemux ! dvdsubparse ! kateenc category=spu-subtitles ! oggmux ! filesink location=test.ogg
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)? */
83 #include <gst/gsttagsetter.h>
84 #include <gst/tag/tag.h>
87 #include "gstkateutil.h"
88 #include "gstkatespu.h"
89 #include "gstkateenc.h"
91 GST_DEBUG_CATEGORY_EXTERN (gst_kateenc_debug);
92 #define GST_CAT_DEFAULT gst_kateenc_debug
94 /* Filter signals and args */
106 ARG_GRANULE_RATE_NUM,
107 ARG_GRANULE_RATE_DEN,
109 ARG_KEEPALIVE_MIN_TIME,
110 ARG_ORIGINAL_CANVAS_WIDTH,
111 ARG_ORIGINAL_CANVAS_HEIGHT,
112 ARG_DEFAULT_SPU_DURATION,
115 #define DEFAULT_KEEPALIVE_MIN_TIME 2.5f
116 #define DEFAULT_DEFAULT_SPU_DURATION 1.5f
118 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
121 GST_STATIC_CAPS ("text/x-raw, format={ pango-markup, utf8 }; "
122 GST_KATE_SPU_MIME_TYPE)
125 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
128 GST_STATIC_CAPS ("subtitle/x-kate; application/x-kate")
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);
137 static gboolean gst_kate_enc_setcaps (GstKateEnc * ke, GstCaps * caps);
138 static GstFlowReturn gst_kate_enc_chain (GstPad * pad, GstObject * parent,
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,
144 static gboolean gst_kate_enc_source_query (GstPad * pad, GstObject * parent,
147 #define gst_kate_enc_parent_class parent_class
148 G_DEFINE_TYPE_WITH_CODE (GstKateEnc, gst_kate_enc, GST_TYPE_ELEMENT,
149 G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL));
151 /* initialize the plugin's class */
153 gst_kate_enc_class_init (GstKateEncClass * klass)
155 GObjectClass *gobject_class;
156 GstElementClass *gstelement_class;
158 gobject_class = (GObjectClass *) klass;
159 gstelement_class = (GstElementClass *) klass;
161 gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_kate_enc_set_property);
162 gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_kate_enc_get_property);
163 gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_kate_enc_dispose);
165 g_object_class_install_property (gobject_class, ARG_LANGUAGE,
166 g_param_spec_string ("language", "Language",
167 "The language of the stream (e.g. \"fr\" or \"fr_FR\" for French)",
168 "", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
170 g_object_class_install_property (gobject_class, ARG_CATEGORY,
171 g_param_spec_string ("category", "Category",
172 "The category of the stream", "",
173 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
175 g_object_class_install_property (gobject_class, ARG_GRANULE_RATE_NUM,
176 g_param_spec_int ("granule-rate-numerator", "Granule rate numerator",
177 "The numerator of the granule rate",
178 1, G_MAXINT, 1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
180 g_object_class_install_property (gobject_class, ARG_GRANULE_RATE_DEN,
181 g_param_spec_int ("granule-rate-denominator", "Granule rate denominator",
182 "The denominator of the granule rate",
183 1, G_MAXINT, 1000, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
185 g_object_class_install_property (gobject_class, ARG_GRANULE_SHIFT,
186 g_param_spec_int ("granule-shift", "Granule shift",
187 "The granule shift", 0, 64, 32,
188 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
190 g_object_class_install_property (gobject_class, ARG_ORIGINAL_CANVAS_WIDTH,
191 g_param_spec_int ("original-canvas-width", "Original canvas width",
192 "The width of the canvas this stream was authored for (0 is unspecified)",
193 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
195 g_object_class_install_property (gobject_class, ARG_ORIGINAL_CANVAS_HEIGHT,
196 g_param_spec_int ("original-canvas-height", "Original canvas height",
197 "The height of the canvas this stream was authored for (0 is unspecified)",
198 0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
200 g_object_class_install_property (gobject_class, ARG_KEEPALIVE_MIN_TIME,
201 g_param_spec_float ("keepalive-min-time", "Keepalive mimimum time",
202 "Minimum time to emit keepalive packets (0 disables keepalive packets)",
203 0.0f, FLT_MAX, DEFAULT_KEEPALIVE_MIN_TIME,
204 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
206 g_object_class_install_property (gobject_class, ARG_DEFAULT_SPU_DURATION,
207 g_param_spec_float ("default-spu-duration", "Default SPU duration",
208 "The assumed max duration (in seconds) of SPUs with no duration specified",
209 0.0f, FLT_MAX, DEFAULT_DEFAULT_SPU_DURATION,
210 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
212 gstelement_class->change_state =
213 GST_DEBUG_FUNCPTR (gst_kate_enc_change_state);
215 gst_element_class_add_static_pad_template (gstelement_class, &src_factory);
216 gst_element_class_add_static_pad_template (gstelement_class, &sink_factory);
218 gst_element_class_set_static_metadata (gstelement_class,
219 "Kate stream encoder", "Codec/Encoder/Subtitle",
220 "Encodes Kate streams from text or subpictures",
221 "Vincent Penquerc'h <ogg.k.ogg.k@googlemail.com>");
224 /* initialize the new element
225 * instantiate pads and add them to element
227 * initialize structure
230 gst_kate_enc_init (GstKateEnc * ke)
232 GST_DEBUG_OBJECT (ke, "gst_kate_enc_init");
234 ke->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
235 gst_pad_set_chain_function (ke->sinkpad,
236 GST_DEBUG_FUNCPTR (gst_kate_enc_chain));
237 gst_pad_set_event_function (ke->sinkpad,
238 GST_DEBUG_FUNCPTR (gst_kate_enc_sink_event));
239 gst_element_add_pad (GST_ELEMENT (ke), ke->sinkpad);
241 ke->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
242 gst_pad_set_query_function (ke->srcpad,
243 GST_DEBUG_FUNCPTR (gst_kate_enc_source_query));
244 gst_element_add_pad (GST_ELEMENT (ke), ke->srcpad);
246 ke->initialized = FALSE;
247 ke->headers_sent = FALSE;
248 ke->last_timestamp = 0;
249 ke->latest_end_time = 0;
252 ke->format = GST_KATE_FORMAT_UNDEFINED;
253 ke->granule_rate_numerator = 1000;
254 ke->granule_rate_denominator = 1;
255 ke->granule_shift = 32;
256 ke->original_canvas_width = 0;
257 ke->original_canvas_height = 0;
258 ke->keepalive_min_time = DEFAULT_KEEPALIVE_MIN_TIME;
259 ke->default_spu_duration = DEFAULT_DEFAULT_SPU_DURATION;
260 memcpy (ke->spu_clut, gst_kate_spu_default_clut,
261 sizeof (gst_kate_spu_default_clut));
262 ke->delayed_spu = FALSE;
263 ke->delayed_bitmap = NULL;
264 ke->delayed_palette = NULL;
265 ke->delayed_region = NULL;
269 gst_kate_enc_dispose (GObject * object)
271 GstKateEnc *ke = GST_KATE_ENC (object);
273 GST_LOG_OBJECT (ke, "disposing");
276 g_free (ke->language);
280 g_free (ke->category);
284 GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
288 gst_kate_enc_set_property (GObject * object, guint prop_id,
289 const GValue * value, GParamSpec * pspec)
291 GstKateEnc *ke = GST_KATE_ENC (object);
297 g_free (ke->language);
300 str = g_value_get_string (value);
302 ke->language = g_strdup (str);
306 g_free (ke->category);
309 str = g_value_get_string (value);
311 ke->category = g_strdup (str);
313 case ARG_GRANULE_RATE_NUM:
314 ke->granule_rate_numerator = g_value_get_int (value);
316 case ARG_GRANULE_RATE_DEN:
317 ke->granule_rate_denominator = g_value_get_int (value);
319 case ARG_GRANULE_SHIFT:
320 ke->granule_rate_denominator = g_value_get_int (value);
322 case ARG_KEEPALIVE_MIN_TIME:
323 ke->keepalive_min_time = g_value_get_float (value);
325 case ARG_ORIGINAL_CANVAS_WIDTH:
326 ke->original_canvas_width = g_value_get_int (value);
328 case ARG_ORIGINAL_CANVAS_HEIGHT:
329 ke->original_canvas_height = g_value_get_int (value);
331 case ARG_DEFAULT_SPU_DURATION:
332 ke->default_spu_duration = g_value_get_float (value);
335 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
341 gst_kate_enc_get_property (GObject * object, guint prop_id,
342 GValue * value, GParamSpec * pspec)
344 GstKateEnc *ke = GST_KATE_ENC (object);
348 g_value_set_string (value, ke->language ? ke->language : "");
351 g_value_set_string (value, ke->category ? ke->category : "");
353 case ARG_GRANULE_RATE_NUM:
354 g_value_set_int (value, ke->granule_rate_numerator);
356 case ARG_GRANULE_RATE_DEN:
357 g_value_set_int (value, ke->granule_rate_denominator);
359 case ARG_GRANULE_SHIFT:
360 g_value_set_int (value, ke->granule_shift);
362 case ARG_KEEPALIVE_MIN_TIME:
363 g_value_set_float (value, ke->keepalive_min_time);
365 case ARG_ORIGINAL_CANVAS_WIDTH:
366 g_value_set_int (value, ke->original_canvas_width);
368 case ARG_ORIGINAL_CANVAS_HEIGHT:
369 g_value_set_int (value, ke->original_canvas_height);
371 case ARG_DEFAULT_SPU_DURATION:
372 g_value_set_float (value, ke->default_spu_duration);
375 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
380 /* GstElement vmethod implementations */
383 gst_kate_enc_create_buffer (GstKateEnc * ke, kate_packet * kp,
384 kate_int64_t granpos, GstClockTime timestamp, GstClockTime duration,
389 g_return_val_if_fail (kp != NULL, NULL);
390 g_return_val_if_fail (kp->data != NULL, NULL);
392 buffer = gst_buffer_new_allocate (NULL, kp->nbytes, NULL);
393 if (G_UNLIKELY (!buffer)) {
394 GST_WARNING_OBJECT (ke, "Failed to allocate buffer for %u bytes",
399 gst_buffer_fill (buffer, 0, kp->data, kp->nbytes);
401 /* same system as other Ogg codecs, as per ext/ogg/README:
402 OFFSET_END is the granulepos
403 OFFSET is its time representation
405 GST_BUFFER_OFFSET_END (buffer) = granpos;
406 GST_BUFFER_OFFSET (buffer) = timestamp;
407 GST_BUFFER_TIMESTAMP (buffer) = timestamp;
408 GST_BUFFER_DURATION (buffer) = duration;
414 gst_kate_enc_push_buffer (GstKateEnc * ke, GstBuffer * buffer)
418 ke->last_timestamp = GST_BUFFER_TIMESTAMP (buffer);
419 if (GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer) >
420 ke->latest_end_time) {
421 ke->latest_end_time =
422 GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer);
425 flow = gst_pad_push (ke->srcpad, buffer);
426 if (G_UNLIKELY (flow != GST_FLOW_OK)) {
427 GST_WARNING_OBJECT (ke->srcpad, "push flow: %s", gst_flow_get_name (flow));
434 gst_kate_enc_push_and_free_kate_packet (GstKateEnc * ke, kate_packet * kp,
435 kate_int64_t granpos, GstClockTime timestamp, GstClockTime duration,
440 GST_LOG_OBJECT (ke, "Creating buffer, %u bytes", (guint) kp->nbytes);
442 gst_kate_enc_create_buffer (ke, kp, granpos, timestamp, duration, header);
443 if (G_UNLIKELY (!buffer)) {
444 GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
445 ("Failed to create buffer, %u bytes", (guint) kp->nbytes));
446 kate_packet_clear (kp);
447 return GST_FLOW_ERROR;
450 kate_packet_clear (kp);
452 return gst_kate_enc_push_buffer (ke, buffer);
456 gst_kate_enc_metadata_set1 (const GstTagList * list, const gchar * tag,
459 GstKateEnc *ke = GST_KATE_ENC (kateenc);
462 vc_list = gst_tag_to_vorbis_comments (list, tag);
464 for (l = vc_list; l != NULL; l = l->next) {
465 const gchar *vc_string = (const gchar *) l->data;
466 gchar *key = NULL, *val = NULL;
468 GST_LOG_OBJECT (ke, "Kate comment: %s", vc_string);
469 if (gst_tag_parse_extended_comment (vc_string, &key, NULL, &val, TRUE)) {
470 kate_comment_add_tag (&ke->kc, key, val);
476 g_list_foreach (vc_list, (GFunc) g_free, NULL);
477 g_list_free (vc_list);
481 gst_kate_enc_set_metadata (GstKateEnc * ke)
483 GstTagList *merged_tags;
484 const GstTagList *user_tags;
486 user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (ke));
488 GST_DEBUG_OBJECT (ke, "upstream tags = %" GST_PTR_FORMAT, ke->tags);
489 GST_DEBUG_OBJECT (ke, "user-set tags = %" GST_PTR_FORMAT, user_tags);
491 /* gst_tag_list_merge() will handle NULL for either or both lists fine */
492 merged_tags = gst_tag_list_merge (user_tags, ke->tags,
493 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (ke)));
496 GST_DEBUG_OBJECT (ke, "merged tags = %" GST_PTR_FORMAT, merged_tags);
497 gst_tag_list_foreach (merged_tags, gst_kate_enc_metadata_set1, ke);
498 gst_tag_list_unref (merged_tags);
503 gst_kate_enc_setcaps (GstKateEnc * ke, GstCaps * caps)
505 GST_LOG_OBJECT (ke, "input caps: %" GST_PTR_FORMAT, caps);
507 /* One day we could try to automatically set the category based on the
508 * input format, assuming that the input is subtitles. Currently that
509 * doesn't work yet though, because we send the header packets already from
510 * the sink event handler when receiving the newsegment event, so before
511 * the first buffer (might be tricky to change too, given that there could
512 * be no data at the beginning for a long time). So for now we just try to
513 * make sure people didn't set the category to something obviously wrong. */
514 if (ke->category != NULL) {
515 GstStructure *s = gst_caps_get_structure (caps, 0);
517 if (gst_structure_has_name (s, "text/x-raw")) {
520 format = gst_structure_get_string (s, "format");
521 if (strcmp (format, "utf8") == 0) {
522 ke->format = GST_KATE_FORMAT_TEXT_UTF8;
523 } else if (strcmp (format, "pango-markup") == 0) {
524 ke->format = GST_KATE_FORMAT_TEXT_PANGO_MARKUP;
527 if (strcmp (ke->category, "K-SPU") == 0 ||
528 strcmp (ke->category, "spu-subtitles") == 0) {
529 GST_ELEMENT_WARNING (ke, LIBRARY, SETTINGS, (NULL),
530 ("Category set to '%s', but input is text-based.", ke->category));
532 } else if (gst_structure_has_name (s, "subpicture/x-dvd")) {
533 ke->format = GST_KATE_FORMAT_SPU;
534 if (strcmp (ke->category, "SUB") == 0 ||
535 strcmp (ke->category, "subtitles") == 0) {
536 GST_ELEMENT_WARNING (ke, LIBRARY, SETTINGS, (NULL),
537 ("Category set to '%s', but input is subpictures.", ke->category));
540 GST_ERROR_OBJECT (ke, "unexpected input caps %" GST_PTR_FORMAT, caps);
549 gst_kate_enc_is_simple_subtitle_category (GstKateEnc * ke, const char *category)
551 static const char *const simple[] = {
561 for (n = 0; n < G_N_ELEMENTS (simple); ++n) {
562 if (!strcmp (category, simple[n]))
569 gst_kate_enc_send_headers (GstKateEnc * ke)
571 GstFlowReturn rflow = GST_FLOW_OK;
573 GList *headers = NULL, *item;
575 if (G_UNLIKELY (ke->category == NULL || *ke->category == '\0')) {
576 /* The error code is a bit of a lie, but seems most appropriate. */
577 GST_ELEMENT_ERROR (ke, LIBRARY, SETTINGS, (NULL),
578 ("The 'category' property must be set. For subtitles, set it to "
579 "either 'SUB' (text subtitles) or 'K-SPU' (dvd-style subtitles)"));
580 return GST_FLOW_ERROR;
583 gst_kate_enc_set_metadata (ke);
585 /* encode headers and store them in a list */
588 int ret = kate_encode_headers (&ke->k, &ke->kc, &kp);
592 buffer = gst_kate_enc_create_buffer (ke, &kp, 0, 0, 0, TRUE);
594 GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
595 ("Failed to create buffer, %u bytes", (guint) kp.nbytes));
596 rflow = GST_FLOW_ERROR;
599 kate_packet_clear (&kp);
601 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_HEADER);
602 headers = g_list_append (headers, buffer);
603 } else if (ret > 0) {
604 GST_LOG_OBJECT (ke, "Last header encoded");
607 GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
608 ("Failed encoding headers: %s",
609 gst_kate_util_get_error_message (ret)));
610 rflow = GST_FLOW_ERROR;
615 if (rflow == GST_FLOW_OK) {
616 if (gst_kate_enc_is_simple_subtitle_category (ke, ke->category)) {
617 caps = gst_kate_util_set_header_on_caps (&ke->element,
618 gst_caps_from_string ("subtitle/x-kate"), headers);
620 caps = gst_kate_util_set_header_on_caps (&ke->element,
621 gst_caps_from_string ("application/x-kate"), headers);
624 GST_DEBUG_OBJECT (ke, "here are the caps: %" GST_PTR_FORMAT, caps);
625 gst_pad_set_caps (ke->srcpad, caps);
626 gst_caps_unref (caps);
628 if (ke->pending_segment)
629 gst_pad_push_event (ke->srcpad, ke->pending_segment);
630 ke->pending_segment = NULL;
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;
784 GstClockTime start, stop;
787 /* allocate region, bitmap, and palette, in case we have to delay encoding them */
788 kregion = (kate_region *) g_malloc (sizeof (kate_region));
789 kbitmap = (kate_bitmap *) g_malloc (sizeof (kate_bitmap));
790 kpalette = (kate_palette *) g_malloc (sizeof (kate_palette));
791 if (!kregion || !kpalette || !kbitmap) {
795 GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL), ("Out of memory"));
796 return GST_FLOW_ERROR;
799 rflow = gst_kate_spu_decode_spu (ke, buf, kregion, kbitmap, kpalette);
800 if (G_UNLIKELY (rflow != GST_FLOW_OK)) {
801 GST_ERROR_OBJECT (ke, "Failed to decode incoming SPU");
804 static int spu_count = 0;
807 snprintf (name, sizeof (name), "/tmp/bad_spu_%04d", spu_count++);
808 name[sizeof (name) - 1] = 0;
809 f = fopen (name, "w");
811 fwrite (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf), 1, f);
819 if (G_UNLIKELY (kbitmap->width == 0 || kbitmap->height == 0)) {
820 /* there are some DVDs (well, at least one) where some dimwits put in a wholly transparent full screen 720x576 SPU !!!!?! */
821 GST_WARNING_OBJECT (ke, "SPU is totally invisible - dimwits");
826 /* timestamp offsets are hidden in the SPU packets */
827 start = GST_BUFFER_TIMESTAMP (buf) + GST_KATE_STM_TO_GST (ke->show_time);
828 stop = GST_BUFFER_TIMESTAMP (buf) + GST_KATE_STM_TO_GST (ke->hide_time);
829 t0 = start / (double) GST_SECOND;
830 t1 = stop / (double) GST_SECOND;
831 GST_DEBUG_OBJECT (ke, "buf ts %f, start/show %hu/%hu",
832 GST_BUFFER_TIMESTAMP (buf) / (double) GST_SECOND, ke->show_time,
837 static int spu_count = 0;
840 snprintf (name, sizeof (name), "/tmp/spu_%04d", spu_count++);
841 name[sizeof (name) - 1] = 0;
842 f = fopen (name, "w");
844 fwrite (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf), 1, f);
849 GST_DEBUG_OBJECT (ke, "Encoding %" G_GSIZE_FORMAT "x%" G_GSIZE_FORMAT
850 " SPU: (%" G_GSIZE_FORMAT " bytes) from %f to %f",
851 kbitmap->width, kbitmap->height, gst_buffer_get_size (buf), t0, t1);
853 ret = kate_encode_set_region (&ke->k, kregion);
854 if (G_UNLIKELY (ret < 0)) {
855 GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
856 ("Failed to set region: %s", gst_kate_util_get_error_message (ret)));
860 ret = kate_encode_set_palette (&ke->k, kpalette);
861 if (G_UNLIKELY (ret < 0)) {
862 GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
863 ("Failed to set palette: %s", gst_kate_util_get_error_message (ret)));
867 ret = kate_encode_set_bitmap (&ke->k, kbitmap);
868 if (G_UNLIKELY (ret < 0)) {
869 GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
870 ("Failed to set bitmap: %s", gst_kate_util_get_error_message (ret)));
874 /* Some SPUs have no hide time - so I'm going to delay the encoding of the packet
875 till either a suitable event happens, and the time of this event will be used
876 as the end time of this SPU, which will then be encoded and sent off. Suitable
877 events are the arrival of a subsequent SPU (eg, this SPU will replace the one
878 with no end), EOS, a new segment event, or a time threshold being reached */
879 if (ke->hide_time <= ke->show_time) {
881 "Cannot encode SPU packet now, hide time is now known (starting at %f) - delaying",
883 ke->delayed_spu = TRUE;
884 ke->delayed_start = start;
885 ke->delayed_bitmap = kbitmap;
886 ke->delayed_palette = kpalette;
887 ke->delayed_region = kregion;
892 ret = kate_encode_text (&ke->k, t0, t1, "", 0, &kp);
893 if (G_UNLIKELY (ret < 0)) {
894 GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
895 ("Failed to encode empty text for SPU buffer: %s",
896 gst_kate_util_get_error_message (ret)));
900 rflow = gst_kate_enc_chain_push_packet (ke, &kp, start, stop - start + 1);
903 /* Cleanup data if we're not keeping it around */
904 if (!ke->delayed_spu) {
905 g_free (kpalette->colors);
907 g_free (kbitmap->pixels);
916 rflow = GST_FLOW_ERROR;
922 gst_kate_enc_chain_text (GstKateEnc * ke, GstBuffer * buf)
924 kate_packet kp = { 0 };
927 GstClockTime start = GST_BUFFER_TIMESTAMP (buf);
928 GstClockTime stop = GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf);
930 if (ke->format == GST_KATE_FORMAT_TEXT_PANGO_MARKUP) {
931 ret = kate_encode_set_markup_type (&ke->k, kate_markup_simple);
932 } else if (ke->format == GST_KATE_FORMAT_TEXT_UTF8) {
933 ret = kate_encode_set_markup_type (&ke->k, kate_markup_none);
935 return GST_FLOW_ERROR;
938 if (G_UNLIKELY (ret < 0)) {
939 GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
940 ("Failed to set markup type: %s",
941 gst_kate_util_get_error_message (ret)));
942 rflow = GST_FLOW_ERROR;
945 gboolean need_unmap = TRUE;
946 kate_float t0 = start / (double) GST_SECOND;
947 kate_float t1 = stop / (double) GST_SECOND;
949 if (!gst_buffer_map (buf, &info, GST_MAP_READ)) {
953 GST_WARNING_OBJECT (buf, "Failed to map buffer");
956 GST_LOG_OBJECT (ke, "Encoding text: %*.*s (%u bytes) from %f to %f",
957 (int) info.size, (int) info.size, info.data, (int) info.size, t0, t1);
958 ret = kate_encode_text (&ke->k, t0, t1, (const char *) info.data, info.size,
960 if (G_UNLIKELY (ret < 0)) {
961 GST_ELEMENT_ERROR (ke, STREAM, ENCODE, (NULL),
962 ("Failed to encode text: %s", gst_kate_util_get_error_message (ret)));
963 rflow = GST_FLOW_ERROR;
965 rflow = gst_kate_enc_chain_push_packet (ke, &kp, start, stop - start + 1);
968 gst_buffer_unmap (buf, &info);
975 * this function does the actual processing
978 gst_kate_enc_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
980 GstKateEnc *ke = GST_KATE_ENC (parent);
983 GST_DEBUG_OBJECT (ke, "got packet, %" G_GSIZE_FORMAT " bytes",
984 gst_buffer_get_size (buf));
986 /* first push headers if we haven't done that yet */
987 rflow = gst_kate_enc_flush_headers (ke);
989 if (G_LIKELY (rflow == GST_FLOW_OK)) {
990 /* flush any packet we had waiting */
991 rflow = gst_kate_enc_flush_waiting (ke, GST_BUFFER_TIMESTAMP (buf));
993 if (G_LIKELY (rflow == GST_FLOW_OK)) {
994 if (ke->format == GST_KATE_FORMAT_SPU) {
995 /* encode a kate_bitmap */
996 rflow = gst_kate_enc_chain_spu (ke, buf);
999 rflow = gst_kate_enc_chain_text (ke, buf);
1004 gst_buffer_unref (buf);
1009 static GstStateChangeReturn
1010 gst_kate_enc_change_state (GstElement * element, GstStateChange transition)
1012 GstKateEnc *ke = GST_KATE_ENC (element);
1013 GstStateChangeReturn res;
1016 GST_INFO_OBJECT (ke, "gst_kate_enc_change_state");
1018 switch (transition) {
1019 case GST_STATE_CHANGE_NULL_TO_READY:
1020 ke->tags = gst_tag_list_new_empty ();
1022 case GST_STATE_CHANGE_READY_TO_PAUSED:
1023 GST_DEBUG_OBJECT (ke, "READY -> PAUSED, initializing kate state");
1024 ret = kate_info_init (&ke->ki);
1026 GST_WARNING_OBJECT (ke, "failed to initialize kate info structure: %s",
1027 gst_kate_util_get_error_message (ret));
1031 ret = kate_info_set_language (&ke->ki, ke->language);
1033 GST_WARNING_OBJECT (ke, "failed to set stream language: %s",
1034 gst_kate_util_get_error_message (ret));
1039 ret = kate_info_set_category (&ke->ki, ke->category);
1041 GST_WARNING_OBJECT (ke, "failed to set stream category: %s",
1042 gst_kate_util_get_error_message (ret));
1047 kate_info_set_original_canvas_size (&ke->ki,
1048 ke->original_canvas_width, ke->original_canvas_height);
1050 GST_WARNING_OBJECT (ke, "failed to set original canvas size: %s",
1051 gst_kate_util_get_error_message (ret));
1054 ret = kate_comment_init (&ke->kc);
1056 GST_WARNING_OBJECT (ke,
1057 "failed to initialize kate comment structure: %s",
1058 gst_kate_util_get_error_message (ret));
1061 ret = kate_encode_init (&ke->k, &ke->ki);
1063 GST_WARNING_OBJECT (ke, "failed to initialize kate state: %s",
1064 gst_kate_util_get_error_message (ret));
1067 ke->headers_sent = FALSE;
1068 ke->initialized = TRUE;
1069 ke->last_timestamp = 0;
1070 ke->latest_end_time = 0;
1071 ke->format = GST_KATE_FORMAT_UNDEFINED;
1073 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1075 case GST_STATE_CHANGE_READY_TO_NULL:
1076 gst_tag_list_unref (ke->tags);
1083 res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1084 if (res == GST_STATE_CHANGE_FAILURE) {
1085 GST_WARNING_OBJECT (ke, "Parent failed to change state");
1089 switch (transition) {
1090 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1092 case GST_STATE_CHANGE_PAUSED_TO_READY:
1093 GST_DEBUG_OBJECT (ke, "PAUSED -> READY, clearing kate state");
1094 if (ke->initialized) {
1095 kate_clear (&ke->k);
1096 kate_info_clear (&ke->ki);
1097 kate_comment_clear (&ke->kc);
1098 ke->initialized = FALSE;
1099 ke->last_timestamp = 0;
1100 ke->latest_end_time = 0;
1102 gst_event_replace (&ke->pending_segment, NULL);
1104 case GST_STATE_CHANGE_READY_TO_NULL:
1110 GST_DEBUG_OBJECT (ke, "State change done");
1116 gst_kate_enc_granule_time (kate_state * k, gint64 granulepos)
1120 if (granulepos == -1)
1123 t = kate_granule_time (k->ki, granulepos);
1124 return t * GST_SECOND;
1128 conversions on the sink:
1130 conversions on the source:
1131 - default is granules at num/den rate
1132 - default -> time is possible
1133 - bytes do not mean anything, packets can be any number of bytes, and we
1134 have no way to know the number of bytes emitted without decoding
1138 gst_kate_enc_convert (GstPad * pad, GstFormat src_fmt, gint64 src_val,
1139 GstFormat * dest_fmt, gint64 * dest_val)
1142 gboolean res = FALSE;
1144 if (src_fmt == *dest_fmt) {
1145 *dest_val = src_val;
1149 ke = GST_KATE_ENC (gst_pad_get_parent (pad));
1151 if (!ke->initialized) {
1152 GST_WARNING_OBJECT (ke, "not initialized yet");
1153 gst_object_unref (ke);
1157 if (src_fmt == GST_FORMAT_BYTES || *dest_fmt == GST_FORMAT_BYTES) {
1158 GST_WARNING_OBJECT (ke, "unsupported format");
1159 gst_object_unref (ke);
1164 case GST_FORMAT_DEFAULT:
1165 switch (*dest_fmt) {
1166 case GST_FORMAT_TIME:
1167 *dest_val = gst_kate_enc_granule_time (&ke->k, src_val);
1181 GST_WARNING_OBJECT (ke, "unsupported format");
1184 gst_object_unref (ke);
1189 gst_kate_enc_source_query (GstPad * pad, GstObject * parent, GstQuery * query)
1191 gboolean res = FALSE;
1193 GST_DEBUG ("source query %d", GST_QUERY_TYPE (query));
1195 switch (GST_QUERY_TYPE (query)) {
1196 case GST_QUERY_CONVERT:
1198 GstFormat src_fmt, dest_fmt;
1199 gint64 src_val, dest_val;
1201 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
1202 if (!gst_kate_enc_convert (pad, src_fmt, src_val, &dest_fmt, &dest_val)) {
1203 return gst_pad_query_default (pad, parent, query);
1205 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
1210 res = gst_pad_query_default (pad, parent, query);
1218 gst_kate_enc_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
1220 GstKateEnc *ke = GST_KATE_ENC (parent);
1221 const GstStructure *structure;
1224 switch (GST_EVENT_TYPE (event)) {
1225 case GST_EVENT_CAPS:
1229 gst_event_parse_caps (event, &caps);
1230 ret = gst_kate_enc_setcaps (ke, caps);
1231 gst_event_unref (event);
1234 case GST_EVENT_SEGMENT:{
1237 GST_LOG_OBJECT (ke, "Got newsegment event");
1239 gst_event_copy_segment (event, &seg);
1241 if (!ke->headers_sent) {
1242 if (ke->pending_segment)
1243 gst_event_unref (ke->pending_segment);
1244 ke->pending_segment = event;
1248 if (ke->initialized) {
1249 GST_LOG_OBJECT (ke, "ensuring all headers are in");
1250 if (gst_kate_enc_flush_headers (ke) != GST_FLOW_OK) {
1251 GST_WARNING_OBJECT (ke, "Failed to flush headers");
1253 if (seg.format != GST_FORMAT_TIME
1254 || !GST_CLOCK_TIME_IS_VALID (seg.start)) {
1255 GST_WARNING_OBJECT (ke,
1256 "No time in newsegment event %p, format %d, timestamp %"
1257 G_GINT64_FORMAT, event, (int) seg.format, seg.start);
1258 /* to be safe, we'd need to generate a keepalive anyway, but we'd have to guess at the timestamp to use; a
1259 good guess would be the last known timestamp plus the keepalive time, but if we then get a packet with a
1260 timestamp less than this, it would fail to encode, which would be Bad. If we don't encode a keepalive, we
1261 run the risk of stalling the pipeline and hanging, which is Very Bad. Oh dear. We can't exit(-1), can we ? */
1263 float t = seg.start / (double) GST_SECOND;
1266 && t - ke->delayed_start / (double) GST_SECOND >=
1267 ke->default_spu_duration) {
1268 if (G_UNLIKELY (gst_kate_enc_flush_waiting (ke,
1269 seg.start) != GST_FLOW_OK)) {
1270 GST_WARNING_OBJECT (ke, "Failed to encode delayed packet");
1271 /* continue with new segment handling anyway */
1275 GST_LOG_OBJECT (ke, "ts %f, last %f (min %f)", t,
1276 ke->last_timestamp / (double) GST_SECOND,
1277 ke->keepalive_min_time);
1278 if (ke->keepalive_min_time > 0.0f
1279 && t - ke->last_timestamp / (double) GST_SECOND >=
1280 ke->keepalive_min_time) {
1281 /* we only generate a keepalive if there is no SPU waiting, as it would
1282 mean out of sequence start times - and granulepos */
1283 if (!ke->delayed_spu) {
1284 gst_kate_enc_generate_keepalive (ke, seg.start);
1291 ret = gst_pad_push_event (ke->srcpad, event);
1296 case GST_EVENT_CUSTOM_DOWNSTREAM:
1297 GST_LOG_OBJECT (ke, "Got custom downstream event");
1298 /* adapted from the dvdsubdec element */
1299 structure = gst_event_get_structure (event);
1300 if (structure != NULL
1301 && gst_structure_has_name (structure, "application/x-gst-dvd")) {
1302 if (ke->initialized) {
1303 GST_LOG_OBJECT (ke, "ensuring all headers are in");
1304 if (gst_kate_enc_flush_headers (ke) != GST_FLOW_OK) {
1305 GST_WARNING_OBJECT (ke, "Failed to flush headers");
1307 const gchar *event_name =
1308 gst_structure_get_string (structure, "event");
1310 if (!strcmp (event_name, "dvd-spu-clut-change")) {
1315 GST_INFO_OBJECT (ke, "New CLUT received");
1316 for (idx = 0; idx < 16; ++idx) {
1317 g_snprintf (name, sizeof (name), "clut%02d", idx);
1318 found = gst_structure_get_int (structure, name, &value);
1320 ke->spu_clut[idx] = value;
1322 GST_WARNING_OBJECT (ke,
1323 "DVD CLUT event did not contain %s field", name);
1326 } else if (!strcmp (event_name, "dvd-lang-codes")) {
1327 /* we can't know which stream corresponds to us */
1330 GST_WARNING_OBJECT (ke, "custom downstream event with no name");
1335 ret = gst_pad_push_event (ke->srcpad, event);
1339 GST_LOG_OBJECT (ke, "Got tag event");
1343 gst_event_parse_tag (event, &list);
1344 gst_tag_list_insert (ke->tags, list,
1345 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (ke)));
1347 g_assert_not_reached ();
1349 ret = gst_pad_event_default (pad, parent, event);
1353 GST_INFO_OBJECT (ke, "Got EOS event");
1354 if (ke->initialized) {
1355 GST_LOG_OBJECT (ke, "ensuring all headers are in");
1356 if (gst_kate_enc_flush_headers (ke) != GST_FLOW_OK) {
1357 GST_WARNING_OBJECT (ke, "Failed to flush headers");
1361 GstClockTime delayed_end =
1362 ke->delayed_start + ke->default_spu_duration * GST_SECOND;
1364 if (G_UNLIKELY (gst_kate_enc_flush_waiting (ke,
1365 delayed_end) != GST_FLOW_OK)) {
1366 GST_WARNING_OBJECT (ke, "Failed to encode delayed packet");
1367 /* continue with EOS handling anyway */
1370 ret = kate_encode_finish (&ke->k, -1, &kp);
1372 GST_WARNING_OBJECT (ke, "Failed to encode EOS packet: %s",
1373 gst_kate_util_get_error_message (ret));
1375 kate_int64_t granpos = kate_encode_get_granule (&ke->k);
1376 GST_LOG_OBJECT (ke, "EOS packet encoded");
1377 if (gst_kate_enc_push_and_free_kate_packet (ke, &kp, granpos,
1378 ke->latest_end_time, 0, FALSE)) {
1379 GST_WARNING_OBJECT (ke, "Failed to push EOS packet");
1384 ret = gst_pad_event_default (pad, parent, event);
1388 GST_LOG_OBJECT (ke, "Got unhandled event");
1389 ret = gst_pad_event_default (pad, parent, event);