gstffmpegdec.c 33.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
#ifdef HAVE_CONFIG_H
21
#include "config.h"
22
#endif
23

24
#include <assert.h>
25
#include <string.h>
26

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

#include <gst/gst.h>

35
#include "gstffmpeg.h"
36
#include "gstffmpegcodecmap.h"
37

38 39
typedef struct _GstFFMpegDec GstFFMpegDec;

Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
40 41
struct _GstFFMpegDec
{
42 43 44 45 46 47
  GstElement element;

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

48
  /* decoding */
49
  AVCodecContext *context;
50
  AVFrame *picture;
51
  gboolean opened;
52 53 54 55 56 57 58
  union {
    struct {
      gint width, height, fps, fps_base;
    } video;
    struct {
      gint channels, samplerate;
    } audio;
59
  } format;
60
  gboolean waiting_for_key;
61
  guint64 next_ts;
62

63 64 65 66
  /* parsing */
  AVCodecParserContext *pctx;
  GstBuffer *pcache;

67
  GValue *par;		/* pixel aspect ratio of incoming data */
68 69

  gint hurry_up, lowres;
70 71 72 73
};

typedef struct _GstFFMpegDecClass GstFFMpegDecClass;

Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
74 75
struct _GstFFMpegDecClass
{
76 77 78
  GstElementClass parent_class;

  AVCodec *in_plugin;
79
  GstPadTemplate *srctempl, *sinktempl;
80 81
};

Ronald S. Bultje's avatar
Bla  
Ronald S. Bultje committed
82 83
typedef struct _GstFFMpegDecClassParams GstFFMpegDecClassParams;

Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
84 85
struct _GstFFMpegDecClassParams
{
86
  AVCodec *in_plugin;
Ronald S. Bultje's avatar
Bla  
Ronald S. Bultje committed
87 88
  GstCaps *srccaps, *sinkcaps;
};
89

90 91 92 93 94 95 96 97 98 99
#define GST_TYPE_FFMPEGDEC \
  (gst_ffmpegdec_get_type())
#define GST_FFMPEGDEC(obj) \
  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FFMPEGDEC,GstFFMpegDec))
#define GST_FFMPEGDEC_CLASS(klass) \
  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FFMPEGDEC,GstFFMpegDecClass))
#define GST_IS_FFMPEGDEC(obj) \
  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FFMPEGDEC))
#define GST_IS_FFMPEGDEC_CLASS(obj) \
  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FFMPEGDEC))
100

Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
101 102
enum
{
103
  ARG_0,
104 105
  ARG_LOWRES,
  ARG_SKIPFRAME
106 107 108 109 110
};

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
111 112 113 114
static void gst_ffmpegdec_base_init (GstFFMpegDecClass * klass);
static void gst_ffmpegdec_class_init (GstFFMpegDecClass * klass);
static void gst_ffmpegdec_init (GstFFMpegDec * ffmpegdec);
static void gst_ffmpegdec_dispose (GObject * object);
115

116 117 118 119
static gboolean gst_ffmpegdec_query (GstPad * pad, GstQueryType type,
    GstFormat * fmt, gint64 * value);
static gboolean gst_ffmpegdec_event (GstPad * pad, GstEvent * event);

Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
120 121 122
static GstPadLinkReturn gst_ffmpegdec_connect (GstPad * pad,
    const GstCaps * caps);
static void gst_ffmpegdec_chain (GstPad * pad, GstData * data);
123

Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
124
static GstElementStateReturn gst_ffmpegdec_change_state (GstElement * element);
125

126 127 128 129 130
static void gst_ffmpegdec_set_property (GObject * object,
    guint prop_id, const GValue * value, GParamSpec * pspec);
static void gst_ffmpegdec_get_property (GObject * object,
    guint prop_id, GValue * value, GParamSpec * pspec);

131
#if 0
132
/* some sort of bufferpool handling, but different */
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
133 134 135 136
static int gst_ffmpegdec_get_buffer (AVCodecContext * context,
    AVFrame * picture);
static void gst_ffmpegdec_release_buffer (AVCodecContext * context,
    AVFrame * picture);
137
#endif
138 139 140

static GstElementClass *parent_class = NULL;

141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
#define GST_FFMPEGDEC_TYPE_LOWRES (gst_ffmpegdec_lowres_get_type())
static GType
gst_ffmpegdec_lowres_get_type (void)
{
  static GType ffmpegdec_lowres_type = 0;

  if (!ffmpegdec_lowres_type) {
    static GEnumValue ffmpegdec_lowres[] = {
      {0, "0", "full"},
      {1, "1", "1/2-size"},
      {2, "2", "1/4-size"},
      {0, NULL, NULL},
    };

    ffmpegdec_lowres_type =
        g_enum_register_static ("GstFFMpegDecLowres", ffmpegdec_lowres);
  }

  return ffmpegdec_lowres_type;
}

#define GST_FFMPEGDEC_TYPE_SKIPFRAME (gst_ffmpegdec_skipframe_get_type())
static GType
gst_ffmpegdec_skipframe_get_type (void)
{
  static GType ffmpegdec_skipframe_type = 0;

  if (!ffmpegdec_skipframe_type) {
    static GEnumValue ffmpegdec_skipframe[] = {
      {0, "0", "Skip nothing"},
      {1, "1", "Skip B-frames"},
      {2, "2", "Skip IDCT/Dequantization"},
      {5, "5", "Skip everything"},
      {0, NULL, NULL},
    };

    ffmpegdec_skipframe_type =
        g_enum_register_static ("GstFFMpegDecSkipFrame", ffmpegdec_skipframe);
  }

  return ffmpegdec_skipframe_type;
}
183

