gstffmpegmux.c 15.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/* GStreamer
 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
 *
 * 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.
 */

20
#ifdef HAVE_CONFIG_H
21
#include "config.h"
22 23 24
#endif

#include <string.h>
25 26 27 28 29
#ifdef HAVE_FFMPEG_UNINSTALLED
#include <avformat.h>
#else
#include <ffmpeg/avformat.h>
#endif
30 31

#include <gst/gst.h>
32

33 34
#include "gstffmpegcodecmap.h"

35 36
typedef struct _GstFFMpegMux GstFFMpegMux;

Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
37 38 39
struct _GstFFMpegMux
{
  GstElement element;
40 41

  /* We need to keep track of our pads, so we do so here. */
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
42
  GstPad *srcpad;
43

Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
44 45
  AVFormatContext *context;
  gboolean opened;
46

Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
47 48 49 50
  GstPad *sinkpads[MAX_STREAMS];
  gint videopads, audiopads;
  GstBuffer *bufferqueue[MAX_STREAMS];
  gboolean eos[MAX_STREAMS];
51 52
};

Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
53 54 55 56
typedef struct _GstFFMpegMuxClassParams
{
  AVOutputFormat *in_plugin;
  GstCaps *srccaps, *videosinkcaps, *audiosinkcaps;
57 58
} GstFFMpegMuxClassParams;

59 60
typedef struct _GstFFMpegMuxClass GstFFMpegMuxClass;

Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
61 62 63
struct _GstFFMpegMuxClass
{
  GstElementClass parent_class;
64

Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
65
  AVOutputFormat *in_plugin;
66 67 68 69 70 71 72 73 74 75 76 77 78
};

#define GST_TYPE_FFMPEGMUX \
  (gst_ffmpegdec_get_type())
#define GST_FFMPEGMUX(obj) \
  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FFMPEGMUX,GstFFMpegMux))
#define GST_FFMPEGMUX_CLASS(klass) \
  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FFMPEGMUX,GstFFMpegMuxClass))
#define GST_IS_FFMPEGMUX(obj) \
  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FFMPEGMUX))
#define GST_IS_FFMPEGMUX_CLASS(obj) \
  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FFMPEGMUX))

Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
79 80
enum
{
81 82 83 84
  /* FILL ME */
  LAST_SIGNAL
};

Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
85 86
enum
{
87 88 89 90 91 92 93
  ARG_0,
  /* FILL ME */
};

static GHashTable *global_plugins;

/* A number of functon prototypes are given so we can refer to them later. */
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
94 95 96 97
static void gst_ffmpegmux_class_init (GstFFMpegMuxClass * klass);
static void gst_ffmpegmux_base_init (GstFFMpegMuxClass * klass);
static void gst_ffmpegmux_init (GstFFMpegMux * ffmpegmux);
static void gst_ffmpegmux_dispose (GObject * object);
98

99
static GstPadLinkReturn
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
100 101 102 103
gst_ffmpegmux_connect (GstPad * pad, const GstCaps * caps);
static GstPad *gst_ffmpegmux_request_new_pad (GstElement * element,
    GstPadTemplate * templ, const gchar * name);
static void gst_ffmpegmux_loop (GstElement * element);
104

Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
105
static GstElementStateReturn gst_ffmpegmux_change_state (GstElement * element);
106 107 108 109 110

static GstElementClass *parent_class = NULL;

/*static guint gst_ffmpegmux_signals[LAST_SIGNAL] = { 0 }; */

Ronald S. Bultje's avatar
Bla  
Ronald S. Bultje committed
111
static void
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
112
gst_ffmpegmux_base_init (GstFFMpegMuxClass * klass)
Ronald S. Bultje's avatar
Bla  
Ronald S. Bultje committed
113 114 115
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
Benjamin Otte's avatar
Benjamin Otte committed
116
  GstElementDetails details;
Ronald S. Bultje's avatar
Bla  
Ronald S. Bultje committed
117 118 119 120
  GstFFMpegMuxClassParams *params;
  GstPadTemplate *videosinktempl, *audiosinktempl, *srctempl;

  params = g_hash_table_lookup (global_plugins,
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
121
      GINT_TO_POINTER (G_OBJECT_CLASS_TYPE (gobject_class)));
122
  if (!params)
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
123
    params = g_hash_table_lookup (global_plugins, GINT_TO_POINTER (0));
124
  g_assert (params);
Ronald S. Bultje's avatar
Bla  
Ronald S. Bultje committed
125 126

  /* construct the element details struct */
