gstffmpegdec.c 34.9 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
//#define FORCE_OUR_GET_BUFFER

40 41
typedef struct _GstFFMpegDec GstFFMpegDec;

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

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

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

65 66 67 68
  /* parsing */
  AVCodecParserContext *pctx;
  GstBuffer *pcache;

69 70
  GstBuffer *last_buffer;

71
  GValue *par;		/* pixel aspect ratio of incoming data */
72 73

  gint hurry_up, lowres;
74 75 76 77
};

typedef struct _GstFFMpegDecClass GstFFMpegDecClass;

Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
78 79
struct _GstFFMpegDecClass
{
80 81 82
  GstElementClass parent_class;

  AVCodec *in_plugin;
83
  GstPadTemplate *srctempl, *sinktempl;
84 85
};

Ronald S. Bultje's avatar
Bla  
Ronald S. Bultje committed
86 87
typedef struct _GstFFMpegDecClassParams GstFFMpegDecClassParams;

Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
88 89
struct _GstFFMpegDecClassParams
{
90
  AVCodec *in_plugin;
Ronald S. Bultje's avatar
Bla  
Ronald S. Bultje committed
91 92
  GstCaps *srccaps, *sinkcaps;
};
93

94 95 96 97 98 99 100 101 102 103
#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))
104

Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
105 106
enum
{
107
  ARG_0,
108 109
  ARG_LOWRES,
  ARG_SKIPFRAME
110 111 112 113 114
};

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
115 116 117 118
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);
119

120 121 122 123
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
124 125 126
static GstPadLinkReturn gst_ffmpegdec_connect (GstPad * pad,
    const GstCaps * caps);
static void gst_ffmpegdec_chain (GstPad * pad, GstData * data);
127

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

130 131 132 133 134
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);

135 136
static gboolean gst_ffmpegdec_negotiate (GstFFMpegDec * ffmpegdec);

137
/* some sort of bufferpool handling, but different */
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
138 139 140 141
static int gst_ffmpegdec_get_buffer (AVCodecContext * context,
    AVFrame * picture);
static void gst_ffmpegdec_release_buffer (AVCodecContext * context,
    AVFrame * picture);
142 143 144

static GstElementClass *parent_class = NULL;

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 183 184 185 186
#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;
}
187

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

  params = g_hash_table_lookup (global_plugins,
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
198
      GINT_TO_POINTER (G_OBJECT_CLASS_TYPE (gobject_class)));
199
  if (!params)
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
200
    params = g_hash_table_lookup (global_plugins, GINT_TO_POINTER (0));
201
  g_assert (params);
Ronald S. Bultje's avatar
Bla  
Ronald S. Bultje committed
202 203

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

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

  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;
}

231
static void
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
232
gst_ffmpegdec_class_init (GstFFMpegDecClass * klass)
233
{
234 235
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
236

237
  parent_class = g_type_class_peek_parent (klass);
238

239 240 241 242 243 244 245 246 247
  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));

248
  gobject_class->dispose = gst_ffmpegdec_dispose;
249 250
  gobject_class->set_property = gst_ffmpegdec_set_property;
  gobject_class->get_property = gst_ffmpegdec_get_property;
251 252 253 254
  gstelement_class->change_state = gst_ffmpegdec_change_state;
}

