diff --git a/ChangeLog b/ChangeLog index 985e2becea..0ff226b702 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2007-10-13 Tim-Philipp Müller + + Patch by: Mark Nauwelaerts + + * gst/dvdsub/Makefile.am: + * gst/dvdsub/gstdvdsubdec.c: + * gst/dvdsub/gstdvdsubparse.c: + * gst/dvdsub/gstdvdsubparse.h: + Add dvd subtitle parser, which just packetizes the input + stream. This is needed to mux dvd subtitles into matroska + files, since the muxer expects unfragmented and properly + timestamped input (#415754). + 2007-10-10 Tim-Philipp Müller * configure.ac: diff --git a/gst/dvdsub/Makefile.am b/gst/dvdsub/Makefile.am index f2e734d5ce..9efff3cbbb 100644 --- a/gst/dvdsub/Makefile.am +++ b/gst/dvdsub/Makefile.am @@ -1,9 +1,8 @@ - plugin_LTLIBRARIES = libgstdvdsub.la -libgstdvdsub_la_SOURCES = gstdvdsubdec.c -libgstdvdsub_la_CFLAGS = $(GST_CFLAGS) -libgstdvdsub_la_LIBADD = $(GST_LIBS) +libgstdvdsub_la_SOURCES = gstdvdsubdec.c gstdvdsubparse.c +libgstdvdsub_la_CFLAGS = $(GST_BASE_CFLAGS) $(GST_CFLAGS) +libgstdvdsub_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS) libgstdvdsub_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -noinst_HEADERS = gstdvdsubdec.h +noinst_HEADERS = gstdvdsubdec.h gstdvdsubparse.h diff --git a/gst/dvdsub/gstdvdsubdec.c b/gst/dvdsub/gstdvdsubdec.c index 02c202e92b..93e47a0782 100644 --- a/gst/dvdsub/gstdvdsubdec.c +++ b/gst/dvdsub/gstdvdsubdec.c @@ -25,6 +25,7 @@ #endif #include "gstdvdsubdec.h" +#include "gstdvdsubparse.h" #include GST_BOILERPLATE (GstDvdSubDec, gst_dvd_sub_dec, GstElement, GST_TYPE_ELEMENT); @@ -43,13 +44,6 @@ static gboolean gst_dvd_sub_dec_sink_event (GstPad * pad, GstEvent * event); static GstFlowReturn gst_send_subtitle_frame (GstDvdSubDec * dec, GstClockTime end_ts); -static const GstElementDetails gst_dvd_sub_dec_details = -GST_ELEMENT_DETAILS ("DVD subtitle Decoder", - "Codec/Decoder/Video", - "Decodes DVD subtitles into AYUV video frames", - "Wim Taymans , " - "Jan Schmidt "); - static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, @@ -110,7 +104,10 @@ gst_dvd_sub_dec_base_init (gpointer klass) gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&subtitle_template)); - gst_element_class_set_details (element_class, &gst_dvd_sub_dec_details); + gst_element_class_set_details_simple (element_class, "DVD subtitle decoder", + "Codec/Decoder/Video", "Decodes DVD subtitles into AYUV video frames", + "Wim Taymans , " + "Jan Schmidt "); } static void @@ -989,12 +986,14 @@ static gboolean plugin_init (GstPlugin * plugin) { if (!gst_element_register (plugin, "dvdsubdec", GST_RANK_NONE, - GST_TYPE_DVD_SUB_DEC)) { + GST_TYPE_DVD_SUB_DEC) || + !gst_element_register (plugin, "dvdsubparse", GST_RANK_NONE, + GST_TYPE_DVD_SUB_PARSE)) { return FALSE; } GST_DEBUG_CATEGORY_INIT (gst_dvd_sub_dec_debug, "dvdsubdec", 0, - "DVD subtitle decoder element"); + "DVD subtitle decoder"); return TRUE; } @@ -1002,5 +1001,5 @@ plugin_init (GstPlugin * plugin) GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, "dvdsub", - "Decode DVD subtitles to AYUV video frames", plugin_init, - VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN); + "DVD subtitle parser and decoder", plugin_init, + VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN); diff --git a/gst/dvdsub/gstdvdsubparse.c b/gst/dvdsub/gstdvdsubparse.c new file mode 100644 index 0000000000..6f499050dc --- /dev/null +++ b/gst/dvdsub/gstdvdsubparse.c @@ -0,0 +1,234 @@ +/* GStreamer DVD subtitle parser + * Copyright (C) 2007 Mark Nauwelaerts + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include "gstdvdsubparse.h" + +GST_DEBUG_CATEGORY_STATIC (dvdsubparse_debug); +#define GST_CAT_DEFAULT dvdsubparse_debug + +static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-dvd-subpicture, parsed=(boolean)true") + ); + +static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-dvd-subpicture") + ); + +static void gst_dvd_sub_parse_finalize (GObject * object); + +static void gst_dvd_sub_parse_reset (GstDvdSubParse * parse); + +static gboolean gst_dvd_sub_parse_event (GstPad * pad, GstEvent * event); +static GstFlowReturn gst_dvd_sub_parse_chain (GstPad * pad, GstBuffer * buf); + +static GstStateChangeReturn gst_dvd_sub_parse_change_state (GstElement * + element, GstStateChange transition); +GST_BOILERPLATE (GstDvdSubParse, gst_dvd_sub_parse, GstElement, + GST_TYPE_ELEMENT); + +static void +gst_dvd_sub_parse_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&src_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&sink_template)); + + gst_element_class_set_details_simple (element_class, "DVD subtitle parser", + "Codec/Parser/Subtitle", "Parses and packetizes DVD subtitle streams", + "Mark Nauwelaerts "); +} + +static void +gst_dvd_sub_parse_class_init (GstDvdSubParseClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + + gobject_class->finalize = gst_dvd_sub_parse_finalize; + + GST_DEBUG_CATEGORY_INIT (dvdsubparse_debug, "dvdsubparse", 0, + "DVD subtitle parser"); + + gstelement_class->change_state = + GST_DEBUG_FUNCPTR (gst_dvd_sub_parse_change_state); +} + +static void +gst_dvd_sub_parse_finalize (GObject * object) +{ + GstDvdSubParse *parse = GST_DVD_SUB_PARSE (object); + + gst_object_unref (parse->adapter); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_dvd_sub_parse_init (GstDvdSubParse * parse, GstDvdSubParseClass * klass) +{ + parse->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink"); + gst_pad_set_chain_function (parse->sinkpad, + GST_DEBUG_FUNCPTR (gst_dvd_sub_parse_chain)); + gst_pad_set_event_function (parse->sinkpad, + GST_DEBUG_FUNCPTR (gst_dvd_sub_parse_event)); + gst_element_add_pad (GST_ELEMENT (parse), parse->sinkpad); + + parse->srcpad = gst_pad_new_from_static_template (&src_template, "src"); + gst_pad_use_fixed_caps (parse->srcpad); + gst_pad_set_caps (parse->srcpad, + gst_pad_template_get_caps (gst_static_pad_template_get (&src_template))); + gst_element_add_pad (GST_ELEMENT (parse), parse->srcpad); + + /* remainder */ + parse->adapter = gst_adapter_new (); + gst_dvd_sub_parse_reset (parse); +} + +static void +gst_dvd_sub_parse_reset (GstDvdSubParse * parse) +{ + parse->needed = 0; + parse->stamp = GST_CLOCK_TIME_NONE; + gst_adapter_clear (parse->adapter); +} + +static gboolean +gst_dvd_sub_parse_event (GstPad * pad, GstEvent * event) +{ + GstDvdSubParse *parse; + gboolean ret; + + parse = GST_DVD_SUB_PARSE (gst_pad_get_parent (pad)); + + switch GST_EVENT_TYPE + (event) { + case GST_EVENT_FLUSH_STOP: + gst_dvd_sub_parse_reset (parse); + /* fall-through */ + default: + ret = gst_pad_event_default (pad, event); + break; + } + + gst_object_unref (parse); + return ret; +} + + +static GstFlowReturn +gst_dvd_sub_parse_chain (GstPad * pad, GstBuffer * buf) +{ + GstDvdSubParse *parse = GST_DVD_SUB_PARSE (GST_PAD_PARENT (pad)); + GstAdapter *adapter; + GstBuffer *outbuf = NULL; + GstFlowReturn ret = GST_FLOW_OK; + + adapter = parse->adapter; + + GST_LOG_OBJECT (parse, "%4u bytes, ts: %" GST_TIME_FORMAT, + GST_BUFFER_SIZE (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); + + gst_adapter_push (adapter, buf); + + if (!parse->needed) { + const guint8 *data; + + data = gst_adapter_peek (adapter, 2); + parse->needed = GST_READ_UINT16_BE (data); + } + + if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { + if (GST_CLOCK_TIME_IS_VALID (parse->stamp)) + /* normally, we expect only the first fragment to carry a timestamp */ + GST_WARNING_OBJECT (parse, "Received more timestamps than expected."); + else + parse->stamp = GST_BUFFER_TIMESTAMP (buf); + } + + if (parse->needed) { + guint av; + + av = gst_adapter_available (adapter); + if (av >= parse->needed) { + if (av > parse->needed) { + /* normally, we expect several fragment, boundary aligned */ + GST_WARNING_OBJECT (parse, "Unexpected: needed %d, " + "but more (%d) is available.", parse->needed, av); + } + outbuf = gst_adapter_take_buffer (adapter, parse->needed); + /* decorate buffer */ + gst_buffer_set_caps (outbuf, GST_PAD_CAPS (parse->srcpad)); + GST_BUFFER_TIMESTAMP (outbuf) = parse->stamp; + /* reset state */ + parse->stamp = GST_CLOCK_TIME_NONE; + parse->needed = 0; + /* and send along */ + ret = gst_pad_push (parse->srcpad, outbuf); + } + } + + return ret; +} + +static GstStateChangeReturn +gst_dvd_sub_parse_change_state (GstElement * element, GstStateChange transition) +{ + GstDvdSubParse *parse = GST_DVD_SUB_PARSE (element); + GstStateChangeReturn ret; + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + case GST_STATE_CHANGE_READY_TO_PAUSED: + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + if (ret != GST_STATE_CHANGE_SUCCESS) + return ret; + + switch (transition) { + case GST_STATE_CHANGE_PAUSED_TO_READY: + gst_dvd_sub_parse_reset (parse); + break; + default: + break; + } + + return GST_STATE_CHANGE_SUCCESS; +} diff --git a/gst/dvdsub/gstdvdsubparse.h b/gst/dvdsub/gstdvdsubparse.h new file mode 100644 index 0000000000..8bf8987448 --- /dev/null +++ b/gst/dvdsub/gstdvdsubparse.h @@ -0,0 +1,65 @@ +/* GStreamer DVD subtitle parser + * Copyright (C) 2007 Mark Nauwelaerts + * + * 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. + */ + +#ifndef __GST_DVDSUBPARSE_H__ +#define __GST_DVDSUBPARSE_H__ + +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_DVD_SUB_PARSE \ + (gst_dvd_sub_parse_get_type()) +#define GST_DVD_SUB_PARSE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_DVD_SUB_PARSE, GstDvdSubParse)) +#define GST_DVD_SUB_PARSE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_DVD_SUB_PARSE, GstDvdSubParseClass)) +#define GST_DVD_SUB_PARSE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), GST_TYPE_DVD_SUB_PARSE, GstDvdSubParseClass)) +#define GST_IS_DVD_SUB_PARSE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_DVD_SUB_PARSE)) +#define GST_IS_DVD_SUB_PARSE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_DVD_SUB_PARSE)) + +typedef struct _GstDvdSubParse GstDvdSubParse; +typedef struct _GstDvdSubParseClass GstDvdSubParseClass; + +struct _GstDvdSubParse { + GstElement element; + + /*< private >*/ + GstPad *srcpad; + GstPad *sinkpad; + + GstAdapter *adapter; /* buffer incoming data */ + GstClockTime stamp; /* timestamp of current packet */ + guint needed; /* size of current packet to be assembled */ +}; + +struct _GstDvdSubParseClass { + GstElementClass parent_class; +}; + +GType gst_dvd_sub_parse_get_type (void); + +G_END_DECLS + +#endif /* __GST_DVDSUBPARSE_H__ */ +