gstffmpegdec.c 37.6 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

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

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

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

  /* setup pads */
  ffmpegdec->sinkpad = gst_pad_new_from_template (oclass->sinktempl, "sink");
262 263
  gst_pad_set_setcaps_function (ffmpegdec->sinkpad, gst_ffmpegdec_setcaps);
  gst_pad_set_event_function (ffmpegdec->sinkpad, gst_ffmpegdec_sink_event);
264
  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_fixed_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
  ffmpegdec->last_buffer = NULL;
286 287 288
}

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

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

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

302
static gboolean
303
gst_ffmpegdec_query (GstPad * pad, GstQuery *query)
304
{
305 306 307 308 309 310 311
  GstFFMpegDec *ffmpegdec;
  GstPad *peer;
  GstFormat bfmt;

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

  if (!peer)
314
    goto no_peer;
315

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

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

332 333 334 335 336 337
  return FALSE;

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

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

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

  gst_event_unref (event);

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

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

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

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

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

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

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

407 408
  ffmpegdec->opened = TRUE;

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

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

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

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

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

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

461
  /* close old session */
462
  gst_ffmpegdec_close (ffmpegdec);
463

464 465
  /* set defaults */
  avcodec_get_context_defaults (ffmpegdec->context);
466

467
  /* set buffer functions */  
468
  ffmpegdec->context->get_buffer = gst_ffmpegdec_get_buffer;
469 470
  ffmpegdec->context->release_buffer = gst_ffmpegdec_release_buffer;      
  
471
  /* get size and so */
472 473
  gst_ffmpeg_caps_with_codecid (oclass->in_plugin->id,
      oclass->in_plugin->type, caps, ffmpegdec->context);
474 475 476 477
  if (!ffmpegdec->context->time_base.den) {
    ffmpegdec->context->time_base.num = 1;
    ffmpegdec->context->time_base.den = 25;
  }
478

479 480 481 482 483 484 485 486 487
  /* 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);
  }

488 489 490
  /* do *not* draw edges */
  ffmpegdec->context->flags |= CODEC_FLAG_EMU_EDGE;

491 492 493
  /* workaround encoder bugs */
  ffmpegdec->context->workaround_bugs |= FF_BUG_AUTODETECT;

494 495 496 497
  /* for slow cpus */
  ffmpegdec->context->lowres = ffmpegdec->lowres;
  ffmpegdec->context->hurry_up = ffmpegdec->hurry_up;

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

509
  return TRUE;
510 511
}

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

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

564 565 566 567 568 569 570 571
  /* 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;
572
  picture->opaque = buf;
573 574 575 576
  gst_buffer_ref (buf);

  return 0;
}
577

578
static void
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
579
gst_ffmpegdec_release_buffer (AVCodecContext * context, AVFrame * picture)
580 581
{
  gint i;
582 583 584 585 586
  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
587

588 589
  if (buf == ffmpegdec->last_buffer)
    ffmpegdec->last_buffer = NULL;
590 591 592
  gst_buffer_unref (buf);

  /* zero out the reference in ffmpeg */
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
593
  for (i = 0; i < 4; i++) {
594 595 596
    picture->data[i] = NULL;
    picture->linesize[i] = 0;
  }
597 598
}

599 600 601 602 603 604 605
static gboolean
gst_ffmpegdec_negotiate (GstFFMpegDec * ffmpegdec)
{
  GstFFMpegDecClass *oclass =
      (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
  GstCaps *caps;

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

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

    if (caps != NULL)
675
      gst_caps_unref (caps);
676 677 678 679

    return FALSE;
  }

680
  gst_caps_unref (caps);
681 682 683

  return TRUE;
}
684

685 686
static gint
gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec,
687
    guint8 * data, guint size, gint * got_data, guint64 * in_ts)
