X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=ext%2Fkate%2Fgstkatedec.c;h=93854ed125e77ced03f7282f6722a0d4e71278a0;hb=93211901dd0f6f59d0c741a7faac580f17d88c3f;hp=6b1ee73d4c3183372f5ea8efb5f1731259dd7d56;hpb=a9f5def9d11c9a6623d7ed9d365160a4d8076b17;p=platform%2Fupstream%2Fgstreamer.git diff --git a/ext/kate/gstkatedec.c b/ext/kate/gstkatedec.c index 6b1ee73..93854ed 100644 --- a/ext/kate/gstkatedec.c +++ b/ext/kate/gstkatedec.c @@ -39,39 +39,36 @@ * * 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. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ /** * SECTION:element-katedec + * @title: katedec * @see_also: oggdemux * - * - * - * This element decodes Kate streams - * Kate is a free codec + * This element decodes Kate streams. + * + * [Kate](http://libkate.googlecode.com/) is a free codec * for text based data, such as subtitles. Any number of kate streams can be * embedded in an Ogg stream. - * - * + * * libkate (see above url) is needed to build this plugin. - * - * Example pipeline - * - * This explicitely decodes a Kate stream: - * - * gst-launch filesrc location=test.ogg ! oggdemux ! katedec ! fakesink silent=TRUE - * - * - * + * + * ## Example pipeline + * + * This explicitly decodes a Kate stream: + * |[ + * gst-launch-1.0 filesrc location=test.ogg ! oggdemux ! katedec ! fakesink silent=TRUE + * ]| + * * This will automatically detect and use any Kate streams multiplexed * in an Ogg stream: - * - * gst-launch playbin uri=file:///tmp/test.ogg - * - * - * + * |[ + * gst-launch-1.0 playbin uri=file:///tmp/test.ogg + * ]| + * */ #ifdef HAVE_CONFIG_H @@ -82,7 +79,7 @@ #include -#include "gstkate.h" +#include "gstkateelements.h" #include "gstkatespu.h" #include "gstkatedec.h" @@ -114,24 +111,37 @@ static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("text/plain; text/x-pango-markup; " GST_KATE_SPU_MIME_TYPE) + GST_STATIC_CAPS ("text/x-raw, format = { pango-markup, utf8 }; " + GST_KATE_SPU_MIME_TYPE) ); +GST_DEBUG_CATEGORY (gst_katedec_debug); + #define gst_kate_dec_parent_class parent_class G_DEFINE_TYPE (GstKateDec, gst_kate_dec, GST_TYPE_ELEMENT); +#define _do_init \ + kate_element_init (plugin); \ + GST_DEBUG_CATEGORY_INIT (gst_katedec_debug, "katedec", 0, "Kate decoder"); +GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (katedec, "katedec", GST_RANK_PRIMARY, + GST_TYPE_KATE_DEC, _do_init); static void gst_kate_dec_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_kate_dec_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static GstFlowReturn gst_kate_dec_chain (GstPad * pad, GstBuffer * buf); +static GstFlowReturn gst_kate_dec_chain (GstPad * pad, GstObject * parent, + GstBuffer * buf); static GstStateChangeReturn gst_kate_dec_change_state (GstElement * element, GstStateChange transition); -static gboolean gst_kate_dec_sink_query (GstPad * pad, GstQuery * query); -static gboolean gst_kate_dec_sink_event (GstPad * pad, GstEvent * event); -static gboolean gst_kate_dec_sink_handle_event (GstPad * pad, GstEvent * event); -static GstCaps *gst_kate_dec_src_get_caps (GstPad * pad, GstCaps * filter); +static gboolean gst_kate_dec_sink_query (GstPad * pad, GstObject * parent, + GstQuery * query); +static gboolean gst_kate_dec_sink_event (GstPad * pad, GstObject * parent, + GstEvent * event); +static gboolean gst_kate_dec_sink_handle_event (GstPad * pad, + GstObject * parent, GstEvent * event); +static gboolean gst_kate_dec_src_query (GstPad * pad, GstObject * parent, + GstQuery * query); /* initialize the plugin's class */ static void @@ -156,12 +166,10 @@ gst_kate_dec_class_init (GstKateDecClass * klass) gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_kate_dec_change_state); - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&src_factory)); - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&sink_factory)); + gst_element_class_add_static_pad_template (gstelement_class, &src_factory); + gst_element_class_add_static_pad_template (gstelement_class, &sink_factory); - gst_element_class_set_details_simple (gstelement_class, + gst_element_class_set_static_metadata (gstelement_class, "Kate stream text decoder", "Codec/Decoder/Subtitle", "Decodes Kate text streams", "Vincent Penquerc'h "); @@ -175,6 +183,7 @@ gst_kate_dec_class_init (GstKateDecClass * klass) static void gst_kate_dec_init (GstKateDec * dec) { + GstCaps *tmp = NULL; GST_DEBUG_OBJECT (dec, "gst_kate_dec_init"); dec->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink"); @@ -186,17 +195,19 @@ gst_kate_dec_init (GstKateDec * dec) GST_DEBUG_FUNCPTR (gst_kate_dec_sink_event)); gst_pad_use_fixed_caps (dec->sinkpad); gst_pad_set_caps (dec->sinkpad, - gst_static_pad_template_get_caps (&sink_factory)); + tmp = gst_static_pad_template_get_caps (&sink_factory)); gst_element_add_pad (GST_ELEMENT (dec), dec->sinkpad); dec->srcpad = gst_pad_new_from_static_template (&src_factory, "src"); - gst_pad_set_getcaps_function (dec->srcpad, - GST_DEBUG_FUNCPTR (gst_kate_dec_src_get_caps)); + gst_pad_set_query_function (dec->srcpad, + GST_DEBUG_FUNCPTR (gst_kate_dec_src_query)); gst_element_add_pad (GST_ELEMENT (dec), dec->srcpad); gst_kate_util_decode_base_init (&dec->decoder, TRUE); + gst_caps_unref(tmp); dec->src_caps = NULL; + dec->output_format = GST_KATE_FORMAT_UNDEFINED; dec->remove_markup = FALSE; } @@ -230,6 +241,114 @@ gst_kate_dec_get_property (GObject * object, guint prop_id, } } +static GstFlowReturn +gst_kate_dec_handle_kate_event (GstKateDec * kd, const kate_event * ev) +{ + GstFlowReturn rflow = GST_FLOW_OK; + GstKateFormat format = GST_KATE_FORMAT_UNDEFINED; + gchar *escaped; + GstBuffer *buffer; + size_t len; + gboolean plain = TRUE; + + if (kd->remove_markup && ev->text_markup_type != kate_markup_none) { + size_t len0 = ev->len + 1; + escaped = g_strdup (ev->text); + if (escaped) { + kate_text_remove_markup (ev->text_encoding, escaped, &len0); + } + plain = TRUE; + } else if (ev->text_markup_type == kate_markup_none) { + /* no pango markup yet, escape text */ + /* TODO: actually do the pango thing */ + escaped = g_strdup (ev->text); + plain = TRUE; + } else { + escaped = g_strdup (ev->text); + plain = FALSE; + } + + if (G_LIKELY (escaped)) { + len = strlen (escaped); + if (len > 0) { + GST_DEBUG_OBJECT (kd, "kate event: %s, escaped %s", ev->text, escaped); + buffer = gst_buffer_new_and_alloc (len + 1); + if (G_LIKELY (buffer)) { + GstCaps *caps; + if (plain) + format = GST_KATE_FORMAT_TEXT_UTF8; + else + format = GST_KATE_FORMAT_TEXT_PANGO_MARKUP; + if (format != kd->output_format) { + caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING, + (format == GST_KATE_FORMAT_TEXT_UTF8) ? "utf8" : "pango-markup", + NULL); + gst_pad_push_event (kd->srcpad, gst_event_new_caps (caps)); + gst_caps_unref (caps); + kd->output_format = format; + } + /* allocate and copy the NULs, but don't include them in passed size */ + gst_buffer_fill (buffer, 0, escaped, len + 1); + gst_buffer_resize (buffer, 0, len); + GST_BUFFER_TIMESTAMP (buffer) = ev->start_time * GST_SECOND; + GST_BUFFER_DURATION (buffer) = + (ev->end_time - ev->start_time) * GST_SECOND; + rflow = gst_pad_push (kd->srcpad, buffer); + if (rflow == GST_FLOW_NOT_LINKED) { + GST_DEBUG_OBJECT (kd, "source pad not linked, ignored"); + } else if (rflow != GST_FLOW_OK) { + GST_WARNING_OBJECT (kd, "failed to push buffer: %s", + gst_flow_get_name (rflow)); + } + } else { + GST_ELEMENT_ERROR (kd, STREAM, DECODE, (NULL), + ("Failed to create buffer")); + rflow = GST_FLOW_ERROR; + } + } else { + GST_WARNING_OBJECT (kd, "Empty string, nothing to do"); + rflow = GST_FLOW_OK; + } + g_free (escaped); + } else { + GST_ELEMENT_ERROR (kd, STREAM, DECODE, (NULL), + ("Failed to allocate string")); + rflow = GST_FLOW_ERROR; + } + + /* if there's a background paletted bitmap, construct a DVD SPU for it */ + if (ev->bitmap && ev->palette) { + GstBuffer *buffer = gst_kate_spu_encode_spu (kd, ev); + if (buffer) { + GstCaps *caps; + + GST_BUFFER_TIMESTAMP (buffer) = ev->start_time * GST_SECOND; + GST_BUFFER_DURATION (buffer) = + (ev->end_time - ev->start_time) * GST_SECOND; + + if (kd->output_format != GST_KATE_FORMAT_SPU) { + caps = gst_caps_new_empty_simple (GST_KATE_SPU_MIME_TYPE); + gst_pad_push_event (kd->srcpad, gst_event_new_caps (caps)); + gst_caps_unref (caps); + kd->output_format = GST_KATE_FORMAT_SPU; + } + + rflow = gst_pad_push (kd->srcpad, buffer); + if (rflow == GST_FLOW_NOT_LINKED) { + GST_DEBUG_OBJECT (kd, "source pad not linked, ignored"); + } else if (rflow != GST_FLOW_OK) { + GST_WARNING_OBJECT (kd, "failed to push buffer: %s", + gst_flow_get_name (rflow)); + } + } else { + GST_ELEMENT_ERROR (kd, STREAM, DECODE, (NULL), + ("failed to create SPU from paletted bitmap")); + rflow = GST_FLOW_ERROR; + } + } + return rflow; +} + /* GstElement vmethod implementations */ /* chain function @@ -237,9 +356,9 @@ gst_kate_dec_get_property (GObject * object, guint prop_id, */ static GstFlowReturn -gst_kate_dec_chain (GstPad * pad, GstBuffer * buf) +gst_kate_dec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { - GstKateDec *kd = GST_KATE_DEC (gst_pad_get_parent (pad)); + GstKateDec *kd = GST_KATE_DEC (parent); const kate_event *ev = NULL; GstFlowReturn rflow = GST_FLOW_OK; @@ -254,96 +373,15 @@ gst_kate_dec_chain (GstPad * pad, GstBuffer * buf) GST_ELEMENT_CAST (kd), pad, buf, kd->srcpad, kd->srcpad, &kd->src_caps, &ev); if (G_UNLIKELY (rflow != GST_FLOW_OK)) { - gst_object_unref (kd); gst_buffer_unref (buf); return rflow; } if (ev) { - gchar *escaped; - GstBuffer *buffer; - size_t len; - gboolean plain = TRUE; - - if (kd->remove_markup && ev->text_markup_type != kate_markup_none) { - size_t len0 = ev->len + 1; - escaped = g_strdup (ev->text); - if (escaped) { - kate_text_remove_markup (ev->text_encoding, escaped, &len0); - } - plain = TRUE; - } else if (ev->text_markup_type == kate_markup_none) { - /* no pango markup yet, escape text */ - /* TODO: actually do the pango thing */ - escaped = g_strdup (ev->text); - plain = TRUE; - } else { - escaped = g_strdup (ev->text); - plain = FALSE; - } - - if (G_LIKELY (escaped)) { - len = strlen (escaped); - if (len > 0) { - GST_DEBUG_OBJECT (kd, "kate event: %s, escaped %s", ev->text, escaped); - buffer = gst_buffer_new_and_alloc (len + 1); - if (G_LIKELY (buffer)) { - const char *mime = plain ? "text/plain" : "text/x-pango-markup"; - GstCaps *caps = gst_caps_new_empty_simple (mime); - gst_caps_unref (caps); - /* allocate and copy the NULs, but don't include them in passed size */ - gst_buffer_fill (buffer, 0, escaped, len + 1); - gst_buffer_resize (buffer, 0, len); - GST_BUFFER_TIMESTAMP (buffer) = ev->start_time * GST_SECOND; - GST_BUFFER_DURATION (buffer) = - (ev->end_time - ev->start_time) * GST_SECOND; - rflow = gst_pad_push (kd->srcpad, buffer); - if (rflow == GST_FLOW_NOT_LINKED) { - GST_DEBUG_OBJECT (kd, "source pad not linked, ignored"); - } else if (rflow != GST_FLOW_OK) { - GST_WARNING_OBJECT (kd, "failed to push buffer: %s", - gst_flow_get_name (rflow)); - } - } else { - GST_ELEMENT_ERROR (kd, STREAM, DECODE, (NULL), - ("Failed to create buffer")); - rflow = GST_FLOW_ERROR; - } - } else { - GST_WARNING_OBJECT (kd, "Empty string, nothing to do"); - rflow = GST_FLOW_OK; - } - g_free (escaped); - } else { - GST_ELEMENT_ERROR (kd, STREAM, DECODE, (NULL), - ("Failed to allocate string")); - rflow = GST_FLOW_ERROR; - } - - // if there's a background paletted bitmap, construct a DVD SPU for it - if (ev->bitmap && ev->palette) { - GstBuffer *buffer = gst_kate_spu_encode_spu (kd, ev); - if (buffer) { - GST_BUFFER_TIMESTAMP (buffer) = ev->start_time * GST_SECOND; - GST_BUFFER_DURATION (buffer) = - (ev->end_time - ev->start_time) * GST_SECOND; - rflow = gst_pad_push (kd->srcpad, buffer); - if (rflow == GST_FLOW_NOT_LINKED) { - GST_DEBUG_OBJECT (kd, "source pad not linked, ignored"); - } else if (rflow != GST_FLOW_OK) { - GST_WARNING_OBJECT (kd, "failed to push buffer: %s", - gst_flow_get_name (rflow)); - } - } else { - GST_ELEMENT_ERROR (kd, STREAM, DECODE, (NULL), - ("failed to create SPU from paletted bitmap")); - rflow = GST_FLOW_ERROR; - } - } + rflow = gst_kate_dec_handle_kate_event (kd, ev); } not_in_seg: - gst_object_unref (kd); gst_buffer_unref (buf); return rflow; } @@ -365,89 +403,161 @@ gst_kate_dec_change_state (GstElement * element, GstStateChange transition) } gboolean -gst_kate_dec_sink_query (GstPad * pad, GstQuery * query) +gst_kate_dec_sink_query (GstPad * pad, GstObject * parent, GstQuery * query) { - GstKateDec *kd = GST_KATE_DEC (gst_pad_get_parent (pad)); + GstKateDec *kd = GST_KATE_DEC (parent); gboolean res = gst_kate_decoder_base_sink_query (&kd->decoder, GST_ELEMENT_CAST (kd), - pad, query); - gst_object_unref (kd); + pad, parent, query); return res; } static gboolean -gst_kate_dec_sink_event (GstPad * pad, GstEvent * event) +gst_kate_dec_set_caps (GstKateDec * kd, GstCaps * caps) { - GstKateDec *kd = (GstKateDec *) (gst_object_get_parent (GST_OBJECT (pad))); + GstStructure *structure = gst_caps_get_structure (caps, 0); + GstFlowReturn rflow = GST_FLOW_OK; + + if (gst_structure_has_field (structure, "streamheader")) { + const GValue *value; + GstBuffer *buf; + const kate_event *ev; + + value = gst_structure_get_value (structure, "streamheader"); + + if (GST_VALUE_HOLDS_BUFFER (value)) { + buf = gst_value_get_buffer (value); + + gst_kate_util_decoder_base_chain_kate_packet (&kd->decoder, + GST_ELEMENT_CAST (kd), kd->sinkpad, buf, kd->srcpad, kd->srcpad, + &kd->src_caps, &ev); + + if (ev) { + rflow = gst_kate_dec_handle_kate_event (kd, ev); + } + } else if (GST_VALUE_HOLDS_ARRAY (value)) { + gint i, size = gst_value_array_get_size (value); + + for (i = 0; i < size; i++) { + const GValue *v = gst_value_array_get_value (value, i); + + buf = gst_value_get_buffer (v); + gst_kate_util_decoder_base_chain_kate_packet (&kd->decoder, + GST_ELEMENT_CAST (kd), kd->sinkpad, buf, kd->srcpad, kd->srcpad, + &kd->src_caps, &ev); + + if (ev) { + rflow = gst_kate_dec_handle_kate_event (kd, ev); + if (rflow != GST_FLOW_OK && rflow != GST_FLOW_NOT_LINKED) + break; + } + } + } else { + GST_WARNING_OBJECT (kd, "Unhandled streamheader type: %s", + G_VALUE_TYPE_NAME (value)); + } + } + + return rflow == GST_FLOW_OK || rflow == GST_FLOW_NOT_LINKED; +} + +static gboolean +gst_kate_dec_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) +{ + GstKateDec *kd = GST_KATE_DEC (parent); gboolean res = TRUE; - GST_LOG_OBJECT (pad, "Event on sink pad: %s", GST_EVENT_TYPE_NAME (event)); + GST_LOG_OBJECT (pad, "Event on sink pad: %" GST_PTR_FORMAT, event); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_CAPS:{ + GstCaps *caps; + + gst_event_parse_caps (event, &caps); + gst_kate_dec_set_caps (kd, caps); + break; + } + default: + break; + } /* Delay events till we've set caps */ if (gst_kate_util_decoder_base_queue_event (&kd->decoder, event, - &gst_kate_dec_sink_handle_event, pad)) { - gst_object_unref (kd); + &gst_kate_dec_sink_handle_event, parent, pad)) { return TRUE; } - res = gst_kate_dec_sink_handle_event (pad, event); - - gst_object_unref (kd); + res = gst_kate_dec_sink_handle_event (pad, parent, event); return res; } static gboolean -gst_kate_dec_sink_handle_event (GstPad * pad, GstEvent * event) +gst_kate_dec_sink_handle_event (GstPad * pad, GstObject * parent, + GstEvent * event) { - GstKateDec *kd = (GstKateDec *) (gst_object_get_parent (GST_OBJECT (pad))); - gboolean res = TRUE; + GstKateDec *kd = GST_KATE_DEC (parent); GST_LOG_OBJECT (pad, "Handling event on sink pad: %s", GST_EVENT_TYPE_NAME (event)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEGMENT: - gst_kate_util_decoder_base_segment_event (&kd->decoder, event); - res = gst_pad_event_default (pad, event); break; case GST_EVENT_FLUSH_START: gst_kate_util_decoder_base_set_flushing (&kd->decoder, TRUE); - res = gst_pad_event_default (pad, event); break; case GST_EVENT_FLUSH_STOP: gst_kate_util_decoder_base_set_flushing (&kd->decoder, FALSE); - res = gst_pad_event_default (pad, event); break; + case GST_EVENT_TAG:{ + GstTagList *tags; + gst_event_parse_tag (event, &tags); + gst_kate_util_decoder_base_add_tags (&kd->decoder, tags, FALSE); + gst_event_unref (event); + event = gst_kate_util_decoder_base_get_tag_event (&kd->decoder); + break; + } default: - res = gst_pad_event_default (pad, event); break; } - gst_object_unref (kd); - - return res; + return gst_pad_event_default (pad, parent, event); } -static GstCaps * -gst_kate_dec_src_get_caps (GstPad * pad, GstCaps * filter) +static gboolean +gst_kate_dec_src_query (GstPad * pad, GstObject * parent, GstQuery * query) { - GstKateDec *kd = (GstKateDec *) (gst_object_get_parent (GST_OBJECT (pad))); - GstCaps *caps; + GstKateDec *kd = GST_KATE_DEC (parent); + gboolean res = TRUE; - if (kd->src_caps) { - GST_DEBUG_OBJECT (kd, "We have src caps %" GST_PTR_FORMAT, kd->src_caps); - caps = kd->src_caps; - } else { - GST_DEBUG_OBJECT (kd, "We have no src caps, using template caps"); - caps = gst_static_pad_template_get_caps (&src_factory); - } + GST_LOG_OBJECT (pad, "Handling query on src pad: %s", + GST_QUERY_TYPE_NAME (query)); + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_CAPS:{ + GstCaps *caps; - caps = gst_caps_copy (caps); + if (kd->src_caps) { + GST_DEBUG_OBJECT (kd, "We have src caps %" GST_PTR_FORMAT, + kd->src_caps); + caps = gst_caps_copy (kd->src_caps); + } else { + GST_DEBUG_OBJECT (kd, "We have no src caps, using template caps"); + caps = gst_static_pad_template_get_caps (&src_factory); + } - gst_object_unref (kd); - return caps; + gst_query_set_caps_result (query, caps); + gst_caps_unref (caps); + break; + } + default: + res = gst_pad_query_default (pad, parent, query); + break; + } + + return res; }