gstffmpegdec.c 36.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
//#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
  union {
    struct {
      gint width, height, fps, fps_base;
57
      enum PixelFormat pix_fmt;
58 59 60 61
    } video;
    struct {
      gint channels, samplerate;
    } audio;
62
  } format;
63
  gboolean waiting_for_key;
64
  guint64 next_ts;
65

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

70 71
  GstBuffer *last_buffer;

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

  gint hurry_up, lowres;
75 76 77 78
};

typedef struct _GstFFMpegDecClass GstFFMpegDecClass;

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

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

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

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

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

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

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

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

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

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

136 137
static gboolean gst_ffmpegdec_negotiate (GstFFMpegDec * ffmpegdec);

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

static GstElementClass *parent_class = NULL;

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 187
#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;
}
188

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

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

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

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

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

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

238
  parent_class = g_type_class_peek_parent (klass);
239

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

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

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

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

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

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

285 286
  ffmpegdec->last_buffer = NULL;

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

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

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

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

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

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

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

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

  gst_event_unref (event);

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

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

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

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

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

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

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

402 403 404 405 406
  /* 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 &&
407 408
      oclass->in_plugin->id != CODEC_ID_MP3 &&
      oclass->in_plugin->id != CODEC_ID_H264) {
409
    ffmpegdec->pctx = av_parser_init (oclass->in_plugin->id);
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;
418
      ffmpegdec->format.video.pix_fmt = PIX_FMT_NB;
419 420 421 422 423 424 425 426
      break;
    case CODEC_TYPE_AUDIO:
      ffmpegdec->format.audio.samplerate = 0;
      ffmpegdec->format.audio.channels = 0;
      break;
    default:
      break;
  }
427
  ffmpegdec->next_ts = 0;
428 429
  
  ffmpegdec->last_buffer = NULL;
430

431 432 433
  return TRUE;
}

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

443
  /* close old session */
444
  gst_ffmpegdec_close (ffmpegdec);
445

446 447
  /* set defaults */
  avcodec_get_context_defaults (ffmpegdec->context);
448

449
  /* set buffer functions */  
450
  ffmpegdec->context->get_buffer = gst_ffmpegdec_get_buffer;
451 452
  ffmpegdec->context->release_buffer = gst_ffmpegdec_release_buffer;      
  
453
  /* get size and so */
454 455
  gst_ffmpeg_caps_with_codecid (oclass->in_plugin->id,
      oclass->in_plugin->type, caps, ffmpegdec->context);
456 457 458 459
  if (!ffmpegdec->context->time_base.den) {
    ffmpegdec->context->time_base.num = 1;
    ffmpegdec->context->time_base.den = 25;
  }
460

461 462 463 464 465 466 467 468 469
  /* 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);
  }

470 471 472
  /* do *not* draw edges */
  ffmpegdec->context->flags |= CODEC_FLAG_EMU_EDGE;

473 474 475
  /* workaround encoder bugs */
  ffmpegdec->context->workaround_bugs |= FF_BUG_AUTODETECT;

476 477 478 479
  /* for slow cpus */
  ffmpegdec->context->lowres = ffmpegdec->lowres;
  ffmpegdec->context->hurry_up = ffmpegdec->hurry_up;

480 481 482
  /* open codec - we don't select an output pix_fmt yet,
   * simply because we don't know! We only get it
   * during playback... */
483 484 485 486 487 488 489 490 491
  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;
492 493
}

494
static int
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
495
gst_ffmpegdec_get_buffer (AVCodecContext * context, AVFrame * picture)
496 497 498
{
  GstBuffer *buf = NULL;
  gulong bufsize = 0;
499 500 501
  GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) context->opaque; 
  int width  = context->width;
  int height = context->height;
502 503 504

  switch (context->codec_type) {
    case CODEC_TYPE_VIDEO:
505 506 507
      
      avcodec_align_dimensions(context, &width, &height);
      
508
      bufsize = avpicture_get_size (context->pix_fmt,
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533
				    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;
      
534 535
      gst_ffmpeg_avpicture_fill ((AVPicture *) picture,
          GST_BUFFER_DATA (buf),
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
536
          context->pix_fmt, context->width, context->height);
537
      break;
538
      
539 540 541 542
    case CODEC_TYPE_AUDIO:
    default:
      g_assert (0);
      break;
543 544
  }

545 546 547 548 549 550 551 552
  /* 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;
553
  picture->opaque = buf;
554 555 556 557
  gst_buffer_ref (buf);

  return 0;
}
558

559
static void
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
560
gst_ffmpegdec_release_buffer (AVCodecContext * context, AVFrame * picture)
561 562
{
  gint i;
563 564 565 566 567
  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
568

569 570
  if (buf == ffmpegdec->last_buffer)
    ffmpegdec->last_buffer = NULL;
571 572 573
  gst_buffer_unref (buf);

  /* zero out the reference in ffmpeg */
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
574
  for (i = 0; i < 4; i++) {
575 576 577
    picture->data[i] = NULL;
    picture->linesize[i] = 0;
  }
578 579
}