688 689 690 691
{
  GstFFMpegDecClass *oclass =
      (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
  GstBuffer *outbuf = NULL;
692
  gint have_data = 0, len = 0;
693 694
  GstFlowReturn ret;  

695 696 697 698
  ffmpegdec->context->frame_number++;

  switch (oclass->in_plugin->type) {
    case CODEC_TYPE_VIDEO:
699
      ffmpegdec->picture->pict_type = -1; /* in case we skip frames */
700 701 702

      ffmpegdec->context->opaque = ffmpegdec;
      
703 704
      len = avcodec_decode_video (ffmpegdec->context,
          ffmpegdec->picture, &have_data, data, size);
705 706
      GST_DEBUG_OBJECT (ffmpegdec,
          "Decode video: len=%d, have_data=%d", len, have_data);
707

708 709 710 711 712 713 714 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
      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 */
        }
      }

745 746 747 748
      if (ffmpegdec->waiting_for_key &&
          ffmpegdec->picture->pict_type != FF_I_TYPE) {
        have_data = 0;
      } else if (len >= 0 && have_data > 0) {
749 750 751
        /* 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... */
752

753 754
	if (ffmpegdec->picture->opaque != NULL) {
	  outbuf = (GstBuffer *) ffmpegdec->picture->opaque;
755 756
          if (outbuf == ffmpegdec->last_buffer)
            ffmpegdec->last_buffer = NULL;
757
	} else {
758 759
	  AVPicture pic;
	  gint fsize = gst_ffmpeg_avpicture_get_size (ffmpegdec->context->pix_fmt,
760 761
            ffmpegdec->context->width, ffmpegdec->context->height);

762 763 764
	  if (!gst_ffmpegdec_negotiate (ffmpegdec))
	    return -1;	
	  
765 766
	  if ((ret = gst_pad_alloc_buffer (ffmpegdec->srcpad, GST_BUFFER_OFFSET_NONE, fsize, GST_PAD_CAPS (ffmpegdec->srcpad), &outbuf)) != GST_FLOW_OK)
            return ret;
767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784

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

786 787
	if (!ffmpegdec->picture->key_frame) {
	  GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
788 789
	}
		
790
        GST_BUFFER_TIMESTAMP (outbuf) = ffmpegdec->next_ts;
791 792
        if (ffmpegdec->context->time_base.num != 0 &&
            ffmpegdec->context->time_base.den != 0) {
793
          GST_BUFFER_DURATION (outbuf) = GST_SECOND *
794 795
              ffmpegdec->context->time_base.num /
              ffmpegdec->context->time_base.den;
796 797 798 799

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

801 802 803 804
          ffmpegdec->next_ts += GST_BUFFER_DURATION (outbuf);
        } else {
          ffmpegdec->next_ts = GST_CLOCK_TIME_NONE;
        }
805 806
      } else if (ffmpegdec->picture->pict_type != -1 &&
		 oclass->in_plugin->capabilities & CODEC_CAP_DELAY) {
807
        /* update time for skip-frame */
808 809 810
        if ((ffmpegdec->picture->pict_type == FF_I_TYPE ||
             !GST_CLOCK_TIME_IS_VALID (ffmpegdec->next_ts)) &&
            GST_CLOCK_TIME_IS_VALID (*in_ts)) {
811
          ffmpegdec->next_ts = *in_ts;
812
	  *in_ts = GST_CLOCK_TIME_NONE;
813
        }
814
        
815 816
        if (ffmpegdec->context->time_base.num != 0 &&
            ffmpegdec->context->time_base.den != 0) {
817
          guint64 dur = GST_SECOND *  
818 819
            ffmpegdec->context->time_base.num /
            ffmpegdec->context->time_base.den;
820 821 822

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

824
          ffmpegdec->next_ts += dur;
825 826
        } else {
          ffmpegdec->next_ts = GST_CLOCK_TIME_NONE;
827
        }
828 829 830 831
      }
      break;

    case CODEC_TYPE_AUDIO:
832 833 834 835 836 837
      if (!ffmpegdec->last_buffer)
        outbuf = gst_buffer_new_and_alloc (AVCODEC_MAX_AUDIO_FRAME_SIZE);
      else {
        outbuf = ffmpegdec->last_buffer;
        ffmpegdec->last_buffer = NULL;
      }
838 839
      len = avcodec_decode_audio (ffmpegdec->context,
          (int16_t *) GST_BUFFER_DATA (outbuf), &have_data, data, size);
840 841
      GST_DEBUG_OBJECT (ffmpegdec,
          "Decode audio: len=%d, have_data=%d", len, have_data);
842 843

      if (len >= 0 && have_data > 0) {
844 845 846 847 848
	if (!gst_ffmpegdec_negotiate (ffmpegdec)) {
	  gst_buffer_unref (outbuf);
	  return -1;
	}

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

890 891
    gst_buffer_set_caps (outbuf, GST_PAD_CAPS (ffmpegdec->srcpad));
    gst_pad_push (ffmpegdec->srcpad, outbuf);
892 893 894 895 896
  }

  return len;
}

897 898
static gboolean
gst_ffmpegdec_sink_event (GstPad * pad, GstEvent * event)
899
{
900
  GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) GST_OBJECT_PARENT (pad);
901 902 903
  GstFFMpegDecClass *oclass =
      (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));