Ronald S. Bultje's avatar
Bla  
Ronald S. Bultje committed
184
static void
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
185
gst_ffmpegdec_base_init (GstFFMpegDecClass * klass)
Ronald S. Bultje's avatar
Bla  
Ronald S. Bultje committed
186 187 188 189
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
  GstFFMpegDecClassParams *params;
Benjamin Otte's avatar
Benjamin Otte committed
190
  GstElementDetails details;
Ronald S. Bultje's avatar
Bla  
Ronald S. Bultje committed
191 192 193
  GstPadTemplate *sinktempl, *srctempl;

  params = g_hash_table_lookup (global_plugins,
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
194
      GINT_TO_POINTER (G_OBJECT_CLASS_TYPE (gobject_class)));
195
  if (!params)
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
196
    params = g_hash_table_lookup (global_plugins, GINT_TO_POINTER (0));
197
  g_assert (params);
Ronald S. Bultje's avatar
Bla  
Ronald S. Bultje committed
198 199

  /* construct the element details struct */
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
200
  details.longname = g_strdup_printf ("FFMPEG %s decoder",
201
      gst_ffmpeg_get_codecid_longname (params->in_plugin->id));
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
202
  details.klass = g_strdup_printf ("Codec/Decoder/%s",
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
203 204 205
      (params->in_plugin->type == CODEC_TYPE_VIDEO) ? "Video" : "Audio");
  details.description = g_strdup_printf ("FFMPEG %s decoder",
      params->in_plugin->name);
Benjamin Otte's avatar
Benjamin Otte committed
206
  details.author = "Wim Taymans <wim.taymans@chello.be>, "
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
207
      "Ronald Bultje <rbultje@ronald.bitfreak.net>";
Benjamin Otte's avatar
Benjamin Otte committed
208 209 210 211
  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
212 213 214

  /* pad templates */
  sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK,
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
215
      GST_PAD_ALWAYS, params->sinkcaps);
Ronald S. Bultje's avatar
Bla  
Ronald S. Bultje committed
216
  srctempl = gst_pad_template_new ("src", GST_PAD_SRC,
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
217
      GST_PAD_ALWAYS, params->srccaps);
Ronald S. Bultje's avatar
Bla  
Ronald S. Bultje committed
218 219 220 221 222 223 224 225 226

  gst_element_class_add_pad_template (element_class, srctempl);
  gst_element_class_add_pad_template (element_class, sinktempl);

  klass->in_plugin = params->in_plugin;
  klass->srctempl = srctempl;
  klass->sinktempl = sinktempl;
}

227
static void
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
228
gst_ffmpegdec_class_init (GstFFMpegDecClass * klass)
229
{
230 231
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
232

233
  parent_class = g_type_class_peek_parent (klass);
234

235 236 237 238 239 240 241 242 243
  g_object_class_install_property (gobject_class, ARG_SKIPFRAME,
      g_param_spec_enum ("skip-frame", "Skip frames",
          "Which types of frames to skip during decoding",
          GST_FFMPEGDEC_TYPE_SKIPFRAME, 0, G_PARAM_READWRITE));
  g_object_class_install_property (gobject_class, ARG_LOWRES,
      g_param_spec_enum ("lowres", "Low resolution",
          "At which resolution to decode images",
          GST_FFMPEGDEC_TYPE_LOWRES, 0, G_PARAM_READWRITE));

244
  gobject_class->dispose = gst_ffmpegdec_dispose;
245 246
  gobject_class->set_property = gst_ffmpegdec_set_property;
  gobject_class->get_property = gst_ffmpegdec_get_property;
247 248 249 250
  gstelement_class->change_state = gst_ffmpegdec_change_state;
}

static void
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
251
gst_ffmpegdec_init (GstFFMpegDec * ffmpegdec)
252
{
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
253 254
  GstFFMpegDecClass *oclass =
      (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
255 256 257 258 259

  /* setup pads */
  ffmpegdec->sinkpad = gst_pad_new_from_template (oclass->sinktempl, "sink");
  gst_pad_set_link_function (ffmpegdec->sinkpad, gst_ffmpegdec_connect);
  gst_pad_set_chain_function (ffmpegdec->sinkpad, gst_ffmpegdec_chain);
260 261
  gst_element_add_pad (GST_ELEMENT (ffmpegdec), ffmpegdec->sinkpad);

262
  ffmpegdec->srcpad = gst_pad_new_from_template (oclass->srctempl, "src");
263
  gst_pad_use_explicit_caps (ffmpegdec->srcpad);
264 265 266 267
  gst_pad_set_event_function (ffmpegdec->srcpad,
      GST_DEBUG_FUNCPTR (gst_ffmpegdec_event));
  gst_pad_set_query_function (ffmpegdec->srcpad,
      GST_DEBUG_FUNCPTR (gst_ffmpegdec_query));
268 269 270
  gst_element_add_pad (GST_ELEMENT (ffmpegdec), ffmpegdec->srcpad);

  /* some ffmpeg data */
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
271 272
  ffmpegdec->context = avcodec_alloc_context ();
  ffmpegdec->picture = avcodec_alloc_frame ();
273 274
  ffmpegdec->pctx = NULL;
  ffmpegdec->pcache = NULL;
275
  ffmpegdec->par = NULL;
276
  ffmpegdec->opened = FALSE;
277
  ffmpegdec->waiting_for_key = FALSE;
278
  ffmpegdec->hurry_up = ffmpegdec->lowres = 0;
279 280

  GST_FLAG_SET (ffmpegdec, GST_ELEMENT_EVENT_AWARE);
281 282 283
}

static void
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
284
gst_ffmpegdec_dispose (GObject * object)
285 286
{
  GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) object;
287 288 289 290

  G_OBJECT_CLASS (parent_class)->dispose (object);
  /* old session should have been closed in element_class->dispose */
  g_assert (!ffmpegdec->opened);
291

292 293 294
  /* clean up remaining allocated data */
  av_free (ffmpegdec->context);
  av_free (ffmpegdec->picture);
295 296
}