Benjamin Otte's avatar
Benjamin Otte committed
127
  details.longname = g_strdup_printf ("FFMPEG %s Muxer",
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
128
      params->in_plugin->name);
Benjamin Otte's avatar
Benjamin Otte committed
129 130
  details.klass = g_strdup ("Codec/Muxer");
  details.description = g_strdup_printf ("FFMPEG %s Muxer",
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
131
      params->in_plugin->name);
Benjamin Otte's avatar
Benjamin Otte committed
132
  details.author = "Wim Taymans <wim.taymans@chello.be>, "
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
133
      "Ronald Bultje <rbultje@ronald.bitfreak.net>";
Benjamin Otte's avatar
Benjamin Otte committed
134 135 136 137
  gst_element_class_set_details (element_class, &details);
  g_free (details.longname);
  g_free (details.klass);
  g_free (details.description);
Ronald S. Bultje's avatar
Bla  
Ronald S. Bultje committed
138 139

  /* pad templates */
140
  srctempl = gst_pad_template_new ("src", GST_PAD_SRC,
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
141
      GST_PAD_ALWAYS, params->srccaps);
Ronald S. Bultje's avatar
Bla  
Ronald S. Bultje committed
142
  audiosinktempl = gst_pad_template_new ("audio_%d",
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
143
      GST_PAD_SINK, GST_PAD_REQUEST, params->audiosinkcaps);
Ronald S. Bultje's avatar
Bla  
Ronald S. Bultje committed
144
  videosinktempl = gst_pad_template_new ("video_%d",
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
145
      GST_PAD_SINK, GST_PAD_REQUEST, params->videosinkcaps);
Ronald S. Bultje's avatar
Bla  
Ronald S. Bultje committed
146 147 148 149 150 151 152 153

  gst_element_class_add_pad_template (element_class, srctempl);
  gst_element_class_add_pad_template (element_class, videosinktempl);
  gst_element_class_add_pad_template (element_class, audiosinktempl);

  klass->in_plugin = params->in_plugin;
}

154
static void
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
155
gst_ffmpegmux_class_init (GstFFMpegMuxClass * klass)
156 157 158 159
{
  GObjectClass *gobject_class;
  GstElementClass *gstelement_class;

Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
160 161
  gobject_class = (GObjectClass *) klass;
  gstelement_class = (GstElementClass *) klass;
162

Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
163
  parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
164

165 166 167
  gstelement_class->request_new_pad = gst_ffmpegmux_request_new_pad;
  gstelement_class->change_state = gst_ffmpegmux_change_state;
  gobject_class->dispose = gst_ffmpegmux_dispose;
168 169
}

170
static void
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
171
gst_ffmpegmux_init (GstFFMpegMux * ffmpegmux)
172
{
173
  GstElementClass *klass = GST_ELEMENT_GET_CLASS (ffmpegmux);
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
174
  GstFFMpegMuxClass *oclass = (GstFFMpegMuxClass *) klass;
175
  GstPadTemplate *templ = gst_element_class_get_pad_template (klass, "src");
176

177
  ffmpegmux->srcpad = gst_pad_new_from_template (templ, "src");
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
178 179
  gst_element_set_loop_function (GST_ELEMENT (ffmpegmux), gst_ffmpegmux_loop);
  gst_element_add_pad (GST_ELEMENT (ffmpegmux), ffmpegmux->srcpad);
180 181 182 183

  ffmpegmux->context = g_new0 (AVFormatContext, 1);
  ffmpegmux->context->oformat = oclass->in_plugin;
  ffmpegmux->context->nb_streams = 0;
184
  snprintf (ffmpegmux->context->filename,
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
185 186
      sizeof (ffmpegmux->context->filename),
      "gstreamer://%p", ffmpegmux->srcpad);
187 188 189 190 191
  ffmpegmux->opened = FALSE;

  ffmpegmux->videopads = 0;
  ffmpegmux->audiopads = 0;
}
192

193
static void
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
194
gst_ffmpegmux_dispose (GObject * object)
195 196
{
  GstFFMpegMux *ffmpegmux = (GstFFMpegMux *) object;
197

198 199 200
  if (ffmpegmux->opened) {
    url_fclose (&ffmpegmux->context->pb);
    ffmpegmux->opened = FALSE;
201 202
  }

203
  g_free (ffmpegmux->context);
204 205
}

206
static GstPad *
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
207 208
gst_ffmpegmux_request_new_pad (GstElement * element,
    GstPadTemplate * templ, const gchar * name)
