gstffmpegenc.c 16.3 KB
Newer Older
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
1
/* GStreamer
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 * 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
#include "config.h"
21 22 23 24

#include <assert.h>
#include <string.h>

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

#include <gst/gst.h>

33 34
#include "gstffmpegcodecmap.h"

35 36 37 38 39 40 41 42 43 44
typedef struct _GstFFMpegEnc GstFFMpegEnc;

struct _GstFFMpegEnc {
  GstElement element;

  /* We need to keep track of our pads, so we do so here. */
  GstPad *srcpad;
  GstPad *sinkpad;

  AVCodecContext *context;
Ronald S. Bultje's avatar
Ronald S. Bultje committed
45 46 47 48 49 50 51 52
  AVFrame *picture;
  gboolean opened;

  /* cache */
  gulong bitrate;
  gint me_method;
  gint gop_size;
  gulong buffer_size;
53 54 55 56 57 58 59 60
};

typedef struct _GstFFMpegEncClass GstFFMpegEncClass;

struct _GstFFMpegEncClass {
  GstElementClass parent_class;

  AVCodec *in_plugin;
Ronald S. Bultje's avatar
Ronald S. Bultje committed
61
  GstPadTemplate *srctempl, *sinktempl;
62 63
};

Ronald S. Bultje's avatar
Ronald S. Bultje committed
64 65 66 67 68
typedef struct {
  AVCodec *in_plugin;
  GstPadTemplate *srctempl, *sinktempl;
} GstFFMpegEncClassParams;

69 70 71 72 73 74 75 76 77 78
#define GST_TYPE_FFMPEGENC \
  (gst_ffmpegenc_get_type())
#define GST_FFMPEGENC(obj) \
  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FFMPEGENC,GstFFMpegEnc))
#define GST_FFMPEGENC_CLASS(klass) \
  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FFMPEGENC,GstFFMpegEncClass))
#define GST_IS_FFMPEGENC(obj) \
  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FFMPEGENC))
#define GST_IS_FFMPEGENC_CLASS(obj) \
  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FFMPEGENC))
79

80 81
#define VIDEO_BUFFER_SIZE (1024*1024)

82 83 84 85 86 87 88 89 90 91
enum {
  /* FILL ME */
  LAST_SIGNAL
};

enum {
  ARG_0,
  ARG_BIT_RATE,
  ARG_GOP_SIZE,
  ARG_ME_METHOD,
Ronald S. Bultje's avatar
Ronald S. Bultje committed
92
  ARG_BUFSIZE
93 94 95 96 97 98 99 100 101 102 103 104 105
  /* FILL ME */
};

#define GST_TYPE_ME_METHOD (gst_ffmpegenc_me_method_get_type())
static GType
gst_ffmpegenc_me_method_get_type (void)
{
  static GType ffmpegenc_me_method_type = 0;
  static GEnumValue ffmpegenc_me_methods[] = {
    { ME_ZERO,  "0", "zero" },
    { ME_FULL,  "1", "full" },
    { ME_LOG,   "2", "logarithmic" },
    { ME_PHODS, "3", "phods" },
106 107
    { ME_EPZS,  "4", "epzs" },
    { ME_X1   , "5", "x1" },
108 109 110 111 112 113 114 115 116 117 118 119 120
    { 0, NULL, NULL },
  };
  if (!ffmpegenc_me_method_type) {
    ffmpegenc_me_method_type = g_enum_register_static ("GstFFMpegEncMeMethod", ffmpegenc_me_methods);
  }
  return ffmpegenc_me_method_type;
}

static GHashTable *enc_global_plugins;

/* A number of functon prototypes are given so we can refer to them later. */
static void	gst_ffmpegenc_class_init	(GstFFMpegEncClass *klass);
static void	gst_ffmpegenc_init		(GstFFMpegEnc *ffmpegenc);
Ronald S. Bultje's avatar
Ronald S. Bultje committed
121 122 123 124
static void	gst_ffmpegenc_dispose		(GObject *object);

static GstPadLinkReturn
		gst_ffmpegenc_connect		(GstPad *pad, GstCaps *caps);
125
static void	gst_ffmpegenc_chain		(GstPad *pad, GstData *_data);
126

Ronald S. Bultje's avatar
Ronald S. Bultje committed
127 128 129 130 131 132 133 134
static void	gst_ffmpegenc_set_property	(GObject *object,
						 guint prop_id,
						 const GValue *value,
						 GParamSpec *pspec);