904 905
  GST_DEBUG_OBJECT (ffmpegdec,
      "Handling event of type %d", GST_EVENT_TYPE (event));
906

907
  switch (GST_EVENT_TYPE (event)) {
908 909 910 911 912 913 914 915 916 917
    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);
      }
918
      goto forward;
919
    case GST_EVENT_FLUSH_STOP:
920 921 922
      if (ffmpegdec->opened) {
        avcodec_flush_buffers (ffmpegdec->context);
      }
923
      goto forward;
924 925 926 927 928 929 930 931
    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;
932
        GST_DEBUG_OBJECT (ffmpegdec, "Discont to time %" GST_TIME_FORMAT,
933 934 935
            GST_TIME_ARGS (start));
      } else if (ffmpegdec->context->bit_rate && fmt == GST_FORMAT_BYTES) {
        ffmpegdec->next_ts = start * GST_SECOND / ffmpegdec->context->bit_rate;
936 937
        GST_DEBUG_OBJECT (ffmpegdec,
            "Discont to byte %lld, time %" GST_TIME_FORMAT,
938
            start, GST_TIME_ARGS (ffmpegdec->next_ts));
939
        gst_event_unref (event);
940 941 942 943
        event = gst_event_new_newsegment (rate, fmt,
            start * GST_SECOND / ffmpegdec->context->bit_rate,
            end * GST_SECOND / ffmpegdec->context->bit_rate,
            base * GST_SECOND / ffmpegdec->context->bit_rate);
944 945 946 947
      } else {
        GST_WARNING_OBJECT (ffmpegdec,
            "Received discont with no useful value...");
      }
948 949
      if (ffmpegdec->opened) {
        avcodec_flush_buffers (ffmpegdec->context);
950 951

        if (ffmpegdec->context->codec_id == CODEC_ID_MPEG2VIDEO ||
952 953
            ffmpegdec->context->codec_id == CODEC_ID_MPEG4 ||
            ffmpegdec->context->codec_id == CODEC_ID_H264) {
954 955
          ffmpegdec->waiting_for_key = TRUE;
        }
956
      }
957 958
      ffmpegdec->waiting_for_key = TRUE;
      ffmpegdec->synctime = ffmpegdec->next_ts;
959 960 961 962
      /* fall-through */
    }
    default:
    forward:
963
      return gst_pad_event_default (ffmpegdec->sinkpad, event);
964
  }
965 966

  return TRUE;
967 968
}

969 970
static GstFlowReturn
gst_ffmpegdec_chain (GstPad * pad, GstBuffer * inbuf)
971
{
972
  GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) (GST_PAD_PARENT (pad));
Thomas Vander Stichele's avatar
indent  
Thomas Vander Stichele committed
973 974
  GstFFMpegDecClass *oclass =
      (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
975
  guint8 *bdata, *data;
976
  gint bsize, size, len, have_data;
977
  guint64 in_ts = GST_BUFFER_TIMESTAMP (inbuf);
Ronald S. Bultje's avatar
Ronald S. Bultje committed
978

979 980 981
  if (!ffmpegdec->opened)
    goto not_negotiated;
  
982 983
  GST_DEBUG_OBJECT (ffmpegdec,
      "Received new data of size %d, time %" GST_TIME_FORMAT,
984
      GST_BUFFER_SIZE (inbuf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)));
985

986 987
  /* parse cache joining */
  if (ffmpegdec->pcache) {
988 989
    inbuf = gst_buffer_span (ffmpegdec->pcache, 0, inbuf,
	    GST_BUFFER_SIZE (ffmpegdec->pcache) + GST_BUFFER_SIZE (inbuf));
990 991