209
{
210
  GstFFMpegMux *ffmpegmux = (GstFFMpegMux *) element;
211
  GstElementClass *klass = GST_ELEMENT_GET_CLASS (element);
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
212
  GstFFMpegMuxClass *oclass = (GstFFMpegMuxClass *) klass;
213 214 215 216
  gchar *padname;
  GstPad *pad;
  AVStream *st;
  enum CodecType type;
217
  gint padnum, bitrate = 0, framesize = 0;
218 219 220 221 222 223

  g_return_val_if_fail (templ != NULL, NULL);
  g_return_val_if_fail (templ->direction == GST_PAD_SINK, NULL);
  g_return_val_if_fail (ffmpegmux->opened == FALSE, NULL);

  /* figure out a name that *we* like */
224
  if (templ == gst_element_class_get_pad_template (klass, "video_%d")) {
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
225
    padname = g_strdup_printf ("video_%d", ffmpegmux->videopads++);
226
    type = CODEC_TYPE_VIDEO;
227 228 229
    bitrate = 64 * 1024;
    framesize = 1152;
  } else if (templ == gst_element_class_get_pad_template (klass, "audio_%d")) {
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
230
    padname = g_strdup_printf ("audio_%d", ffmpegmux->audiopads++);
231
    type = CODEC_TYPE_AUDIO;
232
    bitrate = 285 * 1024;
233
  } else {
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
234
    g_warning ("ffmux: unknown pad template!");
235
    return NULL;
236 237
  }

238 239
  /* create pad */
  pad = gst_pad_new_from_template (templ, padname);
240
  padnum = ffmpegmux->context->nb_streams;
241 242 243 244 245
  ffmpegmux->sinkpads[padnum] = pad;
  gst_pad_set_link_function (pad, gst_ffmpegmux_connect);
  gst_element_add_pad (element, pad);

  /* AVStream needs to be created */
246
  st = av_new_stream (ffmpegmux->context, padnum);
247
  st->codec.codec_type = type;
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
248 249
  st->codec.codec_id = CODEC_ID_NONE;   /* this is a check afterwards */
  st->stream_copy = 1;          /* we're not the actual encoder */
250 251 252
  st->codec.bit_rate = bitrate;
  st->codec.frame_size = framesize;
  /* we fill in codec during capsnego */
253 254

  /* we love debug output (c) (tm) (r) */
255
  GST_DEBUG ("Created %s pad for ffmux_%s element",
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
256
      padname, oclass->in_plugin->name);
257 258 259
  g_free (padname);

  return pad;
260 261
}

262
static GstPadLinkReturn
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
263
gst_ffmpegmux_connect (GstPad * pad, const GstCaps * caps)
264
{
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
265
  GstFFMpegMux *ffmpegmux = (GstFFMpegMux *) (gst_pad_get_parent (pad));
266 267
  gint i;
  AVStream *st;
268

269
  /*g_return_val_if_fail (ffmpegmux->opened == FALSE,
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
270
     GST_PAD_LINK_REFUSED); */
271

272 273 274 275 276 277 278 279 280 281 282 283 284
  for (i = 0; i < ffmpegmux->context->nb_streams; i++) {
    if (pad == ffmpegmux->sinkpads[i]) {
      break;
    }
  }
  if (i == ffmpegmux->context->nb_streams) {
    g_warning ("Unknown pad given during capsnego: %p", pad);
    return GST_PAD_LINK_REFUSED;
  }
  st = ffmpegmux->context->streams[i];

  /* for the format-specific guesses, we'll go to
   * our famous codec mapper */
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
285
  if (gst_ffmpeg_caps_to_codecid (caps, &st->codec) != CODEC_ID_NONE) {
David Schleef's avatar
David Schleef committed
286 287
    ffmpegmux->eos[i] = FALSE;
    return GST_PAD_LINK_OK;
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
288
  }
289 290

  return GST_PAD_LINK_REFUSED;
291 292 293
}

