From 843665f109ee76b07564af09252e658198fb3b17 Mon Sep 17 00:00:00 2001 From: Julien Moutte Date: Fri, 26 Oct 2007 16:08:04 +0000 Subject: Add a simple MPEG4 ES parser. Original commit message from CVS: 2007-10-26 Julien MOUTTE * configure.ac: * gst/mpeg4videoparse/Makefile.am: * gst/mpeg4videoparse/mpeg4videoparse.c: (gst_mpeg4vparse_drain), (gst_mpeg4vparse_chain), (gst_mpeg4vparse_sink_setcaps), (gst_mpeg4vparse_sink_event), (gst_mpeg4vparse_cleanup), (gst_mpeg4vparse_change_state), (gst_mpeg4vparse_dispose), (gst_mpeg4vparse_base_init), (gst_mpeg4vparse_class_init), (gst_mpeg4vparse_init), (plugin_init): * gst/mpeg4videoparse/mpeg4videoparse.h: Add a simple MPEG4 ES parser. --- gst/mpeg4videoparse/Makefile.am | 9 ++ gst/mpeg4videoparse/mpeg4videoparse.c | 281 ++++++++++++++++++++++++++++++++++ gst/mpeg4videoparse/mpeg4videoparse.h | 62 ++++++++ 3 files changed, 352 insertions(+) create mode 100644 gst/mpeg4videoparse/Makefile.am create mode 100644 gst/mpeg4videoparse/mpeg4videoparse.c create mode 100644 gst/mpeg4videoparse/mpeg4videoparse.h (limited to 'gst/mpeg4videoparse') diff --git a/gst/mpeg4videoparse/Makefile.am b/gst/mpeg4videoparse/Makefile.am new file mode 100644 index 00000000..793b013f --- /dev/null +++ b/gst/mpeg4videoparse/Makefile.am @@ -0,0 +1,9 @@ + +plugin_LTLIBRARIES = libgstmpeg4videoparse.la + +libgstmpeg4videoparse_la_SOURCES = mpeg4videoparse.c +libgstmpeg4videoparse_la_CFLAGS = $(GST_CFLAGS) +libgstmpeg4videoparse_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS) +libgstmpeg4videoparse_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) + +noinst_HEADERS = mpeg4videoparse.h diff --git a/gst/mpeg4videoparse/mpeg4videoparse.c b/gst/mpeg4videoparse/mpeg4videoparse.c new file mode 100644 index 00000000..21be173c --- /dev/null +++ b/gst/mpeg4videoparse/mpeg4videoparse.c @@ -0,0 +1,281 @@ +/* GStreamer + * Copyright (C) <2007> Julien Moutte + * + * 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 "mpeg4videoparse.h" + +GST_DEBUG_CATEGORY_STATIC (mpeg4v_parse_debug); +#define GST_CAT_DEFAULT mpeg4v_parse_debug + +/* elementfactory information */ +static GstElementDetails mpeg4vparse_details = +GST_ELEMENT_DETAILS ("MPEG 4 video elementary stream parser", + "Codec/Parser/Video", + "Parses MPEG-4 Part 2 elementary video streams", + "Julien Moutte "); + +static GstStaticPadTemplate src_template = +GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/mpeg, " + "mpegversion = (int) 4, " + "parsed = (boolean) true, " "systemstream = (boolean) false") + ); + +static GstStaticPadTemplate sink_template = +GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/mpeg, " + "mpegversion = (int) 4, " + "parsed = (boolean) false, " "systemstream = (boolean) false") + ); + +GST_BOILERPLATE (GstMpeg4VParse, gst_mpeg4vparse, GstElement, GST_TYPE_ELEMENT); + +static GstFlowReturn +gst_mpeg4vparse_drain (GstMpeg4VParse * parse) +{ + GstFlowReturn ret = GST_FLOW_OK; + const guint8 *data = NULL; + guint i = 0, available = 0; + + while (gst_adapter_available (parse->adapter) >= 4) { + /* If we have enough data, ensure we're aligned to a start code */ + data = gst_adapter_peek (parse->adapter, 4); + if (data[0] == 0 && data[1] == 0 && data[2] == 1) { + GST_LOG_OBJECT (parse, "found start code with type %02X", data[3]); + parse->found_start = TRUE; + break; + } else { + GST_LOG_OBJECT (parse, "flushing 1 byte"); + gst_adapter_flush (parse->adapter, 1); + } + } + + if (G_UNLIKELY (!parse->found_start)) { + GST_DEBUG_OBJECT (parse, "start code not found, need more data"); + goto beach; + } + + if (G_UNLIKELY (gst_adapter_available (parse->adapter) < 8)) { + GST_DEBUG_OBJECT (parse, "start code found, need more data to find next"); + goto beach; + } + + /* Found a start code, search for the next one */ + available = gst_adapter_available (parse->adapter); + data = gst_adapter_peek (parse->adapter, available); + for (i = 4; i < available - 4; i++) { + /* We generate packets based on VOP start code */ + if (data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 1 && + data[i + 3] == 0xB6) { + GstBuffer *out_buf = gst_adapter_take_buffer (parse->adapter, i); + + GST_LOG_OBJECT (parse, "found next start code at %u", i); + if (out_buf) { + gst_buffer_set_caps (out_buf, GST_PAD_CAPS (parse->srcpad)); + gst_pad_push (parse->srcpad, out_buf); + } + parse->found_start = FALSE; + } + } + +beach: + return ret; +} + +static GstFlowReturn +gst_mpeg4vparse_chain (GstPad * pad, GstBuffer * buffer) +{ + GstMpeg4VParse *parse = GST_MPEG4VIDEOPARSE (gst_pad_get_parent (pad)); + GstFlowReturn ret = GST_FLOW_OK; + + GST_DEBUG_OBJECT (parse, "received buffer of %u bytes with ts %" + GST_TIME_FORMAT " and offset %" G_GINT64_FORMAT, GST_BUFFER_SIZE (buffer), + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)), + GST_BUFFER_OFFSET (buffer)); + + gst_adapter_push (parse->adapter, buffer); + + ret = gst_mpeg4vparse_drain (parse); + + gst_object_unref (parse); + + return ret; +} + +static gboolean +gst_mpeg4vparse_sink_setcaps (GstPad * pad, GstCaps * caps) +{ + gboolean res = TRUE; + GstCaps *out_caps = NULL; + GstMpeg4VParse *parse = GST_MPEG4VIDEOPARSE (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT (parse, "setcaps called with %" GST_PTR_FORMAT, caps); + + out_caps = gst_caps_new_simple ("video/mpeg", + "mpegversion", G_TYPE_INT, 4, + "systemstream", G_TYPE_BOOLEAN, FALSE, + "parsed", G_TYPE_BOOLEAN, TRUE, NULL); + + if (out_caps) { + GST_DEBUG_OBJECT (parse, "setting downstream caps to %" GST_PTR_FORMAT, + caps); + res = gst_pad_set_caps (parse->srcpad, out_caps); + gst_caps_unref (out_caps); + } + + gst_object_unref (parse); + + return res; +} + +static gboolean +gst_mpeg4vparse_sink_event (GstPad * pad, GstEvent * event) +{ + gboolean res = TRUE; + GstMpeg4VParse *parse = GST_MPEG4VIDEOPARSE (gst_pad_get_parent (pad)); + + GST_DEBUG_OBJECT (parse, "handling event type %s", + GST_EVENT_TYPE_NAME (event)); + + switch (GST_EVENT_TYPE (event)) { + default: + res = gst_pad_event_default (pad, event); + break; + } + + gst_object_unref (parse); + + return res; +} + +static void +gst_mpeg4vparse_cleanup (GstMpeg4VParse * parse) +{ + if (parse->adapter) { + gst_adapter_clear (parse->adapter); + } + + parse->found_start = FALSE; +} + +static GstStateChangeReturn +gst_mpeg4vparse_change_state (GstElement * element, GstStateChange transition) +{ + GstMpeg4VParse *parse = GST_MPEG4VIDEOPARSE (element); + GstStateChangeReturn ret; + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + + switch (transition) { + case GST_STATE_CHANGE_PAUSED_TO_READY: + gst_mpeg4vparse_cleanup (parse); + break; + default: + break; + } + + return ret; +} + +static void +gst_mpeg4vparse_dispose (GObject * object) +{ + GstMpeg4VParse *parse = GST_MPEG4VIDEOPARSE (object); + + if (parse->adapter) { + g_object_unref (parse->adapter); + parse->adapter = NULL; + } + + GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object)); +} + +static void +gst_mpeg4vparse_base_init (gpointer klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + 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 (element_class, &mpeg4vparse_details); +} + +static void +gst_mpeg4vparse_class_init (GstMpeg4VParseClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gstelement_class = (GstElementClass *) klass; + gobject_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_mpeg4vparse_dispose); + gstelement_class->change_state = + GST_DEBUG_FUNCPTR (gst_mpeg4vparse_change_state); +} + +static void +gst_mpeg4vparse_init (GstMpeg4VParse * parse, GstMpeg4VParseClass * g_class) +{ + parse->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink"); + gst_pad_set_chain_function (parse->sinkpad, + GST_DEBUG_FUNCPTR (gst_mpeg4vparse_chain)); + gst_pad_set_event_function (parse->sinkpad, + GST_DEBUG_FUNCPTR (gst_mpeg4vparse_sink_event)); + gst_pad_set_setcaps_function (parse->sinkpad, + GST_DEBUG_FUNCPTR (gst_mpeg4vparse_sink_setcaps)); + 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_element_add_pad (GST_ELEMENT (parse), parse->srcpad); + + parse->adapter = gst_adapter_new (); + + gst_mpeg4vparse_cleanup (parse); +} + +static gboolean +plugin_init (GstPlugin * plugin) +{ + GST_DEBUG_CATEGORY_INIT (mpeg4v_parse_debug, "mpeg4videoparse", 0, + "MPEG-4 video parser"); + + if (!gst_element_register (plugin, "mpeg4videoparse", GST_RANK_SECONDARY, + gst_mpeg4vparse_get_type ())) + return FALSE; + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "mpeg4videoparse", + "MPEG-4 video parser", + plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/gst/mpeg4videoparse/mpeg4videoparse.h b/gst/mpeg4videoparse/mpeg4videoparse.h new file mode 100644 index 00000000..0fb434c3 --- /dev/null +++ b/gst/mpeg4videoparse/mpeg4videoparse.h @@ -0,0 +1,62 @@ +/* GStreamer + * Copyright (C) <2007> Julien Moutte + * + * 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 __MPEG4VIDEOPARSE_H__ +#define __MPEG4VIDEOPARSE_H__ + +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_MPEG4VIDEOPARSE (gst_mpeg4vparse_get_type()) +#define GST_MPEG4VIDEOPARSE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),\ + GST_TYPE_MPEG4VIDEOPARSE, GstMpeg4VParse)) +#define GST_MPEG4VIDEOPARSE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),\ + GST_TYPE_MPEG4VIDEOPARSE, GstMpeg4VParseClass)) +#define GST_MPEG4VIDEOPARSE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),\ + GST_TYPE_MPEG4VIDEOPARSE, GstMpeg4VParseClass)) +#define GST_IS_MPEG4VIDEOPARSE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),\ + GST_TYPE_MPEG4VIDEOPARSE)) +#define GST_IS_MPEG4VIDEOPARSE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),\ + GST_TYPE_MPEG4VIDEOPARSE)) + +typedef struct _GstMpeg4VParse GstMpeg4VParse; +typedef struct _GstMpeg4VParseClass GstMpeg4VParseClass; + +struct _GstMpeg4VParse { + GstElement element; + + GstPad * sinkpad; + GstPad * srcpad; + + GstAdapter * adapter; + + gboolean found_start; +}; + +struct _GstMpeg4VParseClass { + GstElementClass parent_class; +}; + +GType gst_mpeg4vparse_get_type (void); + +G_END_DECLS + +#endif /* __MPEG4VIDEOPARSE_H__ */ -- cgit v1.2.1