gstffmpegdec.c 38.1 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, synctime;
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
static gboolean gst_ffmpegdec_query (GstPad * pad, GstQuery *query);
122 123
static gboolean gst_ffmpegdec_event (GstPad * pad, GstEvent * event);

124 125 126
static gboolean gst_ffmpegdec_setcaps (GstPad * pad, GstCaps * caps);
static gboolean gst_ffmpegdec_sink_event (GstPad * pad, GstEvent * event);
static GstFlowReturn gst_ffmpegdec_chain (GstPad * pad, GstBuffer * buf);
127

128 129
static GstStateChangeReturn gst_ffmpegdec_change_state (GstElement * element,
    GstStateChange transition);
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
  gobject_class->dispose = gst_ffmpegdec_dispose;
  gobject_class->set_property = gst_ffmpegdec_set_property;
  gobject_class->get_property = gst_ffmpegdec_get_property;
  gstelement_class->change_state = gst_ffmpegdec_change_state;

245 246 247 248 249 250 251 252
  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));
253 254 255
}

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

  /* setup pads */
  ffmpegdec->sinkpad = gst_pad_new_from_template (oclass->sinktempl, "sink");
263 264
  gst_pad_set_setcaps_function (ffmpegdec->sinkpad, gst_ffmpegdec_setcaps);
  gst_pad_set_event_function (ffmpegdec->sinkpad, gst_ffmpegdec_sink_event);
265
  gst_pad_set_chain_function (ffmpegdec->sinkpad, gst_ffmpegdec_chain);
266 267
  gst_element_add_pad (GST_ELEMENT (ffmpegdec), ffmpegdec->sinkpad);

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

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

286
  ffmpegdec->last_buffer = NULL;
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
static gboolean
304
gst_ffmpegdec_query (GstPad * pad, GstQuery *query)
305
{
306 307 308 309 310 311 312
  GstFFMpegDec *ffmpegdec;
  GstPad *peer;
  GstFormat bfmt;

  bfmt = GST_FORMAT_BYTES;
  ffmpegdec = (GstFFMpegDec *) GST_PAD_PARENT (pad);
  peer = GST_PAD_PEER (ffmpegdec->sinkpad);
313 314

  if (!peer)
315
    goto no_peer;
316

317 318
  /* just forward to peer */
  if (gst_pad_query (peer, query))
319
    return TRUE;
320

321
#if 0
322
  /* ok, do bitrate calc... */
323
  if ((type != GST_QUERY_POSITION && type != GST_QUERY_TOTAL) ||
324 325 326 327 328 329 330
           *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;
331
#endif
332

333 334 335 336 337 338
  return FALSE;

no_peer:
  {
    return FALSE;
  }
339 340 341 342 343
}

static gboolean
gst_ffmpegdec_event (GstPad * pad, GstEvent * event)
{
344 345 346 347 348
  GstFFMpegDec *ffmpegdec;
  GstPad *peer;
  
  ffmpegdec = (GstFFMpegDec *) GST_PAD_PARENT (pad);
  peer = GST_PAD_PEER (ffmpegdec->sinkpad);
349 350 351

  if (!peer)
    return FALSE;
352
  
353 354 355
  gst_event_ref (event);
  if (gst_pad_send_event (peer, event)) {
    gst_event_unref (event);
356
    return TRUE;
357 358 359 360 361
  }

  gst_event_unref (event);

  return FALSE; /* .. */
362 363
}

364 365 366 367 368 369
static void
gst_ffmpegdec_close (GstFFMpegDec *ffmpegdec)
{
  if (!ffmpegdec->opened)
    return;

370 371 372 373 374
  if (ffmpegdec->par) {
    g_free (ffmpegdec->par);
    ffmpegdec->par = NULL;
  }

375 376
  if (ffmpegdec->context->priv_data)
    avcodec_close (ffmpegdec->context);
377 378 379 380 381 382 383 384 385 386 387
  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;
  }
388 389 390 391 392 393 394 395 396

  if (ffmpegdec->pctx) {
    if (ffmpegdec->pcache) {
      gst_buffer_unref (ffmpegdec->pcache);
      ffmpegdec->pcache = NULL;
    }
    av_parser_close (ffmpegdec->pctx);
    ffmpegdec->pctx = NULL;
  }
397 398 399 400 401 402 403 404
}

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