297 298 299 300 301 302 303 304 305 306
static gboolean
gst_ffmpegdec_query (GstPad * pad, GstQueryType type,
    GstFormat * fmt, gint64 * value)
{
  GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) gst_pad_get_parent (pad);
  GstPad *peer = GST_PAD_PEER (ffmpegdec->sinkpad);
  GstFormat bfmt = GST_FORMAT_BYTES;

  if (!peer)
    return FALSE;
307 308

  if (gst_pad_query (peer, type, fmt, value))
309
    return TRUE;
310

311
  /* ok, do bitrate calc... */
312
  if ((type != GST_QUERY_POSITION && type != GST_QUERY_TOTAL) ||
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
           *fmt != GST_FORMAT_TIME || ffmpegdec->context->bit_rate == 0 ||
           !gst_pad_query (peer, type, &bfmt, value))
    return FALSE;

  if (ffmpegdec->pcache && type == GST_QUERY_POSITION)
    *value -= GST_BUFFER_SIZE (ffmpegdec->pcache);
  *value *= GST_SECOND / ffmpegdec->context->bit_rate;

  return TRUE;
}

static gboolean
gst_ffmpegdec_event (GstPad * pad, GstEvent * event)
{
  GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) gst_pad_get_parent (pad);
  GstPad *peer = GST_PAD_PEER (ffmpegdec->sinkpad);

  if (!peer)
    return FALSE;
332 333 334 335

  gst_event_ref (event);
  if (gst_pad_send_event (peer, event)) {
    gst_event_unref (event);
336
    return TRUE;
337 338 339 340 341
  }

  gst_event_unref (event);

  return FALSE; /* .. */
342 343
}

344 345 346 347 348 349
static void
gst_ffmpegdec_close (GstFFMpegDec *ffmpegdec)
{
  if (!ffmpegdec->opened)
    return;

350 351 352 353 354
  if (ffmpegdec->par) {
    g_free (ffmpegdec->par);
    ffmpegdec->par = NULL;
  }

355 356
  if (ffmpegdec->context->priv_data)
    avcodec_close (ffmpegdec->context);
357 358 359 360 361 362 363 364 365 366 367
  ffmpegdec->opened = FALSE;

  if (ffmpegdec->context->palctrl) {
    av_free (ffmpegdec->context->palctrl);
    ffmpegdec->context->palctrl = NULL;
  }

  if (ffmpegdec->context->extradata) {
    av_free (ffmpegdec->context->extradata);
    ffmpegdec->context->extradata = NULL;
  }
368 369 370 371 372 373 374 375 376

  if (ffmpegdec->pctx) {
    if (ffmpegdec->pcache) {
      gst_buffer_unref (ffmpegdec->pcache);
      ffmpegdec->pcache = NULL;
    }
    av_parser_close (ffmpegdec->pctx);
    ffmpegdec->pctx = NULL;
  }
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392
}

static gboolean
gst_ffmpegdec_open (GstFFMpegDec *ffmpegdec)
{
  GstFFMpegDecClass *oclass =
      (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));

  ffmpegdec->opened = TRUE;
  if (avcodec_open (ffmpegdec->context, oclass->in_plugin) < 0) {
    gst_ffmpegdec_close (ffmpegdec);
    GST_DEBUG ("ffdec_%s: Failed to open FFMPEG codec",
        oclass->in_plugin->name);
    return FALSE;
  }

393 394
  GST_LOG ("Opened ffmpeg codec %s", oclass->in_plugin->name);

395 396 397 398 399
  /* open a parser if we can - exclude mpeg4, because it is already
   * framed (divx), mp3 because it doesn't work (?) and mjpeg because
   * of $(see mpeg4)... */
  if (oclass->in_plugin->id != CODEC_ID_MPEG4 &&
      oclass->in_plugin->id != CODEC_ID_MJPEG &&
400
      oclass->in_plugin->id != CODEC_ID_MP3) {
401
    ffmpegdec->pctx = av_parser_init (oclass->in_plugin->id);
402
  }
403

404 405 406 407 408 409 410 411 412 413 414 415 416 417
  switch (oclass->in_plugin->type) {
    case CODEC_TYPE_VIDEO:
      ffmpegdec->format.video.width = 0;
      ffmpegdec->format.video.height = 0;
      ffmpegdec->format.video.fps = 0;
      ffmpegdec->format.video.fps_base = 0;
      break;
    case CODEC_TYPE_AUDIO:
      ffmpegdec->format.audio.samplerate = 0;
      ffmpegdec->format.audio.channels = 0;
      break;
    default:
      break;
  }
418
  ffmpegdec->next_ts = 0;
419