static void
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
294
gst_ffmpegmux_loop (GstElement * element)
295
{
296 297 298
  GstFFMpegMux *ffmpegmux = (GstFFMpegMux *) element;
  gint i, bufnum;

299
  /* start by filling an internal queue of buffers */
300
  for (i = 0; i < ffmpegmux->context->nb_streams; i++) {
301
    GstPad *pad = ffmpegmux->sinkpads[i];
302

303 304
    /* check for "pull'ability" */
    while (pad != NULL &&
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
305 306
        GST_PAD_IS_USABLE (pad) &&
        ffmpegmux->eos[i] == FALSE && ffmpegmux->bufferqueue[i] == NULL) {
307 308 309 310 311
      GstData *data;

      /* we can pull a buffer! */
      data = gst_pad_pull (pad);
      if (GST_IS_EVENT (data)) {
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
312
        GstEvent *event = GST_EVENT (data);
313

Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
314
        switch (GST_EVENT_TYPE (event)) {
315 316 317 318
          case GST_EVENT_EOS:
            /* flag EOS on this stream */
            ffmpegmux->eos[i] = TRUE;
            gst_event_unref (event);
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
319 320 321 322
            break;
          default:
            gst_pad_event_default (pad, event);
            break;
323 324 325 326
        }
      } else {
        ffmpegmux->bufferqueue[i] = GST_BUFFER (data);
      }
327 328
    }
  }
329

330 331
  /* open "file" (gstreamer protocol to next element) */
  if (!ffmpegmux->opened) {
332 333 334 335 336
    /* we do need all streams to have started capsnego,
     * or things will go horribly wrong */
    for (i = 0; i < ffmpegmux->context->nb_streams; i++) {
      AVStream *st = ffmpegmux->context->streams[i];

Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
337
      /* check whether the pad has successfully completed capsnego */
338 339
      if (st->codec.codec_id == CODEC_ID_NONE) {
        GST_ELEMENT_ERROR (element, CORE, NEGOTIATION, (NULL),
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
340 341 342
            ("no caps set on stream %d (%s)", i,
                (st->codec.codec_type == CODEC_TYPE_VIDEO) ?
                "video" : "audio"));
343 344 345 346
        return;
      }
    }

347
    if (url_fopen (&ffmpegmux->context->pb,
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
348
            ffmpegmux->context->filename, URL_WRONLY) < 0) {
349
      GST_ELEMENT_ERROR (element, LIBRARY, TOO_LAZY, (NULL),
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
350
          ("Failed to open stream context in ffmux"));
351
      return;
352 353
    }

354 355
    if (av_set_parameters (ffmpegmux->context, NULL)) {
      GST_ELEMENT_ERROR (element, LIBRARY, INIT, (NULL),
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
356
          ("Failed to initialize muxer"));
357 358 359
      return;
    }

360 361
    /* we're now opened */
    ffmpegmux->opened = TRUE;
362

363
    /* now open the mux format */
364
    av_write_header (ffmpegmux->context);
365 366
  }

367 368 369 370 371 372 373 374
  /* take the one with earliest timestamp,
   * and push it forward */
  bufnum = -1;
  for (i = 0; i < ffmpegmux->context->nb_streams; i++) {
    /* if there's no buffer, just continue */
    if (ffmpegmux->bufferqueue[i] == NULL) {
      continue;
    }
375

376 377 378
    /* if we have no buffer yet, just use the first one */
    if (bufnum == -1) {
      bufnum = i;
379
      continue;
380
    }
381

382 383
    /* if we do have one, only use this one if it's older */
    if (GST_BUFFER_TIMESTAMP (ffmpegmux->bufferqueue[i]) <
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
384
        GST_BUFFER_TIMESTAMP (ffmpegmux->bufferqueue[bufnum])) {
385 386 387
      bufnum = i;
    }
  }
388

389 390 391
  /* now handle the buffer, or signal EOS if we have
   * no buffers left */
  if (bufnum >= 0) {
392 393
    GstBuffer *buf;

394 395 396
    /* push out current buffer */
    buf = ffmpegmux->bufferqueue[bufnum];
    ffmpegmux->bufferqueue[bufnum] = NULL;
397 398 399 400

    ffmpegmux->context->streams[bufnum]->codec.frame_number++;

    /* set time */
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
401 402 403 404
    ffmpegmux->context->streams[bufnum]->pts.val =
        (GST_BUFFER_TIMESTAMP (buf) * 90) / 1000000;
    av_write_frame (ffmpegmux->context, bufnum, GST_BUFFER_DATA (buf),
        GST_BUFFER_SIZE (buf));
405
    //ffmpegmux->context->streams[bufnum]->codec.real_pict_num++;
406 407 408
    gst_buffer_unref (buf);
  } else {
    /* close down */
409
    av_write_trailer (ffmpegmux->context);
410 411 412
    url_fclose (&ffmpegmux->context->pb);
    ffmpegmux->opened = FALSE;
    gst_element_set_eos (element);
413 414 415
  }
}

