diff options
-rw-r--r-- | ChangeLog | 11 | ||||
-rw-r--r-- | gst/cdxaparse/Makefile.am | 11 | ||||
-rw-r--r-- | gst/cdxaparse/gstcdxaparse.c | 19 | ||||
-rw-r--r-- | gst/cdxaparse/gstcdxastrip.c | 410 | ||||
-rw-r--r-- | gst/cdxaparse/gstcdxastrip.h | 67 | ||||
-rw-r--r-- | gst/cdxaparse/gstvcdparse.c | 565 | ||||
-rw-r--r-- | gst/cdxaparse/gstvcdparse.h | 57 |
7 files changed, 339 insertions, 801 deletions
@@ -1,3 +1,14 @@ +2008-04-11 Tim-Philipp Müller <tim at centricular dot net> + + * gst/cdxaparse/Makefile.am: + * gst/cdxaparse/gstcdxaparse.c: + * gst/cdxaparse/gstcdxastrip.c: + * gst/cdxaparse/gstcdxastrip.h: + * gst/cdxaparse/gstvcdparse.c: + * gst/cdxaparse/gstvcdparse.h: + Port VCD parser (formerly cdxastrip) from 0.8 to 0.10. Doesn't do + anything the 0.8 version didn't do though. + 2008-04-11 Julien Moutte <julien@fluendo.com> * sys/oss4/oss4-mixer-enum.c: diff --git a/gst/cdxaparse/Makefile.am b/gst/cdxaparse/Makefile.am index 07a2d076..db2a333d 100644 --- a/gst/cdxaparse/Makefile.am +++ b/gst/cdxaparse/Makefile.am @@ -1,21 +1,22 @@ plugin_LTLIBRARIES = libgstcdxaparse.la -# gstcdxastrip.c -# gstcdxastrip.h - libgstcdxaparse_la_SOURCES = \ - gstcdxaparse.c + gstcdxaparse.c \ + gstvcdparse.c noinst_HEADERS = \ - gstcdxaparse.h + gstcdxaparse.h \ + gstvcdparse.h libgstcdxaparse_la_CFLAGS = \ $(GST_CFLAGS) \ + $(GST_BASE_CFLAGS) \ $(GST_PLUGINS_BASE_CFLAGS) libgstcdxaparse_la_LIBADD = \ $(GST_LIBS) \ + $(GST_BASE_LIBS) \ $(GST_PLUGINS_BASE_LIBS) \ -lgstriff-@GST_MAJORMINOR@ diff --git a/gst/cdxaparse/gstcdxaparse.c b/gst/cdxaparse/gstcdxaparse.c index 1169cef3..373aac75 100644 --- a/gst/cdxaparse/gstcdxaparse.c +++ b/gst/cdxaparse/gstcdxaparse.c @@ -25,10 +25,13 @@ #include <string.h> #include "gstcdxaparse.h" -/* #include "gstcdxastrip.h" */ +#include "gstvcdparse.h" + #include <gst/riff/riff-ids.h> #include <gst/riff/riff-read.h> +GST_DEBUG_CATEGORY (vcdparse_debug); + GST_DEBUG_CATEGORY_STATIC (cdxaparse_debug); #define GST_CAT_DEFAULT cdxaparse_debug @@ -552,13 +555,15 @@ gst_cdxa_parse_change_state (GstElement * element, GstStateChange transition) static gboolean plugin_init (GstPlugin * plugin) { - if (!gst_element_register (plugin, "cdxaparse", GST_RANK_PRIMARY, GST_TYPE_CDXA_PARSE) /* || - !gst_element_register (plugin, "cdxastrip", GST_RANK_PRIMARY, - GST_TYPE_CDXASTRIP) */ ) { - return FALSE; - } - GST_DEBUG_CATEGORY_INIT (cdxaparse_debug, "cdxaparse", 0, "CDXA Parser"); + GST_DEBUG_CATEGORY_INIT (vcdparse_debug, "vcdparse", 0, "VCD Parser"); + + if (!gst_element_register (plugin, "cdxaparse", GST_RANK_PRIMARY, + GST_TYPE_CDXA_PARSE)) + return FALSE; + if (!gst_element_register (plugin, "vcdparse", GST_RANK_PRIMARY, + GST_TYPE_VCD_PARSE)) + return FALSE; return TRUE; } diff --git a/gst/cdxaparse/gstcdxastrip.c b/gst/cdxaparse/gstcdxastrip.c deleted file mode 100644 index 80bf7c87..00000000 --- a/gst/cdxaparse/gstcdxastrip.c +++ /dev/null @@ -1,410 +0,0 @@ -/* GStreamer CDXA sync strippper - * Copyright (C) 2004 Ronald Bultje <rbultje@ronald.bitfreak.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. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <string.h> -#include <gst/gst.h> -#include "gstcdxastrip.h" - -static void gst_cdxastrip_base_init (GstCDXAStripClass * klass); -static void gst_cdxastrip_class_init (GstCDXAStripClass * klass); -static void gst_cdxastrip_init (GstCDXAStrip * cdxastrip); - -static const GstEventMask *gst_cdxastrip_get_event_mask (GstPad * pad); -static gboolean gst_cdxastrip_handle_src_event (GstPad * pad, GstEvent * event); -static const GstFormat *gst_cdxastrip_get_src_formats (GstPad * pad); -static const GstQueryType *gst_cdxastrip_get_src_query_types (GstPad * pad); -static gboolean gst_cdxastrip_handle_src_query (GstPad * pad, - GstQueryType type, GstFormat * format, gint64 * value); - -static void gst_cdxastrip_chain (GstPad * pad, GstData * data); -static GstStateChangeReturn gst_cdxastrip_change_state (GstElement * element, - GstStateChange transition); - -static GstStaticPadTemplate sink_template_factory = -GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/x-vcd") - ); - -static GstStaticPadTemplate src_template_factory = -GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/mpeg, " "systemstream = (boolean) TRUE") - ); - -static GstElementClass *parent_class = NULL; - -GType -gst_cdxastrip_get_type (void) -{ - static GType cdxastrip_type = 0; - - if (!cdxastrip_type) { - static const GTypeInfo cdxastrip_info = { - sizeof (GstCDXAStripClass), - (GBaseInitFunc) gst_cdxastrip_base_init, - NULL, - (GClassInitFunc) gst_cdxastrip_class_init, - NULL, - NULL, - sizeof (GstCDXAStrip), - 0, - (GInstanceInitFunc) gst_cdxastrip_init, - }; - - cdxastrip_type = - g_type_register_static (GST_TYPE_ELEMENT, "GstCDXAStrip", - &cdxastrip_info, 0); - } - - return cdxastrip_type; -} - -static void -gst_cdxastrip_base_init (GstCDXAStripClass * klass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - static const GstElementDetails gst_cdxastrip_details = - GST_ELEMENT_DETAILS ("(S)VCD stream parser", - "Codec/Parser", - "Strip (S)VCD stream from its syncheaders", - "Ronald Bultje <rbultje@ronald.bitfreak.net>"); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&sink_template_factory)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&src_template_factory)); - - gst_element_class_set_details (element_class, &gst_cdxastrip_details); -} - -static void -gst_cdxastrip_class_init (GstCDXAStripClass * klass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - - parent_class = g_type_class_peek_parent (klass); - - element_class->change_state = gst_cdxastrip_change_state; -} - -static void -gst_cdxastrip_init (GstCDXAStrip * cdxastrip) -{ - GST_OBJECT_FLAG_SET (cdxastrip, GST_ELEMENT_EVENT_AWARE); - - cdxastrip->sinkpad = - gst_pad_new_from_static_template (&sink_template_factory, "sink"); - gst_pad_set_chain_function (cdxastrip->sinkpad, gst_cdxastrip_chain); - gst_element_add_pad (GST_ELEMENT (cdxastrip), cdxastrip->sinkpad); - - cdxastrip->srcpad = - gst_pad_new_from_static_template (&src_template_factory, "src"); - gst_pad_set_formats_function (cdxastrip->srcpad, - gst_cdxastrip_get_src_formats); - gst_pad_set_event_mask_function (cdxastrip->srcpad, - gst_cdxastrip_get_event_mask); - gst_pad_set_event_function (cdxastrip->srcpad, - gst_cdxastrip_handle_src_event); - gst_pad_set_query_type_function (cdxastrip->srcpad, - gst_cdxastrip_get_src_query_types); - gst_pad_set_query_function (cdxastrip->srcpad, - gst_cdxastrip_handle_src_query); - gst_element_add_pad (GST_ELEMENT (cdxastrip), cdxastrip->srcpad); -} - -/* - * Stuff. - */ - -static const GstFormat * -gst_cdxastrip_get_src_formats (GstPad * pad) -{ - static const GstFormat formats[] = { - GST_FORMAT_BYTES, - 0 - }; - - return formats; -} - -static const GstQueryType * -gst_cdxastrip_get_src_query_types (GstPad * pad) -{ - static const GstQueryType types[] = { - GST_QUERY_TOTAL, - GST_QUERY_POSITION, - 0 - }; - - return types; -} - -static gboolean -gst_cdxastrip_handle_src_query (GstPad * pad, - GstQueryType type, GstFormat * format, gint64 * value) -{ - GstCDXAStrip *cdxa = GST_CDXASTRIP (gst_pad_get_parent (pad)); - - if (!gst_pad_query (GST_PAD_PEER (cdxa->sinkpad), type, format, value)) - return FALSE; - - if (*format != GST_FORMAT_BYTES) - return TRUE; - - switch (type) { - case GST_QUERY_TOTAL: - case GST_QUERY_POSITION:{ - gint num, rest; - - num = *value / GST_CDXA_SECTOR_SIZE; - rest = *value % GST_CDXA_SECTOR_SIZE; - - *value = num * GST_CDXA_DATA_SIZE; - if (rest > GST_CDXA_HEADER_SIZE) { - if (rest >= GST_CDXA_HEADER_SIZE + GST_CDXA_DATA_SIZE) - *value += GST_CDXA_DATA_SIZE; - else - *value += rest - GST_CDXA_HEADER_SIZE; - } - break; - } - default: - break; - } - - return TRUE; -} - -static const GstEventMask * -gst_cdxastrip_get_event_mask (GstPad * pad) -{ - static const GstEventMask masks[] = { - {GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_KEY_UNIT}, - {0,} - }; - - return masks; -} - -static gboolean -gst_cdxastrip_handle_src_event (GstPad * pad, GstEvent * event) -{ - GstCDXAStrip *cdxa = GST_CDXASTRIP (gst_pad_get_parent (pad)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_SEEK: - switch (GST_EVENT_SEEK_FORMAT (event)) { - case GST_FORMAT_BYTES:{ - GstEvent *new; - gint64 off; - gint num, rest; - - off = GST_EVENT_SEEK_OFFSET (event); - num = off / GST_CDXA_DATA_SIZE; - rest = off % GST_CDXA_DATA_SIZE; - off = num * GST_CDXA_SECTOR_SIZE; - if (rest > 0) - off += rest + GST_CDXA_HEADER_SIZE; - new = gst_event_new_seek (GST_EVENT_SEEK_TYPE (event), off); - gst_event_unref (event); - event = new; - } - default: - break; - } - break; - default: - break; - } - - return gst_pad_send_event (GST_PAD_PEER (cdxa->sinkpad), event); -} - -/* - * A sector is 2352 bytes long and is composed of: - * - * ! sync ! header ! subheader ! data ... ! edc ! - * ! 12 bytes ! 4 bytes ! 8 bytes ! 2324 bytes ! 4 bytes ! - * !-------------------------------------------------------! - * - * We strip the data out of it and send it to the srcpad. - * - * sync : 00 FF FF FF FF FF FF FF FF FF FF 00 - * header : hour minute second mode - * sub-header : track channel sub_mode coding repeat (4 bytes) - * edc : checksum - */ - -GstBuffer * -gst_cdxastrip_strip (GstBuffer * buf) -{ - GstBuffer *sub; - - g_assert (GST_BUFFER_SIZE (buf) >= GST_CDXA_SECTOR_SIZE); - - /* Skip CDXA headers, only keep data. - * FIXME: check sync, resync, ... */ - sub = gst_buffer_create_sub (buf, GST_CDXA_HEADER_SIZE, GST_CDXA_DATA_SIZE); - gst_buffer_unref (buf); - - return sub; -} - -/* - * -1 = no sync (discard buffer), - * otherwise offset indicates syncpoint in buffer. - */ - -gint -gst_cdxastrip_sync (GstBuffer * buf) -{ - guint size, off = 0; - guint8 *data; - - for (size = GST_BUFFER_SIZE (buf), data = GST_BUFFER_DATA (buf); - size >= 12; size--, data++, off++) { - /* we could do a checksum check as well, but who cares... */ - if (!memcmp (data, "\000\377\377\377\377\377\377\377\377\377\377\000", 12)) - return off; - } - - return -1; -} - -/* - * Do stuff. - */ - -static void -gst_cdxastrip_handle_event (GstCDXAStrip * cdxa, GstEvent * event) -{ - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_DISCONTINUOUS:{ - gint64 new_off, off; - - if (gst_event_discont_get_value (event, GST_FORMAT_BYTES, &new_off)) { - GstEvent *new; - gint chunknum, rest; - - chunknum = new_off / GST_CDXA_SECTOR_SIZE; - rest = new_off % GST_CDXA_SECTOR_SIZE; - off = chunknum * GST_CDXA_DATA_SIZE; - if (rest > GST_CDXA_HEADER_SIZE) { - if (rest >= GST_CDXA_HEADER_SIZE + GST_CDXA_DATA_SIZE) - off += GST_CDXA_DATA_SIZE; - else - off += rest - GST_CDXA_HEADER_SIZE; - } - new = gst_event_new_discontinuous (GST_EVENT_DISCONT_NEW_MEDIA (event), - GST_FORMAT_BYTES, new_off, GST_FORMAT_UNDEFINED); - gst_event_unref (event); - event = new; - } - gst_pad_event_default (cdxa->sinkpad, event); - break; - } - case GST_EVENT_FLUSH: - if (cdxa->cache) { - gst_buffer_unref (cdxa->cache); - cdxa->cache = NULL; - } - /* fall-through */ - default: - gst_pad_event_default (cdxa->sinkpad, event); - break; - } -} - -static void -gst_cdxastrip_chain (GstPad * pad, GstData * data) -{ - GstCDXAStrip *cdxa = GST_CDXASTRIP (gst_pad_get_parent (pad)); - GstBuffer *buf, *sub; - gint sync; - - if (GST_IS_EVENT (data)) { - gst_cdxastrip_handle_event (cdxa, GST_EVENT (data)); - return; - } - - buf = GST_BUFFER (data); - if (cdxa->cache) { - buf = gst_buffer_join (cdxa->cache, buf); - } - cdxa->cache = NULL; - - while (buf && GST_BUFFER_SIZE (buf) >= GST_CDXA_SECTOR_SIZE) { - /* sync */ - sync = gst_cdxastrip_sync (buf); - if (sync < 0) { - gst_buffer_unref (buf); - return; - } - sub = gst_buffer_create_sub (buf, sync, GST_BUFFER_SIZE (buf) - sync); - gst_buffer_unref (buf); - buf = sub; - if (GST_BUFFER_SIZE (buf) < GST_CDXA_SECTOR_SIZE) - break; - - /* one chunk */ - sub = gst_cdxastrip_strip (gst_buffer_ref (buf)); - gst_pad_push (cdxa->srcpad, GST_DATA (sub)); - - /* cache */ - if (GST_BUFFER_SIZE (buf) != GST_CDXA_SECTOR_SIZE) { - sub = gst_buffer_create_sub (buf, GST_CDXA_SECTOR_SIZE, - GST_BUFFER_SIZE (buf) - GST_CDXA_SECTOR_SIZE); - } else { - sub = NULL; - } - gst_buffer_unref (buf); - buf = sub; - } - - cdxa->cache = buf; -} - -static GstStateChangeReturn -gst_cdxastrip_change_state (GstElement * element, GstStateChange transition) -{ - GstCDXAStrip *cdxa = GST_CDXASTRIP (element); - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY: - if (cdxa->cache) { - gst_buffer_unref (cdxa->cache); - cdxa->cache = NULL; - } - break; - default: - break; - } - - if (parent_class->change_state) - return parent_class->change_state (element, transition); - - return GST_STATE_CHANGE_SUCCESS; -} diff --git a/gst/cdxaparse/gstcdxastrip.h b/gst/cdxaparse/gstcdxastrip.h deleted file mode 100644 index b53a5be7..00000000 --- a/gst/cdxaparse/gstcdxastrip.h +++ /dev/null @@ -1,67 +0,0 @@ -/* GStreamer CDXA sync strippper - * Copyright (C) 2004 Ronald Bultje <rbultje@ronald.bitfreak.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. - */ - -#ifndef __GST_CDXASTRIP_H__ -#define __GST_CDXASTRIP_H__ - -#include <gst/gst.h> - -G_BEGIN_DECLS - -#define GST_TYPE_CDXASTRIP \ - (gst_cdxastrip_get_type()) -#define GST_CDXASTRIP(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CDXASTRIP,GstCDXAStrip)) -#define GST_CDXASTRIP_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CDXASTRIP,GstCDXAStripClass)) -#define GST_IS_CDXASTRIP(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CDXASTRIP)) -#define GST_IS_CDXASTRIP_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CDXASTRIP)) - -#define GST_CDXA_SECTOR_SIZE 2352 -#define GST_CDXA_DATA_SIZE 2324 -#define GST_CDXA_HEADER_SIZE 24 - -typedef struct _GstCDXAStrip GstCDXAStrip; -typedef struct _GstCDXAStripClass GstCDXAStripClass; - -struct _GstCDXAStrip { - GstElement parent; - - /* pads */ - GstPad *sinkpad, *srcpad; - GstBuffer *cache; -}; - -struct _GstCDXAStripClass { - GstElementClass parent_class; -}; - -GType gst_cdxastrip_get_type (void); - -/* - * Also useful for CDXAparse. - */ -GstBuffer * gst_cdxastrip_strip (GstBuffer * buf); -gint gst_cdxastrip_sync (GstBuffer * buf); - -G_END_DECLS - -#endif /* __GST_CDXASTRIP_H__ */ diff --git a/gst/cdxaparse/gstvcdparse.c b/gst/cdxaparse/gstvcdparse.c index 80bf7c87..4bf148b8 100644 --- a/gst/cdxaparse/gstvcdparse.c +++ b/gst/cdxaparse/gstvcdparse.c @@ -1,5 +1,6 @@ -/* GStreamer CDXA sync strippper +/* GStreamer CDXA sync strippper / VCD parser * Copyright (C) 2004 Ronald Bultje <rbultje@ronald.bitfreak.net> + * Copyright (C) 2008 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 @@ -22,389 +23,389 @@ #endif #include <string.h> -#include <gst/gst.h> -#include "gstcdxastrip.h" - -static void gst_cdxastrip_base_init (GstCDXAStripClass * klass); -static void gst_cdxastrip_class_init (GstCDXAStripClass * klass); -static void gst_cdxastrip_init (GstCDXAStrip * cdxastrip); - -static const GstEventMask *gst_cdxastrip_get_event_mask (GstPad * pad); -static gboolean gst_cdxastrip_handle_src_event (GstPad * pad, GstEvent * event); -static const GstFormat *gst_cdxastrip_get_src_formats (GstPad * pad); -static const GstQueryType *gst_cdxastrip_get_src_query_types (GstPad * pad); -static gboolean gst_cdxastrip_handle_src_query (GstPad * pad, - GstQueryType type, GstFormat * format, gint64 * value); - -static void gst_cdxastrip_chain (GstPad * pad, GstData * data); -static GstStateChangeReturn gst_cdxastrip_change_state (GstElement * element, + +#include "gstvcdparse.h" + +GST_DEBUG_CATEGORY_EXTERN (vcdparse_debug); +#define GST_CAT_DEFAULT vcdparse_debug + +static gboolean gst_vcd_parse_sink_event (GstPad * pad, GstEvent * event); +static gboolean gst_vcd_parse_src_event (GstPad * pad, GstEvent * event); +static gboolean gst_vcd_parse_src_query (GstPad * pad, GstQuery * query); +static GstFlowReturn gst_vcd_parse_chain (GstPad * pad, GstBuffer * buf); +static GstStateChangeReturn gst_vcd_parse_change_state (GstElement * element, GstStateChange transition); -static GstStaticPadTemplate sink_template_factory = -GST_STATIC_PAD_TEMPLATE ("sink", +static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS ("video/x-vcd") ); -static GstStaticPadTemplate src_template_factory = -GST_STATIC_PAD_TEMPLATE ("src", +static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/mpeg, " "systemstream = (boolean) TRUE") + GST_STATIC_CAPS ("video/mpeg, systemstream = (boolean) TRUE") ); -static GstElementClass *parent_class = NULL; - -GType -gst_cdxastrip_get_type (void) -{ - static GType cdxastrip_type = 0; - - if (!cdxastrip_type) { - static const GTypeInfo cdxastrip_info = { - sizeof (GstCDXAStripClass), - (GBaseInitFunc) gst_cdxastrip_base_init, - NULL, - (GClassInitFunc) gst_cdxastrip_class_init, - NULL, - NULL, - sizeof (GstCDXAStrip), - 0, - (GInstanceInitFunc) gst_cdxastrip_init, - }; - - cdxastrip_type = - g_type_register_static (GST_TYPE_ELEMENT, "GstCDXAStrip", - &cdxastrip_info, 0); - } - - return cdxastrip_type; -} +GST_BOILERPLATE (GstVcdParse, gst_vcd_parse, GstElement, GST_TYPE_ELEMENT); static void -gst_cdxastrip_base_init (GstCDXAStripClass * klass) +gst_vcd_parse_base_init (gpointer klass) { GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - static const GstElementDetails gst_cdxastrip_details = - GST_ELEMENT_DETAILS ("(S)VCD stream parser", - "Codec/Parser", - "Strip (S)VCD stream from its syncheaders", - "Ronald Bultje <rbultje@ronald.bitfreak.net>"); gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&sink_template_factory)); + gst_static_pad_template_get (&sink_factory)); gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&src_template_factory)); + gst_static_pad_template_get (&src_factory)); - gst_element_class_set_details (element_class, &gst_cdxastrip_details); + gst_element_class_set_details_simple (element_class, "(S)VCD stream parser", + "Codec/Parser", "Strip (S)VCD stream from its sync headers", + "Tim-Philipp Müller <tim centricular net>, " + "Ronald Bultje <rbultje@ronald.bitfreak.net>"); } static void -gst_cdxastrip_class_init (GstCDXAStripClass * klass) +gst_vcd_parse_class_init (GstVcdParseClass * klass) { GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - parent_class = g_type_class_peek_parent (klass); - - element_class->change_state = gst_cdxastrip_change_state; + element_class->change_state = GST_DEBUG_FUNCPTR (gst_vcd_parse_change_state); } static void -gst_cdxastrip_init (GstCDXAStrip * cdxastrip) +gst_vcd_parse_init (GstVcdParse * vcd, GstVcdParseClass * klass) { - GST_OBJECT_FLAG_SET (cdxastrip, GST_ELEMENT_EVENT_AWARE); - - cdxastrip->sinkpad = - gst_pad_new_from_static_template (&sink_template_factory, "sink"); - gst_pad_set_chain_function (cdxastrip->sinkpad, gst_cdxastrip_chain); - gst_element_add_pad (GST_ELEMENT (cdxastrip), cdxastrip->sinkpad); - - cdxastrip->srcpad = - gst_pad_new_from_static_template (&src_template_factory, "src"); - gst_pad_set_formats_function (cdxastrip->srcpad, - gst_cdxastrip_get_src_formats); - gst_pad_set_event_mask_function (cdxastrip->srcpad, - gst_cdxastrip_get_event_mask); - gst_pad_set_event_function (cdxastrip->srcpad, - gst_cdxastrip_handle_src_event); - gst_pad_set_query_type_function (cdxastrip->srcpad, - gst_cdxastrip_get_src_query_types); - gst_pad_set_query_function (cdxastrip->srcpad, - gst_cdxastrip_handle_src_query); - gst_element_add_pad (GST_ELEMENT (cdxastrip), cdxastrip->srcpad); + vcd->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink"); + gst_pad_set_chain_function (vcd->sinkpad, + GST_DEBUG_FUNCPTR (gst_vcd_parse_chain)); + gst_pad_set_event_function (vcd->sinkpad, + GST_DEBUG_FUNCPTR (gst_vcd_parse_sink_event)); + gst_element_add_pad (GST_ELEMENT (vcd), vcd->sinkpad); + + vcd->srcpad = gst_pad_new_from_static_template (&src_factory, "src"); + gst_pad_set_event_function (vcd->srcpad, + GST_DEBUG_FUNCPTR (gst_vcd_parse_src_event)); + gst_pad_set_query_function (vcd->srcpad, + GST_DEBUG_FUNCPTR (gst_vcd_parse_src_query)); + gst_pad_use_fixed_caps (vcd->srcpad); + gst_pad_set_caps (vcd->srcpad, + gst_static_pad_template_get_caps (&src_factory)); + gst_element_add_pad (GST_ELEMENT (vcd), vcd->srcpad); } -/* - * Stuff. - */ +/* These conversion functions assume there's no junk between sectors */ -static const GstFormat * -gst_cdxastrip_get_src_formats (GstPad * pad) +static gint64 +gst_vcd_parse_get_out_offset (gint64 in_offset) { - static const GstFormat formats[] = { - GST_FORMAT_BYTES, - 0 - }; + gint64 out_offset, chunknum, rest; + + if (in_offset == -1) + return -1; + + if (G_UNLIKELY (in_offset < -1)) { + GST_WARNING ("unexpected/invalid in_offset %" G_GINT64_FORMAT, in_offset); + return in_offset; + } + + chunknum = in_offset / GST_CDXA_SECTOR_SIZE; + rest = in_offset % GST_CDXA_SECTOR_SIZE; - return formats; + out_offset = chunknum * GST_CDXA_DATA_SIZE; + if (rest > GST_CDXA_HEADER_SIZE) { + if (rest >= GST_CDXA_HEADER_SIZE + GST_CDXA_DATA_SIZE) + out_offset += GST_CDXA_DATA_SIZE; + else + out_offset += rest - GST_CDXA_HEADER_SIZE; + } + + GST_LOG ("transformed in_offset %" G_GINT64_FORMAT " to out_offset %" + G_GINT64_FORMAT, in_offset, out_offset); + + return out_offset; } -static const GstQueryType * -gst_cdxastrip_get_src_query_types (GstPad * pad) +static gint64 +gst_vcd_parse_get_in_offset (gint64 out_offset) { - static const GstQueryType types[] = { - GST_QUERY_TOTAL, - GST_QUERY_POSITION, - 0 - }; + gint64 in_offset, chunknum, rest; + + if (out_offset == -1) + return -1; + + if (G_UNLIKELY (out_offset < -1)) { + GST_WARNING ("unexpected/invalid out_offset %" G_GINT64_FORMAT, out_offset); + return out_offset; + } + + chunknum = out_offset / GST_CDXA_DATA_SIZE; + rest = out_offset % GST_CDXA_DATA_SIZE; + + in_offset = chunknum * GST_CDXA_SECTOR_SIZE; + if (rest > 0) + in_offset += GST_CDXA_HEADER_SIZE + rest; - return types; + GST_LOG ("transformed out_offset %" G_GINT64_FORMAT " to in_offset %" + G_GINT64_FORMAT, out_offset, in_offset); + + return in_offset; } static gboolean -gst_cdxastrip_handle_src_query (GstPad * pad, - GstQueryType type, GstFormat * format, gint64 * value) +gst_vcd_parse_src_query (GstPad * pad, GstQuery * query) { - GstCDXAStrip *cdxa = GST_CDXASTRIP (gst_pad_get_parent (pad)); + GstVcdParse *vcd = GST_VCD_PARSE (gst_pad_get_parent (pad)); + gboolean res = FALSE; + + switch (GST_QUERY_TYPE (query)) { + case GST_QUERY_DURATION:{ + GstFormat format; + gint64 dur; + + /* first try upstream */ + if (!gst_pad_query_default (pad, query)) + break; - if (!gst_pad_query (GST_PAD_PEER (cdxa->sinkpad), type, format, value)) - return FALSE; + /* we can only handle BYTES */ + gst_query_parse_duration (query, &format, &dur); + if (format != GST_FORMAT_BYTES) + break; - if (*format != GST_FORMAT_BYTES) - return TRUE; + gst_query_set_duration (query, GST_FORMAT_BYTES, + gst_vcd_parse_get_out_offset (dur)); - switch (type) { - case GST_QUERY_TOTAL: + res = TRUE; + break; + } case GST_QUERY_POSITION:{ - gint num, rest; + GstFormat format; + gint64 pos; - num = *value / GST_CDXA_SECTOR_SIZE; - rest = *value % GST_CDXA_SECTOR_SIZE; + /* first try upstream */ + if (!gst_pad_query_default (pad, query)) + break; - *value = num * GST_CDXA_DATA_SIZE; - if (rest > GST_CDXA_HEADER_SIZE) { - if (rest >= GST_CDXA_HEADER_SIZE + GST_CDXA_DATA_SIZE) - *value += GST_CDXA_DATA_SIZE; - else - *value += rest - GST_CDXA_HEADER_SIZE; - } + /* we can only handle BYTES */ + gst_query_parse_position (query, &format, &pos); + if (format != GST_FORMAT_BYTES) + break; + + gst_query_set_position (query, GST_FORMAT_BYTES, + gst_vcd_parse_get_out_offset (pos)); + + res = TRUE; break; } default: + res = gst_pad_query_default (pad, query); break; } - return TRUE; -} - -static const GstEventMask * -gst_cdxastrip_get_event_mask (GstPad * pad) -{ - static const GstEventMask masks[] = { - {GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_KEY_UNIT}, - {0,} - }; - - return masks; + gst_object_unref (vcd); + return res; } static gboolean -gst_cdxastrip_handle_src_event (GstPad * pad, GstEvent * event) +gst_vcd_parse_sink_event (GstPad * pad, GstEvent * event) { - GstCDXAStrip *cdxa = GST_CDXASTRIP (gst_pad_get_parent (pad)); + GstVcdParse *vcd = GST_VCD_PARSE (gst_pad_get_parent (pad)); + gboolean res; switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_SEEK: - switch (GST_EVENT_SEEK_FORMAT (event)) { - case GST_FORMAT_BYTES:{ - GstEvent *new; - gint64 off; - gint num, rest; - - off = GST_EVENT_SEEK_OFFSET (event); - num = off / GST_CDXA_DATA_SIZE; - rest = off % GST_CDXA_DATA_SIZE; - off = num * GST_CDXA_SECTOR_SIZE; - if (rest > 0) - off += rest + GST_CDXA_HEADER_SIZE; - new = gst_event_new_seek (GST_EVENT_SEEK_TYPE (event), off); - gst_event_unref (event); - event = new; - } - default: - break; + case GST_EVENT_NEWSEGMENT:{ + GstFormat format; + gboolean update; + gdouble rate, applied_rate; + gint64 start, stop, position; + + gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate, + &format, &start, &stop, &position); + + if (format == GST_FORMAT_BYTES) { + gst_event_unref (event); + event = gst_event_new_new_segment_full (update, rate, applied_rate, + GST_FORMAT_BYTES, gst_vcd_parse_get_out_offset (start), + gst_vcd_parse_get_out_offset (stop), position); + } else { + GST_WARNING_OBJECT (vcd, "newsegment event in non-byte format"); } + res = gst_pad_event_default (pad, event); break; + } + case GST_EVENT_FLUSH_START: + gst_adapter_clear (vcd->adapter); + /* fall through */ default: + res = gst_pad_event_default (pad, event); break; } - return gst_pad_send_event (GST_PAD_PEER (cdxa->sinkpad), event); + gst_object_unref (vcd); + return res; } -/* - * A sector is 2352 bytes long and is composed of: - * - * ! sync ! header ! subheader ! data ... ! edc ! - * ! 12 bytes ! 4 bytes ! 8 bytes ! 2324 bytes ! 4 bytes ! - * !-------------------------------------------------------! - * - * We strip the data out of it and send it to the srcpad. - * - * sync : 00 FF FF FF FF FF FF FF FF FF FF 00 - * header : hour minute second mode - * sub-header : track channel sub_mode coding repeat (4 bytes) - * edc : checksum - */ - -GstBuffer * -gst_cdxastrip_strip (GstBuffer * buf) -{ - GstBuffer *sub; - - g_assert (GST_BUFFER_SIZE (buf) >= GST_CDXA_SECTOR_SIZE); - - /* Skip CDXA headers, only keep data. - * FIXME: check sync, resync, ... */ - sub = gst_buffer_create_sub (buf, GST_CDXA_HEADER_SIZE, GST_CDXA_DATA_SIZE); - gst_buffer_unref (buf); - - return sub; -} - -/* - * -1 = no sync (discard buffer), - * otherwise offset indicates syncpoint in buffer. - */ - -gint -gst_cdxastrip_sync (GstBuffer * buf) +static gboolean +gst_vcd_parse_src_event (GstPad * pad, GstEvent * event) { - guint size, off = 0; - guint8 *data; - - for (size = GST_BUFFER_SIZE (buf), data = GST_BUFFER_DATA (buf); - size >= 12; size--, data++, off++) { - /* we could do a checksum check as well, but who cares... */ - if (!memcmp (data, "\000\377\377\377\377\377\377\377\377\377\377\000", 12)) - return off; - } + GstVcdParse *vcd = GST_VCD_PARSE (gst_pad_get_parent (pad)); + gboolean res; - return -1; -} + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_SEEK:{ + GstSeekType start_type, stop_type; + GstSeekFlags flags; + GstFormat format; + gdouble rate; + gint64 start, stop; -/* - * Do stuff. - */ + gst_event_parse_seek (event, &rate, &format, &flags, &start_type, + &start, &stop_type, &stop); -static void -gst_cdxastrip_handle_event (GstCDXAStrip * cdxa, GstEvent * event) -{ - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_DISCONTINUOUS:{ - gint64 new_off, off; - - if (gst_event_discont_get_value (event, GST_FORMAT_BYTES, &new_off)) { - GstEvent *new; - gint chunknum, rest; - - chunknum = new_off / GST_CDXA_SECTOR_SIZE; - rest = new_off % GST_CDXA_SECTOR_SIZE; - off = chunknum * GST_CDXA_DATA_SIZE; - if (rest > GST_CDXA_HEADER_SIZE) { - if (rest >= GST_CDXA_HEADER_SIZE + GST_CDXA_DATA_SIZE) - off += GST_CDXA_DATA_SIZE; - else - off += rest - GST_CDXA_HEADER_SIZE; - } - new = gst_event_new_discontinuous (GST_EVENT_DISCONT_NEW_MEDIA (event), - GST_FORMAT_BYTES, new_off, GST_FORMAT_UNDEFINED); + if (format == GST_FORMAT_BYTES) { gst_event_unref (event); - event = new; + if (start_type != GST_SEEK_TYPE_NONE) + start = gst_vcd_parse_get_in_offset (start); + if (stop_type != GST_SEEK_TYPE_NONE) + stop = gst_vcd_parse_get_in_offset (stop); + event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, start_type, + start, stop_type, stop); + } else { + GST_WARNING_OBJECT (vcd, "seek event in non-byte format"); } - gst_pad_event_default (cdxa->sinkpad, event); + res = gst_pad_event_default (pad, event); break; } - case GST_EVENT_FLUSH: - if (cdxa->cache) { - gst_buffer_unref (cdxa->cache); - cdxa->cache = NULL; - } - /* fall-through */ default: - gst_pad_event_default (cdxa->sinkpad, event); + res = gst_pad_event_default (pad, event); break; } + + gst_object_unref (vcd); + return res; } -static void -gst_cdxastrip_chain (GstPad * pad, GstData * data) +/* -1 = no sync (discard buffer), + * otherwise offset indicates sync point in buffer */ +static gint +gst_vcd_parse_sync (const guint8 * data, guint size) { - GstCDXAStrip *cdxa = GST_CDXASTRIP (gst_pad_get_parent (pad)); - GstBuffer *buf, *sub; - gint sync; + const guint8 sync_marker[12] = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 + }; + guint off = 0; - if (GST_IS_EVENT (data)) { - gst_cdxastrip_handle_event (cdxa, GST_EVENT (data)); - return; - } + while (size >= 12) { + if (memcmp (data, sync_marker, 12) == 0) + return off; - buf = GST_BUFFER (data); - if (cdxa->cache) { - buf = gst_buffer_join (cdxa->cache, buf); + --size; + ++data; + ++off; } - cdxa->cache = NULL; - - while (buf && GST_BUFFER_SIZE (buf) >= GST_CDXA_SECTOR_SIZE) { - /* sync */ - sync = gst_cdxastrip_sync (buf); - if (sync < 0) { - gst_buffer_unref (buf); - return; + return -1; +} + +static GstFlowReturn +gst_vcd_parse_chain (GstPad * pad, GstBuffer * buf) +{ + GstVcdParse *vcd = GST_VCD_PARSE (GST_PAD_PARENT (pad)); + GstFlowReturn flow = GST_FLOW_OK; + + gst_adapter_push (vcd->adapter, buf); + buf = NULL; + + while (gst_adapter_available (vcd->adapter) >= GST_CDXA_SECTOR_SIZE) { + const guint8 *data; + guint8 header[4 + 8]; + gint sync_offset; + + /* find sync (we could peek any size though really) */ + data = gst_adapter_peek (vcd->adapter, GST_CDXA_SECTOR_SIZE); + sync_offset = gst_vcd_parse_sync (data, GST_CDXA_SECTOR_SIZE); + GST_LOG_OBJECT (vcd, "sync offset = %d", sync_offset); + + if (sync_offset < 0) { + gst_adapter_flush (vcd->adapter, GST_CDXA_SECTOR_SIZE - 12); + continue; /* try again */ } - sub = gst_buffer_create_sub (buf, sync, GST_BUFFER_SIZE (buf) - sync); - gst_buffer_unref (buf); - buf = sub; - if (GST_BUFFER_SIZE (buf) < GST_CDXA_SECTOR_SIZE) - break; - /* one chunk */ - sub = gst_cdxastrip_strip (gst_buffer_ref (buf)); - gst_pad_push (cdxa->srcpad, GST_DATA (sub)); + gst_adapter_flush (vcd->adapter, sync_offset); + + if (gst_adapter_available (vcd->adapter) < GST_CDXA_SECTOR_SIZE) { + GST_LOG_OBJECT (vcd, "not enough data in adapter, waiting for more"); + break; + } - /* cache */ - if (GST_BUFFER_SIZE (buf) != GST_CDXA_SECTOR_SIZE) { - sub = gst_buffer_create_sub (buf, GST_CDXA_SECTOR_SIZE, - GST_BUFFER_SIZE (buf) - GST_CDXA_SECTOR_SIZE); - } else { - sub = NULL; + GST_LOG_OBJECT (vcd, "have full sector"); + + /* have one sector: a sector is 2352 bytes long and is composed of: + * + * +-------------------------------------------------------+ + * ! sync ! header ! subheader ! data ... ! edc ! + * ! 12 bytes ! 4 bytes ! 8 bytes ! 2324 bytes ! 4 bytes ! + * +-------------------------------------------------------+ + * + * We strip the data out of it and send it to the srcpad. + * + * sync : 00 FF FF FF FF FF FF FF FF FF FF 00 + * header : hour minute second mode + * sub-header : track channel sub_mode coding repeat (4 bytes) + * edc : checksum + */ + + /* Skip CDXA header and edc footer, only keep data in the middle */ + gst_adapter_copy (vcd->adapter, header, 12, sizeof (header)); + gst_adapter_flush (vcd->adapter, GST_CDXA_HEADER_SIZE); + buf = gst_adapter_take_buffer (vcd->adapter, GST_CDXA_DATA_SIZE); + gst_adapter_flush (vcd->adapter, 4); + + /* we could probably do something clever to keep track of buffer offsets */ + buf = gst_buffer_make_metadata_writable (buf); + GST_BUFFER_OFFSET (buf) = GST_BUFFER_OFFSET_NONE; + GST_BUFFER_TIMESTAMP (buf) = GST_CLOCK_TIME_NONE; + gst_buffer_set_caps (buf, GST_PAD_CAPS (vcd->srcpad)); + + flow = gst_pad_push (vcd->srcpad, buf); + buf = NULL; + + if (G_UNLIKELY (flow != GST_FLOW_OK)) { + GST_DEBUG_OBJECT (vcd, "flow: %s", gst_flow_get_name (flow)); + break; } - gst_buffer_unref (buf); - buf = sub; } - cdxa->cache = buf; + return flow; } static GstStateChangeReturn -gst_cdxastrip_change_state (GstElement * element, GstStateChange transition) +gst_vcd_parse_change_state (GstElement * element, GstStateChange transition) { - GstCDXAStrip *cdxa = GST_CDXASTRIP (element); + GstStateChangeReturn res = GST_STATE_CHANGE_SUCCESS; + GstVcdParse *vcd = GST_VCD_PARSE (element); + + switch (transition) { + case GST_STATE_CHANGE_READY_TO_PAUSED: + vcd->adapter = gst_adapter_new (); + break; + default: + break; + } + + res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_READY: - if (cdxa->cache) { - gst_buffer_unref (cdxa->cache); - cdxa->cache = NULL; + case GST_STATE_CHANGE_READY_TO_NULL: + if (vcd->adapter) { + g_object_unref (vcd->adapter); + vcd->adapter = NULL; } break; default: break; } - if (parent_class->change_state) - return parent_class->change_state (element, transition); - - return GST_STATE_CHANGE_SUCCESS; + return res; } diff --git a/gst/cdxaparse/gstvcdparse.h b/gst/cdxaparse/gstvcdparse.h index b53a5be7..e0583ad2 100644 --- a/gst/cdxaparse/gstvcdparse.h +++ b/gst/cdxaparse/gstvcdparse.h @@ -1,5 +1,6 @@ -/* GStreamer CDXA sync strippper +/* GStreamer CDXA sync strippper / VCD parser * Copyright (C) 2004 Ronald Bultje <rbultje@ronald.bitfreak.net> + * Copyright (C) 2008 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 @@ -17,51 +18,47 @@ * Boston, MA 02111-1307, USA. */ -#ifndef __GST_CDXASTRIP_H__ -#define __GST_CDXASTRIP_H__ +#ifndef __GST_VCD_PARSE_H__ +#define __GST_VCD_PARSE_H__ #include <gst/gst.h> +#include <gst/base/gstadapter.h> G_BEGIN_DECLS -#define GST_TYPE_CDXASTRIP \ - (gst_cdxastrip_get_type()) -#define GST_CDXASTRIP(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CDXASTRIP,GstCDXAStrip)) -#define GST_CDXASTRIP_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CDXASTRIP,GstCDXAStripClass)) -#define GST_IS_CDXASTRIP(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CDXASTRIP)) -#define GST_IS_CDXASTRIP_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CDXASTRIP)) +#define GST_TYPE_VCD_PARSE \ + (gst_vcd_parse_get_type()) +#define GST_VCD_PARSE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VCD_PARSE,GstVcdParse)) +#define GST_VCD_PARSE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VCD_PARSE,GstVcdParseClass)) +#define GST_IS_VCD_PARSE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VCD_PARSE)) +#define GST_IS_VCD_PARSE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VCD_PARSE)) #define GST_CDXA_SECTOR_SIZE 2352 #define GST_CDXA_DATA_SIZE 2324 #define GST_CDXA_HEADER_SIZE 24 -typedef struct _GstCDXAStrip GstCDXAStrip; -typedef struct _GstCDXAStripClass GstCDXAStripClass; +typedef struct _GstVcdParse GstVcdParse; +typedef struct _GstVcdParseClass GstVcdParseClass; -struct _GstCDXAStrip { - GstElement parent; +struct _GstVcdParse { + GstElement element; - /* pads */ - GstPad *sinkpad, *srcpad; - GstBuffer *cache; + GstPad *sinkpad; + GstPad *srcpad; + GstAdapter *adapter; }; -struct _GstCDXAStripClass { - GstElementClass parent_class; +struct _GstVcdParseClass { + GstElementClass element_class; }; -GType gst_cdxastrip_get_type (void); - -/* - * Also useful for CDXAparse. - */ -GstBuffer * gst_cdxastrip_strip (GstBuffer * buf); -gint gst_cdxastrip_sync (GstBuffer * buf); +GType gst_vcd_parse_get_type (void); G_END_DECLS -#endif /* __GST_CDXASTRIP_H__ */ +#endif /* __GST_VCD_PARSE_H__ */ + |