420 421 422
  return TRUE;
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
423
static GstPadLinkReturn
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
424
gst_ffmpegdec_connect (GstPad * pad, const GstCaps * caps)
425
{
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
426 427 428
  GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) (gst_pad_get_parent (pad));
  GstFFMpegDecClass *oclass =
      (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
429 430
  GstStructure *structure;
  const GValue *par;
431

432
  /* close old session */
433
  gst_ffmpegdec_close (ffmpegdec);
434

435 436
  /* set defaults */
  avcodec_get_context_defaults (ffmpegdec->context);
437

438
#if 0
439 440 441
  /* set buffer functions */
  ffmpegdec->context->get_buffer = gst_ffmpegdec_get_buffer;
  ffmpegdec->context->release_buffer = gst_ffmpegdec_release_buffer;
442
#endif
443

444
  /* get size and so */
445 446
  gst_ffmpeg_caps_with_codecid (oclass->in_plugin->id,
      oclass->in_plugin->type, caps, ffmpegdec->context);
447

448 449 450 451 452 453 454 455 456
  /* get pixel aspect ratio if it's set */
  structure = gst_caps_get_structure (caps, 0);
  par = gst_structure_get_value (structure, "pixel-aspect-ratio");
  if (par) {
    GST_DEBUG_OBJECT (ffmpegdec, "sink caps have pixel-aspect-ratio");
    ffmpegdec->par = g_new0 (GValue, 1);
    gst_value_init_and_copy (ffmpegdec->par, par);
  }

457 458 459
  /* do *not* draw edges */
  ffmpegdec->context->flags |= CODEC_FLAG_EMU_EDGE;

460 461 462
  /* workaround encoder bugs */
  ffmpegdec->context->workaround_bugs |= FF_BUG_AUTODETECT;

463 464 465 466
  /* for slow cpus */
  ffmpegdec->context->lowres = ffmpegdec->lowres;
  ffmpegdec->context->hurry_up = ffmpegdec->hurry_up;

467 468 469
  /* open codec - we don't select an output pix_fmt yet,
   * simply because we don't know! We only get it
   * during playback... */
470 471 472 473 474 475 476 477 478
  if (!gst_ffmpegdec_open (ffmpegdec)) {
    if (ffmpegdec->par) {
      g_free (ffmpegdec->par);
      ffmpegdec->par = NULL;
    }
    return GST_PAD_LINK_REFUSED;
  }

  return GST_PAD_LINK_OK;
479 480
}

481
#if 0
482
static int
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
483
gst_ffmpegdec_get_buffer (AVCodecContext * context, AVFrame * picture)
484 485 486 487 488 489
{
  GstBuffer *buf = NULL;
  gulong bufsize = 0;

  switch (context->codec_type) {
    case CODEC_TYPE_VIDEO:
490
      bufsize = avpicture_get_size (context->pix_fmt,
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
491
          context->width, context->height);
492
      buf = gst_buffer_new_and_alloc (bufsize);
493 494
      gst_ffmpeg_avpicture_fill ((AVPicture *) picture,
          GST_BUFFER_DATA (buf),
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
495
          context->pix_fmt, context->width, context->height);
496 497 498 499 500 501
      break;

    case CODEC_TYPE_AUDIO:
    default:
      g_assert (0);
      break;
502 503
  }

504 505 506 507 508 509 510 511 512 513 514 515 516
  /* tell ffmpeg we own this buffer
   *
   * we also use an evil hack (keep buffer in base[0])
   * to keep a reference to the buffer in release_buffer(),
   * so that we can ref() it here and unref() it there
   * so that we don't need to copy data */
  picture->type = FF_BUFFER_TYPE_USER;
  picture->age = G_MAXINT;
  picture->base[0] = (int8_t *) buf;
  gst_buffer_ref (buf);

  return 0;
}
517

518
static void
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
519
gst_ffmpegdec_release_buffer (AVCodecContext * context, AVFrame * picture)
520 521 522
{
  gint i;
  GstBuffer *buf = GST_BUFFER (picture->base[0]);
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
523

524 525 526
  gst_buffer_unref (buf);

  /* zero out the reference in ffmpeg */
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
527
  for (i = 0; i < 4; i++) {
528 529 530
    picture->data[i] = NULL;
    picture->linesize[i] = 0;
  }
531
}
532
#endif
533

534 535 536 537 538 539 540
static gboolean
gst_ffmpegdec_negotiate (GstFFMpegDec * ffmpegdec)
{
  GstFFMpegDecClass *oclass =
      (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
  GstCaps *caps;

541 542 543 544 545 546 547 548
  switch (oclass->in_plugin->type) {
    case CODEC_TYPE_VIDEO:
      if (ffmpegdec->format.video.width == ffmpegdec->context->width &&
          ffmpegdec->format.video.height == ffmpegdec->context->height &&
          ffmpegdec->format.video.fps == ffmpegdec->context->frame_rate &&
          ffmpegdec->format.video.fps_base ==
              ffmpegdec->context->frame_rate_base)
        return TRUE;
549 550 551 552 553 554 555 556 557
      GST_DEBUG ("Renegotiating video from %dx%d@%d/%dfps to %dx%d@%d/%dfps",
          ffmpegdec->format.video.width, ffmpegdec->format.video.height,
          ffmpegdec->format.video.fps, ffmpegdec->format.video.fps_base,
          ffmpegdec->context->width, ffmpegdec->context->height,
          ffmpegdec->context->frame_rate, ffmpegdec->context->frame_rate_base);
      ffmpegdec->format.video.width = ffmpegdec->context->width;
      ffmpegdec->format.video.height = ffmpegdec->context->height;
      ffmpegdec->format.video.fps = ffmpegdec->context->frame_rate;
      ffmpegdec->format.video.fps_base = ffmpegdec->context->frame_rate_base;
558 559 560 561 562 563
      break;
    case CODEC_TYPE_AUDIO:
      if (ffmpegdec->format.audio.samplerate ==
              ffmpegdec->context->sample_rate &&
          ffmpegdec->format.audio.channels == ffmpegdec->context->channels)
        return TRUE;
564 565 566 567
      GST_DEBUG ("Renegotiating audio from %dHz@%dchannels to %dHz@%dchannels",
          ffmpegdec->format.audio.samplerate, ffmpegdec->format.audio.channels,
          ffmpegdec->context->sample_rate, ffmpegdec->context->channels);
      ffmpegdec->format.audio.samplerate = ffmpegdec->context->sample_rate;
568
      ffmpegdec->format.audio.channels = ffmpegdec->context->channels;
569 570 571 572 573
      break;
    default:
      break;
  }

574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615
  caps = gst_ffmpeg_codectype_to_caps (oclass->in_plugin->type,
      ffmpegdec->context);

  /* add in pixel-aspect-ratio if we have it,
   * prefer ffmpeg par over sink par (since it's provided
   * by the codec, which is more often correct).
   */
 if (caps) {
   if (ffmpegdec->context->sample_aspect_ratio.num &&
       ffmpegdec->context->sample_aspect_ratio.den) {
     GST_DEBUG ("setting ffmpeg provided pixel-aspect-ratio");
     gst_structure_set (gst_caps_get_structure (caps, 0),
         "pixel-aspect-ratio", GST_TYPE_FRACTION,
         ffmpegdec->context->sample_aspect_ratio.num,
         ffmpegdec->context->sample_aspect_ratio.den,
         NULL);
    } else if (ffmpegdec->par) {
      GST_DEBUG ("passing on pixel-aspect-ratio from sink");
      gst_structure_set (gst_caps_get_structure (caps, 0),
          "pixel-aspect-ratio", GST_TYPE_FRACTION,
           gst_value_get_fraction_numerator (ffmpegdec->par),
           gst_value_get_fraction_denominator (ffmpegdec->par),
           NULL);
    }
  }

  if (caps == NULL ||
      !gst_pad_set_explicit_caps (ffmpegdec->srcpad, caps)) {
    GST_ELEMENT_ERROR (ffmpegdec, CORE, NEGOTIATION, (NULL),
        ("Failed to link ffmpeg decoder (%s) to next element",
        oclass->in_plugin->name));

    if (caps != NULL)
      gst_caps_free (caps);

    return FALSE;
  }

  gst_caps_free (caps);

  return TRUE;
}
616

617 618
static gint
gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec,
619
    guint8 * data, guint size, gint * got_data, guint64 * in_ts)