static void	gst_ffmpegenc_get_property	(GObject *object,
						 guint prop_id,
						 GValue *value,
						 GParamSpec *pspec);
135

Ronald S. Bultje's avatar
Ronald S. Bultje committed
136 137
static GstElementStateReturn
		gst_ffmpegenc_change_state	(GstElement *element);
138 139 140

static GstElementClass *parent_class = NULL;

141
/*static guint gst_ffmpegenc_signals[LAST_SIGNAL] = { 0 }; */
142 143 144 145 146 147

static void
gst_ffmpegenc_class_init (GstFFMpegEncClass *klass)
{
  GObjectClass *gobject_class;
  GstElementClass *gstelement_class;
Ronald S. Bultje's avatar
Ronald S. Bultje committed
148
  GstFFMpegEncClassParams *params;
149 150 151 152 153 154

  gobject_class = (GObjectClass*)klass;
  gstelement_class = (GstElementClass*)klass;

  parent_class = g_type_class_ref(GST_TYPE_ELEMENT);

Ronald S. Bultje's avatar
Ronald S. Bultje committed
155
  params = g_hash_table_lookup (enc_global_plugins,
156 157
		  GINT_TO_POINTER (G_OBJECT_CLASS_TYPE (gobject_class)));

Ronald S. Bultje's avatar
Ronald S. Bultje committed
158 159 160 161
  klass->in_plugin = params->in_plugin;
  klass->srctempl = params->srctempl;
  klass->sinktempl = params->sinktempl;

162 163
  if (klass->in_plugin->type == CODEC_TYPE_VIDEO) {
    g_object_class_install_property(G_OBJECT_CLASS (klass), ARG_BIT_RATE,
Ronald S. Bultje's avatar
Ronald S. Bultje committed
164 165 166
      g_param_spec_ulong ("bitrate","Bit Rate",
			  "Target Video Bitrate",
			  0, G_MAXULONG, 300000, G_PARAM_READWRITE)); 
167
    g_object_class_install_property(G_OBJECT_CLASS (klass), ARG_GOP_SIZE,
Ronald S. Bultje's avatar
Ronald S. Bultje committed
168 169 170
      g_param_spec_int ("gop_size","GOP Size",
			"Number of frames within one GOP",
			0, G_MAXINT, 15, G_PARAM_READWRITE)); 
171
    g_object_class_install_property(G_OBJECT_CLASS (klass), ARG_ME_METHOD,
Ronald S. Bultje's avatar
Ronald S. Bultje committed
172 173 174 175 176 177 178
      g_param_spec_enum ("me_method","ME Method",
			 "Motion Estimation Method",
                         GST_TYPE_ME_METHOD, ME_LOG, G_PARAM_READWRITE));
    g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BUFSIZE,
      g_param_spec_ulong("buffer_size", "Buffer Size",
                         "Size of the video buffers",
                         0,G_MAXULONG,0,G_PARAM_READWRITE));
179 180 181
  }
  else if (klass->in_plugin->type == CODEC_TYPE_AUDIO) {
    g_object_class_install_property(G_OBJECT_CLASS (klass), ARG_BIT_RATE,
Ronald S. Bultje's avatar
Ronald S. Bultje committed
182 183 184
      g_param_spec_ulong ("bitrate","Bit Rate",
			  "Target Audio Bitrate",
			  0, G_MAXULONG, 128000, G_PARAM_READWRITE)); 
185 186 187 188 189
  }

  gobject_class->set_property = gst_ffmpegenc_set_property;
  gobject_class->get_property = gst_ffmpegenc_get_property;

Ronald S. Bultje's avatar
Ronald S. Bultje committed
190
  gstelement_class->change_state = gst_ffmpegenc_change_state;
191

Ronald S. Bultje's avatar
Ronald S. Bultje committed
192
  gobject_class->dispose = gst_ffmpegenc_dispose;
193 194 195 196 197 198 199
}

