renatofilho@609: /* concat muxer plugin for GStreamer renatofilho@609: * Copyright (C) 2004 Renato Filhps renatofilho@609: * renatofilho@609: * This library is free software; you can redistribute it and/or renatofilho@609: * modify it under the terms of the GNU Library General Public renatofilho@609: * License as published by the Free Software Foundation; either renatofilho@609: * version 2 of the License, or (at your option) any later version. renatofilho@609: * renatofilho@609: * This library is distributed in the hope that it will be useful, renatofilho@609: * but WITHOUT ANY WARRANTY; without even the implied warranty of renatofilho@609: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU renatofilho@609: * Library General Public License for more details. renatofilho@609: * renatofilho@609: * You should have received a copy of the GNU Library General Public renatofilho@609: * License along with this library; if not, write to the renatofilho@609: * Free Software Foundation, Inc., 59 Temple Place - Suite 330, renatofilho@609: * Boston, MA 02111-1307, USA. renatofilho@609: */ renatofilho@609: renatofilho@609: /** renatofilho@609: * SECTION:element-concatmux renatofilho@609: * @short_description: Concat that takes one or several digital streams renatofilho@609: * and muxes them to a single stream. renatofilho@609: * renatofilho@609: * renatofilho@609: * Sample pipelines renatofilho@609: * renatofilho@609: * Here is a simple pipeline to concat 2 files into a another file: renatofilho@609: * renatofilho@609: * gst-launch concatmux name=m ! filesink location=output.txt filesrc location=file_a.txt ! m. filesrc location=file_b.txt ! m. renatofilho@609: * renatofilho@609: * renatofilho@609: * renatofilho@609: */ renatofilho@609: renatofilho@609: #ifdef HAVE_CONFIG_H renatofilho@609: #include "config.h" renatofilho@609: #endif renatofilho@609: renatofilho@609: #include renatofilho@609: #include renatofilho@609: renatofilho@609: #include renatofilho@609: renatofilho@751: GST_DEBUG_CATEGORY_STATIC(gst_concat_mux_debug); renatofilho@609: #define GST_CAT_DEFAULT gst_concat_mux_debug renatofilho@609: renatofilho@609: #define GST_TYPE_CONCAT_MUX (gst_concat_mux_get_type()) renatofilho@609: #define GST_CONCAT_MUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CONCAT_MUX, GstConcatMux)) renatofilho@609: #define GST_CONCAT_MUX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CONCAT_MUX, GstConcatMux)) renatofilho@609: #define GST_IS_CONCAT_MUX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CONCAT_MUX)) renatofilho@609: #define GST_IS_CONCAT_MUX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CONCAT_MUX)) renatofilho@609: renatofilho@609: typedef struct _GstConcatMux GstConcatMux; renatofilho@609: typedef struct _GstConcatMuxClass GstConcatMuxClass; renatofilho@609: renatofilho@609: /** renatofilho@609: * GstConcatMux: renatofilho@609: * renatofilho@609: * The opaque #GstConcatMux structure. renatofilho@609: */ renatofilho@609: struct _GstConcatMux renatofilho@609: { renatofilho@609: GstElement element; renatofilho@609: renatofilho@751: /* Caps */ renatofilho@609: GstCaps *sink_caps; renatofilho@609: renatofilho@751: /* pad */ renatofilho@609: GstPad *srcpad; renatofilho@609: GstPad *sinkpad; renatofilho@609: renatofilho@751: /* sinkpads */ renatofilho@609: GSList *sinks; renatofilho@609: gint numpads; renatofilho@609: renatofilho@751: /* offset in stream */ renatofilho@609: guint64 offset; renatofilho@609: guint64 timeoffset; renatofilho@609: guint64 start_time; renatofilho@609: renatofilho@609: gboolean negotiated; renatofilho@609: gboolean resync; renatofilho@609: gboolean done; renatofilho@609: }; renatofilho@609: renatofilho@609: struct _GstConcatMuxClass renatofilho@609: { renatofilho@609: GstElementClass parent_class; renatofilho@609: }; renatofilho@609: renatofilho@609: /* elementfactory information */ renatofilho@609: static const GstElementDetails gst_concat_mux_details = renatofilho@751: GST_ELEMENT_DETAILS("Concat muxer", renatofilho@751: "Codec/Muxer", renatofilho@751: "mux concat streams", renatofilho@751: "Renato Filho "); renatofilho@609: renatofilho@751: static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE("src", renatofilho@751: GST_PAD_SRC, renatofilho@751: GST_PAD_ALWAYS, renatofilho@751: GST_STATIC_CAPS_ANY); renatofilho@609: renatofilho@751: static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE("sink_%d", renatofilho@751: GST_PAD_SINK, renatofilho@751: GST_PAD_REQUEST, renatofilho@751: GST_STATIC_CAPS_ANY); renatofilho@609: renatofilho@751: static void gst_concat_mux_base_init(gpointer g_class); renatofilho@751: static void gst_concat_mux_class_init(GstConcatMuxClass * klass); renatofilho@751: static void gst_concat_mux_init(GstConcatMux * concat_mux); renatofilho@609: renatofilho@751: static void gst_concat_mux_finalize(GObject * object); renatofilho@609: renatofilho@751: static gboolean gst_concat_mux_handle_src_event(GstPad * pad, renatofilho@751: GstEvent * event); renatofilho@751: static gboolean gst_concat_mux_handle_sink_event(GstPad * pad, renatofilho@751: GstEvent * event); renatofilho@609: renatofilho@751: static GstPad *gst_concat_mux_request_new_pad(GstElement * element, renatofilho@751: GstPadTemplate * templ, renatofilho@751: const gchar * name); renatofilho@751: static GstStateChangeReturn gst_concat_mux_change_state(GstElement * element, renatofilho@751: GstStateChange renatofilho@751: transition); renatofilho@609: renatofilho@751: static GstFlowReturn gst_concat_mux_chain(GstPad * pad, GstBuffer * buf); renatofilho@751: static void gst_concat_mux_clear(GstConcatMux * mux); renatofilho@609: renatofilho@609: renatofilho@609: static GstElementClass *parent_class = NULL; renatofilho@609: renatofilho@609: GType renatofilho@751: gst_concat_mux_get_type(void) renatofilho@609: { renatofilho@609: static GType concat_mux_type = 0; renatofilho@609: renatofilho@751: if (!concat_mux_type) renatofilho@751: { renatofilho@751: static const GTypeInfo concat_mux_info = { renatofilho@751: sizeof(GstConcatMuxClass), renatofilho@751: gst_concat_mux_base_init, renatofilho@751: NULL, renatofilho@751: (GClassInitFunc) gst_concat_mux_class_init, renatofilho@751: NULL, renatofilho@751: NULL, renatofilho@751: sizeof(GstConcatMux), renatofilho@751: 0, renatofilho@751: (GInstanceInitFunc) gst_concat_mux_init, renatofilho@751: }; renatofilho@609: renatofilho@751: concat_mux_type = renatofilho@751: g_type_register_static(GST_TYPE_ELEMENT, "GstConcatMux", renatofilho@751: &concat_mux_info, 0); renatofilho@751: } renatofilho@609: return concat_mux_type; renatofilho@609: } renatofilho@609: renatofilho@609: static void renatofilho@751: gst_concat_mux_base_init(gpointer g_class) renatofilho@609: { renatofilho@751: GstElementClass *element_class = GST_ELEMENT_CLASS(g_class); renatofilho@609: renatofilho@751: gst_element_class_add_pad_template(element_class, renatofilho@751: gst_static_pad_template_get renatofilho@751: (&src_factory)); renatofilho@751: gst_element_class_add_pad_template(element_class, renatofilho@751: gst_static_pad_template_get renatofilho@751: (&sink_factory)); renatofilho@609: renatofilho@751: gst_element_class_set_details(element_class, &gst_concat_mux_details); renatofilho@609: } renatofilho@609: renatofilho@609: static void renatofilho@751: gst_concat_mux_class_init(GstConcatMuxClass * klass) renatofilho@609: { renatofilho@609: GObjectClass *gobject_class; renatofilho@609: GstElementClass *gstelement_class; renatofilho@609: renatofilho@609: gobject_class = (GObjectClass *) klass; renatofilho@609: gstelement_class = (GstElementClass *) klass; renatofilho@609: renatofilho@751: parent_class = g_type_class_peek_parent(klass); renatofilho@609: renatofilho@609: gobject_class->finalize = gst_concat_mux_finalize; renatofilho@609: renatofilho@609: gstelement_class->request_new_pad = gst_concat_mux_request_new_pad; renatofilho@609: gstelement_class->change_state = gst_concat_mux_change_state; renatofilho@609: } renatofilho@609: renatofilho@609: static void renatofilho@751: gst_concat_mux_init(GstConcatMux * concat_mux) renatofilho@609: { renatofilho@751: GstElementClass *klass = GST_ELEMENT_GET_CLASS(concat_mux); renatofilho@609: renatofilho@609: concat_mux->srcpad = renatofilho@751: gst_pad_new_from_template(gst_element_class_get_pad_template(klass, renatofilho@751: "src"), renatofilho@751: "src"); renatofilho@751: gst_pad_set_event_function(concat_mux->srcpad, renatofilho@751: gst_concat_mux_handle_src_event); renatofilho@751: gst_element_add_pad(GST_ELEMENT(concat_mux), concat_mux->srcpad); renatofilho@609: } renatofilho@609: renatofilho@609: static void renatofilho@751: gst_concat_mux_finalize(GObject * object) renatofilho@609: { renatofilho@609: GstConcatMux *concat_mux; renatofilho@609: renatofilho@751: concat_mux = GST_CONCAT_MUX(object); renatofilho@751: gst_concat_mux_clear(GST_CONCAT_MUX(object)); renatofilho@609: renatofilho@751: G_OBJECT_CLASS(parent_class)->finalize(object); renatofilho@609: } renatofilho@609: renatofilho@609: static void renatofilho@751: gst_concat_mux_free_pad(gpointer data, gpointer user_data) renatofilho@609: { renatofilho@751: GMutex *mux; renatofilho@609: renatofilho@751: mux = gst_pad_get_element_private(GST_PAD(data)); renatofilho@751: g_mutex_unlock(mux); renatofilho@751: g_mutex_free(mux); renatofilho@751: gst_object_unref(GST_OBJECT(data)); renatofilho@609: } renatofilho@609: renatofilho@609: static void renatofilho@751: gst_concat_mux_clear(GstConcatMux * mux) renatofilho@609: { renatofilho@609: mux->resync = TRUE; renatofilho@609: mux->timeoffset = 0; renatofilho@609: mux->offset = 0; renatofilho@609: mux->negotiated = FALSE; renatofilho@609: mux->done = TRUE; renatofilho@751: if (mux->sinks != NULL) renatofilho@751: { renatofilho@751: g_slist_foreach(mux->sinks, gst_concat_mux_free_pad, mux); renatofilho@751: g_slist_free(mux->sinks); renatofilho@751: mux->sinks = NULL; renatofilho@751: } renatofilho@609: } renatofilho@609: renatofilho@609: renatofilho@609: static GstPadLinkReturn renatofilho@751: gst_concat_mux_sinkconnect(GstPad * pad, GstPad * peer) renatofilho@609: { renatofilho@609: gchar *pad_name = NULL; renatofilho@609: GstConcatMux *concat_mux; renatofilho@609: renatofilho@751: concat_mux = GST_CONCAT_MUX(gst_pad_get_parent(pad)); renatofilho@609: renatofilho@751: if (concat_mux->sink_caps != NULL) renatofilho@751: { renatofilho@751: GstCaps *peer_caps = gst_pad_get_caps(peer); renatofilho@751: GstCaps *intersect; renatofilho@609: renatofilho@751: intersect = gst_caps_intersect(concat_mux->sink_caps, peer_caps); renatofilho@751: if (intersect == NULL) renatofilho@751: { renatofilho@751: gst_caps_unref(peer_caps); renatofilho@751: return GST_PAD_LINK_NOFORMAT; renatofilho@751: } renatofilho@751: gst_caps_unref(peer_caps); renatofilho@751: gst_caps_unref(intersect); renatofilho@751: } renatofilho@751: else renatofilho@751: { renatofilho@751: concat_mux->sink_caps = gst_pad_get_caps(pad); renatofilho@751: } renatofilho@609: renatofilho@751: pad_name = gst_pad_get_name(pad); renatofilho@609: renatofilho@751: GST_DEBUG_OBJECT(concat_mux, "sinkconnect triggered on %s", pad_name); renatofilho@609: renatofilho@751: g_free(pad_name); renatofilho@609: renatofilho@751: gst_object_unref(concat_mux); renatofilho@609: renatofilho@609: return GST_PAD_LINK_OK; renatofilho@609: } renatofilho@609: renatofilho@609: static GstPad * renatofilho@751: gst_concat_mux_request_new_pad(GstElement * element, renatofilho@751: GstPadTemplate * templ, const gchar * req_name) renatofilho@609: { renatofilho@609: GstConcatMux *concat_mux; renatofilho@609: GstPad *newpad; renatofilho@751: GstElementClass *klass = GST_ELEMENT_GET_CLASS(element); renatofilho@609: GMutex *mutex; renatofilho@609: renatofilho@751: g_return_val_if_fail(templ != NULL, NULL); renatofilho@609: renatofilho@751: if (templ->direction != GST_PAD_SINK) renatofilho@751: { renatofilho@751: g_warning("concat_mux: request pad that is not a SINK pad\n"); renatofilho@751: return NULL; renatofilho@751: } renatofilho@609: renatofilho@751: g_return_val_if_fail(GST_IS_CONCAT_MUX(element), NULL); renatofilho@609: renatofilho@751: concat_mux = GST_CONCAT_MUX(element); renatofilho@609: renatofilho@751: if (templ == gst_element_class_get_pad_template(klass, "sink_%d")) renatofilho@751: { renatofilho@751: gchar *name; renatofilho@609: renatofilho@751: /* create new pad with the name */ renatofilho@751: name = g_strdup_printf("sink_%02d", concat_mux->numpads); renatofilho@751: g_debug("NEw pad %s", name); renatofilho@751: newpad = gst_pad_new_from_template(templ, name); renatofilho@751: g_free(name); renatofilho@751: concat_mux->sinks = g_slist_append(concat_mux->sinks, newpad); renatofilho@751: g_debug("New sink %p / %d", newpad, g_slist_length(concat_mux->sinks)); renatofilho@751: concat_mux->numpads++; renatofilho@751: } renatofilho@751: else renatofilho@751: { renatofilho@751: g_warning("concat_mux: this is not our template!\n"); renatofilho@751: return NULL; renatofilho@751: } renatofilho@609: renatofilho@751: mutex = g_mutex_new(); renatofilho@609: renatofilho@751: if (concat_mux->sinkpad == NULL) renatofilho@751: { renatofilho@751: concat_mux->sinkpad = newpad; renatofilho@751: } renatofilho@751: else renatofilho@751: { renatofilho@751: g_mutex_lock(mutex); renatofilho@751: } renatofilho@609: renatofilho@751: gst_pad_set_element_private(newpad, mutex); renatofilho@751: /* setup some pad functions */ renatofilho@751: gst_pad_set_link_function(newpad, gst_concat_mux_sinkconnect); renatofilho@751: gst_pad_set_event_function(newpad, gst_concat_mux_handle_sink_event); renatofilho@751: gst_pad_set_chain_function(newpad, gst_concat_mux_chain); renatofilho@609: renatofilho@751: /* add the pad to the element */ renatofilho@751: gst_element_add_pad(element, newpad); renatofilho@609: renatofilho@609: return newpad; renatofilho@609: } renatofilho@609: renatofilho@609: /* handle events */ renatofilho@609: static gboolean renatofilho@751: gst_concat_mux_handle_src_event(GstPad * pad, GstEvent * event) renatofilho@609: { renatofilho@609: GstConcatMux *concat_mux; renatofilho@609: GstEventType type; renatofilho@609: renatofilho@751: concat_mux = GST_CONCAT_MUX(gst_pad_get_parent(pad)); renatofilho@609: renatofilho@751: type = event ? GST_EVENT_TYPE(event) : GST_EVENT_UNKNOWN; renatofilho@609: renatofilho@751: switch (type) renatofilho@751: { renatofilho@751: case GST_EVENT_SEEK: renatofilho@751: /* disable seeking for now */ renatofilho@751: return FALSE; renatofilho@751: default: renatofilho@751: break; renatofilho@751: } renatofilho@609: renatofilho@751: gst_object_unref(concat_mux); renatofilho@609: renatofilho@751: return gst_pad_event_default(pad, event); renatofilho@609: } renatofilho@609: renatofilho@609: /* handle events */ renatofilho@609: static gboolean renatofilho@751: gst_concat_mux_handle_sink_event(GstPad * pad, GstEvent * event) renatofilho@609: { renatofilho@609: GstConcatMux *mux; renatofilho@609: GstEventType type; renatofilho@609: renatofilho@751: mux = GST_CONCAT_MUX(gst_pad_get_parent(pad)); renatofilho@609: renatofilho@751: type = event ? GST_EVENT_TYPE(event) : GST_EVENT_UNKNOWN; renatofilho@609: renatofilho@751: switch (type) renatofilho@751: { renatofilho@751: case GST_EVENT_EOS: renatofilho@751: { renatofilho@751: mux->resync = TRUE; renatofilho@751: g_debug("sink EOS %p / %d", pad, g_slist_length(mux->sinks)); renatofilho@751: /* mark pad eos */ renatofilho@751: mux->sinks = g_slist_remove(mux->sinks, pad); renatofilho@751: g_debug("sink len %d", g_slist_length(mux->sinks)); renatofilho@751: if (g_slist_length(mux->sinks) != 0) renatofilho@751: { renatofilho@751: GMutex *mutex; renatofilho@751: mux->sinkpad = mux->sinks->data; renatofilho@751: mutex = (GMutex *) gst_pad_get_element_private(mux->sinkpad); renatofilho@751: g_mutex_unlock(mutex); renatofilho@751: g_debug("sink pad %p", mux->sinkpad); renatofilho@751: return TRUE; renatofilho@751: } renatofilho@609: renatofilho@751: g_debug("sink list is empty"); renatofilho@751: } renatofilho@751: default: renatofilho@751: break; renatofilho@751: } renatofilho@609: renatofilho@751: gst_object_unref(mux); renatofilho@609: renatofilho@751: return gst_pad_event_default(pad, event); renatofilho@609: } renatofilho@609: renatofilho@609: static GstFlowReturn renatofilho@751: gst_concat_mux_chain(GstPad * pad, GstBuffer * buf) renatofilho@609: { renatofilho@751: GstConcatMux *mux = (GstConcatMux *) GST_PAD_PARENT(pad); renatofilho@609: GstBuffer *databuf = NULL; renatofilho@609: GstFlowReturn ret = GST_FLOW_OK; renatofilho@609: GMutex *mutex; renatofilho@609: renatofilho@609: renatofilho@751: mutex = (GMutex *) gst_pad_get_element_private(pad); renatofilho@609: renatofilho@751: g_mutex_lock(mutex); renatofilho@751: if (mux->done) renatofilho@751: { renatofilho@751: g_debug("DONE pad %p", pad); renatofilho@751: g_mutex_unlock(mutex); renatofilho@751: return GST_FLOW_OK; renatofilho@751: } renatofilho@609: renatofilho@751: databuf = gst_buffer_make_metadata_writable(buf); renatofilho@609: renatofilho@751: if (!mux->negotiated) renatofilho@751: { renatofilho@751: /* renatofilho@751: GstCaps *newcaps; renatofilho@751: newcaps = gst_pad_get_caps (mux->sinkpad); renatofilho@609: renatofilho@751: g_debug ("CAPS: %s",gst_caps_to_string (newcaps)); renatofilho@609: renatofilho@751: if (!gst_pad_set_caps (mux->srcpad, newcaps)) renatofilho@751: goto nego_error; renatofilho@751: */ renatofilho@751: mux->negotiated = TRUE; renatofilho@751: } renatofilho@609: renatofilho@751: /* renatofilho@751: g_debug ("Running [%s]\n" renatofilho@751: "\tTOFFSET [%"G_GUINT64_FORMAT"]\n" renatofilho@751: "\tB_TSTAMP [%"G_GUINT64_FORMAT"]\n" renatofilho@751: "\tB_DURATION [%"G_GUINT64_FORMAT"]\n" renatofilho@751: "\tOFFSET [%"G_GUINT64_FORMAT"]\n" renatofilho@751: "\tB_OFFSET [%"G_GUINT64_FORMAT"]", renatofilho@751: gst_element_get_name (mux), renatofilho@751: mux->timeoffset, renatofilho@751: GST_BUFFER_TIMESTAMP (databuf), renatofilho@751: GST_BUFFER_DURATION (databuf), renatofilho@751: mux->offset, renatofilho@751: GST_BUFFER_OFFSET (databuf)); renatofilho@751: */ renatofilho@609: renatofilho@609: renatofilho@751: if (mux->resync) renatofilho@751: { renatofilho@751: g_debug("RESYNC [%s]", gst_element_get_name(mux)); renatofilho@751: mux->timeoffset += GST_BUFFER_TIMESTAMP(databuf); renatofilho@751: GST_BUFFER_TIMESTAMP(databuf) = mux->timeoffset; renatofilho@751: mux->timeoffset += GST_BUFFER_DURATION(databuf); renatofilho@609: renatofilho@751: mux->offset += GST_BUFFER_OFFSET(databuf); renatofilho@751: GST_BUFFER_OFFSET(databuf) = mux->offset; renatofilho@751: mux->offset += GST_BUFFER_SIZE(databuf); renatofilho@751: mux->resync = FALSE; renatofilho@751: } renatofilho@751: else renatofilho@751: { renatofilho@609: renatofilho@751: GST_BUFFER_TIMESTAMP(databuf) = mux->timeoffset; renatofilho@751: mux->timeoffset += GST_BUFFER_DURATION(databuf); renatofilho@609: renatofilho@751: GST_BUFFER_OFFSET(databuf) = mux->offset; renatofilho@751: mux->offset += GST_BUFFER_SIZE(databuf); renatofilho@751: } renatofilho@609: renatofilho@751: gst_buffer_set_caps(databuf, GST_PAD_CAPS(pad)); renatofilho@751: ret = gst_pad_push(mux->srcpad, databuf); renatofilho@609: renatofilho@751: //gst_buffer_unref (buf); renatofilho@609: renatofilho@751: g_mutex_unlock(mutex); renatofilho@609: return ret; renatofilho@609: /* renatofilho@609: nego_error: renatofilho@609: { renatofilho@609: GST_WARNING_OBJECT (mux, "failed to set caps"); renatofilho@609: GST_ELEMENT_ERROR (mux, CORE, NEGOTIATION, (NULL), (NULL)); renatofilho@609: return GST_FLOW_NOT_NEGOTIATED; renatofilho@609: } renatofilho@609: */ renatofilho@751: /* renatofilho@751: no_caps: renatofilho@751: { renatofilho@609: GST_WARNING_OBJECT (mux, "no caps on the incoming buffer %p", best->buffer); renatofilho@609: GST_ELEMENT_ERROR (mux, CORE, NEGOTIATION, (NULL), (NULL)); renatofilho@609: ret = GST_FLOW_NOT_NEGOTIATED; renatofilho@609: goto beach; renatofilho@751: } renatofilho@609: */ renatofilho@609: } renatofilho@609: renatofilho@609: static GstStateChangeReturn renatofilho@751: gst_concat_mux_change_state(GstElement * element, GstStateChange transition) renatofilho@609: { renatofilho@609: GstConcatMux *concat_mux; renatofilho@609: GstStateChangeReturn ret; renatofilho@609: renatofilho@751: concat_mux = GST_CONCAT_MUX(element); renatofilho@609: renatofilho@751: switch (transition) renatofilho@751: { renatofilho@751: case GST_STATE_CHANGE_READY_TO_PAUSED: renatofilho@751: concat_mux->done = FALSE; renatofilho@751: concat_mux->resync = TRUE; renatofilho@751: GST_DEBUG_OBJECT(concat_mux, "starting collect pads"); renatofilho@751: break; renatofilho@751: case GST_STATE_CHANGE_PAUSED_TO_READY: renatofilho@751: GST_DEBUG_OBJECT(concat_mux, "stopping collect pads"); renatofilho@751: gst_concat_mux_clear(concat_mux); renatofilho@751: break; renatofilho@751: default: renatofilho@751: break; renatofilho@751: } renatofilho@609: renatofilho@751: ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition); renatofilho@609: if (ret == GST_STATE_CHANGE_FAILURE) renatofilho@751: return ret; renatofilho@609: renatofilho@751: switch (transition) renatofilho@751: { renatofilho@751: default: renatofilho@751: break; renatofilho@751: } renatofilho@609: renatofilho@609: return ret; renatofilho@609: } renatofilho@609: renatofilho@609: gboolean renatofilho@751: gst_concat_mux_plugin_init(GstPlugin * plugin) renatofilho@609: { renatofilho@609: #ifdef ENABLE_NLS renatofilho@751: setlocale(LC_ALL, ""); renatofilho@751: bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR); renatofilho@609: #endif /* ENABLE_NLS */ renatofilho@609: renatofilho@751: GST_DEBUG_CATEGORY_INIT(gst_concat_mux_debug, "concatmux", 0, renatofilho@751: "concat muxer"); renatofilho@751: renatofilho@751: return gst_element_register(plugin, "concatmux", GST_RANK_NONE, renatofilho@751: GST_TYPE_CONCAT_MUX); renatofilho@609: } renatofilho@609: renatofilho@751: GST_PLUGIN_DEFINE(GST_VERSION_MAJOR, renatofilho@751: GST_VERSION_MINOR, renatofilho@751: "concatmux", renatofilho@751: "Concat streamers", renatofilho@751: gst_concat_mux_plugin_init, VERSION, GST_LICENSE, renatofilho@751: GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)