620 621 622 623 624 625 626 627 628 629
{
  GstFFMpegDecClass *oclass =
      (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
  GstBuffer *outbuf = NULL;
  gint have_data, len = 0;

  ffmpegdec->context->frame_number++;

  switch (oclass->in_plugin->type) {
    case CODEC_TYPE_VIDEO:
630
      ffmpegdec->picture->pict_type = -1; /* in case we skip frames */
631 632
      len = avcodec_decode_video (ffmpegdec->context,
          ffmpegdec->picture, &have_data, data, size);
633 634
      GST_DEBUG_OBJECT (ffmpegdec,
          "Decode video: len=%d, have_data=%d", len, have_data);
635

636 637 638 639
      if (ffmpegdec->waiting_for_key &&
          ffmpegdec->picture->pict_type != FF_I_TYPE) {
        have_data = 0;
      } else if (len >= 0 && have_data > 0) {
640 641 642 643 644 645 646
        /* libavcodec constantly crashes on stupid buffer allocation
         * errors inside. This drives me crazy, so we let it allocate
         * it's own buffers and copy to our own buffer afterwards... */
        AVPicture pic;
        gint fsize = gst_ffmpeg_avpicture_get_size (ffmpegdec->context->pix_fmt,
            ffmpegdec->context->width, ffmpegdec->context->height);

647
        ffmpegdec->waiting_for_key = FALSE;
648 649 650 651 652

	if (!gst_ffmpegdec_negotiate (ffmpegdec))
	  return -1;	

	outbuf = gst_pad_alloc_buffer (ffmpegdec->srcpad, GST_BUFFER_OFFSET_NONE, fsize);
653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668

        /* original ffmpeg code does not handle odd sizes correctly.
         * This patched up version does */
        gst_ffmpeg_avpicture_fill (&pic, GST_BUFFER_DATA (outbuf),
            ffmpegdec->context->pix_fmt,
            ffmpegdec->context->width, ffmpegdec->context->height);

        /* the original convert function did not do the right thing, this
         * is a patched up version that adjust widht/height so that the
         * ffmpeg one works correctly. */
        gst_ffmpeg_img_convert (&pic, ffmpegdec->context->pix_fmt,
            (AVPicture *) ffmpegdec->picture,
            ffmpegdec->context->pix_fmt,
            ffmpegdec->context->width, 
            ffmpegdec->context->height);

669 670 671 672
        /* note that ffmpeg sometimes gets the FPS wrong.
         * For B-frame containing movies, we get all pictures delayed
         * except for the I frames, so we synchronize only on I frames
         * and keep an internal counter based on FPS for the others. */
673 674 675
        if ((ffmpegdec->picture->pict_type == FF_I_TYPE ||
             !GST_CLOCK_TIME_IS_VALID (ffmpegdec->next_ts)) &&
            GST_CLOCK_TIME_IS_VALID (*in_ts)) {
676
          ffmpegdec->next_ts = *in_ts;
677
        }
678

679
        GST_BUFFER_TIMESTAMP (outbuf) = ffmpegdec->next_ts;
680 681 682 683 684
        if (ffmpegdec->context->frame_rate_base != 0 &&
            ffmpegdec->context->frame_rate != 0) {
          GST_BUFFER_DURATION (outbuf) = GST_SECOND *
              ffmpegdec->context->frame_rate_base /
              ffmpegdec->context->frame_rate;
685 686 687 688 689

          /* Take repeat_pict into account */
          GST_BUFFER_DURATION (outbuf) += GST_BUFFER_DURATION (outbuf)
              * ffmpegdec->picture->repeat_pict / 2;
	  
690 691 692 693
          ffmpegdec->next_ts += GST_BUFFER_DURATION (outbuf);
        } else {
          ffmpegdec->next_ts = GST_CLOCK_TIME_NONE;
        }
694 695
      } else if (ffmpegdec->picture->pict_type != -1) {
        /* update time for skip-frame */
696 697 698
        if ((ffmpegdec->picture->pict_type == FF_I_TYPE ||
             !GST_CLOCK_TIME_IS_VALID (ffmpegdec->next_ts)) &&
            GST_CLOCK_TIME_IS_VALID (*in_ts)) {
699
          ffmpegdec->next_ts = *in_ts;
700
        }
701
        
702 703
        if (ffmpegdec->context->frame_rate_base != 0 &&
            ffmpegdec->context->frame_rate != 0) {
704
          guint64 dur = GST_SECOND *  
705 706
            ffmpegdec->context->frame_rate_base /
            ffmpegdec->context->frame_rate;
707 708 709 710 711

          /* Take repeat_pict into account */
          dur += dur * ffmpegdec->picture->repeat_pict / 2;
	  
          ffmpegdec->next_ts += dur;
712 713
        } else {
          ffmpegdec->next_ts = GST_CLOCK_TIME_NONE;
714
        }
715 716 717 718 719 720 721
      }
      break;

    case CODEC_TYPE_AUDIO:
      outbuf = gst_buffer_new_and_alloc (AVCODEC_MAX_AUDIO_FRAME_SIZE);
      len = avcodec_decode_audio (ffmpegdec->context,
          (int16_t *) GST_BUFFER_DATA (outbuf), &have_data, data, size);
722 723
      GST_DEBUG_OBJECT (ffmpegdec,
          "Decode audio: len=%d, have_data=%d", len, have_data);
724 725

      if (len >= 0 && have_data > 0) {
726 727 728 729 730 731

	if (!gst_ffmpegdec_negotiate (ffmpegdec)) {
	  gst_buffer_unref (outbuf);
	  return -1;
	}

732
        GST_BUFFER_SIZE (outbuf) = have_data;
733 734
        if (GST_CLOCK_TIME_IS_VALID (*in_ts)) {
          ffmpegdec->next_ts = *in_ts;
735
        }
736 737 738 739 740 741
        GST_BUFFER_TIMESTAMP (outbuf) = ffmpegdec->next_ts;
        GST_BUFFER_DURATION (outbuf) = (have_data * GST_SECOND) /
            (2 * ffmpegdec->context->channels *
            ffmpegdec->context->sample_rate);
        ffmpegdec->next_ts += GST_BUFFER_DURATION (outbuf);
        *in_ts += GST_BUFFER_DURATION (outbuf);
742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760
      } else {
        gst_buffer_unref (outbuf);
      }
      break;
    default:
      g_assert (0);
      break;
  }

  if (len < 0 || have_data < 0) {
    GST_ERROR_OBJECT (ffmpegdec,
        "ffdec_%s: decoding error (len: %d, have_data: %d)",
        oclass->in_plugin->name, len, have_data);
    *got_data = 0;
    return len;
  } else if (len == 0 && have_data == 0) {
    *got_data = 0;
    return 0;
  } else {
761 762
    /* this is where I lost my last clue on ffmpeg... */
    *got_data = 1; //(ffmpegdec->pctx || have_data) ? 1 : 0;
763 764 765
  }

  if (have_data) {
766 767
    GST_DEBUG_OBJECT (ffmpegdec, "Decoded data, now pushing (%"
        GST_TIME_FORMAT ")", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
768 769 770 771 772 773 774 775 776 777

    if (GST_PAD_IS_USABLE (ffmpegdec->srcpad))
      gst_pad_push (ffmpegdec->srcpad, GST_DATA (outbuf));
    else
      gst_buffer_unref (outbuf);
  }

  return len;
}

778 779 780
static void
gst_ffmpegdec_handle_event (GstFFMpegDec * ffmpegdec, GstEvent * event)
{
781 782
  GST_DEBUG_OBJECT (ffmpegdec,
      "Handling event of type %d", GST_EVENT_TYPE (event));
783

784
  switch (GST_EVENT_TYPE (event)) {
785
    case GST_EVENT_EOS: {
786
      gint have_data, len, try = 0;
787

788
      /* max. 10 times, for safety (see e.g. #300200) */
789 790 791 792 793
      do {
        len = gst_ffmpegdec_frame (ffmpegdec, NULL, 0, &have_data,
            &ffmpegdec->next_ts);
        if (len < 0 || have_data == 0)
          break;
794
      } while (try++ < 10);
795 796
      goto forward;
    }
797
    case GST_EVENT_FLUSH:
798 799 800
      if (ffmpegdec->opened) {
        avcodec_flush_buffers (ffmpegdec->context);
      }
801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824
      goto forward;
    case GST_EVENT_DISCONTINUOUS: {
      gint64 value;

      if (gst_event_discont_get_value (event, GST_FORMAT_TIME, &value)) {
        ffmpegdec->next_ts = value;
        GST_DEBUG_OBJECT (ffmpegdec, "Discont to time %" GST_TIME_FORMAT,
            GST_TIME_ARGS (value));
      } else if (ffmpegdec->context->bit_rate &&
          gst_event_discont_get_value (event, GST_FORMAT_BYTES, &value)) {
        gboolean new_media;

        ffmpegdec->next_ts = value * GST_SECOND / ffmpegdec->context->bit_rate;
        GST_DEBUG_OBJECT (ffmpegdec,
            "Discont to byte %lld, time %" GST_TIME_FORMAT,
            value, GST_TIME_ARGS (ffmpegdec->next_ts));
        new_media = GST_EVENT_DISCONT_NEW_MEDIA (event);
        gst_event_unref (event);
        event = gst_event_new_discontinuous (new_media,
            GST_FORMAT_TIME, ffmpegdec->next_ts, GST_FORMAT_UNDEFINED);
      } else {
        GST_WARNING_OBJECT (ffmpegdec,
            "Received discont with no useful value...");
      }
825 826
      if (ffmpegdec->opened) {
        avcodec_flush_buffers (ffmpegdec->context);
827 828 829 830 831

        if (ffmpegdec->context->codec_id == CODEC_ID_MPEG2VIDEO ||
            ffmpegdec->context->codec_id == CODEC_ID_MPEG4) {
          ffmpegdec->waiting_for_key = TRUE;
        }
832
      }
833 834 835 836 837 838 839 840 841
      /* fall-through */
    }
    default:
    forward:
      gst_pad_event_default (ffmpegdec->sinkpad, event);
      return;
  }
}

842
static void
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
843
gst_ffmpegdec_chain (GstPad * pad, GstData * _data)
844
{
845
  GstBuffer *inbuf;
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
846 847 848
  GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) (gst_pad_get_parent (pad));
  GstFFMpegDecClass *oclass =
      (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
849
  guint8 *bdata, *data;
850
  gint bsize, size, len, have_data;
851 852 853 854 855 856 857 858 859 860
  guint64 in_ts;

  /* event handling */
  if (GST_IS_EVENT (_data)) {
    gst_ffmpegdec_handle_event (ffmpegdec, GST_EVENT (_data));
    return;
  }

  inbuf = GST_BUFFER (_data);
  in_ts = GST_BUFFER_TIMESTAMP (inbuf);
861

Ronald S. Bultje's avatar
Ronald S. Bultje committed
862
  if (!ffmpegdec->opened) {
863
    GST_ELEMENT_ERROR (ffmpegdec, CORE, NEGOTIATION, (NULL),
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
864 865
        ("ffdec_%s: input format was not set before data start",
            oclass->in_plugin->name));
Ronald S. Bultje's avatar
Ronald S. Bultje committed
866 867 868
    return;
  }

869 870
  GST_DEBUG_OBJECT (ffmpegdec,
      "Received new data of size %d, time %" GST_TIME_FORMAT,
871
      GST_BUFFER_SIZE (inbuf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)));
872

873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892
  /* parse cache joining */
  if (ffmpegdec->pcache) {
    inbuf = gst_buffer_join (ffmpegdec->pcache, inbuf);
    ffmpegdec->pcache = NULL;
    bdata = GST_BUFFER_DATA (inbuf);
    bsize = GST_BUFFER_SIZE (inbuf);
  }
  /* workarounds, functions write to buffers:
   *  libavcodec/svq1.c:svq1_decode_frame writes to the given buffer.
   *  libavcodec/svq3.c:svq3_decode_slice_header too.
   * ffmpeg devs know about it and will fix it (they said). */
  else if (oclass->in_plugin->id == CODEC_ID_SVQ1 ||
      oclass->in_plugin->id == CODEC_ID_SVQ3) {
    inbuf = gst_buffer_copy_on_write (inbuf);
    bdata = GST_BUFFER_DATA (inbuf);
    bsize = GST_BUFFER_SIZE (inbuf);
  } else {
    bdata = GST_BUFFER_DATA (inbuf);
    bsize = GST_BUFFER_SIZE (inbuf);
  }
893 894

  do {
895
    /* parse, if at all possible */
896
    if (ffmpegdec->pctx) {
897
      gint res;
898
      gint64 ffpts = AV_NOPTS_VALUE;
899

900 901 902
      if (GST_CLOCK_TIME_IS_VALID (in_ts))
	ffpts = in_ts / (GST_SECOND / AV_TIME_BASE);
    
903 904
      res = av_parser_parse (ffmpegdec->pctx, ffmpegdec->context,
          &data, &size, bdata, bsize,
905
          ffpts, ffpts);
906

907 908
      GST_DEBUG_OBJECT (ffmpegdec, "Parsed video frame, res=%d, size=%d",
          res, size);
909 910 911 912
      
      if (ffmpegdec->pctx->pts != AV_NOPTS_VALUE)
        in_ts = ffmpegdec->pctx->pts * (GST_SECOND / AV_TIME_BASE);

913
      if (res == 0 || size == 0)
914
        break;
915
      else {
916 917 918 919 920 921 922 923
        bsize -= res;
        bdata += res;
      }
    } else {
      data = bdata;
      size = bsize;
    }

924
    if ((len = gst_ffmpegdec_frame (ffmpegdec, data, size,
925
             &have_data, &in_ts)) < 0)
926 927
      break;

928
    if (!ffmpegdec->pctx) {
929 930 931
      bsize -= len;
      bdata += len;
    }
932 933 934 935

    if (!have_data) {
      break;
    }
936
  } while (bsize > 0);
937

938 939
  if ((ffmpegdec->pctx || oclass->in_plugin->id == CODEC_ID_MP3) &&
      bsize > 0) {
940
    GST_DEBUG_OBJECT (ffmpegdec, "Keeping %d bytes of data", bsize);
941

942 943 944
    ffmpegdec->pcache = gst_buffer_create_sub (inbuf,
        GST_BUFFER_SIZE (inbuf) - bsize, bsize);
  }
945 946 947
  gst_buffer_unref (inbuf);
}

948
static GstElementStateReturn
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
949
gst_ffmpegdec_change_state (GstElement * element)
950
{
951 952 953 954 955
  GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) element;
  gint transition = GST_STATE_TRANSITION (element);

  switch (transition) {
    case GST_STATE_PAUSED_TO_READY:
956
      gst_ffmpegdec_close (ffmpegdec);
957 958 959
      break;
  }

960 961
  if (GST_ELEMENT_CLASS (parent_class)->change_state)
    return GST_ELEMENT_CLASS (parent_class)->change_state (element);
962

963
  return GST_STATE_SUCCESS;
964 965
}