405 406 407
  if (avcodec_open (ffmpegdec->context, oclass->in_plugin) < 0)
    goto could_not_open;

408 409
  ffmpegdec->opened = TRUE;

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

412 413 414 415 416
  /* 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 &&
417 418
      oclass->in_plugin->id != CODEC_ID_MP3 &&
      oclass->in_plugin->id != CODEC_ID_H264) {
419
    ffmpegdec->pctx = av_parser_init (oclass->in_plugin->id);
420
  }
421

422 423 424 425 426 427
  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;
428
      ffmpegdec->format.video.pix_fmt = PIX_FMT_NB;
429 430 431 432 433 434 435 436
      break;
    case CODEC_TYPE_AUDIO:
      ffmpegdec->format.audio.samplerate = 0;
      ffmpegdec->format.audio.channels = 0;
      break;
    default:
      break;
  }
437
  ffmpegdec->next_ts = 0;
438
  ffmpegdec->synctime = GST_CLOCK_TIME_NONE;
439
  ffmpegdec->last_buffer = NULL;
440

441
  return TRUE;
442 443 444 445 446 447 448 449 450

  /* ERRORS */
could_not_open:
  {
    gst_ffmpegdec_close (ffmpegdec);
    GST_DEBUG ("ffdec_%s: Failed to open FFMPEG codec",
        oclass->in_plugin->name);
    return FALSE;
  }
451 452
}

Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
453
static GstPadLinkReturn
454
gst_ffmpegdec_setcaps (GstPad * pad, GstCaps * caps)
455
{
456
  GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) (GST_OBJECT_PARENT (pad));
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
457 458
  GstFFMpegDecClass *oclass =
      (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
459 460
  GstStructure *structure;
  const GValue *par;
461

462 463
  GST_DEBUG ("setcaps called");

464
  /* close old session */
465
  gst_ffmpegdec_close (ffmpegdec);
466

467 468
  /* set defaults */
  avcodec_get_context_defaults (ffmpegdec->context);
469

470
  /* set buffer functions */  
471
  ffmpegdec->context->get_buffer = gst_ffmpegdec_get_buffer;
472 473
  ffmpegdec->context->release_buffer = gst_ffmpegdec_release_buffer;      
  
474
  /* get size and so */
475 476
  gst_ffmpeg_caps_with_codecid (oclass->in_plugin->id,
      oclass->in_plugin->type, caps, ffmpegdec->context);
477

478
  if (!ffmpegdec->context->time_base.den) {
479
    GST_DEBUG ("forcing 25/1 framerate");
480 481 482
    ffmpegdec->context->time_base.num = 1;
    ffmpegdec->context->time_base.den = 25;
  }
483

484 485 486 487 488 489 490 491 492
  /* 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);
  }

493 494 495
  /* do *not* draw edges */
  ffmpegdec->context->flags |= CODEC_FLAG_EMU_EDGE;

496 497 498
  /* workaround encoder bugs */
  ffmpegdec->context->workaround_bugs |= FF_BUG_AUTODETECT;

499 500 501 502
  /* for slow cpus */
  ffmpegdec->context->lowres = ffmpegdec->lowres;
  ffmpegdec->context->hurry_up = ffmpegdec->hurry_up;

503 504 505
  /* open codec - we don't select an output pix_fmt yet,
   * simply because we don't know! We only get it
   * during playback... */
506 507 508 509 510
  if (!gst_ffmpegdec_open (ffmpegdec)) {
    if (ffmpegdec->par) {
      g_free (ffmpegdec->par);
      ffmpegdec->par = NULL;
    }
511
    return FALSE;
512 513
  }

514
  return TRUE;
515 516
}

517
static int
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
518
gst_ffmpegdec_get_buffer (AVCodecContext * context, AVFrame * picture)
519 520 521
{
  GstBuffer *buf = NULL;
  gulong bufsize = 0;
522 523 524
  GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) context->opaque; 
  int width  = context->width;
  int height = context->height;
525 526 527

  switch (context->codec_type) {
    case CODEC_TYPE_VIDEO:
528 529 530
      
      avcodec_align_dimensions(context, &width, &height);
      
531
      bufsize = avpicture_get_size (context->pix_fmt,
532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553
				    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);
      }
      