580 581 582 583 584 585 586
static gboolean
gst_ffmpegdec_negotiate (GstFFMpegDec * ffmpegdec)
{
  GstFFMpegDecClass *oclass =
      (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
  GstCaps *caps;

587 588 589 590
  switch (oclass->in_plugin->type) {
    case CODEC_TYPE_VIDEO:
      if (ffmpegdec->format.video.width == ffmpegdec->context->width &&
          ffmpegdec->format.video.height == ffmpegdec->context->height &&
591
          ffmpegdec->format.video.fps == ffmpegdec->context->time_base.den &&
592
          ffmpegdec->format.video.fps_base ==
593
              ffmpegdec->context->time_base.num &&
594
	  ffmpegdec->format.video.pix_fmt == ffmpegdec->context->pix_fmt)
595
        return TRUE;
596 597 598 599
      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,
600 601
          ffmpegdec->context->time_base.den,
          ffmpegdec->context->time_base.num);
602 603
      ffmpegdec->format.video.width = ffmpegdec->context->width;
      ffmpegdec->format.video.height = ffmpegdec->context->height;
604 605
      ffmpegdec->format.video.fps = ffmpegdec->context->time_base.den;
      ffmpegdec->format.video.fps_base = ffmpegdec->context->time_base.num;
606
      ffmpegdec->format.video.pix_fmt = ffmpegdec->context->pix_fmt;
607 608 609 610 611 612
      break;
    case CODEC_TYPE_AUDIO:
      if (ffmpegdec->format.audio.samplerate ==
              ffmpegdec->context->sample_rate &&
          ffmpegdec->format.audio.channels == ffmpegdec->context->channels)
        return TRUE;
613 614 615 616
      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;
617
      ffmpegdec->format.audio.channels = ffmpegdec->context->channels;
618 619 620 621 622
      break;
    default:
      break;
  }

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 655 656 657 658 659 660 661 662 663 664
  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;
}
665

666 667
static gint
gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec,
668
    guint8 * data, guint size, gint * got_data, guint64 * in_ts)