static void
gst_ffmpegenc_init(GstFFMpegEnc *ffmpegenc)
{
  GstFFMpegEncClass *oclass = (GstFFMpegEncClass*)(G_OBJECT_GET_CLASS (ffmpegenc));

Ronald S. Bultje's avatar
Ronald S. Bultje committed
200 201 202 203 204
  /* setup pads */
  ffmpegenc->sinkpad = gst_pad_new_from_template (oclass->sinktempl, "sink");
  gst_pad_set_link_function (ffmpegenc->sinkpad, gst_ffmpegenc_connect);
  gst_pad_set_chain_function (ffmpegenc->sinkpad, gst_ffmpegenc_chain);
  ffmpegenc->srcpad = gst_pad_new_from_template (oclass->srctempl, "src");
205 206 207 208

  gst_element_add_pad (GST_ELEMENT (ffmpegenc), ffmpegenc->sinkpad);
  gst_element_add_pad (GST_ELEMENT (ffmpegenc), ffmpegenc->srcpad);

Ronald S. Bultje's avatar
Ronald S. Bultje committed
209 210 211 212 213 214 215 216 217 218 219 220
  /* ffmpeg objects */
  ffmpegenc->context = avcodec_alloc_context();
  ffmpegenc->picture = avcodec_alloc_frame();
  ffmpegenc->opened = FALSE;

  if (oclass->in_plugin->type == CODEC_TYPE_VIDEO) {
    ffmpegenc->bitrate = 300000;
    ffmpegenc->buffer_size = 512 * 1024;
    ffmpegenc->gop_size = 15;
  } else if (oclass->in_plugin->type == CODEC_TYPE_AUDIO) {
    ffmpegenc->bitrate = 128000;
  }
221 222 223
}

static void
Ronald S. Bultje's avatar
Ronald S. Bultje committed
224
gst_ffmpegenc_dispose (GObject *object)
225
{
Ronald S. Bultje's avatar
Ronald S. Bultje committed
226
  GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) object;
227

Ronald S. Bultje's avatar
Ronald S. Bultje committed
228 229 230 231 232
  /* close old session */
  if (ffmpegenc->opened) {
    avcodec_close (ffmpegenc->context);
    ffmpegenc->opened = FALSE;
  }
233

Ronald S. Bultje's avatar
Ronald S. Bultje committed
234 235 236 237
  /* clean up remaining allocated data */
  av_free (ffmpegenc->context);
  av_free (ffmpegenc->picture);
}
238

Ronald S. Bultje's avatar
Ronald S. Bultje committed
239 240 241 242 243 244 245 246
static GstPadLinkReturn
gst_ffmpegenc_connect (GstPad  *pad,
		       GstCaps *caps)
{
  GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) gst_pad_get_parent (pad);
  GstFFMpegEncClass *oclass = (GstFFMpegEncClass*)(G_OBJECT_GET_CLASS(ffmpegenc));
  GstCaps *ret_caps;
  GstPadLinkReturn ret;
247

Ronald S. Bultje's avatar
Ronald S. Bultje committed
248 249
  if (!GST_CAPS_IS_FIXED (caps))
    return GST_PAD_LINK_DELAYED;
250

Ronald S. Bultje's avatar
Ronald S. Bultje committed
251 252 253 254 255
  /* close old session */
  if (ffmpegenc->opened) {
    avcodec_close (ffmpegenc->context);
    ffmpegenc->opened = FALSE;
  }
256

Ronald S. Bultje's avatar
Ronald S. Bultje committed
257 258 259 260 261 262 263 264
  /* set defaults */
  avcodec_get_context_defaults (ffmpegenc->context);

  /* user defined properties */
  ffmpegenc->context->bit_rate = ffmpegenc->bitrate;
  ffmpegenc->context->bit_rate_tolerance = ffmpegenc->bitrate;
  ffmpegenc->context->gop_size = ffmpegenc->gop_size;
  ffmpegenc->context->me_method = ffmpegenc->me_method;
265

Ronald S. Bultje's avatar
Ronald S. Bultje committed
266 267 268 269
  /* general properties */
  ffmpegenc->context->qmin = 3;
  ffmpegenc->context->qmax = 15;
  ffmpegenc->context->max_qdiff = 3;
270

Ronald S. Bultje's avatar
Ronald S. Bultje committed
271 272
  /* no edges */
  ffmpegenc->context->flags |= CODEC_FLAG_EMU_EDGE;
273

Ronald S. Bultje's avatar
Ronald S. Bultje committed
274 275 276 277 278
  /* FIXME: we actually need to request the framerate
   * from the previous element - we currently use the
   * default (25.0), which is just plain wrong */
  ffmpegenc->context->frame_rate = 25 * DEFAULT_FRAME_RATE_BASE;
  ffmpegenc->context->frame_rate_base = DEFAULT_FRAME_RATE_BASE;