554 555
      if (gst_pad_alloc_buffer (ffmpegdec->srcpad, GST_BUFFER_OFFSET_NONE, bufsize, GST_PAD_CAPS (ffmpegdec->srcpad), &buf) != GST_FLOW_OK)
        return -1;
556 557
      ffmpegdec->last_buffer = buf;
      
558 559
      gst_ffmpeg_avpicture_fill ((AVPicture *) picture,
          GST_BUFFER_DATA (buf),
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
560
          context->pix_fmt, context->width, context->height);
561
      break;
562
      
563 564 565 566
    case CODEC_TYPE_AUDIO:
    default:
      g_assert (0);
      break;
567 568
  }

569 570 571 572 573 574 575 576
  /* 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;
577
  picture->opaque = buf;
578 579 580 581
  gst_buffer_ref (buf);

  return 0;
}
582

583
static void
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
584
gst_ffmpegdec_release_buffer (AVCodecContext * context, AVFrame * picture)
585 586
{
  gint i;
587 588 589 590 591
  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
592

593 594
  if (buf == ffmpegdec->last_buffer)
    ffmpegdec->last_buffer = NULL;
595 596 597
  gst_buffer_unref (buf);

  /* zero out the reference in ffmpeg */
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
598
  for (i = 0; i < 4; i++) {
599 600 601
    picture->data[i] = NULL;
    picture->linesize[i] = 0;
  }
602 603
}

604 605 606 607 608 609 610
static gboolean
gst_ffmpegdec_negotiate (GstFFMpegDec * ffmpegdec)
{
  GstFFMpegDecClass *oclass =
      (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
  GstCaps *caps;

611 612 613 614
  switch (oclass->in_plugin->type) {
    case CODEC_TYPE_VIDEO:
      if (ffmpegdec->format.video.width == ffmpegdec->context->width &&
          ffmpegdec->format.video.height == ffmpegdec->context->height &&
615
          ffmpegdec->format.video.fps == ffmpegdec->context->time_base.den &&
616
          ffmpegdec->format.video.fps_base ==
617
              ffmpegdec->context->time_base.num &&
618
	  ffmpegdec->format.video.pix_fmt == ffmpegdec->context->pix_fmt)
619
        return TRUE;
620 621 622 623
      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,
624 625
          ffmpegdec->context->time_base.den,
          ffmpegdec->context->time_base.num);
626 627
      ffmpegdec->format.video.width = ffmpegdec->context->width;
      ffmpegdec->format.video.height = ffmpegdec->context->height;
628 629
      ffmpegdec->format.video.fps = ffmpegdec->context->time_base.den;
      ffmpegdec->format.video.fps_base = ffmpegdec->context->time_base.num;
630
      ffmpegdec->format.video.pix_fmt = ffmpegdec->context->pix_fmt;
631 632 633 634 635 636
      break;
    case CODEC_TYPE_AUDIO:
      if (ffmpegdec->format.audio.samplerate ==
              ffmpegdec->context->sample_rate &&
          ffmpegdec->format.audio.channels == ffmpegdec->context->channels)
        return TRUE;
637 638 639 640
      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;
641
      ffmpegdec->format.audio.channels = ffmpegdec->context->channels;
642 643 644 645 646
      break;
    default:
      break;
  }

647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673
  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 ||
674
      !gst_pad_set_caps (ffmpegdec->srcpad, caps)) {
675 676 677 678 679
    GST_ELEMENT_ERROR (ffmpegdec, CORE, NEGOTIATION, (NULL),
        ("Failed to link ffmpeg decoder (%s) to next element",
        oclass->in_plugin->name));

    if (caps != NULL)
680
      gst_caps_unref (caps);
681 682 683 684

    return FALSE;
  }

685
  gst_caps_unref (caps);
686 687 688

  return TRUE;
}
689

690 691
static gint
gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec,
692 693
    guint8 * data, guint size, gint * got_data, guint64 * in_ts,
    GstFlowReturn * ret)