static void
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
255
gst_ffmpegdec_init (GstFFMpegDec * ffmpegdec)
256
{
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
257 258
  GstFFMpegDecClass *oclass =
      (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
259 260 261 262 263

  /* 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);
264 265
  gst_element_add_pad (GST_ELEMENT (ffmpegdec), ffmpegdec->sinkpad);

266
  ffmpegdec->srcpad = gst_pad_new_from_template (oclass->srctempl, "src");
267
  gst_pad_use_explicit_caps (ffmpegdec->srcpad);
268 269 270 271
  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));
272 273 274
  gst_element_add_pad (GST_ELEMENT (ffmpegdec), ffmpegdec->srcpad);

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

284 285
  ffmpegdec->last_buffer = NULL;

286
  GST_FLAG_SET (ffmpegdec, GST_ELEMENT_EVENT_AWARE);
287 288 289
}

static void
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
290
gst_ffmpegdec_dispose (GObject * object)
291 292
{
  GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) object;
293 294 295 296

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

298 299 300
  /* clean up remaining allocated data */
  av_free (ffmpegdec->context);
  av_free (ffmpegdec->picture);
301 302
}

303 304 305 306 307 308 309 310 311 312
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;
313 314

  if (gst_pad_query (peer, type, fmt, value))
315
    return TRUE;
316

317
  /* ok, do bitrate calc... */
318
  if ((type != GST_QUERY_POSITION && type != GST_QUERY_TOTAL) ||
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
           *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;
338 339 340 341

  gst_event_ref (event);
  if (gst_pad_send_event (peer, event)) {
    gst_event_unref (event);
342
    return TRUE;
343 344 345 346 347
  }

  gst_event_unref (event);

  return FALSE; /* .. */
348 349
}

350 351 352 353 354 355
static void
gst_ffmpegdec_close (GstFFMpegDec *ffmpegdec)
{
  if (!ffmpegdec->opened)
    return;

356 357 358 359 360
  if (ffmpegdec->par) {
    g_free (ffmpegdec->par);
    ffmpegdec->par = NULL;
  }

361 362
  if (ffmpegdec->context->priv_data)
    avcodec_close (ffmpegdec->context);
363 364 365 366 367 368 369 370 371 372 373
  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;
  }
374 375 376 377 378 379 380 381 382

  if (ffmpegdec->pctx) {
    if (ffmpegdec->pcache) {
      gst_buffer_unref (ffmpegdec->pcache);
      ffmpegdec->pcache = NULL;
    }
    av_parser_close (ffmpegdec->pctx);
    ffmpegdec->pctx = NULL;
  }
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398
}

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;
  }

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

401 402 403 404 405
  /* 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 &&
406 407
      oclass->in_plugin->id != CODEC_ID_MP3 &&
      oclass->in_plugin->id != CODEC_ID_H264) {
408
    ffmpegdec->pctx = av_parser_init (oclass->in_plugin->id);
409
  }
410

411 412 413 414 415 416 417 418 419 420 421 422 423 424
  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;
  }
425
  ffmpegdec->next_ts = 0;
426 427
  
  ffmpegdec->last_buffer = NULL;
428

429 430 431
  return TRUE;
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
432
static GstPadLinkReturn
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
433
gst_ffmpegdec_connect (GstPad * pad, const GstCaps * caps)
434
{
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
435 436 437
  GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) (gst_pad_get_parent (pad));
  GstFFMpegDecClass *oclass =
      (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
438 439
  GstStructure *structure;
  const GValue *par;
440

441
  /* close old session */
442
  gst_ffmpegdec_close (ffmpegdec);
443

444 445
  /* set defaults */
  avcodec_get_context_defaults (ffmpegdec->context);
446

447
  /* set buffer functions */  
448
  ffmpegdec->context->get_buffer = gst_ffmpegdec_get_buffer;
449 450
  ffmpegdec->context->release_buffer = gst_ffmpegdec_release_buffer;      
  
451
  /* get size and so */
452 453
  gst_ffmpeg_caps_with_codecid (oclass->in_plugin->id,
      oclass->in_plugin->type, caps, ffmpegdec->context);
454

455 456 457 458 459 460 461 462 463
  /* 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);
  }

464 465 466
  /* do *not* draw edges */
  ffmpegdec->context->flags |= CODEC_FLAG_EMU_EDGE;

467 468 469
  /* workaround encoder bugs */
  ffmpegdec->context->workaround_bugs |= FF_BUG_AUTODETECT;

470 471 472 473
  /* for slow cpus */
  ffmpegdec->context->lowres = ffmpegdec->lowres;
  ffmpegdec->context->hurry_up = ffmpegdec->hurry_up;

474 475 476
  /* open codec - we don't select an output pix_fmt yet,
   * simply because we don't know! We only get it
   * during playback... */
477 478 479 480 481 482 483 484 485
  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;
486 487
}