669 670 671 672
{
  GstFFMpegDecClass *oclass =
      (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
  GstBuffer *outbuf = NULL;
673
  gint have_data = 0, len = 0;
674
  
675 676 677 678
  ffmpegdec->context->frame_number++;

  switch (oclass->in_plugin->type) {
    case CODEC_TYPE_VIDEO:
679
      ffmpegdec->picture->pict_type = -1; /* in case we skip frames */
680 681 682

      ffmpegdec->context->opaque = ffmpegdec;
      
683 684
      len = avcodec_decode_video (ffmpegdec->context,
          ffmpegdec->picture, &have_data, data, size);
685 686
      GST_DEBUG_OBJECT (ffmpegdec,
          "Decode video: len=%d, have_data=%d", len, have_data);
687

688 689 690 691
      if (ffmpegdec->waiting_for_key &&
          ffmpegdec->picture->pict_type != FF_I_TYPE) {
        have_data = 0;
      } else if (len >= 0 && have_data > 0) {
692 693 694
        /* 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... */
695

696 697
	if (ffmpegdec->picture->opaque != NULL) {
	  outbuf = (GstBuffer *) ffmpegdec->picture->opaque;
698 699
          if (outbuf == ffmpegdec->last_buffer)
            ffmpegdec->last_buffer = NULL;
700
	} else {
701 702
	  AVPicture pic;
	  gint fsize = gst_ffmpeg_avpicture_get_size (ffmpegdec->context->pix_fmt,
703 704
            ffmpegdec->context->width, ffmpegdec->context->height);

705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726
	  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;
727

728 729 730 731
        /* 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. */
732 733 734 735
        if (!(oclass->in_plugin->capabilities & CODEC_CAP_DELAY) ||
	    ((ffmpegdec->picture->pict_type == FF_I_TYPE ||
              !GST_CLOCK_TIME_IS_VALID (ffmpegdec->next_ts)) &&
             GST_CLOCK_TIME_IS_VALID (*in_ts))) {
736
          ffmpegdec->next_ts = *in_ts;
737
	  *in_ts = GST_CLOCK_TIME_NONE;
738
        }
739

740 741 742 743 744 745
	if (ffmpegdec->picture->key_frame) {
	  GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_KEY_UNIT);
	} else {
	  GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_DELTA_UNIT);
	}
		
746
        GST_BUFFER_TIMESTAMP (outbuf) = ffmpegdec->next_ts;
747 748
        if (ffmpegdec->context->time_base.num != 0 &&
            ffmpegdec->context->time_base.den != 0) {
749
          GST_BUFFER_DURATION (outbuf) = GST_SECOND *
750 751
              ffmpegdec->context->time_base.num /
              ffmpegdec->context->time_base.den;
752 753 754 755 756

          /* Take repeat_pict into account */
          GST_BUFFER_DURATION (outbuf) += GST_BUFFER_DURATION (outbuf)
              * ffmpegdec->picture->repeat_pict / 2;
	  
757 758 759 760
          ffmpegdec->next_ts += GST_BUFFER_DURATION (outbuf);
        } else {
          ffmpegdec->next_ts = GST_CLOCK_TIME_NONE;
        }
761 762
      } else if (ffmpegdec->picture->pict_type != -1 &&
		 oclass->in_plugin->capabilities & CODEC_CAP_DELAY) {
763
        /* update time for skip-frame */
764 765 766
        if ((ffmpegdec->picture->pict_type == FF_I_TYPE ||
             !GST_CLOCK_TIME_IS_VALID (ffmpegdec->next_ts)) &&
            GST_CLOCK_TIME_IS_VALID (*in_ts)) {
767
          ffmpegdec->next_ts = *in_ts;
768
	  *in_ts = GST_CLOCK_TIME_NONE;
769
        }
770
        
771 772
        if (ffmpegdec->context->time_base.num != 0 &&
            ffmpegdec->context->time_base.den != 0) {
773
          guint64 dur = GST_SECOND *  
774 775
            ffmpegdec->context->time_base.num /
            ffmpegdec->context->time_base.den;
776 777 778 779 780

          /* Take repeat_pict into account */
          dur += dur * ffmpegdec->picture->repeat_pict / 2;
	  
          ffmpegdec->next_ts += dur;
781 782
        } else {
          ffmpegdec->next_ts = GST_CLOCK_TIME_NONE;
783
        }
784 785 786 787
      }
      break;

    case CODEC_TYPE_AUDIO:
788 789 790 791 792 793
      if (!ffmpegdec->last_buffer)
        outbuf = gst_buffer_new_and_alloc (AVCODEC_MAX_AUDIO_FRAME_SIZE);
      else {
        outbuf = ffmpegdec->last_buffer;
        ffmpegdec->last_buffer = NULL;
      }
794 795
      len = avcodec_decode_audio (ffmpegdec->context,
          (int16_t *) GST_BUFFER_DATA (outbuf), &have_data, data, size);
796 797
      GST_DEBUG_OBJECT (ffmpegdec,
          "Decode audio: len=%d, have_data=%d", len, have_data);
798 799

      if (len >= 0 && have_data > 0) {
800 801 802 803 804
	if (!gst_ffmpegdec_negotiate (ffmpegdec)) {
	  gst_buffer_unref (outbuf);
	  return -1;
	}

805
        GST_BUFFER_SIZE (outbuf) = have_data;
806 807
        if (GST_CLOCK_TIME_IS_VALID (*in_ts)) {
          ffmpegdec->next_ts = *in_ts;
808
        }
809 810 811 812 813
        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);
814 815
        if (GST_CLOCK_TIME_IS_VALID (*in_ts))
          *in_ts += GST_BUFFER_DURATION (outbuf);
816 817 818
      } else if (len > 0 && have_data == 0) {
        /* cache output, because it may be used for caching (in-place) */
        ffmpegdec->last_buffer = outbuf;
819 820 821 822 823 824 825 826
      } else {
        gst_buffer_unref (outbuf);
      }
      break;
    default:
      g_assert (0);
      break;
  }
827
  
828 829 830 831 832 833 834 835 836 837
  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 {
838 839
    /* this is where I lost my last clue on ffmpeg... */
    *got_data = 1; //(ffmpegdec->pctx || have_data) ? 1 : 0;
840
  }
841
  
842
  if (have_data) {
843

844 845
    GST_DEBUG_OBJECT (ffmpegdec, "Decoded data, now pushing (%"
        GST_TIME_FORMAT ")", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
846 847 848 849 850 851 852 853 854 855

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

  return len;
}

856 857 858
static void
gst_ffmpegdec_handle_event (GstFFMpegDec * ffmpegdec, GstEvent * event)
{
859 860 861
  GstFFMpegDecClass *oclass =
      (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));

862 863
  GST_DEBUG_OBJECT (ffmpegdec,
      "Handling event of type %d", GST_EVENT_TYPE (event));
864

865
  switch (GST_EVENT_TYPE (event)) {
866 867 868 869 870 871 872 873 874 875
    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);
      }
876
      goto forward;
877
    case GST_EVENT_FLUSH:
878 879 880
      if (ffmpegdec->opened) {
        avcodec_flush_buffers (ffmpegdec->context);
      }