279

280 281 282 283 284 285 286
  for (ret_caps = caps; ret_caps != NULL; ret_caps = ret_caps->next) {
    /* fetch pix_fmt and so on */
    gst_ffmpeg_caps_to_codectype (oclass->in_plugin->type,
				  caps, ffmpegenc->context);

    /* open codec */
    if (avcodec_open (ffmpegenc->context, oclass->in_plugin) < 0) {
287
      GST_DEBUG (
288 289 290 291 292 293 294 295 296
		 "ffenc_%s: Failed to open FFMPEG codec",
		 oclass->in_plugin->name);
      continue;
    }

    break;
  }

  if (ret_caps == NULL) {
Ronald S. Bultje's avatar
Ronald S. Bultje committed
297 298
    return GST_PAD_LINK_REFUSED;
  }
299

Ronald S. Bultje's avatar
Ronald S. Bultje committed
300 301 302 303 304
  /* try to set this caps on the other side */
  ret_caps = gst_ffmpeg_codecid_to_caps (oclass->in_plugin->id,
					 ffmpegenc->context);
  if (!ret_caps) {
    avcodec_close (ffmpegenc->context);
305
    GST_DEBUG (
Ronald S. Bultje's avatar
Ronald S. Bultje committed
306 307
	       "Unsupported codec - no caps found");
    return GST_PAD_LINK_REFUSED;
308
  }
Ronald S. Bultje's avatar
Ronald S. Bultje committed
309 310 311

  if ((ret = gst_pad_try_set_caps (ffmpegenc->srcpad, ret_caps)) <= 0) {
    avcodec_close (ffmpegenc->context);
312
    GST_DEBUG (
Ronald S. Bultje's avatar
Ronald S. Bultje committed
313 314 315
	       "Failed to set caps on next element for ffmpeg encoder (%s)",
               oclass->in_plugin->name);
    return ret;
316 317
  }

Ronald S. Bultje's avatar
Ronald S. Bultje committed
318 319 320 321
  /* success! */
  ffmpegenc->opened = TRUE;

  return GST_PAD_LINK_OK;
322 323 324
}

static void
Ronald S. Bultje's avatar
Ronald S. Bultje committed
325
gst_ffmpegenc_chain (GstPad    *pad,
326
		     GstData *_data)
327
{
328
  GstBuffer *inbuf = GST_BUFFER (_data);
Ronald S. Bultje's avatar
Ronald S. Bultje committed
329
  GstBuffer *outbuf = NULL;
330
  GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *)(gst_pad_get_parent (pad));
Ronald S. Bultje's avatar
Ronald S. Bultje committed
331
  GstFFMpegEncClass *oclass = (GstFFMpegEncClass*)(G_OBJECT_GET_CLASS(ffmpegenc));
332
  gpointer data;
Ronald S. Bultje's avatar
Ronald S. Bultje committed
333
  gint size, ret_size = 0;
334 335 336 337

  data = GST_BUFFER_DATA (inbuf);
  size = GST_BUFFER_SIZE (inbuf);

Ronald S. Bultje's avatar
Ronald S. Bultje committed
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352
  /* FIXME: events (discont (flush!) and eos (close down) etc.) */

  switch (oclass->in_plugin->type) {
    case CODEC_TYPE_VIDEO:
      outbuf = gst_buffer_new_and_alloc (ffmpegenc->buffer_size);
      avpicture_fill ((AVPicture *) ffmpegenc->picture,
		      GST_BUFFER_DATA (inbuf),
		      ffmpegenc->context->pix_fmt,
		      ffmpegenc->context->width,
		      ffmpegenc->context->height);
      ret_size = avcodec_encode_video (ffmpegenc->context,
				       GST_BUFFER_DATA (outbuf),
				       GST_BUFFER_MAXSIZE (outbuf),
				       ffmpegenc->picture);
      break;
353

Ronald S. Bultje's avatar
Ronald S. Bultje committed
354 355 356 357 358 359 360 361 362
    case CODEC_TYPE_AUDIO:
      ffmpegenc->context->frame_size = GST_BUFFER_SIZE (inbuf) /
					 (2 * ffmpegenc->context->channels);
      outbuf = gst_buffer_new_and_alloc (GST_BUFFER_SIZE (inbuf));
      ret_size = avcodec_encode_audio (ffmpegenc->context,
				       GST_BUFFER_DATA (outbuf),
				       GST_BUFFER_MAXSIZE (outbuf),
				       (const short int *)
					 GST_BUFFER_DATA (inbuf));
363
      break;
Ronald S. Bultje's avatar
Ronald S. Bultje committed
364

365
    default:
Ronald S. Bultje's avatar
Ronald S. Bultje committed
366
      g_assert(0);
367 368 369
      break;
  }