488
static int
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
489
gst_ffmpegdec_get_buffer (AVCodecContext * context, AVFrame * picture)
490 491 492
{
  GstBuffer *buf = NULL;
  gulong bufsize = 0;
493 494 495
  GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) context->opaque; 
  int width  = context->width;
  int height = context->height;
496 497 498

  switch (context->codec_type) {
    case CODEC_TYPE_VIDEO:
499 500 501
      
      avcodec_align_dimensions(context, &width, &height);
      
502
      bufsize = avpicture_get_size (context->pix_fmt,
503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527
				    width, height);
      
      if((width != context->width) || (height != context->height)) {
#ifdef FORCE_OUR_GET_BUFFER
	context->width = width;
	context->height = height;
#else	
	/* revert to ffmpeg's default functions */
	ffmpegdec->context->get_buffer = avcodec_default_get_buffer;
	ffmpegdec->context->release_buffer = avcodec_default_release_buffer;       	

	return avcodec_default_get_buffer(context, picture);
#endif
	
      } 
      
      if (!gst_ffmpegdec_negotiate (ffmpegdec)) {
	GST_ELEMENT_ERROR (ffmpegdec, CORE, NEGOTIATION, (NULL),
			   ("Failed to link ffmpeg decoder to next element"));
	return avcodec_default_get_buffer(context, picture);
      }
      
      buf = gst_pad_alloc_buffer (ffmpegdec->srcpad, GST_BUFFER_OFFSET_NONE, bufsize);
      ffmpegdec->last_buffer = buf;
      
528 529
      gst_ffmpeg_avpicture_fill ((AVPicture *) picture,
          GST_BUFFER_DATA (buf),
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
530
          context->pix_fmt, context->width, context->height);
531
      break;
532
      
533 534 535 536
    case CODEC_TYPE_AUDIO:
    default:
      g_assert (0);
      break;
537 538
  }

539 540 541 542 543 544 545 546
  /* 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;
547
  picture->opaque = buf;
548 549 550 551
  gst_buffer_ref (buf);

  return 0;
}
552

553
static void
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
554
gst_ffmpegdec_release_buffer (AVCodecContext * context, AVFrame * picture)
555 556
{
  gint i;
557 558 559 560 561
  GstBuffer *buf = GST_BUFFER (picture->opaque);
  GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) context->opaque; 
  
  g_return_if_fail (buf != NULL);
  g_return_if_fail (picture->type == FF_BUFFER_TYPE_USER);
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
562

563
  ffmpegdec->last_buffer = NULL;
564 565 566
  gst_buffer_unref (buf);

  /* zero out the reference in ffmpeg */
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
567
  for (i = 0; i < 4; i++) {
568 569 570
    picture->data[i] = NULL;
    picture->linesize[i] = 0;
  }
571 572
}

573 574 575 576 577 578 579
static gboolean
gst_ffmpegdec_negotiate (GstFFMpegDec * ffmpegdec)
{
  GstFFMpegDecClass *oclass =
      (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
  GstCaps *caps;

580 581 582 583 584 585 586 587
  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;
588 589 590 591 592 593 594 595 596
      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;
597 598 599 600 601 602
      break;
    case CODEC_TYPE_AUDIO:
      if (ffmpegdec->format.audio.samplerate ==
              ffmpegdec->context->sample_rate &&
          ffmpegdec->format.audio.channels == ffmpegdec->context->channels)
        return TRUE;
603 604 605 606
      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;
607
      ffmpegdec->format.audio.channels = ffmpegdec->context->channels;
608 609 610 611 612
      break;
    default:
      break;
  }

613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654
  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;
}
655

656 657
static gint
gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec,
658
    guint8 * data, guint size, gint * got_data, guint64 * in_ts)
