diff options
Diffstat (limited to 'gst/subparse/gstssaparse.c')
-rw-r--r-- | gst/subparse/gstssaparse.c | 384 |
1 files changed, 0 insertions, 384 deletions
diff --git a/gst/subparse/gstssaparse.c b/gst/subparse/gstssaparse.c deleted file mode 100644 index d4000770..00000000 --- a/gst/subparse/gstssaparse.c +++ /dev/null @@ -1,384 +0,0 @@ -/* GStreamer SSA subtitle parser - * Copyright (c) 2006 Tim-Philipp Müller <tim centricular net> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* Super-primitive SSA parser - we just want the text and ignore - * everything else like styles and timing codes etc. for now */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <stdlib.h> /* atoi() */ -#include <string.h> - -#include "gstssaparse.h" - -GST_DEBUG_CATEGORY_STATIC (ssa_parse_debug); -#define GST_CAT_DEFAULT ssa_parse_debug - -static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("application/x-ssa; application/x-ass") - ); - -static GstStaticPadTemplate src_templ = GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("text/x-pango-markup") - ); - -GST_BOILERPLATE (GstSsaParse, gst_ssa_parse, GstElement, GST_TYPE_ELEMENT); - -static GstStateChangeReturn gst_ssa_parse_change_state (GstElement * - element, GstStateChange transition); -static gboolean gst_ssa_parse_setcaps (GstPad * sinkpad, GstCaps * caps); -static gboolean gst_ssa_parse_src_event (GstPad * pad, GstEvent * event); -static gboolean gst_ssa_parse_sink_event (GstPad * pad, GstEvent * event); -static GstFlowReturn gst_ssa_parse_chain (GstPad * sinkpad, GstBuffer * buf); - -static void -gst_ssa_parse_base_init (gpointer klass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - static GstElementDetails ssa_parse_details = { - "SSA Subtitle Parser", - "Codec/Parser/Subtitle", - "Parses SSA subtitle streams", - "Tim-Philipp Müller <tim centricular net>" - }; - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&sink_templ)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&src_templ)); - gst_element_class_set_details (element_class, &ssa_parse_details); - - GST_DEBUG_CATEGORY_INIT (ssa_parse_debug, "ssaparse", 0, - "SSA subtitle parser"); -} - -static void -gst_ssa_parse_dispose (GObject * object) -{ - GstSsaParse *parse = GST_SSA_PARSE (object); - - g_free (parse->ini); - parse->ini = NULL; - - GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object)); -} - -static void -gst_ssa_parse_init (GstSsaParse * parse, GstSsaParseClass * klass) -{ - parse->sinkpad = gst_pad_new_from_static_template (&sink_templ, "sink"); - gst_pad_set_setcaps_function (parse->sinkpad, - GST_DEBUG_FUNCPTR (gst_ssa_parse_setcaps)); - gst_pad_set_chain_function (parse->sinkpad, - GST_DEBUG_FUNCPTR (gst_ssa_parse_chain)); - gst_pad_set_event_function (parse->sinkpad, - GST_DEBUG_FUNCPTR (gst_ssa_parse_sink_event)); - gst_element_add_pad (GST_ELEMENT (parse), parse->sinkpad); - - parse->srcpad = gst_pad_new_from_static_template (&src_templ, "src"); - gst_pad_set_event_function (parse->srcpad, - GST_DEBUG_FUNCPTR (gst_ssa_parse_src_event)); - gst_element_add_pad (GST_ELEMENT (parse), parse->srcpad); - gst_pad_use_fixed_caps (parse->srcpad); - gst_pad_set_caps (parse->srcpad, - gst_static_pad_template_get_caps (&src_templ)); - - parse->ini = NULL; - parse->framed = FALSE; - parse->send_tags = FALSE; -} - -static void -gst_ssa_parse_class_init (GstSsaParseClass * klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - - object_class->dispose = gst_ssa_parse_dispose; - - element_class->change_state = GST_DEBUG_FUNCPTR (gst_ssa_parse_change_state); -} - -static gboolean -gst_ssa_parse_src_event (GstPad * pad, GstEvent * event) -{ - return gst_pad_event_default (pad, event); -} - -static gboolean -gst_ssa_parse_sink_event (GstPad * pad, GstEvent * event) -{ - return gst_pad_event_default (pad, event); -} - -static gboolean -gst_ssa_parse_setcaps (GstPad * sinkpad, GstCaps * caps) -{ - GstSsaParse *parse = GST_SSA_PARSE (GST_PAD_PARENT (sinkpad)); - const GValue *val; - GstStructure *s; - const guchar bom_utf8[] = { 0xEF, 0xBB, 0xBF }; - GstBuffer *priv; - gchar *data; - guint size; - - s = gst_caps_get_structure (caps, 0); - val = gst_structure_get_value (s, "codec_data"); - if (val == NULL) { - parse->framed = FALSE; - GST_ERROR ("Only SSA subtitles embedded in containers are supported"); - return FALSE; - } - - parse->framed = TRUE; - parse->send_tags = TRUE; - - priv = (GstBuffer *) gst_value_get_mini_object (val); - g_return_val_if_fail (priv != NULL, FALSE); - - gst_buffer_ref (priv); - - data = (gchar *) GST_BUFFER_DATA (priv); - size = GST_BUFFER_SIZE (priv); - /* skip UTF-8 BOM */ - if (size >= 3 && memcmp (data, bom_utf8, 3) == 0) { - data += 3; - size -= 3; - } - - if (!strstr (data, "[Script Info]")) { - GST_WARNING_OBJECT (parse, "Invalid Init section - no Script Info header"); - gst_buffer_unref (priv); - return FALSE; - } - - if (!g_utf8_validate (data, size, NULL)) { - GST_WARNING_OBJECT (parse, "Init section is not valid UTF-8"); - gst_buffer_unref (priv); - return FALSE; - } - - /* FIXME: parse initial section */ - parse->ini = g_strndup (data, size); - GST_LOG_OBJECT (parse, "Init section:\n%s", parse->ini); - - gst_buffer_unref (priv); - - return TRUE; -} - -static gboolean -gst_ssa_parse_remove_override_codes (GstSsaParse * parse, gchar * txt) -{ - gchar *t, *end; - gboolean removed_any = FALSE; - - while ((t = strchr (txt, '{'))) { - end = strchr (txt, '}'); - if (end == NULL) { - GST_WARNING_OBJECT (parse, "Missing { for style override code"); - return removed_any; - } - /* move terminating NUL character forward as well */ - g_memmove (t, end + 1, strlen (end + 1) + 1); - removed_any = TRUE; - } - - /* these may occur outside of curly brackets. We don't handle the different - * wrapping modes yet, so just remove these markers from the text for now */ - while ((t = strstr (txt, "\\n"))) { - t[0] = ' '; - t[1] = '\n'; - } - while ((t = strstr (txt, "\\N"))) { - t[0] = ' '; - t[1] = '\n'; - } - while ((t = strstr (txt, "\\h"))) { - t[0] = ' '; - t[1] = ' '; - } - - return removed_any; -} - -/** - * gst_ssa_parse_push_line: - * @parse: caller element - * @txt: text to push - * @start: timestamp for the buffer - * @duration: duration for the buffer - * - * Parse the text in a buffer with the given properties and - * push it to the srcpad of the @parse element - * - * Returns: result of the push of the created buffer - */ -static GstFlowReturn -gst_ssa_parse_push_line (GstSsaParse * parse, gchar * txt, - GstClockTime start, GstClockTime duration) -{ - GstFlowReturn ret; - GstBuffer *buf; - gchar *t, *escaped; - gint num, i, len; - - num = atoi (txt); - GST_LOG_OBJECT (parse, "Parsing line #%d at %" GST_TIME_FORMAT, - num, GST_TIME_ARGS (start)); - - /* skip all non-text fields before the actual text */ - t = txt; - for (i = 0; i < 8; ++i) { - t = strchr (t, ','); - if (t == NULL) - return GST_FLOW_ERROR; - ++t; - } - - GST_LOG_OBJECT (parse, "Text : %s", t); - - if (gst_ssa_parse_remove_override_codes (parse, t)) { - GST_LOG_OBJECT (parse, "Clean: %s", t); - } - - /* we claim to output pango markup, so we must escape the - * text even if we don't actually use any pango markup yet */ - escaped = g_markup_printf_escaped ("%s", t); - - len = strlen (escaped); - - /* allocate enough for a terminating NUL, but don't include it in buf size */ - buf = gst_buffer_new_and_alloc (len + 1); - memcpy (GST_BUFFER_DATA (buf), escaped, len + 1); - GST_BUFFER_SIZE (buf) = len; - g_free (escaped); - - GST_BUFFER_TIMESTAMP (buf) = start; - GST_BUFFER_DURATION (buf) = duration; - - gst_buffer_set_caps (buf, GST_PAD_CAPS (parse->srcpad)); - - GST_LOG_OBJECT (parse, "Pushing buffer with timestamp %" GST_TIME_FORMAT - " and duration %" GST_TIME_FORMAT, GST_TIME_ARGS (start), - GST_TIME_ARGS (duration)); - - ret = gst_pad_push (parse->srcpad, buf); - - if (ret != GST_FLOW_OK) { - GST_DEBUG_OBJECT (parse, "Push of text '%s' returned flow %s", txt, - gst_flow_get_name (ret)); - } - - return ret; -} - -static GstFlowReturn -gst_ssa_parse_chain (GstPad * sinkpad, GstBuffer * buf) -{ - GstFlowReturn ret; - GstSsaParse *parse = GST_SSA_PARSE (GST_PAD_PARENT (sinkpad)); - GstClockTime ts; - gchar *txt; - - if (G_UNLIKELY (!parse->framed)) - goto not_framed; - - if (G_UNLIKELY (parse->send_tags)) { - GstTagList *tags; - - tags = gst_tag_list_new (); - gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_SUBTITLE_CODEC, - "SubStation Alpha", NULL); - gst_element_found_tags_for_pad (GST_ELEMENT (parse), parse->srcpad, tags); - parse->send_tags = FALSE; - } - - /* make double-sure it's 0-terminated and all */ - txt = g_strndup ((gchar *) GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); - if (txt == NULL) - goto empty_text; - - ts = GST_BUFFER_TIMESTAMP (buf); - ret = gst_ssa_parse_push_line (parse, txt, ts, GST_BUFFER_DURATION (buf)); - - if (ret != GST_FLOW_OK && GST_CLOCK_TIME_IS_VALID (ts)) { - /* just advance time without sending anything */ - gst_pad_push_event (parse->srcpad, - gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_TIME, ts, -1, ts)); - ret = GST_FLOW_OK; - } - - gst_buffer_unref (buf); - g_free (txt); - - return ret; - -/* ERRORS */ -not_framed: - { - GST_ELEMENT_ERROR (parse, STREAM, FORMAT, (NULL), - ("Only SSA subtitles embedded in containers are supported")); - gst_buffer_unref (buf); - return GST_FLOW_NOT_NEGOTIATED; - } -empty_text: - { - GST_ELEMENT_WARNING (parse, STREAM, FORMAT, (NULL), - ("Received empty subtitle")); - gst_buffer_unref (buf); - return GST_FLOW_OK; - } -} - -static GstStateChangeReturn -gst_ssa_parse_change_state (GstElement * element, GstStateChange transition) -{ - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - GstSsaParse *parse = GST_SSA_PARSE (element); - - switch (transition) { - case GST_STATE_CHANGE_READY_TO_PAUSED: - break; - default: - break; - } - - ret = parent_class->change_state (element, transition); - if (ret == GST_STATE_CHANGE_FAILURE) - return ret; - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY: - g_free (parse->ini); - parse->ini = NULL; - parse->framed = FALSE; - break; - default: - break; - } - - return ret; -} |