694 695 696 697
{
  GstFFMpegDecClass *oclass =
      (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
  GstBuffer *outbuf = NULL;
698
  gint have_data = 0, len = 0;
699

700 701 702
  if (ffmpegdec->context->codec == NULL)
    return -1;

703 704 705 706
  ffmpegdec->context->frame_number++;

  switch (oclass->in_plugin->type) {
    case CODEC_TYPE_VIDEO:
707
      ffmpegdec->picture->pict_type = -1; /* in case we skip frames */
708 709 710

      ffmpegdec->context->opaque = ffmpegdec;
      
711 712
      len = avcodec_decode_video (ffmpegdec->context,
          ffmpegdec->picture, &have_data, data, size);
713 714
      GST_DEBUG_OBJECT (ffmpegdec,
          "Decode video: len=%d, have_data=%d", len, have_data);
715

716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752
      if (ffmpegdec->waiting_for_key) {
        if (ffmpegdec->picture->pict_type == FF_I_TYPE) {
          ffmpegdec->waiting_for_key = FALSE;
        } else {
          GST_WARNING_OBJECT (ffmpegdec,
              "Dropping non-keyframe (seek/init)");
          have_data = 0;
          break;
        }
      }

      /* 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. */
      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))) {
        ffmpegdec->next_ts = *in_ts;
        *in_ts = GST_CLOCK_TIME_NONE;
      }

      /* precise seeking.... */
      if (GST_CLOCK_TIME_IS_VALID (ffmpegdec->synctime)) {
        if (ffmpegdec->next_ts >= ffmpegdec->synctime) {
          ffmpegdec->synctime = GST_CLOCK_TIME_NONE;
        } else {
          GST_WARNING_OBJECT (ffmpegdec,
              "Dropping frame for synctime %" GST_TIME_FORMAT ", expected %"
              GST_TIME_FORMAT, GST_TIME_ARGS (ffmpegdec->synctime),
              GST_TIME_ARGS (ffmpegdec->next_ts));
          have_data = 0;
          /* don´t break here! Timestamps are updated below */
        }
      }

753 754 755 756
      if (ffmpegdec->waiting_for_key &&
          ffmpegdec->picture->pict_type != FF_I_TYPE) {
        have_data = 0;
      } else if (len >= 0 && have_data > 0) {
757 758 759
        /* 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... */
760

761 762
	if (ffmpegdec->picture->opaque != NULL) {
	  outbuf = (GstBuffer *) ffmpegdec->picture->opaque;
763 764
          if (outbuf == ffmpegdec->last_buffer)
            ffmpegdec->last_buffer = NULL;
765
	} else {
766 767
	  AVPicture pic;
	  gint fsize = gst_ffmpeg_avpicture_get_size (ffmpegdec->context->pix_fmt,
768 769
            ffmpegdec->context->width, ffmpegdec->context->height);

770 771 772
	  if (!gst_ffmpegdec_negotiate (ffmpegdec))
	    return -1;	
	  
773 774
	  if ((*ret = gst_pad_alloc_buffer (ffmpegdec->srcpad, GST_BUFFER_OFFSET_NONE, fsize, GST_PAD_CAPS (ffmpegdec->srcpad), &outbuf)) != GST_FLOW_OK)
            return -1;
775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792

	  /* 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;
793

794 795
	if (!ffmpegdec->picture->key_frame) {
	  GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
796 797
	}
		
798
        GST_BUFFER_TIMESTAMP (outbuf) = ffmpegdec->next_ts;
799 800
        if (ffmpegdec->context->time_base.num != 0 &&
            ffmpegdec->context->time_base.den != 0) {
801
          GST_BUFFER_DURATION (outbuf) = GST_SECOND *
802 803
              ffmpegdec->context->time_base.num /
              ffmpegdec->context->time_base.den;
804 805 806 807

          /* Take repeat_pict into account */
          GST_BUFFER_DURATION (outbuf) += GST_BUFFER_DURATION (outbuf)
              * ffmpegdec->picture->repeat_pict / 2;
808

809 810 811 812
          ffmpegdec->next_ts += GST_BUFFER_DURATION (outbuf);
        } else {
          ffmpegdec->next_ts = GST_CLOCK_TIME_NONE;
        }
813 814
      } else if (ffmpegdec->picture->pict_type != -1 &&
		 oclass->in_plugin->capabilities & CODEC_CAP_DELAY) {
815
        /* update time for skip-frame */
816 817 818
        if ((ffmpegdec->picture->pict_type == FF_I_TYPE ||
             !GST_CLOCK_TIME_IS_VALID (ffmpegdec->next_ts)) &&
            GST_CLOCK_TIME_IS_VALID (*in_ts)) {
819
          ffmpegdec->next_ts = *in_ts;
820
	  *in_ts = GST_CLOCK_TIME_NONE;
821
        }
822
        
823 824
        if (ffmpegdec->context->time_base.num != 0 &&
            ffmpegdec->context->time_base.den != 0) {
825
          guint64 dur = GST_SECOND *  
826 827
            ffmpegdec->context->time_base.num /
            ffmpegdec->context->time_base.den;
828 829 830

          /* Take repeat_pict into account */
          dur += dur * ffmpegdec->picture->repeat_pict / 2;
831

832
          ffmpegdec->next_ts += dur;
833 834
        } else {
          ffmpegdec->next_ts = GST_CLOCK_TIME_NONE;
835
        }
836 837 838 839
      }
      break;

    case CODEC_TYPE_AUDIO:
840 841 842 843 844 845
      if (!ffmpegdec->last_buffer)
        outbuf = gst_buffer_new_and_alloc (AVCODEC_MAX_AUDIO_FRAME_SIZE);
      else {
        outbuf = ffmpegdec->last_buffer;
        ffmpegdec->last_buffer = NULL;
      }
846 847
      len = avcodec_decode_audio (ffmpegdec->context,
          (int16_t *) GST_BUFFER_DATA (outbuf), &have_data, data, size);
848 849
      GST_DEBUG_OBJECT (ffmpegdec,
          "Decode audio: len=%d, have_data=%d", len, have_data);
850 851

      if (len >= 0 && have_data > 0) {
852 853 854 855 856
	if (!gst_ffmpegdec_negotiate (ffmpegdec)) {
	  gst_buffer_unref (outbuf);
	  return -1;
	}

857
        GST_BUFFER_SIZE (outbuf) = have_data;
858 859
        if (GST_CLOCK_TIME_IS_VALID (*in_ts)) {
          ffmpegdec->next_ts = *in_ts;
860
        }
861 862 863 864 865
        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);
866 867
        if (GST_CLOCK_TIME_IS_VALID (*in_ts))
          *in_ts += GST_BUFFER_DURATION (outbuf);
868 869 870
      } else if (len > 0 && have_data == 0) {
        /* cache output, because it may be used for caching (in-place) */
        ffmpegdec->last_buffer = outbuf;
871 872 873 874 875 876 877 878
      } else {
        gst_buffer_unref (outbuf);
      }
      break;
    default:
      g_assert (0);
      break;
  }
879
  
880 881 882 883 884 885 886 887 888 889
  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 {
890 891
    /* this is where I lost my last clue on ffmpeg... */
    *got_data = 1; //(ffmpegdec->pctx || have_data) ? 1 : 0;
892
  }
893
  
894
  if (have_data) {
895 896
    GST_DEBUG_OBJECT (ffmpegdec, "Decoded data, now pushing (%"
        GST_TIME_FORMAT ")", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
897

898
    gst_buffer_set_caps (outbuf, GST_PAD_CAPS (ffmpegdec->srcpad));
899
    *ret = gst_pad_push (ffmpegdec->srcpad, outbuf);
900 901 902 903 904
  }

  return len;
}

905 906
static gboolean
gst_ffmpegdec_sink_event (GstPad * pad, GstEvent * event)
907
{
908
  GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) GST_OBJECT_PARENT (pad);
909 910 911
  GstFFMpegDecClass *oclass =
      (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));

912 913
  GST_DEBUG_OBJECT (ffmpegdec,
      "Handling event of type %d", GST_EVENT_TYPE (event));
914