659 660 661 662 663
{
  GstFFMpegDecClass *oclass =
      (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
  GstBuffer *outbuf = NULL;
  gint have_data, len = 0;
664
  
665 666 667 668
  ffmpegdec->context->frame_number++;

  switch (oclass->in_plugin->type) {
    case CODEC_TYPE_VIDEO:
669
      ffmpegdec->picture->pict_type = -1; /* in case we skip frames */
670 671 672

      ffmpegdec->context->opaque = ffmpegdec;
      
673 674
      len = avcodec_decode_video (ffmpegdec->context,
          ffmpegdec->picture, &have_data, data, size);
675 676
      GST_DEBUG_OBJECT (ffmpegdec,
          "Decode video: len=%d, have_data=%d", len, have_data);
677

678 679 680 681
      if (ffmpegdec->waiting_for_key &&
          ffmpegdec->picture->pict_type != FF_I_TYPE) {
        have_data = 0;
      } else if (len >= 0 && have_data > 0) {
682 683 684
        /* 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... */
685

686 687 688 689 690
	if (ffmpegdec->picture->opaque != NULL) {
	  outbuf = (GstBuffer *) ffmpegdec->picture->opaque;
	}else {
	  AVPicture pic;
	  gint fsize = gst_ffmpeg_avpicture_get_size (ffmpegdec->context->pix_fmt,
691 692
            ffmpegdec->context->width, ffmpegdec->context->height);

693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714
	  if (!gst_ffmpegdec_negotiate (ffmpegdec))
	    return -1;	
	  
	  outbuf = gst_pad_alloc_buffer (ffmpegdec->srcpad, GST_BUFFER_OFFSET_NONE, fsize);

	  /* 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);
	}	
	
	ffmpegdec->waiting_for_key = FALSE;
715

716 717 718 719
        /* 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. */
720 721 722
        if ((ffmpegdec->picture->pict_type == FF_I_TYPE ||
             !GST_CLOCK_TIME_IS_VALID (ffmpegdec->next_ts)) &&
            GST_CLOCK_TIME_IS_VALID (*in_ts)) {
723
          ffmpegdec->next_ts = *in_ts;
724
        }
725

726
        GST_BUFFER_TIMESTAMP (outbuf) = ffmpegdec->next_ts;
727 728 729 730 731
        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;
732 733 734 735 736

          /* Take repeat_pict into account */
          GST_BUFFER_DURATION (outbuf) += GST_BUFFER_DURATION (outbuf)
              * ffmpegdec->picture->repeat_pict / 2;
	  
737 738 739 740
          ffmpegdec->next_ts += GST_BUFFER_DURATION (outbuf);
        } else {
          ffmpegdec->next_ts = GST_CLOCK_TIME_NONE;
        }
741 742
      } else if (ffmpegdec->picture->pict_type != -1) {
        /* update time for skip-frame */
743 744 745
        if ((ffmpegdec->picture->pict_type == FF_I_TYPE ||
             !GST_CLOCK_TIME_IS_VALID (ffmpegdec->next_ts)) &&
            GST_CLOCK_TIME_IS_VALID (*in_ts)) {
746
          ffmpegdec->next_ts = *in_ts;
747
        }
748
        
749 750
        if (ffmpegdec->context->frame_rate_base != 0 &&
            ffmpegdec->context->frame_rate != 0) {
751
          guint64 dur = GST_SECOND *  
752 753
            ffmpegdec->context->frame_rate_base /
            ffmpegdec->context->frame_rate;
754 755 756 757 758

          /* Take repeat_pict into account */
          dur += dur * ffmpegdec->picture->repeat_pict / 2;
	  
          ffmpegdec->next_ts += dur;
759 760
        } else {
          ffmpegdec->next_ts = GST_CLOCK_TIME_NONE;
761
        }
762 763 764 765 766 767 768
      }
      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);
769 770
      GST_DEBUG_OBJECT (ffmpegdec,
          "Decode audio: len=%d, have_data=%d", len, have_data);
771 772

      if (len >= 0 && have_data > 0) {
773 774 775 776 777 778

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

779
        GST_BUFFER_SIZE (outbuf) = have_data;
780 781
        if (GST_CLOCK_TIME_IS_VALID (*in_ts)) {
          ffmpegdec->next_ts = *in_ts;
782
        }
783 784 785 786 787 788
        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);
789 790 791 792 793 794 795 796
      } else {
        gst_buffer_unref (outbuf);
      }
      break;
    default:
      g_assert (0);
      break;
  }
797
  
