# HG changeset patch # User renatofilho # Date 1178033486 -3600 # Node ID 4aac3034598660affd4854eaad2a0683c0b055e1 # Parent 43ce4ea2f9fb60b298a1d77a432022b6cf715c11 [svn r615] added concat element diff -r 43ce4ea2f9fb -r 4aac30345986 gst-gmyth/Makefile.am --- a/gst-gmyth/Makefile.am Tue May 01 16:04:02 2007 +0100 +++ b/gst-gmyth/Makefile.am Tue May 01 16:31:26 2007 +0100 @@ -1,3 +1,9 @@ -SUBDIRS = mythtvsrc nuvdemux +SUBDIRS = \ + mythtvsrc \ + nuvdemux \ + concatmux -DIST_SUBDIRS = mythtvsrc nuvdemux +DIST_SUBDIRS = \ + mythtvsrc \ + nuvdemux \ + concatmux diff -r 43ce4ea2f9fb -r 4aac30345986 gst-gmyth/concatmux/Makefile.am --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gst-gmyth/concatmux/Makefile.am Tue May 01 16:31:26 2007 +0100 @@ -0,0 +1,22 @@ +plugin_LTLIBRARIES = libgstconcatmux.la + +libgstconcatmux_la_SOURCES = \ + gstconcatmux.c + +libgstconcatmux_la_CFLAGS = \ + $(GST_CFLAGS) \ + $(GST_BASE_CFLAGS) \ + $(GST_PLUGINS_BASE_CFLAGS) + +libgstconcatmux_la_LIBADD = \ + $(GST_LIBS_LIBS) + +libgstconcatmux_la_LDFLAGS = \ + $(GST_LIBS) \ + $(GST_PLUGIN_LDFLAGS) \ + $(GST_BASE_LIBS) \ + $(GST_PLUGINS_BASE_LIBS) + +noinst_HEADERS = \ + gstconcatmux.h + diff -r 43ce4ea2f9fb -r 4aac30345986 gst-gmyth/concatmux/gstconcatmux.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gst-gmyth/concatmux/gstconcatmux.c Tue May 01 16:31:26 2007 +0100 @@ -0,0 +1,539 @@ +/* concat muxer plugin for GStreamer + * Copyright (C) 2004 Renato Filhps + * + * 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. + */ + +/** + * SECTION:element-concatmux + * @short_description: Concat that takes one or several digital streams + * and muxes them to a single stream. + * + * + * Sample pipelines + * + * Here is a simple pipeline to concat 2 files into a another file: + * + * gst-launch concatmux name=m ! filesink location=output.txt filesrc location=file_a.txt ! m. filesrc location=file_b.txt ! m. + * + * + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include + +GST_DEBUG_CATEGORY_STATIC (gst_concat_mux_debug); +#define GST_CAT_DEFAULT gst_concat_mux_debug + +#define GST_TYPE_CONCAT_MUX (gst_concat_mux_get_type()) +#define GST_CONCAT_MUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CONCAT_MUX, GstConcatMux)) +#define GST_CONCAT_MUX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CONCAT_MUX, GstConcatMux)) +#define GST_IS_CONCAT_MUX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CONCAT_MUX)) +#define GST_IS_CONCAT_MUX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CONCAT_MUX)) + +typedef struct _GstConcatMux GstConcatMux; +typedef struct _GstConcatMuxClass GstConcatMuxClass; + +/** + * GstConcatMux: + * + * The opaque #GstConcatMux structure. + */ +struct _GstConcatMux +{ + GstElement element; + + /* Caps */ + GstCaps *sink_caps; + + /* pad */ + GstPad *srcpad; + GstPad *sinkpad; + + /* sinkpads */ + GSList *sinks; + gint numpads; + + /* offset in stream */ + guint64 offset; + guint64 timeoffset; + guint64 start_time; + + gboolean negotiated; + gboolean resync; + gboolean done; +}; + +struct _GstConcatMuxClass +{ + GstElementClass parent_class; +}; + +/* elementfactory information */ +static const GstElementDetails gst_concat_mux_details = +GST_ELEMENT_DETAILS ("Concat muxer", + "Codec/Muxer", + "mux concat streams", + "Renato Filho "); + +static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY + ); + +static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink_%d", + GST_PAD_SINK, + GST_PAD_REQUEST, + GST_STATIC_CAPS_ANY + ); + +static void gst_concat_mux_base_init (gpointer g_class); +static void gst_concat_mux_class_init (GstConcatMuxClass * klass); +static void gst_concat_mux_init (GstConcatMux * concat_mux); + +static void gst_concat_mux_finalize (GObject * object); + +static gboolean gst_concat_mux_handle_src_event (GstPad * pad, + GstEvent * event); +static gboolean gst_concat_mux_handle_sink_event (GstPad * pad, + GstEvent * event); + +static GstPad *gst_concat_mux_request_new_pad (GstElement * element, + GstPadTemplate * templ, const gchar * name); +static GstStateChangeReturn gst_concat_mux_change_state (GstElement * + element, GstStateChange transition); + +static GstFlowReturn gst_concat_mux_chain (GstPad * pad, GstBuffer * buf); +static void gst_concat_mux_clear (GstConcatMux *mux); + + +static GstElementClass *parent_class = NULL; + +GType +gst_concat_mux_get_type (void) +{ + static GType concat_mux_type = 0; + + if (!concat_mux_type) { + static const GTypeInfo concat_mux_info = { + sizeof (GstConcatMuxClass), + gst_concat_mux_base_init, + NULL, + (GClassInitFunc) gst_concat_mux_class_init, + NULL, + NULL, + sizeof (GstConcatMux), + 0, + (GInstanceInitFunc) gst_concat_mux_init, + }; + + concat_mux_type = + g_type_register_static (GST_TYPE_ELEMENT, "GstConcatMux", + &concat_mux_info, 0); + } + return concat_mux_type; +} + +static void +gst_concat_mux_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_factory)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&sink_factory)); + + gst_element_class_set_details (element_class, &gst_concat_mux_details); +} + +static void +gst_concat_mux_class_init (GstConcatMuxClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + + parent_class = g_type_class_peek_parent (klass); + + gobject_class->finalize = gst_concat_mux_finalize; + + gstelement_class->request_new_pad = gst_concat_mux_request_new_pad; + gstelement_class->change_state = gst_concat_mux_change_state; +} + +static void +gst_concat_mux_init (GstConcatMux * concat_mux) +{ + GstElementClass *klass = GST_ELEMENT_GET_CLASS (concat_mux); + + concat_mux->srcpad = + gst_pad_new_from_template (gst_element_class_get_pad_template (klass, + "src"), "src"); + gst_pad_set_event_function (concat_mux->srcpad, + gst_concat_mux_handle_src_event); + gst_element_add_pad (GST_ELEMENT (concat_mux), concat_mux->srcpad); +} + +static void +gst_concat_mux_finalize (GObject * object) +{ + GstConcatMux *concat_mux; + + concat_mux = GST_CONCAT_MUX (object); + gst_concat_mux_clear (GST_CONCAT_MUX (object)); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_concat_mux_free_pad (gpointer data, + gpointer user_data) +{ + GMutex *mux; + + mux = gst_pad_get_element_private (GST_PAD (data)); + g_mutex_unlock (mux); + g_mutex_free (mux); + gst_object_unref (GST_OBJECT (data)); +} + +static void +gst_concat_mux_clear (GstConcatMux *mux) +{ + mux->resync = TRUE; + mux->timeoffset = 0; + mux->offset = 0; + mux->negotiated = FALSE; + mux->done = TRUE; + if (mux->sinks != NULL) { + g_slist_foreach (mux->sinks, gst_concat_mux_free_pad, mux); + g_slist_free (mux->sinks); + mux->sinks = NULL; + } +} + + +static GstPadLinkReturn +gst_concat_mux_sinkconnect (GstPad * pad, GstPad * peer) +{ + gchar *pad_name = NULL; + GstConcatMux *concat_mux; + + concat_mux = GST_CONCAT_MUX (gst_pad_get_parent (pad)); + + if (concat_mux->sink_caps != NULL) { + GstCaps *peer_caps = gst_pad_get_caps (peer); + GstCaps *intersect; + + intersect = gst_caps_intersect (concat_mux->sink_caps, peer_caps); + if (intersect == NULL) { + gst_caps_unref (peer_caps); + return GST_PAD_LINK_NOFORMAT; + } + gst_caps_unref (peer_caps); + gst_caps_unref (intersect); + } else { + concat_mux->sink_caps = gst_pad_get_caps (pad); + } + + pad_name = gst_pad_get_name (pad); + + GST_DEBUG_OBJECT (concat_mux, "sinkconnect triggered on %s", pad_name); + + g_free (pad_name); + + gst_object_unref (concat_mux); + + return GST_PAD_LINK_OK; +} + +static GstPad * +gst_concat_mux_request_new_pad (GstElement * element, + GstPadTemplate * templ, const gchar * req_name) +{ + GstConcatMux *concat_mux; + GstPad *newpad; + GstElementClass *klass = GST_ELEMENT_GET_CLASS (element); + GMutex *mutex; + + g_return_val_if_fail (templ != NULL, NULL); + + if (templ->direction != GST_PAD_SINK) { + g_warning ("concat_mux: request pad that is not a SINK pad\n"); + return NULL; + } + + g_return_val_if_fail (GST_IS_CONCAT_MUX (element), NULL); + + concat_mux = GST_CONCAT_MUX (element); + + if (templ == gst_element_class_get_pad_template (klass, "sink_%d")) { + gchar *name; + + /* create new pad with the name */ + name = g_strdup_printf ("sink_%02d", concat_mux->numpads); + g_debug ("NEw pad %s", name); + newpad = gst_pad_new_from_template (templ, name); + g_free (name); + concat_mux->sinks = g_slist_append (concat_mux->sinks, newpad); + g_debug ("New sink %p / %d", newpad, g_slist_length (concat_mux->sinks)); + concat_mux->numpads++; + } else { + g_warning ("concat_mux: this is not our template!\n"); + return NULL; + } + + mutex = g_mutex_new (); + + if (concat_mux->sinkpad == NULL) { + concat_mux->sinkpad = newpad; + } + else { + g_mutex_lock (mutex); + } + + gst_pad_set_element_private (newpad, mutex); + /* setup some pad functions */ + gst_pad_set_link_function (newpad, gst_concat_mux_sinkconnect); + gst_pad_set_event_function (newpad, gst_concat_mux_handle_sink_event); + gst_pad_set_chain_function (newpad, gst_concat_mux_chain); + + /* add the pad to the element */ + gst_element_add_pad (element, newpad); + + return newpad; +} + +/* handle events */ +static gboolean +gst_concat_mux_handle_src_event (GstPad * pad, GstEvent * event) +{ + GstConcatMux *concat_mux; + GstEventType type; + + concat_mux = GST_CONCAT_MUX (gst_pad_get_parent (pad)); + + type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN; + + switch (type) { + case GST_EVENT_SEEK: + /* disable seeking for now */ + return FALSE; + default: + break; + } + + gst_object_unref (concat_mux); + + return gst_pad_event_default (pad, event); +} + +/* handle events */ +static gboolean +gst_concat_mux_handle_sink_event (GstPad * pad, GstEvent * event) +{ + GstConcatMux *mux; + GstEventType type; + + mux = GST_CONCAT_MUX (gst_pad_get_parent (pad)); + + type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN; + + switch (type) { + case GST_EVENT_EOS: + { + mux->resync = TRUE; + g_debug ("sink EOS %p / %d", pad, g_slist_length (mux->sinks)); + /* mark pad eos */ + mux->sinks = g_slist_remove (mux->sinks, pad); + g_debug ("sink len %d", g_slist_length (mux->sinks)); + if (g_slist_length (mux->sinks) != 0) { + GMutex *mutex; + mux->sinkpad = mux->sinks->data; + mutex = (GMutex *) gst_pad_get_element_private (mux->sinkpad); + g_mutex_unlock (mutex); + g_debug ("sink pad %p", mux->sinkpad); + return TRUE; + } + + g_debug ("sink list is empty"); + } + default: + break; + } + + gst_object_unref (mux); + + return gst_pad_event_default (pad, event); +} + +static GstFlowReturn +gst_concat_mux_chain (GstPad * pad, GstBuffer * buf) +{ + GstConcatMux *mux = (GstConcatMux *) GST_PAD_PARENT (pad); + GstBuffer *databuf = NULL; + GstFlowReturn ret = GST_FLOW_OK; + GMutex *mutex; + + + mutex = (GMutex*) gst_pad_get_element_private (pad); + + g_mutex_lock (mutex); + if (mux->done) { + g_debug ("DONE pad %p", pad); + return GST_FLOW_OK; + } + + databuf = gst_buffer_make_metadata_writable (buf); + + if (!mux->negotiated) { + /* + GstCaps *newcaps; + newcaps = gst_pad_get_caps (mux->sinkpad); + + g_debug ("CAPS: %s",gst_caps_to_string (newcaps)); + + if (!gst_pad_set_caps (mux->srcpad, newcaps)) + goto nego_error; + */ + mux->negotiated = TRUE; + } + + g_debug ("Running [%s]\n" + "\tTOFFSET [%"G_GUINT64_FORMAT"]\n" + "\tB_TSTAMP [%"G_GUINT64_FORMAT"]\n" + "\tB_DURATION [%"G_GUINT64_FORMAT"]\n" + "\tOFFSET [%"G_GUINT64_FORMAT"]\n" + "\tB_OFFSET [%"G_GUINT64_FORMAT"]", + gst_element_get_name (mux), + mux->timeoffset, + GST_BUFFER_TIMESTAMP (databuf), + GST_BUFFER_DURATION (databuf), + mux->offset, + GST_BUFFER_OFFSET (databuf)); + + + if (mux->resync) { + g_debug ("RESYNC [%s]", gst_element_get_name (mux)); + mux->timeoffset += GST_BUFFER_TIMESTAMP (databuf); + GST_BUFFER_TIMESTAMP (databuf) = mux->timeoffset; + mux->timeoffset += GST_BUFFER_DURATION (databuf); + + mux->offset += GST_BUFFER_OFFSET (databuf); + GST_BUFFER_OFFSET (databuf) = mux->offset; + mux->offset += GST_BUFFER_SIZE (databuf); + mux->resync = FALSE; + } else { + + GST_BUFFER_TIMESTAMP (databuf) = mux->timeoffset; + mux->timeoffset += GST_BUFFER_DURATION (databuf); + + GST_BUFFER_OFFSET (databuf) = mux->offset; + mux->offset += GST_BUFFER_SIZE (databuf); + } + + gst_buffer_set_caps (databuf, GST_PAD_CAPS (pad)); + ret = gst_pad_push (mux->srcpad, databuf); + + //gst_buffer_unref (buf); + + g_mutex_unlock (mutex); + return ret; +/* +nego_error: + { + GST_WARNING_OBJECT (mux, "failed to set caps"); + GST_ELEMENT_ERROR (mux, CORE, NEGOTIATION, (NULL), (NULL)); + return GST_FLOW_NOT_NEGOTIATED; + } + */ + /* +no_caps: + { + GST_WARNING_OBJECT (mux, "no caps on the incoming buffer %p", best->buffer); + GST_ELEMENT_ERROR (mux, CORE, NEGOTIATION, (NULL), (NULL)); + ret = GST_FLOW_NOT_NEGOTIATED; + goto beach; + } + */ +} + +static GstStateChangeReturn +gst_concat_mux_change_state (GstElement * element, GstStateChange transition) +{ + GstConcatMux *concat_mux; + GstStateChangeReturn ret; + + concat_mux = GST_CONCAT_MUX (element); + + switch (transition) { + case GST_STATE_CHANGE_READY_TO_PAUSED: + concat_mux->done = FALSE; + concat_mux->resync = TRUE; + GST_DEBUG_OBJECT (concat_mux, "starting collect pads"); + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + GST_DEBUG_OBJECT (concat_mux, "stopping collect pads"); + gst_concat_mux_clear (concat_mux); + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + if (ret == GST_STATE_CHANGE_FAILURE) + return ret; + + switch (transition) { + default: + break; + } + + return ret; +} + +gboolean +gst_concat_mux_plugin_init (GstPlugin * plugin) +{ +#ifdef ENABLE_NLS + setlocale (LC_ALL, ""); + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); +#endif /* ENABLE_NLS */ + + GST_DEBUG_CATEGORY_INIT (gst_concat_mux_debug, "concatmux", 0, + "concat muxer"); + + return gst_element_register (plugin, "concatmux", GST_RANK_NONE, + GST_TYPE_CONCAT_MUX); +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "concat muxer", + "Concat streamers", + plugin_init, VERSION, "LGPL", "ConcatMux", "") + diff -r 43ce4ea2f9fb -r 4aac30345986 gst-gmyth/configure.ac --- a/gst-gmyth/configure.ac Tue May 01 16:04:02 2007 +0100 +++ b/gst-gmyth/configure.ac Tue May 01 16:31:26 2007 +0100 @@ -166,7 +166,9 @@ AC_CONFIG_FILES([ Makefile -src/Makefile +mythtvsrc/Makefile +nuvdemux/Makefile +concatmux/Makefile ]) AC_OUTPUT