915
  switch (GST_EVENT_TYPE (event)) {
916 917 918 919
    case GST_EVENT_EOS:
      if (oclass->in_plugin->capabilities & CODEC_CAP_DELAY) {
        gint have_data, len, try = 0;
        do {
920
          GstFlowReturn ret;
921
          len = gst_ffmpegdec_frame (ffmpegdec, NULL, 0, &have_data,
922
              &ffmpegdec->next_ts, &ret);
923 924 925 926
          if (len < 0 || have_data == 0)
            break;
        } while (try++ < 10);
      }
927
      goto forward;
928
    case GST_EVENT_FLUSH_STOP:
929 930 931
      if (ffmpegdec->opened) {
        avcodec_flush_buffers (ffmpegdec->context);
      }
932
      goto forward;
933 934 935 936 937 938 939 940
    case GST_EVENT_NEWSEGMENT: {
      gint64 base, start, end;
      gdouble rate;
      GstFormat fmt;

      gst_event_parse_newsegment (event, &rate, &fmt, &start, &end, &base);
      if (fmt == GST_FORMAT_TIME) {
        ffmpegdec->next_ts = start;
941
        GST_DEBUG_OBJECT (ffmpegdec, "Discont to time %" GST_TIME_FORMAT,
942 943 944
            GST_TIME_ARGS (start));
      } else if (ffmpegdec->context->bit_rate && fmt == GST_FORMAT_BYTES) {
        ffmpegdec->next_ts = start * GST_SECOND / ffmpegdec->context->bit_rate;
945
        GST_DEBUG_OBJECT (ffmpegdec,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
946 947 948 949 950 951
            "Newsegment in bytes from byte %" G_GINT64_FORMAT
            " (time %" GST_TIME_FORMAT ") to byte % "G_GINT64_FORMAT
            " (time %" GST_TIME_FORMAT ")",
            start, GST_TIME_ARGS (ffmpegdec->next_ts),
            end,
            GST_TIME_ARGS (end * GST_SECOND / ffmpegdec->context->bit_rate));
952
        gst_event_unref (event);
953 954
        event = gst_event_new_newsegment (rate, fmt,
            start * GST_SECOND / ffmpegdec->context->bit_rate,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
955
            end == -1 ? -1 : end * GST_SECOND / ffmpegdec->context->bit_rate,
956
            base * GST_SECOND / ffmpegdec->context->bit_rate);
957 958 959 960
      } else {
        GST_WARNING_OBJECT (ffmpegdec,
            "Received discont with no useful value...");
      }
961 962
      if (ffmpegdec->opened) {
        avcodec_flush_buffers (ffmpegdec->context);
963 964

        if (ffmpegdec->context->codec_id == CODEC_ID_MPEG2VIDEO ||
965 966
            ffmpegdec->context->codec_id == CODEC_ID_MPEG4 ||
            ffmpegdec->context->codec_id == CODEC_ID_H264) {
967 968
          ffmpegdec->waiting_for_key = TRUE;
        }
969
      }
970 971
      ffmpegdec->waiting_for_key = TRUE;
      ffmpegdec->synctime = ffmpegdec->next_ts;
972 973 974 975
      /* fall-through */
    }
    default:
    forward:
976
      return gst_pad_event_default (ffmpegdec->sinkpad, event);
977
  }
978 979

  return TRUE;
980 981
}

982 983
static GstFlowReturn
gst_ffmpegdec_chain (GstPad * pad, GstBuffer * inbuf)
984
{
985
  GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) (GST_PAD_PARENT (pad));
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
986 987
  GstFFMpegDecClass *oclass =
      (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
988
  guint8 *bdata, *data;
989
  gint bsize, size, len, have_data;
990
  guint64 in_ts = GST_BUFFER_TIMESTAMP (inbuf);
991
  GstFlowReturn ret = GST_FLOW_OK;
Ronald S. Bultje's avatar
Ronald S. Bultje committed
992

993 994 995
  if (!ffmpegdec->opened)
    goto not_negotiated;
  
996 997
  GST_DEBUG_OBJECT (ffmpegdec,
      "Received new data of size %d, time %" GST_TIME_FORMAT,
998
      GST_BUFFER_SIZE (inbuf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)));
999

1000 1001
  /* parse cache joining */
  if (ffmpegdec->pcache) {
1002 1003
    inbuf = gst_buffer_span (ffmpegdec->pcache, 0, inbuf,
	    GST_BUFFER_SIZE (ffmpegdec->pcache) + GST_BUFFER_SIZE (inbuf));
1004 1005 1006 1007 1008 1009 1010 1011 1012 1013
    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) {
1014
    inbuf = gst_buffer_make_writable (inbuf);