416
static GstElementStateReturn
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
417
gst_ffmpegmux_change_state (GstElement * element)
418
{
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
419
  GstFFMpegMux *ffmpegmux = (GstFFMpegMux *) (element);
420 421 422 423 424 425 426 427
  gint transition = GST_STATE_TRANSITION (element);

  switch (transition) {
    case GST_STATE_PAUSED_TO_READY:
      if (ffmpegmux->opened) {
        url_fclose (&ffmpegmux->context->pb);
        ffmpegmux->opened = FALSE;
      }
428 429
      break;
  }
430 431 432 433 434

  if (GST_ELEMENT_CLASS (parent_class)->change_state)
    return GST_ELEMENT_CLASS (parent_class)->change_state (element);

  return GST_STATE_SUCCESS;
435 436
}

437

438
gboolean
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
439
gst_ffmpegmux_register (GstPlugin * plugin)
440 441
{
  GTypeInfo typeinfo = {
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
442 443
    sizeof (GstFFMpegMuxClass),
    (GBaseInitFunc) gst_ffmpegmux_base_init,
444
    NULL,
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
445
    (GClassInitFunc) gst_ffmpegmux_class_init,
446 447
    NULL,
    NULL,
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
448
    sizeof (GstFFMpegMux),
449
    0,
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
450
    (GInstanceInitFunc) gst_ffmpegmux_init,
451 452
  };
  GType type;
453 454 455
  AVOutputFormat *in_plugin;
  GstFFMpegMuxClassParams *params;
  AVCodec *in_codec;
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
456

457
  in_plugin = first_oformat;
458 459 460 461 462

  global_plugins = g_hash_table_new (NULL, NULL);

  while (in_plugin) {
    gchar *type_name;
463 464
    gchar *p;
    GstCaps *srccaps, *audiosinkcaps, *videosinkcaps;
465

466 467 468
    /* Try to find the caps that belongs here */
    srccaps = gst_ffmpeg_formatid_to_caps (in_plugin->name);
    if (!srccaps) {
469 470
      goto next;
    }
471 472 473
    /* This is a bit ugly, but we just take all formats
     * for the pad template. We'll get an exact match
     * when we open the stream */
474 475
    audiosinkcaps = gst_caps_new_empty ();
    videosinkcaps = gst_caps_new_empty ();
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
476
    for (in_codec = first_avcodec; in_codec != NULL; in_codec = in_codec->next) {
477
      GstCaps *temp = gst_ffmpeg_codecid_to_caps (in_codec->id, NULL, TRUE);
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
478

479 480 481 482 483
      if (!temp) {
        continue;
      }
      switch (in_codec->type) {
        case CODEC_TYPE_VIDEO:
David Schleef's avatar
David Schleef committed
484
          gst_caps_append (videosinkcaps, temp);
485 486
          break;
        case CODEC_TYPE_AUDIO:
David Schleef's avatar
David Schleef committed
487
          gst_caps_append (audiosinkcaps, temp);
488 489
          break;
        default:
David Schleef's avatar
David Schleef committed
490
          gst_caps_free (temp);
491 492 493 494
          break;
      }
    }

495
    /* construct the type */
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
496
    type_name = g_strdup_printf ("ffmux_%s", in_plugin->name);
497 498 499 500

    p = type_name;

    while (*p) {
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
501 502
      if (*p == '.')
        *p = '_';
503 504
      p++;
    }
505 506

    /* if it's already registered, drop it */
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
507 508
    if (g_type_from_name (type_name)) {
      g_free (type_name);
509 510 511
      goto next;
    }

512 513 514
    /* create a cache for these properties */
    params = g_new0 (GstFFMpegMuxClassParams, 1);
    params->in_plugin = in_plugin;
Ronald S. Bultje's avatar
Bla  
Ronald S. Bultje committed
515 516 517
    params->srccaps = srccaps;
    params->videosinkcaps = videosinkcaps;
    params->audiosinkcaps = audiosinkcaps;
518

Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
519 520
    g_hash_table_insert (global_plugins,
        GINT_TO_POINTER (0), (gpointer) params);
521 522

    /* create the type now */
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
523
    type = g_type_register_static (GST_TYPE_ELEMENT, type_name, &typeinfo, 0);
524 525 526
    if (!gst_element_register (plugin, type_name, GST_RANK_NONE, type))
      return FALSE;

Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
527 528
    g_hash_table_insert (global_plugins,
        GINT_TO_POINTER (type), (gpointer) params);
529

Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
530
  next:
531 532
    in_plugin = in_plugin->next;
  }
533
  g_hash_table_remove (global_plugins, GINT_TO_POINTER (0));
534 535 536

  return TRUE;
}