798 799 800 801 802 803 804 805 806 807
  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 {
808 809
    /* this is where I lost my last clue on ffmpeg... */
    *got_data = 1; //(ffmpegdec->pctx || have_data) ? 1 : 0;
810
  }
811
  
812
  if (have_data) {
813

814 815
    GST_DEBUG_OBJECT (ffmpegdec, "Decoded data, now pushing (%"
        GST_TIME_FORMAT ")", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
816 817 818 819 820 821 822 823 824 825

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

  return len;
}

826 827 828
static void
gst_ffmpegdec_handle_event (GstFFMpegDec * ffmpegdec, GstEvent * event)
{
829 830 831
  GstFFMpegDecClass *oclass =
      (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));

832 833
  GST_DEBUG_OBJECT (ffmpegdec,
      "Handling event of type %d", GST_EVENT_TYPE (event));
834

835
  switch (GST_EVENT_TYPE (event)) {
836 837 838 839 840 841 842 843 844 845
    case GST_EVENT_EOS:
      if (oclass->in_plugin->capabilities & CODEC_CAP_DELAY) {
        gint have_data, len, try = 0;
        do {
          len = gst_ffmpegdec_frame (ffmpegdec, NULL, 0, &have_data,
              &ffmpegdec->next_ts);
          if (len < 0 || have_data == 0)
            break;
        } while (try++ < 10);
      }
846
      goto forward;
847
    case GST_EVENT_FLUSH:
848 849 850
      if (ffmpegdec->opened) {
        avcodec_flush_buffers (ffmpegdec->context);
      }
851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874
      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...");
      }
875 876
      if (ffmpegdec->opened) {
        avcodec_flush_buffers (ffmpegdec->context);
877 878

        if (ffmpegdec->context->codec_id == CODEC_ID_MPEG2VIDEO ||
879 880
            ffmpegdec->context->codec_id == CODEC_ID_MPEG4 ||
            ffmpegdec->context->codec_id == CODEC_ID_H264) {
881 882
          ffmpegdec->waiting_for_key = TRUE;
        }
883
      }
884 885 886 887 888 889 890 891 892
      /* fall-through */
    }
    default:
    forward:
      gst_pad_event_default (ffmpegdec->sinkpad, event);
      return;
  }
}

893
static void
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
894
gst_ffmpegdec_chain (GstPad * pad, GstData * _data)
895
{
896
  GstBuffer *inbuf;
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
897 898 899
  GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) (gst_pad_get_parent (pad));
  GstFFMpegDecClass *oclass =
      (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
900
  guint8 *bdata, *data;
901
  gint bsize, size, len, have_data;
902 903 904 905 906 907 908 909 910 911
  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);
912

Ronald S. Bultje's avatar
Ronald S. Bultje committed
913
  if (!ffmpegdec->opened) {
914
    GST_ELEMENT_ERROR (ffmpegdec, CORE, NEGOTIATION, (NULL),
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
915 916
        ("ffdec_%s: input format was not set before data start",
            oclass->in_plugin->name));
Ronald S. Bultje's avatar
Ronald S. Bultje committed
917 918 919
    return;
  }

920 921
  GST_DEBUG_OBJECT (ffmpegdec,
      "Received new data of size %d, time %" GST_TIME_FORMAT,
922
      GST_BUFFER_SIZE (inbuf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)));
923

924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943
  /* 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);
  }
944 945

  do {
946
    /* parse, if at all possible */
947
    if (ffmpegdec->pctx) {
948
      gint res;
949 950 951
      gint64 ffpts;
      
      ffpts = gst_ffmpeg_pts_gst_to_ffmpeg (in_ts);
952 953 954

      res = av_parser_parse (ffmpegdec->pctx, ffmpegdec->context,
          &data, &size, bdata, bsize,
955
          ffpts, ffpts);
956

957 958
      GST_DEBUG_OBJECT (ffmpegdec, "Parsed video frame, res=%d, size=%d",
          res, size);
959
      
960
      in_ts = gst_ffmpeg_pts_ffmpeg_to_gst (ffmpegdec->pctx->pts);
961

962
      if (res == 0 || size == 0)
963
        break;
964
      else {
965 966 967 968 969 970 971 972
        bsize -= res;
        bdata += res;
      }
    } else {
      data = bdata;
      size = bsize;
    }

