gst-gmyth/concatmux/gstconcatmux.c
branchtrunk
changeset 610 3cdc32e43041
child 611 aa1f309ec686
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gst-gmyth/concatmux/gstconcatmux.c	Tue May 01 16:36:58 2007 +0100
     1.3 @@ -0,0 +1,539 @@
     1.4 +/* concat muxer plugin for GStreamer
     1.5 + * Copyright (C) 2004 Renato Filhps <renato.filho@indt.org.br>
     1.6 + *
     1.7 + * This library is free software; you can redistribute it and/or
     1.8 + * modify it under the terms of the GNU Library General Public
     1.9 + * License as published by the Free Software Foundation; either
    1.10 + * version 2 of the License, or (at your option) any later version.
    1.11 + *
    1.12 + * This library is distributed in the hope that it will be useful,
    1.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    1.15 + * Library General Public License for more details.
    1.16 + *
    1.17 + * You should have received a copy of the GNU Library General Public
    1.18 + * License along with this library; if not, write to the
    1.19 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    1.20 + * Boston, MA 02111-1307, USA.
    1.21 + */
    1.22 +
    1.23 +/**
    1.24 + * SECTION:element-concatmux
    1.25 + * @short_description: Concat that takes one or several digital streams
    1.26 + * and muxes them to a single stream.
    1.27 + *
    1.28 + * <refsect2>
    1.29 + * <title>Sample pipelines</title>
    1.30 + * <para>
    1.31 + * Here is a simple pipeline to concat 2 files into a another file:
    1.32 + * <programlisting>
    1.33 + * gst-launch concatmux name=m ! filesink location=output.txt  filesrc location=file_a.txt !  m. filesrc location=file_b.txt ! m.
    1.34 + * </programlisting>
    1.35 + * </para>
    1.36 + * </refsect2>
    1.37 + */
    1.38 +
    1.39 +#ifdef HAVE_CONFIG_H
    1.40 +#include "config.h"
    1.41 +#endif
    1.42 +
    1.43 +#include <gst/gst.h>
    1.44 +#include <gst/base/gstcollectpads.h>
    1.45 +
    1.46 +#include <string.h>
    1.47 +
    1.48 +GST_DEBUG_CATEGORY_STATIC (gst_concat_mux_debug);
    1.49 +#define GST_CAT_DEFAULT gst_concat_mux_debug
    1.50 +
    1.51 +#define GST_TYPE_CONCAT_MUX (gst_concat_mux_get_type())
    1.52 +#define GST_CONCAT_MUX(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CONCAT_MUX, GstConcatMux))
    1.53 +#define GST_CONCAT_MUX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CONCAT_MUX, GstConcatMux))
    1.54 +#define GST_IS_CONCAT_MUX(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CONCAT_MUX))
    1.55 +#define GST_IS_CONCAT_MUX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CONCAT_MUX))
    1.56 +
    1.57 +typedef struct _GstConcatMux GstConcatMux;
    1.58 +typedef struct _GstConcatMuxClass GstConcatMuxClass;
    1.59 +
    1.60 +/**
    1.61 + * GstConcatMux:
    1.62 + *
    1.63 + * The opaque #GstConcatMux structure.
    1.64 + */
    1.65 +struct _GstConcatMux
    1.66 +{
    1.67 +  GstElement element;
    1.68 +
    1.69 +  /* Caps */
    1.70 +  GstCaps *sink_caps;
    1.71 +
    1.72 +  /* pad */
    1.73 +  GstPad *srcpad;
    1.74 +  GstPad *sinkpad;
    1.75 +
    1.76 +  /* sinkpads */
    1.77 +  GSList *sinks;
    1.78 +  gint numpads;
    1.79 +
    1.80 +  /* offset in stream */
    1.81 +  guint64 offset;
    1.82 +  guint64 timeoffset;
    1.83 +  guint64 start_time;
    1.84 +
    1.85 +  gboolean negotiated;
    1.86 +  gboolean resync;
    1.87 +  gboolean done;
    1.88 +};
    1.89 +
    1.90 +struct _GstConcatMuxClass
    1.91 +{
    1.92 +  GstElementClass parent_class;
    1.93 +};
    1.94 +
    1.95 +/* elementfactory information */
    1.96 +static const GstElementDetails gst_concat_mux_details =
    1.97 +GST_ELEMENT_DETAILS ("Concat muxer",
    1.98 +    "Codec/Muxer",
    1.99 +    "mux concat streams",
   1.100 +    "Renato Filho <renato.filho@indt.org>");
   1.101 +
   1.102 +static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
   1.103 +    GST_PAD_SRC,
   1.104 +    GST_PAD_ALWAYS,
   1.105 +    GST_STATIC_CAPS_ANY
   1.106 +    );
   1.107 +
   1.108 +static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink_%d",
   1.109 +    GST_PAD_SINK,
   1.110 +    GST_PAD_REQUEST,
   1.111 +    GST_STATIC_CAPS_ANY         
   1.112 +    );
   1.113 +
   1.114 +static void gst_concat_mux_base_init (gpointer g_class);
   1.115 +static void gst_concat_mux_class_init (GstConcatMuxClass * klass);
   1.116 +static void gst_concat_mux_init (GstConcatMux * concat_mux);
   1.117 +
   1.118 +static void gst_concat_mux_finalize (GObject * object);
   1.119 +
   1.120 +static gboolean gst_concat_mux_handle_src_event (GstPad * pad,
   1.121 +    GstEvent * event);
   1.122 +static gboolean gst_concat_mux_handle_sink_event (GstPad * pad,
   1.123 +    GstEvent * event);
   1.124 +
   1.125 +static GstPad *gst_concat_mux_request_new_pad (GstElement * element,
   1.126 +    GstPadTemplate * templ, const gchar * name);
   1.127 +static GstStateChangeReturn gst_concat_mux_change_state (GstElement *
   1.128 +    element, GstStateChange transition);
   1.129 +
   1.130 +static GstFlowReturn gst_concat_mux_chain (GstPad * pad,  GstBuffer * buf);
   1.131 +static void gst_concat_mux_clear (GstConcatMux *mux);
   1.132 +
   1.133 +
   1.134 +static GstElementClass *parent_class = NULL;
   1.135 +
   1.136 +GType
   1.137 +gst_concat_mux_get_type (void)
   1.138 +{
   1.139 +  static GType concat_mux_type = 0;
   1.140 +
   1.141 +  if (!concat_mux_type) {
   1.142 +    static const GTypeInfo concat_mux_info = {
   1.143 +      sizeof (GstConcatMuxClass),
   1.144 +      gst_concat_mux_base_init,
   1.145 +      NULL,
   1.146 +      (GClassInitFunc) gst_concat_mux_class_init,
   1.147 +      NULL,
   1.148 +      NULL,
   1.149 +      sizeof (GstConcatMux),
   1.150 +      0,
   1.151 +      (GInstanceInitFunc) gst_concat_mux_init,
   1.152 +    };
   1.153 +
   1.154 +    concat_mux_type =
   1.155 +        g_type_register_static (GST_TYPE_ELEMENT, "GstConcatMux",
   1.156 +        &concat_mux_info, 0);
   1.157 +  }
   1.158 +  return concat_mux_type;
   1.159 +}
   1.160 +
   1.161 +static void
   1.162 +gst_concat_mux_base_init (gpointer g_class)
   1.163 +{
   1.164 +  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
   1.165 +
   1.166 +  gst_element_class_add_pad_template (element_class,
   1.167 +      gst_static_pad_template_get (&src_factory));
   1.168 +  gst_element_class_add_pad_template (element_class,
   1.169 +      gst_static_pad_template_get (&sink_factory));
   1.170 +
   1.171 +  gst_element_class_set_details (element_class, &gst_concat_mux_details);
   1.172 +}
   1.173 +
   1.174 +static void
   1.175 +gst_concat_mux_class_init (GstConcatMuxClass * klass)
   1.176 +{
   1.177 +  GObjectClass *gobject_class;
   1.178 +  GstElementClass *gstelement_class;
   1.179 +
   1.180 +  gobject_class = (GObjectClass *) klass;
   1.181 +  gstelement_class = (GstElementClass *) klass;
   1.182 +
   1.183 +  parent_class = g_type_class_peek_parent (klass);
   1.184 +
   1.185 +  gobject_class->finalize = gst_concat_mux_finalize;
   1.186 +
   1.187 +  gstelement_class->request_new_pad = gst_concat_mux_request_new_pad;
   1.188 +  gstelement_class->change_state = gst_concat_mux_change_state;
   1.189 +}
   1.190 +
   1.191 +static void
   1.192 +gst_concat_mux_init (GstConcatMux * concat_mux)
   1.193 +{
   1.194 +  GstElementClass *klass = GST_ELEMENT_GET_CLASS (concat_mux);
   1.195 +
   1.196 +  concat_mux->srcpad =
   1.197 +      gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
   1.198 +          "src"), "src");
   1.199 +  gst_pad_set_event_function (concat_mux->srcpad,
   1.200 +      gst_concat_mux_handle_src_event);
   1.201 +  gst_element_add_pad (GST_ELEMENT (concat_mux), concat_mux->srcpad);
   1.202 +}
   1.203 +
   1.204 +static void
   1.205 +gst_concat_mux_finalize (GObject * object)
   1.206 +{
   1.207 +  GstConcatMux *concat_mux;
   1.208 +
   1.209 +  concat_mux = GST_CONCAT_MUX (object);
   1.210 +  gst_concat_mux_clear (GST_CONCAT_MUX (object));
   1.211 +
   1.212 +  G_OBJECT_CLASS (parent_class)->finalize (object);
   1.213 +}
   1.214 +
   1.215 +static void
   1.216 +gst_concat_mux_free_pad (gpointer data,
   1.217 +                            gpointer user_data)
   1.218 +{
   1.219 +   GMutex *mux;
   1.220 +
   1.221 +   mux = gst_pad_get_element_private (GST_PAD (data));
   1.222 +   g_mutex_unlock (mux);
   1.223 +   g_mutex_free (mux);
   1.224 +   gst_object_unref (GST_OBJECT (data)); 
   1.225 +}
   1.226 +
   1.227 +static void
   1.228 +gst_concat_mux_clear (GstConcatMux *mux)
   1.229 +{
   1.230 +  mux->resync = TRUE;
   1.231 +  mux->timeoffset = 0;
   1.232 +  mux->offset = 0;
   1.233 +  mux->negotiated = FALSE;
   1.234 +  mux->done = TRUE;
   1.235 +  if (mux->sinks != NULL) {
   1.236 +    g_slist_foreach (mux->sinks, gst_concat_mux_free_pad, mux);
   1.237 +    g_slist_free (mux->sinks);
   1.238 +    mux->sinks = NULL;
   1.239 +  }
   1.240 +}
   1.241 +
   1.242 +
   1.243 +static GstPadLinkReturn
   1.244 +gst_concat_mux_sinkconnect (GstPad * pad, GstPad * peer)
   1.245 +{
   1.246 +  gchar *pad_name = NULL;
   1.247 +  GstConcatMux *concat_mux;
   1.248 +
   1.249 +  concat_mux = GST_CONCAT_MUX (gst_pad_get_parent (pad));
   1.250 +
   1.251 +  if (concat_mux->sink_caps != NULL) {
   1.252 +      GstCaps *peer_caps = gst_pad_get_caps (peer);
   1.253 +      GstCaps *intersect;
   1.254 +
   1.255 +      intersect =  gst_caps_intersect (concat_mux->sink_caps, peer_caps);
   1.256 +      if (intersect == NULL) {
   1.257 +          gst_caps_unref (peer_caps);
   1.258 +          return GST_PAD_LINK_NOFORMAT;
   1.259 +      }
   1.260 +      gst_caps_unref (peer_caps);
   1.261 +      gst_caps_unref (intersect);
   1.262 +  } else {
   1.263 +      concat_mux->sink_caps = gst_pad_get_caps (pad);
   1.264 +  }
   1.265 +
   1.266 +  pad_name = gst_pad_get_name (pad);
   1.267 +
   1.268 +  GST_DEBUG_OBJECT (concat_mux, "sinkconnect triggered on %s", pad_name);
   1.269 +
   1.270 +  g_free (pad_name);
   1.271 +
   1.272 +  gst_object_unref (concat_mux);
   1.273 +
   1.274 +  return GST_PAD_LINK_OK;
   1.275 +}
   1.276 +
   1.277 +static GstPad *
   1.278 +gst_concat_mux_request_new_pad (GstElement * element,
   1.279 +    GstPadTemplate * templ, const gchar * req_name)
   1.280 +{
   1.281 +  GstConcatMux *concat_mux;
   1.282 +  GstPad *newpad;
   1.283 +  GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
   1.284 +  GMutex *mutex;
   1.285 +
   1.286 +  g_return_val_if_fail (templ != NULL, NULL);
   1.287 +
   1.288 +  if (templ->direction != GST_PAD_SINK) {
   1.289 +    g_warning ("concat_mux: request pad that is not a SINK pad\n");
   1.290 +    return NULL;
   1.291 +  }
   1.292 +
   1.293 +  g_return_val_if_fail (GST_IS_CONCAT_MUX (element), NULL);
   1.294 +
   1.295 +  concat_mux = GST_CONCAT_MUX (element);
   1.296 +
   1.297 +  if (templ == gst_element_class_get_pad_template (klass, "sink_%d")) {
   1.298 +    gchar *name;
   1.299 +
   1.300 +    /* create new pad with the name */
   1.301 +    name = g_strdup_printf ("sink_%02d", concat_mux->numpads);
   1.302 +    g_debug ("NEw pad %s", name);
   1.303 +    newpad = gst_pad_new_from_template (templ, name);
   1.304 +    g_free (name);
   1.305 +    concat_mux->sinks = g_slist_append (concat_mux->sinks, newpad);
   1.306 +    g_debug ("New sink %p / %d", newpad, g_slist_length (concat_mux->sinks));
   1.307 +    concat_mux->numpads++;
   1.308 +  } else {
   1.309 +    g_warning ("concat_mux: this is not our template!\n");
   1.310 +    return NULL;
   1.311 +  }
   1.312 +
   1.313 +  mutex = g_mutex_new ();
   1.314 +
   1.315 +  if (concat_mux->sinkpad == NULL) {
   1.316 +      concat_mux->sinkpad = newpad;
   1.317 +  }
   1.318 +  else {
   1.319 +      g_mutex_lock (mutex);
   1.320 +  }
   1.321 +
   1.322 +  gst_pad_set_element_private (newpad, mutex);
   1.323 +  /* setup some pad functions */
   1.324 +  gst_pad_set_link_function (newpad, gst_concat_mux_sinkconnect);
   1.325 +  gst_pad_set_event_function (newpad, gst_concat_mux_handle_sink_event);
   1.326 +  gst_pad_set_chain_function (newpad, gst_concat_mux_chain);
   1.327 +
   1.328 +  /* add the pad to the element */
   1.329 +  gst_element_add_pad (element, newpad);
   1.330 +
   1.331 +  return newpad;
   1.332 +}
   1.333 +
   1.334 +/* handle events */
   1.335 +static gboolean
   1.336 +gst_concat_mux_handle_src_event (GstPad * pad, GstEvent * event)
   1.337 +{
   1.338 +  GstConcatMux *concat_mux;
   1.339 +  GstEventType type;
   1.340 +
   1.341 +  concat_mux = GST_CONCAT_MUX (gst_pad_get_parent (pad));
   1.342 +
   1.343 +  type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
   1.344 +
   1.345 +  switch (type) {
   1.346 +    case GST_EVENT_SEEK:
   1.347 +      /* disable seeking for now */
   1.348 +      return FALSE;
   1.349 +    default:
   1.350 +      break;
   1.351 +  }
   1.352 +
   1.353 +  gst_object_unref (concat_mux);
   1.354 +
   1.355 +  return gst_pad_event_default (pad, event);
   1.356 +}
   1.357 +
   1.358 +/* handle events */
   1.359 +static gboolean
   1.360 +gst_concat_mux_handle_sink_event (GstPad * pad, GstEvent * event)
   1.361 +{
   1.362 +  GstConcatMux *mux;
   1.363 +  GstEventType type;
   1.364 +
   1.365 +  mux = GST_CONCAT_MUX (gst_pad_get_parent (pad));
   1.366 +
   1.367 +  type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
   1.368 +
   1.369 +  switch (type) {
   1.370 +    case GST_EVENT_EOS:
   1.371 +    {
   1.372 +        mux->resync = TRUE;
   1.373 +        g_debug ("sink EOS %p / %d", pad, g_slist_length (mux->sinks));
   1.374 +        /* mark pad eos */
   1.375 +        mux->sinks  = g_slist_remove (mux->sinks, pad);
   1.376 +        g_debug ("sink len %d", g_slist_length (mux->sinks));
   1.377 +        if (g_slist_length (mux->sinks) != 0) {
   1.378 +           GMutex *mutex;
   1.379 +           mux->sinkpad = mux->sinks->data;
   1.380 +           mutex = (GMutex *) gst_pad_get_element_private (mux->sinkpad);
   1.381 +           g_mutex_unlock (mutex);
   1.382 +           g_debug ("sink pad %p", mux->sinkpad);
   1.383 +           return TRUE;
   1.384 +        }
   1.385 +
   1.386 +        g_debug ("sink list is empty");
   1.387 +    }
   1.388 +    default:
   1.389 +      break;
   1.390 +  }
   1.391 +
   1.392 +  gst_object_unref (mux);
   1.393 +
   1.394 +  return gst_pad_event_default (pad, event);
   1.395 +}
   1.396 +
   1.397 +static GstFlowReturn
   1.398 +gst_concat_mux_chain (GstPad * pad,  GstBuffer * buf)
   1.399 +{
   1.400 +  GstConcatMux *mux = (GstConcatMux *) GST_PAD_PARENT (pad);
   1.401 +  GstBuffer *databuf = NULL;
   1.402 +  GstFlowReturn ret = GST_FLOW_OK;
   1.403 +  GMutex *mutex;
   1.404 +
   1.405 +
   1.406 +  mutex = (GMutex*) gst_pad_get_element_private (pad);
   1.407 +
   1.408 +  g_mutex_lock (mutex);
   1.409 +  if (mux->done) {
   1.410 +      g_debug ("DONE pad %p", pad);
   1.411 +      return GST_FLOW_OK;
   1.412 +  }
   1.413 +
   1.414 +  databuf = gst_buffer_make_metadata_writable (buf);
   1.415 +
   1.416 +  if (!mux->negotiated) {
   1.417 +      /*
   1.418 +    GstCaps *newcaps;
   1.419 +    newcaps = gst_pad_get_caps (mux->sinkpad);
   1.420 +
   1.421 +    g_debug ("CAPS: %s",gst_caps_to_string (newcaps));
   1.422 +
   1.423 +    if (!gst_pad_set_caps (mux->srcpad, newcaps))
   1.424 +      goto nego_error;
   1.425 +    */
   1.426 +    mux->negotiated = TRUE;            
   1.427 +  } 
   1.428 +
   1.429 +  g_debug ("Running [%s]\n"
   1.430 +        "\tTOFFSET    [%"G_GUINT64_FORMAT"]\n"
   1.431 +        "\tB_TSTAMP   [%"G_GUINT64_FORMAT"]\n"
   1.432 +        "\tB_DURATION [%"G_GUINT64_FORMAT"]\n"
   1.433 +        "\tOFFSET     [%"G_GUINT64_FORMAT"]\n"
   1.434 +        "\tB_OFFSET   [%"G_GUINT64_FORMAT"]",
   1.435 +        gst_element_get_name (mux),
   1.436 +        mux->timeoffset, 
   1.437 +        GST_BUFFER_TIMESTAMP (databuf),
   1.438 +        GST_BUFFER_DURATION (databuf),
   1.439 +        mux->offset,
   1.440 +        GST_BUFFER_OFFSET (databuf));
   1.441 +
   1.442 +
   1.443 +  if (mux->resync) {
   1.444 +    g_debug ("RESYNC [%s]", gst_element_get_name (mux));
   1.445 +    mux->timeoffset += GST_BUFFER_TIMESTAMP (databuf);
   1.446 +    GST_BUFFER_TIMESTAMP (databuf) = mux->timeoffset;
   1.447 +    mux->timeoffset += GST_BUFFER_DURATION (databuf);
   1.448 +
   1.449 +    mux->offset += GST_BUFFER_OFFSET (databuf);
   1.450 +    GST_BUFFER_OFFSET (databuf) = mux->offset;
   1.451 +    mux->offset += GST_BUFFER_SIZE (databuf);
   1.452 +    mux->resync = FALSE;
   1.453 +  } else {
   1.454 +
   1.455 +    GST_BUFFER_TIMESTAMP (databuf) = mux->timeoffset;
   1.456 +    mux->timeoffset += GST_BUFFER_DURATION (databuf);
   1.457 +
   1.458 +    GST_BUFFER_OFFSET (databuf) = mux->offset;
   1.459 +    mux->offset += GST_BUFFER_SIZE (databuf);
   1.460 +  }
   1.461 +
   1.462 +  gst_buffer_set_caps (databuf, GST_PAD_CAPS (pad));
   1.463 +  ret = gst_pad_push (mux->srcpad, databuf);
   1.464 +
   1.465 +  //gst_buffer_unref (buf);
   1.466 +
   1.467 +  g_mutex_unlock (mutex);
   1.468 +  return ret;
   1.469 +/*
   1.470 +nego_error:
   1.471 +  {
   1.472 +    GST_WARNING_OBJECT (mux, "failed to set caps");
   1.473 +    GST_ELEMENT_ERROR (mux, CORE, NEGOTIATION, (NULL), (NULL));
   1.474 +    return GST_FLOW_NOT_NEGOTIATED;
   1.475 +  }
   1.476 +  */
   1.477 +  /*
   1.478 +no_caps:
   1.479 +  {
   1.480 +    GST_WARNING_OBJECT (mux, "no caps on the incoming buffer %p", best->buffer);
   1.481 +    GST_ELEMENT_ERROR (mux, CORE, NEGOTIATION, (NULL), (NULL));
   1.482 +    ret = GST_FLOW_NOT_NEGOTIATED;
   1.483 +    goto beach;
   1.484 +  }
   1.485 +  */
   1.486 +}
   1.487 +
   1.488 +static GstStateChangeReturn
   1.489 +gst_concat_mux_change_state (GstElement * element, GstStateChange transition)
   1.490 +{
   1.491 +  GstConcatMux *concat_mux;
   1.492 +  GstStateChangeReturn ret;
   1.493 +
   1.494 +  concat_mux = GST_CONCAT_MUX (element);
   1.495 +
   1.496 +  switch (transition) {
   1.497 +    case GST_STATE_CHANGE_READY_TO_PAUSED:
   1.498 +      concat_mux->done = FALSE;
   1.499 +      concat_mux->resync = TRUE;
   1.500 +      GST_DEBUG_OBJECT (concat_mux, "starting collect pads");
   1.501 +      break;
   1.502 +    case GST_STATE_CHANGE_PAUSED_TO_READY:
   1.503 +      GST_DEBUG_OBJECT (concat_mux, "stopping collect pads");
   1.504 +      gst_concat_mux_clear (concat_mux);
   1.505 +      break;
   1.506 +    default:
   1.507 +      break;
   1.508 +  }
   1.509 +
   1.510 +  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
   1.511 +  if (ret == GST_STATE_CHANGE_FAILURE)
   1.512 +    return ret;
   1.513 +
   1.514 +  switch (transition) {
   1.515 +    default:
   1.516 +      break;
   1.517 +  }
   1.518 +
   1.519 +  return ret;
   1.520 +}
   1.521 +
   1.522 +gboolean
   1.523 +gst_concat_mux_plugin_init (GstPlugin * plugin)
   1.524 +{
   1.525 +#ifdef ENABLE_NLS
   1.526 +  setlocale (LC_ALL, "");
   1.527 +  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
   1.528 +#endif /* ENABLE_NLS */
   1.529 +
   1.530 +  GST_DEBUG_CATEGORY_INIT (gst_concat_mux_debug, "concatmux", 0,
   1.531 +      "concat muxer");
   1.532 +      
   1.533 +  return gst_element_register (plugin, "concatmux", GST_RANK_NONE,
   1.534 +      GST_TYPE_CONCAT_MUX);
   1.535 +}
   1.536 +
   1.537 +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
   1.538 +    GST_VERSION_MINOR,
   1.539 +    "concat muxer",
   1.540 +    "Concat streamers",
   1.541 +     plugin_init, VERSION, "LGPL", "ConcatMux", "")
   1.542 +