370 371 372 373 374 375 376
  if (ret_size < 0) {
    g_warning("ffenc_%s: failed to encode buffer",
	      oclass->in_plugin->name);
    gst_buffer_unref (inbuf);
    return;
  }

Ronald S. Bultje's avatar
Ronald S. Bultje committed
377 378 379 380
  /* bla */
  GST_BUFFER_SIZE (outbuf) = ret_size;
  GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (inbuf);
  GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (inbuf);
381
  gst_pad_push (ffmpegenc->srcpad, GST_DATA (outbuf));
382 383 384 385 386

  gst_buffer_unref (inbuf);
}

static void
Ronald S. Bultje's avatar
Ronald S. Bultje committed
387 388 389 390
gst_ffmpegenc_set_property (GObject      *object,
			    guint         prop_id,
			    const GValue *value,
			    GParamSpec   *pspec)
391 392 393 394 395 396 397 398 399
{
  GstFFMpegEnc *ffmpegenc;

  /* Get a pointer of the right type. */
  ffmpegenc = (GstFFMpegEnc *)(object);

  /* Check the argument id to see which argument we're setting. */
  switch (prop_id) {
    case ARG_BIT_RATE:
Ronald S. Bultje's avatar
Ronald S. Bultje committed
400
      ffmpegenc->bitrate = g_value_get_ulong (value);
401 402
      break;
    case ARG_GOP_SIZE:
Ronald S. Bultje's avatar
Ronald S. Bultje committed
403
      ffmpegenc->gop_size = g_value_get_int (value);
404 405
      break;
    case ARG_ME_METHOD:
Ronald S. Bultje's avatar
Ronald S. Bultje committed
406 407 408 409
      ffmpegenc->me_method = g_value_get_enum (value);
      break;
    case ARG_BUFSIZE:
      ffmpegenc->buffer_size = g_value_get_ulong(value);
410 411 412 413 414 415 416 417 418
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

/* The set function is simply the inverse of the get fuction. */
static void
Ronald S. Bultje's avatar
Ronald S. Bultje committed
419 420 421 422
gst_ffmpegenc_get_property (GObject    *object,
			    guint       prop_id,
			    GValue     *value,
			    GParamSpec *pspec)
423 424 425 426 427 428 429 430
{
  GstFFMpegEnc *ffmpegenc;

  /* It's not null if we got it, but it might not be ours */
  ffmpegenc = (GstFFMpegEnc *)(object);

  switch (prop_id) {
    case ARG_BIT_RATE:
Ronald S. Bultje's avatar
Ronald S. Bultje committed
431
      g_value_set_ulong (value, ffmpegenc->bitrate);
432 433
      break;
    case ARG_GOP_SIZE:
Ronald S. Bultje's avatar
Ronald S. Bultje committed
434
      g_value_set_int (value, ffmpegenc->gop_size);
435 436
      break;
    case ARG_ME_METHOD:
Ronald S. Bultje's avatar
Ronald S. Bultje committed
437 438 439 440
      g_value_set_enum (value, ffmpegenc->me_method);
      break;
    case ARG_BUFSIZE:
      g_value_set_ulong (value, ffmpegenc->buffer_size);
441 442 443 444 445 446 447
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

Ronald S. Bultje's avatar
Ronald S. Bultje committed
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
static GstElementStateReturn
gst_ffmpegenc_change_state (GstElement *element)
{
  GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) element;
  gint transition = GST_STATE_TRANSITION (element);

  switch (transition) {
    case GST_STATE_PAUSED_TO_READY:
      if (ffmpegenc->opened) {
        avcodec_close (ffmpegenc->context);
        ffmpegenc->opened = FALSE;
      }
      break;
  }

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

  return GST_STATE_SUCCESS;
}

469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
gboolean
gst_ffmpegenc_register (GstPlugin *plugin)
{
  GstElementFactory *factory;
  GTypeInfo typeinfo = {
    sizeof(GstFFMpegEncClass),      
    NULL,
    NULL,
    (GClassInitFunc)gst_ffmpegenc_class_init,
    NULL,
    NULL,
    sizeof(GstFFMpegEnc),
    0,
    (GInstanceInitFunc)gst_ffmpegenc_init,
  };
  GType type;
  GstElementDetails *details;
  AVCodec *in_plugin;
  
  in_plugin = first_avcodec;

  enc_global_plugins = g_hash_table_new (NULL, NULL);

  while (in_plugin) {
    gchar *type_name;
Ronald S. Bultje's avatar
Ronald S. Bultje committed
494 495 496
    GstCaps *srccaps, *sinkcaps;
    GstPadTemplate *srctempl, *sinktempl;
    GstFFMpegEncClassParams *params;
497

Ronald S. Bultje's avatar
Ronald S. Bultje committed
498 499 500
    /* no quasi codecs, please */
    if (in_plugin->id == CODEC_ID_RAWVIDEO ||
	(in_plugin->id >= CODEC_ID_PCM_S16LE &&
501
	 in_plugin->id <= CODEC_ID_PCM_ALAW)) {
Ronald S. Bultje's avatar
Ronald S. Bultje committed
502
      goto next;
503
    }
Ronald S. Bultje's avatar
Ronald S. Bultje committed
504 505 506

    /* only encoders */
    if (!in_plugin->encode) {
507 508
      goto next;
    }
Ronald S. Bultje's avatar
Ronald S. Bultje committed
509 510 511 512 513 514 515

    /* first make sure we've got a supported type */
    srccaps = gst_ffmpeg_codecid_to_caps (in_plugin->id, NULL);
    sinkcaps  = gst_ffmpeg_codectype_to_caps (in_plugin->type, NULL);
    if (!sinkcaps || !srccaps)
      goto next;

516
    /* construct the type */
Ronald S. Bultje's avatar
Ronald S. Bultje committed
517
    type_name = g_strdup_printf("ffenc_%s", in_plugin->name);
518

519
    /* if it's already registered, drop it */
520 521 522 523 524
    if (g_type_from_name(type_name)) {
      g_free(type_name);
      goto next;
    }

525
    /* create the glib type now */
526
    type = g_type_register_static(GST_TYPE_ELEMENT, type_name , &typeinfo, 0);
527
    g_return_val_if_fail(type != 0, FALSE);
528

529
    /* construct the element details struct */
530
    details = g_new0 (GstElementDetails,1);
531 532
    details->longname = g_strdup_printf("FFMPEG %s encoder",
					in_plugin->name);
Ronald S. Bultje's avatar
Ronald S. Bultje committed
533 534 535 536 537 538 539
    details->klass = g_strdup_printf("Codec/%s/Encoder",
				     (in_plugin->type == CODEC_TYPE_VIDEO) ?
				     "Video" : "Audio");
    details->license = g_strdup("LGPL");
    details->description = g_strdup_printf("FFMPEG %s encoder",
					   in_plugin->name);
    details->version = g_strdup(VERSION);
540 541
    details->author = g_strdup("The FFMPEG crew, "
				"Wim Taymans <wim.taymans@chello.be>, "
Ronald S. Bultje's avatar
Ronald S. Bultje committed
542 543
				"Ronald Bultje <rbultje@ronald.bitfreak.net>");
    details->copyright = g_strdup("(c) 2001-2003");
544

545
    /* register the plugin with gstreamer */
546
    factory = gst_element_factory_new(type_name,type,details);
547 548
    g_return_val_if_fail(factory != NULL, FALSE);

Ronald S. Bultje's avatar
Ronald S. Bultje committed
549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
    sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK,
				      GST_PAD_ALWAYS, sinkcaps, NULL);
    gst_element_factory_add_pad_template (factory, sinktempl);

    srctempl = gst_pad_template_new ("src", GST_PAD_SRC,
				     GST_PAD_ALWAYS, srccaps, NULL);
    gst_element_factory_add_pad_template (factory, srctempl);

    params = g_new0 (GstFFMpegEncClassParams, 1);
    params->in_plugin = in_plugin;
    params->sinktempl = sinktempl;
    params->srctempl = srctempl;

    g_hash_table_insert (enc_global_plugins, 
		         GINT_TO_POINTER (type), 
			 (gpointer) params);
565 566 567 568 569 570 571 572 573 574

    /* The very last thing is to register the elementfactory with the plugin. */
    gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));

next:
    in_plugin = in_plugin->next;
  }

  return TRUE;
}