973
    if ((len = gst_ffmpegdec_frame (ffmpegdec, data, size,
974
             &have_data, &in_ts)) < 0)
975 976
      break;

977
    if (!ffmpegdec->pctx) {
978 979 980
      bsize -= len;
      bdata += len;
    }
981 982 983 984

    if (!have_data) {
      break;
    }
985
  } while (bsize > 0);
986

987 988
  if ((ffmpegdec->pctx || oclass->in_plugin->id == CODEC_ID_MP3) &&
      bsize > 0) {
989
    GST_DEBUG_OBJECT (ffmpegdec, "Keeping %d bytes of data", bsize);
990

991 992 993
    ffmpegdec->pcache = gst_buffer_create_sub (inbuf,
        GST_BUFFER_SIZE (inbuf) - bsize, bsize);
  }
994 995 996
  gst_buffer_unref (inbuf);
}

997
static GstElementStateReturn
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
998
gst_ffmpegdec_change_state (GstElement * element)
999
{
1000 1001 1002 1003 1004
  GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) element;
  gint transition = GST_STATE_TRANSITION (element);

  switch (transition) {
    case GST_STATE_PAUSED_TO_READY:
1005 1006 1007
      if (ffmpegdec->last_buffer != NULL) {
	gst_buffer_unref (ffmpegdec->last_buffer);
      }
1008
      gst_ffmpegdec_close (ffmpegdec);
1009 1010 1011
      break;
  }

1012 1013
  if (GST_ELEMENT_CLASS (parent_class)->change_state)
    return GST_ELEMENT_CLASS (parent_class)->change_state (element);
1014

1015
  return GST_STATE_SUCCESS;
1016 1017
}

1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057
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;
  }
}

1058
gboolean
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
1059
gst_ffmpegdec_register (GstPlugin * plugin)
1060 1061
{
  GTypeInfo typeinfo = {
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
1062 1063
    sizeof (GstFFMpegDecClass),
    (GBaseInitFunc) gst_ffmpegdec_base_init,
1064
    NULL,
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
1065
    (GClassInitFunc) gst_ffmpegdec_class_init,
1066 1067
    NULL,
    NULL,
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
1068
    sizeof (GstFFMpegDec),
1069
    0,
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
1070
    (GInstanceInitFunc) gst_ffmpegdec_init,
1071 1072 1073
  };
  GType type;
  AVCodec *in_plugin;
1074
  gint rank;
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
1075

1076 1077 1078 1079 1080
  in_plugin = first_avcodec;

  global_plugins = g_hash_table_new (NULL, NULL);

  while (in_plugin) {
1081
    GstFFMpegDecClassParams *params;
Ronald S. Bultje's avatar
Bla  
Ronald S. Bultje committed
1082 1083
    GstCaps *srccaps, *sinkcaps;
    gchar *type_name;
1084

Ronald S. Bultje's avatar
Ronald S. Bultje committed
1085 1086
    /* no quasi-codecs, please */
    if (in_plugin->id == CODEC_ID_RAWVIDEO ||
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
1087
        (in_plugin->id >= CODEC_ID_PCM_S16LE &&
1088
            in_plugin->id <= CODEC_ID_PCM_U8)) {
Ronald S. Bultje's avatar
Ronald S. Bultje committed
1089
      goto next;
1090
    }
Ronald S. Bultje's avatar
Ronald S. Bultje committed
1091 1092 1093

    /* only decoders */
    if (!in_plugin->decode) {
1094 1095
      goto next;
    }
1096

1097
    /* name */
1098 1099 1100
    if (!gst_ffmpeg_get_codecid_longname (in_plugin->id)) {
      g_warning ("Add decoder %s (%d) please",
          in_plugin->name, in_plugin->id);
1101
      goto next;
1102
    }
1103

1104
    /* first make sure we've got a supported type */
1105
    sinkcaps = gst_ffmpeg_codecid_to_caps (in_plugin->id, NULL, FALSE);