881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904
      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...");
      }
905 906
      if (ffmpegdec->opened) {
        avcodec_flush_buffers (ffmpegdec->context);
907 908

        if (ffmpegdec->context->codec_id == CODEC_ID_MPEG2VIDEO ||
909 910
            ffmpegdec->context->codec_id == CODEC_ID_MPEG4 ||
            ffmpegdec->context->codec_id == CODEC_ID_H264) {
911 912
          ffmpegdec->waiting_for_key = TRUE;
        }
913
      }
914 915 916 917 918 919 920 921 922
      /* fall-through */
    }
    default:
    forward:
      gst_pad_event_default (ffmpegdec->sinkpad, event);
      return;
  }
}

923
static void
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
924
gst_ffmpegdec_chain (GstPad * pad, GstData * _data)
925
{
926
  GstBuffer *inbuf;
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
927 928 929
  GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) (gst_pad_get_parent (pad));
  GstFFMpegDecClass *oclass =
      (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
930
  guint8 *bdata, *data;
931
  gint bsize, size, len, have_data;
932 933 934 935 936 937 938 939 940 941
  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);
942

Ronald S. Bultje's avatar
Ronald S. Bultje committed
943
  if (!ffmpegdec->opened) {
944
    GST_ELEMENT_ERROR (ffmpegdec, CORE, NEGOTIATION, (NULL),
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
945 946
        ("ffdec_%s: input format was not set before data start",
            oclass->in_plugin->name));
Ronald S. Bultje's avatar
Ronald S. Bultje committed
947 948 949
    return;
  }

950 951
  GST_DEBUG_OBJECT (ffmpegdec,
      "Received new data of size %d, time %" GST_TIME_FORMAT,
952
      GST_BUFFER_SIZE (inbuf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)));
953

954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973
  /* 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);
  }
974 975

  do {
976
    /* parse, if at all possible */
977
    if (ffmpegdec->pctx) {
978
      gint res;
979
      gint64 ffpts;
980

981
      ffpts = gst_ffmpeg_time_gst_to_ff (in_ts, ffmpegdec->context->time_base);
982 983
      res = av_parser_parse (ffmpegdec->pctx, ffmpegdec->context,
          &data, &size, bdata, bsize,
984
          ffpts, ffpts);
985

986 987
      GST_DEBUG_OBJECT (ffmpegdec, "Parsed video frame, res=%d, size=%d",
          res, size);
988
      
989 990
      in_ts = gst_ffmpeg_time_ff_to_gst (ffmpegdec->pctx->pts,
          ffmpegdec->context->time_base);
991
      if (res == 0 || size == 0)
992
        break;
993
      else {
994 995 996 997 998 999 1000 1001
        bsize -= res;
        bdata += res;
      }
    } else {
      data = bdata;
      size = bsize;
    }

1002
    if ((len = gst_ffmpegdec_frame (ffmpegdec, data, size,
1003
             &have_data, &in_ts)) < 0)
1004 1005
      break;

1006
    if (!ffmpegdec->pctx) {
1007 1008 1009
      bsize -= len;
      bdata += len;
    }
1010 1011 1012 1013

    if (!have_data) {
      break;
    }
1014
  } while (bsize > 0);
1015

1016 1017
  if ((ffmpegdec->pctx || oclass->in_plugin->id == CODEC_ID_MP3) &&
      bsize > 0) {
1018
    GST_DEBUG_OBJECT (ffmpegdec, "Keeping %d bytes of data", bsize);
1019

1020 1021
    ffmpegdec->pcache = gst_buffer_create_sub (inbuf,
        GST_BUFFER_SIZE (inbuf) - bsize, bsize);
1022 1023
  } else if (bsize > 0) {
    GST_DEBUG_OBJECT (ffmpegdec, "Dropping %d bytes of data", bsize);
1024
  }
1025 1026 1027
  gst_buffer_unref (inbuf);
}

1028
static GstElementStateReturn
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
1029
gst_ffmpegdec_change_state (GstElement * element)
1030
{
1031 1032 1033 1034 1035
  GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) element;
  gint transition = GST_STATE_TRANSITION (element);

  switch (transition) {
    case GST_STATE_PAUSED_TO_READY:
1036
      gst_ffmpegdec_close (ffmpegdec);
1037 1038
      if (ffmpegdec->last_buffer != NULL) {
	gst_buffer_unref (ffmpegdec->last_buffer);
1039
        ffmpegdec->last_buffer = NULL;
1040
      }
1041 1042 1043
      break;
  }

1044 1045
  if (GST_ELEMENT_CLASS (parent_class)->change_state)
    return GST_ELEMENT_CLASS (parent_class)->change_state (element);
1046

1047
  return GST_STATE_SUCCESS;
1048 1049
}

1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089
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