966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005
static void
gst_ffmpegdec_set_property (GObject * object,
    guint prop_id, const GValue * value, GParamSpec * pspec)
{
  GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) object;

  switch (prop_id) {
    case ARG_LOWRES:
      ffmpegdec->lowres = ffmpegdec->context->lowres =
          g_value_get_enum (value);
      break;
    case ARG_SKIPFRAME:
      ffmpegdec->hurry_up = ffmpegdec->context->hurry_up =
          g_value_get_enum (value);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static void
gst_ffmpegdec_get_property (GObject * object,
    guint prop_id, GValue * value, GParamSpec * pspec)
{
  GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) object;

  switch (prop_id) {
    case ARG_LOWRES:
      g_value_set_enum (value, ffmpegdec->context->lowres);
      break;
    case ARG_SKIPFRAME:
      g_value_set_enum (value, ffmpegdec->context->hurry_up);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

1006
gboolean
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
1007
gst_ffmpegdec_register (GstPlugin * plugin)
1008 1009
{
  GTypeInfo typeinfo = {
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
1010 1011
    sizeof (GstFFMpegDecClass),
    (GBaseInitFunc) gst_ffmpegdec_base_init,
1012
    NULL,
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
1013
    (GClassInitFunc) gst_ffmpegdec_class_init,
1014 1015
    NULL,
    NULL,
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
1016
    sizeof (GstFFMpegDec),
1017
    0,
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
1018
    (GInstanceInitFunc) gst_ffmpegdec_init,
1019 1020 1021
  };
  GType type;
  AVCodec *in_plugin;
1022
  gint rank;
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
1023

1024 1025 1026 1027 1028
  in_plugin = first_avcodec;

  global_plugins = g_hash_table_new (NULL, NULL);

  while (in_plugin) {
1029
    GstFFMpegDecClassParams *params;
Ronald S. Bultje's avatar
Bla  
Ronald S. Bultje committed
1030 1031
    GstCaps *srccaps, *sinkcaps;
    gchar *type_name;
1032

Ronald S. Bultje's avatar
Ronald S. Bultje committed
1033 1034
    /* no quasi-codecs, please */
    if (in_plugin->id == CODEC_ID_RAWVIDEO ||
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
1035
        (in_plugin->id >= CODEC_ID_PCM_S16LE &&
1036
            in_plugin->id <= CODEC_ID_PCM_U8)) {
Ronald S. Bultje's avatar
Ronald S. Bultje committed
1037
      goto next;
1038
    }
Ronald S. Bultje's avatar
Ronald S. Bultje committed
1039 1040 1041

    /* only decoders */
    if (!in_plugin->decode) {
1042 1043
      goto next;
    }
1044

1045
    /* name */
1046 1047 1048
    if (!gst_ffmpeg_get_codecid_longname (in_plugin->id)) {
      g_warning ("Add decoder %s (%d) please",
          in_plugin->name, in_plugin->id);
1049
      goto next;
1050
    }
1051

1052
    /* first make sure we've got a supported type */
1053
    sinkcaps = gst_ffmpeg_codecid_to_caps (in_plugin->id, NULL, FALSE);
1054 1055 1056 1057 1058
    if (in_plugin->type == CODEC_TYPE_VIDEO) {
      srccaps = gst_caps_from_string ("video/x-raw-rgb; video/x-raw-yuv");
    } else {
      srccaps = gst_ffmpeg_codectype_to_caps (in_plugin->type, NULL);
    }
Benjamin Otte's avatar
Benjamin Otte committed
1059 1060 1061
    if (!sinkcaps || !srccaps) {
      if (sinkcaps) gst_caps_free (sinkcaps);
      if (srccaps) gst_caps_free (srccaps);
1062
      goto next;
Benjamin Otte's avatar
Benjamin Otte committed
1063
    }
1064

1065
    /* construct the type */
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
1066
    type_name = g_strdup_printf ("ffdec_%s", in_plugin->name);
1067

1068
    /* if it's already registered, drop it */
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
1069 1070
    if (g_type_from_name (type_name)) {
      g_free (type_name);
1071 1072 1073
      goto next;
    }

1074 1075 1076 1077
    params = g_new0 (GstFFMpegDecClassParams, 1);
    params->in_plugin = in_plugin;
    params->srccaps = srccaps;
    params->sinkcaps = sinkcaps;
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
1078 1079 1080
    g_hash_table_insert (global_plugins,
        GINT_TO_POINTER (0), (gpointer) params);

1081
    /* create the gtype now */
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
1082
    type = g_type_register_static (GST_TYPE_ELEMENT, type_name, &typeinfo, 0);
1083 1084 1085

    /* (Ronald) MPEG-4 gets a higher priority because it has been well-
     * tested and by far outperforms divxdec/xviddec - so we prefer it.
1086
     * msmpeg4v3 same, as it outperforms divxdec for divx3 playback.
1087
     * VC1/WMV3 are not working and thus unpreferred for now. */
1088 1089 1090 1091 1092 1093 1094 1095
    switch (in_plugin->id) {
      case CODEC_ID_MPEG4:
      case CODEC_ID_MSMPEG4V3:
        rank = GST_RANK_PRIMARY;
        break;
      default:
        rank = GST_RANK_MARGINAL;
        break;
1096 1097
      case CODEC_ID_WMV3:
      case CODEC_ID_VC9:
1098 1099 1100 1101
      /* what's that? */
      case CODEC_ID_SP5X:
        rank = GST_RANK_NONE;
        break;
1102 1103
    }
    if (!gst_element_register (plugin, type_name, rank, type)) {
David Schleef's avatar
David Schleef committed
1104
      g_free (type_name);
Ronald S. Bultje's avatar
Bla