Remove mentions of ffmpegcolorspace now that it's in gst-plugins-base
[platform/upstream/gst-libav.git] / ext / ffmpeg / gstffmpegdec.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <assert.h>
25 #include <string.h>
26
27 #ifdef HAVE_FFMPEG_UNINSTALLED
28 #include <avcodec.h>
29 #else
30 #include <ffmpeg/avcodec.h>
31 #endif
32
33 #include <gst/gst.h>
34
35 #include "gstffmpeg.h"
36 #include "gstffmpegcodecmap.h"
37
38 //#define FORCE_OUR_GET_BUFFER
39
40 typedef struct _GstFFMpegDec GstFFMpegDec;
41
42 struct _GstFFMpegDec
43 {
44   GstElement element;
45
46   /* We need to keep track of our pads, so we do so here. */
47   GstPad *srcpad;
48   GstPad *sinkpad;
49
50   /* decoding */
51   AVCodecContext *context;
52   AVFrame *picture;
53   gboolean opened;
54   union
55   {
56     struct
57     {
58       gint width, height;
59       gint fps_n, fps_d;
60       gint old_fps_n, old_fps_d;
61
62       enum PixelFormat pix_fmt;
63     } video;
64     struct
65     {
66       gint channels, samplerate;
67     } audio;
68   } format;
69   gboolean waiting_for_key;
70   guint64 next_ts, synctime;
71
72   /* parsing */
73   AVCodecParserContext *pctx;
74   GstBuffer *pcache;
75
76   GstBuffer *last_buffer;
77
78   GValue *par;                  /* pixel aspect ratio of incoming data */
79
80   gint hurry_up, lowres;
81 };
82
83 typedef struct _GstFFMpegDecClass GstFFMpegDecClass;
84
85 struct _GstFFMpegDecClass
86 {
87   GstElementClass parent_class;
88
89   AVCodec *in_plugin;
90   GstPadTemplate *srctempl, *sinktempl;
91 };
92
93 typedef struct _GstFFMpegDecClassParams GstFFMpegDecClassParams;
94
95 struct _GstFFMpegDecClassParams
96 {
97   AVCodec *in_plugin;
98   GstCaps *srccaps, *sinkcaps;
99 };
100
101 #define GST_TYPE_FFMPEGDEC \
102   (gst_ffmpegdec_get_type())
103 #define GST_FFMPEGDEC(obj) \
104   (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FFMPEGDEC,GstFFMpegDec))
105 #define GST_FFMPEGDEC_CLASS(klass) \
106   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FFMPEGDEC,GstFFMpegDecClass))
107 #define GST_IS_FFMPEGDEC(obj) \
108   (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FFMPEGDEC))
109 #define GST_IS_FFMPEGDEC_CLASS(obj) \
110   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FFMPEGDEC))
111
112 enum
113 {
114   ARG_0,
115   ARG_LOWRES,
116   ARG_SKIPFRAME
117 };
118
119 static GHashTable *global_plugins;
120
121 /* A number of functon prototypes are given so we can refer to them later. */
122 static void gst_ffmpegdec_base_init (GstFFMpegDecClass * klass);
123 static void gst_ffmpegdec_class_init (GstFFMpegDecClass * klass);
124 static void gst_ffmpegdec_init (GstFFMpegDec * ffmpegdec);
125 static void gst_ffmpegdec_dispose (GObject * object);
126
127 static gboolean gst_ffmpegdec_query (GstPad * pad, GstQuery * query);
128 static gboolean gst_ffmpegdec_event (GstPad * pad, GstEvent * event);
129
130 static gboolean gst_ffmpegdec_setcaps (GstPad * pad, GstCaps * caps);
131 static gboolean gst_ffmpegdec_sink_event (GstPad * pad, GstEvent * event);
132 static GstFlowReturn gst_ffmpegdec_chain (GstPad * pad, GstBuffer * buf);
133
134 static GstStateChangeReturn gst_ffmpegdec_change_state (GstElement * element,
135     GstStateChange transition);
136
137 static void gst_ffmpegdec_set_property (GObject * object,
138     guint prop_id, const GValue * value, GParamSpec * pspec);
139 static void gst_ffmpegdec_get_property (GObject * object,
140     guint prop_id, GValue * value, GParamSpec * pspec);
141
142 static gboolean gst_ffmpegdec_negotiate (GstFFMpegDec * ffmpegdec);
143
144 /* some sort of bufferpool handling, but different */
145 static int gst_ffmpegdec_get_buffer (AVCodecContext * context,
146     AVFrame * picture);
147 static void gst_ffmpegdec_release_buffer (AVCodecContext * context,
148     AVFrame * picture);
149
150 static GstElementClass *parent_class = NULL;
151
152 #define GST_FFMPEGDEC_TYPE_LOWRES (gst_ffmpegdec_lowres_get_type())
153 static GType
154 gst_ffmpegdec_lowres_get_type (void)
155 {
156   static GType ffmpegdec_lowres_type = 0;
157
158   if (!ffmpegdec_lowres_type) {
159     static GEnumValue ffmpegdec_lowres[] = {
160       {0, "0", "full"},
161       {1, "1", "1/2-size"},
162       {2, "2", "1/4-size"},
163       {0, NULL, NULL},
164     };
165
166     ffmpegdec_lowres_type =
167         g_enum_register_static ("GstFFMpegDecLowres", ffmpegdec_lowres);
168   }
169
170   return ffmpegdec_lowres_type;
171 }
172
173 #define GST_FFMPEGDEC_TYPE_SKIPFRAME (gst_ffmpegdec_skipframe_get_type())
174 static GType
175 gst_ffmpegdec_skipframe_get_type (void)
176 {
177   static GType ffmpegdec_skipframe_type = 0;
178
179   if (!ffmpegdec_skipframe_type) {
180     static GEnumValue ffmpegdec_skipframe[] = {
181       {0, "0", "Skip nothing"},
182       {1, "1", "Skip B-frames"},
183       {2, "2", "Skip IDCT/Dequantization"},
184       {5, "5", "Skip everything"},
185       {0, NULL, NULL},
186     };
187
188     ffmpegdec_skipframe_type =
189         g_enum_register_static ("GstFFMpegDecSkipFrame", ffmpegdec_skipframe);
190   }
191
192   return ffmpegdec_skipframe_type;
193 }
194
195 static void
196 gst_ffmpegdec_base_init (GstFFMpegDecClass * klass)
197 {
198   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
199   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
200   GstFFMpegDecClassParams *params;
201   GstElementDetails details;
202   GstPadTemplate *sinktempl, *srctempl;
203
204   params = g_hash_table_lookup (global_plugins,
205       GINT_TO_POINTER (G_OBJECT_CLASS_TYPE (gobject_class)));
206   if (!params)
207     params = g_hash_table_lookup (global_plugins, GINT_TO_POINTER (0));
208   g_assert (params);
209
210   /* construct the element details struct */
211   details.longname = g_strdup_printf ("FFMPEG %s decoder",
212       gst_ffmpeg_get_codecid_longname (params->in_plugin->id));
213   details.klass = g_strdup_printf ("Codec/Decoder/%s",
214       (params->in_plugin->type == CODEC_TYPE_VIDEO) ? "Video" : "Audio");
215   details.description = g_strdup_printf ("FFMPEG %s decoder",
216       params->in_plugin->name);
217   details.author = "Wim Taymans <wim.taymans@chello.be>, "
218       "Ronald Bultje <rbultje@ronald.bitfreak.net>";
219   gst_element_class_set_details (element_class, &details);
220   g_free (details.longname);
221   g_free (details.klass);
222   g_free (details.description);
223
224   /* pad templates */
225   sinktempl = gst_pad_template_new ("sink", GST_PAD_SINK,
226       GST_PAD_ALWAYS, params->sinkcaps);
227   srctempl = gst_pad_template_new ("src", GST_PAD_SRC,
228       GST_PAD_ALWAYS, params->srccaps);
229
230   gst_element_class_add_pad_template (element_class, srctempl);
231   gst_element_class_add_pad_template (element_class, sinktempl);
232
233   klass->in_plugin = params->in_plugin;
234   klass->srctempl = srctempl;
235   klass->sinktempl = sinktempl;
236 }
237
238 static void
239 gst_ffmpegdec_class_init (GstFFMpegDecClass * klass)
240 {
241   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
242   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
243
244   parent_class = g_type_class_peek_parent (klass);
245
246   gobject_class->dispose = gst_ffmpegdec_dispose;
247   gobject_class->set_property = gst_ffmpegdec_set_property;
248   gobject_class->get_property = gst_ffmpegdec_get_property;
249   gstelement_class->change_state = gst_ffmpegdec_change_state;
250
251   g_object_class_install_property (gobject_class, ARG_SKIPFRAME,
252       g_param_spec_enum ("skip-frame", "Skip frames",
253           "Which types of frames to skip during decoding",
254           GST_FFMPEGDEC_TYPE_SKIPFRAME, 0, G_PARAM_READWRITE));
255   g_object_class_install_property (gobject_class, ARG_LOWRES,
256       g_param_spec_enum ("lowres", "Low resolution",
257           "At which resolution to decode images",
258           GST_FFMPEGDEC_TYPE_LOWRES, 0, G_PARAM_READWRITE));
259 }
260
261 static void
262 gst_ffmpegdec_init (GstFFMpegDec * ffmpegdec)
263 {
264   GstFFMpegDecClass *oclass =
265       (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
266
267   /* setup pads */
268   ffmpegdec->sinkpad = gst_pad_new_from_template (oclass->sinktempl, "sink");
269   gst_pad_set_setcaps_function (ffmpegdec->sinkpad, gst_ffmpegdec_setcaps);
270   gst_pad_set_event_function (ffmpegdec->sinkpad, gst_ffmpegdec_sink_event);
271   gst_pad_set_chain_function (ffmpegdec->sinkpad, gst_ffmpegdec_chain);
272   gst_element_add_pad (GST_ELEMENT (ffmpegdec), ffmpegdec->sinkpad);
273
274   ffmpegdec->srcpad = gst_pad_new_from_template (oclass->srctempl, "src");
275   gst_pad_use_fixed_caps (ffmpegdec->srcpad);
276   gst_pad_set_event_function (ffmpegdec->srcpad,
277       GST_DEBUG_FUNCPTR (gst_ffmpegdec_event));
278   gst_pad_set_query_function (ffmpegdec->srcpad,
279       GST_DEBUG_FUNCPTR (gst_ffmpegdec_query));
280   gst_element_add_pad (GST_ELEMENT (ffmpegdec), ffmpegdec->srcpad);
281
282   /* some ffmpeg data */
283   ffmpegdec->context = avcodec_alloc_context ();
284   ffmpegdec->picture = avcodec_alloc_frame ();
285   ffmpegdec->pctx = NULL;
286   ffmpegdec->pcache = NULL;
287   ffmpegdec->par = NULL;
288   ffmpegdec->opened = FALSE;
289   ffmpegdec->waiting_for_key = FALSE;
290   ffmpegdec->hurry_up = ffmpegdec->lowres = 0;
291
292   ffmpegdec->last_buffer = NULL;
293
294   ffmpegdec->format.video.fps_n = -1;
295   ffmpegdec->format.video.old_fps_n = -1;
296 }
297
298 static void
299 gst_ffmpegdec_dispose (GObject * object)
300 {
301   GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) object;
302
303   G_OBJECT_CLASS (parent_class)->dispose (object);
304   /* old session should have been closed in element_class->dispose */
305   g_assert (!ffmpegdec->opened);
306
307   /* clean up remaining allocated data */
308   av_free (ffmpegdec->context);
309   av_free (ffmpegdec->picture);
310 }
311
312 static gboolean
313 gst_ffmpegdec_query (GstPad * pad, GstQuery * query)
314 {
315   GstFFMpegDec *ffmpegdec;
316   GstPad *peer;
317   GstFormat bfmt;
318
319   bfmt = GST_FORMAT_BYTES;
320   ffmpegdec = (GstFFMpegDec *) GST_PAD_PARENT (pad);
321   peer = GST_PAD_PEER (ffmpegdec->sinkpad);
322
323   if (!peer)
324     goto no_peer;
325
326   /* just forward to peer */
327   if (gst_pad_query (peer, query))
328     return TRUE;
329
330 #if 0
331   /* ok, do bitrate calc... */
332   if ((type != GST_QUERY_POSITION && type != GST_QUERY_TOTAL) ||
333       *fmt != GST_FORMAT_TIME || ffmpegdec->context->bit_rate == 0 ||
334       !gst_pad_query (peer, type, &bfmt, value))
335     return FALSE;
336
337   if (ffmpegdec->pcache && type == GST_QUERY_POSITION)
338     *value -= GST_BUFFER_SIZE (ffmpegdec->pcache);
339   *value *= GST_SECOND / ffmpegdec->context->bit_rate;
340 #endif
341
342   return FALSE;
343
344 no_peer:
345   {
346     return FALSE;
347   }
348 }
349
350 static gboolean
351 gst_ffmpegdec_event (GstPad * pad, GstEvent * event)
352 {
353   GstFFMpegDec *ffmpegdec;
354   GstPad *peer;
355
356   ffmpegdec = (GstFFMpegDec *) GST_PAD_PARENT (pad);
357   peer = GST_PAD_PEER (ffmpegdec->sinkpad);
358
359   if (!peer)
360     return FALSE;
361
362   gst_event_ref (event);
363   if (gst_pad_send_event (peer, event)) {
364     gst_event_unref (event);
365     return TRUE;
366   }
367
368   gst_event_unref (event);
369
370   return FALSE;                 /* .. */
371 }
372
373 static void
374 gst_ffmpegdec_close (GstFFMpegDec * ffmpegdec)
375 {
376   if (!ffmpegdec->opened)
377     return;
378
379   if (ffmpegdec->par) {
380     g_free (ffmpegdec->par);
381     ffmpegdec->par = NULL;
382   }
383
384   if (ffmpegdec->context->priv_data)
385     avcodec_close (ffmpegdec->context);
386   ffmpegdec->opened = FALSE;
387
388   if (ffmpegdec->context->palctrl) {
389     av_free (ffmpegdec->context->palctrl);
390     ffmpegdec->context->palctrl = NULL;
391   }
392
393   if (ffmpegdec->context->extradata) {
394     av_free (ffmpegdec->context->extradata);
395     ffmpegdec->context->extradata = NULL;
396   }
397
398   if (ffmpegdec->pctx) {
399     if (ffmpegdec->pcache) {
400       gst_buffer_unref (ffmpegdec->pcache);
401       ffmpegdec->pcache = NULL;
402     }
403     av_parser_close (ffmpegdec->pctx);
404     ffmpegdec->pctx = NULL;
405   }
406
407   ffmpegdec->format.video.fps_n = -1;
408   ffmpegdec->format.video.old_fps_n = -1;
409 }
410
411 static gboolean
412 gst_ffmpegdec_open (GstFFMpegDec * ffmpegdec)
413 {
414   GstFFMpegDecClass *oclass =
415       (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
416
417   if (avcodec_open (ffmpegdec->context, oclass->in_plugin) < 0)
418     goto could_not_open;
419
420   ffmpegdec->opened = TRUE;
421
422   GST_LOG ("Opened ffmpeg codec %s", oclass->in_plugin->name);
423
424   /* open a parser if we can - exclude mpeg4, because it is already
425    * framed (divx), mp3 because it doesn't work (?) and mjpeg because
426    * of $(see mpeg4)... */
427   if (oclass->in_plugin->id != CODEC_ID_MPEG4 &&
428       oclass->in_plugin->id != CODEC_ID_MJPEG &&
429       oclass->in_plugin->id != CODEC_ID_MP3 &&
430       oclass->in_plugin->id != CODEC_ID_H264) {
431     ffmpegdec->pctx = av_parser_init (oclass->in_plugin->id);
432   }
433
434   switch (oclass->in_plugin->type) {
435     case CODEC_TYPE_VIDEO:
436       ffmpegdec->format.video.width = 0;
437       ffmpegdec->format.video.height = 0;
438       ffmpegdec->format.video.pix_fmt = PIX_FMT_NB;
439       break;
440     case CODEC_TYPE_AUDIO:
441       ffmpegdec->format.audio.samplerate = 0;
442       ffmpegdec->format.audio.channels = 0;
443       break;
444     default:
445       break;
446   }
447   ffmpegdec->next_ts = 0;
448   ffmpegdec->synctime = GST_CLOCK_TIME_NONE;
449   ffmpegdec->last_buffer = NULL;
450
451   return TRUE;
452
453   /* ERRORS */
454 could_not_open:
455   {
456     gst_ffmpegdec_close (ffmpegdec);
457     GST_DEBUG ("ffdec_%s: Failed to open FFMPEG codec",
458         oclass->in_plugin->name);
459     return FALSE;
460   }
461 }
462
463 static GstPadLinkReturn
464 gst_ffmpegdec_setcaps (GstPad * pad, GstCaps * caps)
465 {
466   GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) (GST_OBJECT_PARENT (pad));
467   GstFFMpegDecClass *oclass =
468       (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
469   GstStructure *structure;
470   const GValue *par;
471   const GValue *fps;
472
473   GST_DEBUG ("setcaps called");
474
475   /* close old session */
476   gst_ffmpegdec_close (ffmpegdec);
477
478   /* set defaults */
479   avcodec_get_context_defaults (ffmpegdec->context);
480
481   /* set buffer functions */
482   ffmpegdec->context->get_buffer = gst_ffmpegdec_get_buffer;
483   ffmpegdec->context->release_buffer = gst_ffmpegdec_release_buffer;
484
485   /* get size and so */
486   gst_ffmpeg_caps_with_codecid (oclass->in_plugin->id,
487       oclass->in_plugin->type, caps, ffmpegdec->context);
488
489   if (!ffmpegdec->context->time_base.den || !ffmpegdec->context->time_base.num) {
490     GST_DEBUG ("forcing 25/1 framerate");
491     ffmpegdec->context->time_base.num = 1;
492     ffmpegdec->context->time_base.den = 25;
493   }
494
495   /* get pixel aspect ratio if it's set */
496   structure = gst_caps_get_structure (caps, 0);
497   par = gst_structure_get_value (structure, "pixel-aspect-ratio");
498   if (par) {
499     GST_DEBUG_OBJECT (ffmpegdec, "sink caps have pixel-aspect-ratio");
500     ffmpegdec->par = g_new0 (GValue, 1);
501     gst_value_init_and_copy (ffmpegdec->par, par);
502   }
503
504   fps = gst_structure_get_value (structure, "framerate");
505   if (fps != NULL && GST_VALUE_HOLDS_FRACTION (fps)) {
506     ffmpegdec->format.video.fps_n = gst_value_get_fraction_numerator (fps);
507     ffmpegdec->format.video.fps_d = gst_value_get_fraction_denominator (fps);
508   } else {
509     ffmpegdec->format.video.fps_n = -1;
510   }
511
512   /* do *not* draw edges */
513   ffmpegdec->context->flags |= CODEC_FLAG_EMU_EDGE;
514
515   /* workaround encoder bugs */
516   ffmpegdec->context->workaround_bugs |= FF_BUG_AUTODETECT;
517
518   /* for slow cpus */
519   ffmpegdec->context->lowres = ffmpegdec->lowres;
520   ffmpegdec->context->hurry_up = ffmpegdec->hurry_up;
521
522   /* open codec - we don't select an output pix_fmt yet,
523    * simply because we don't know! We only get it
524    * during playback... */
525   if (!gst_ffmpegdec_open (ffmpegdec)) {
526     if (ffmpegdec->par) {
527       g_free (ffmpegdec->par);
528       ffmpegdec->par = NULL;
529     }
530     return FALSE;
531   }
532
533   return TRUE;
534 }
535
536 static int
537 gst_ffmpegdec_get_buffer (AVCodecContext * context, AVFrame * picture)
538 {
539   GstBuffer *buf = NULL;
540   gulong bufsize = 0;
541   GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) context->opaque;
542   int width = context->width;
543   int height = context->height;
544
545   switch (context->codec_type) {
546     case CODEC_TYPE_VIDEO:
547
548       avcodec_align_dimensions (context, &width, &height);
549
550       bufsize = avpicture_get_size (context->pix_fmt, width, height);
551
552       if ((width != context->width) || (height != context->height) || 1) {
553 #ifdef FORCE_OUR_GET_BUFFER
554         context->width = width;
555         context->height = height;
556 #else
557         /* revert to ffmpeg's default functions */
558         ffmpegdec->context->get_buffer = avcodec_default_get_buffer;
559         ffmpegdec->context->release_buffer = avcodec_default_release_buffer;
560
561         return avcodec_default_get_buffer (context, picture);
562 #endif
563
564       }
565
566       if (!gst_ffmpegdec_negotiate (ffmpegdec)) {
567         GST_ELEMENT_ERROR (ffmpegdec, CORE, NEGOTIATION, (NULL),
568             ("Failed to link ffmpeg decoder to next element"));
569         return avcodec_default_get_buffer (context, picture);
570       }
571
572       if (gst_pad_alloc_buffer (ffmpegdec->srcpad, GST_BUFFER_OFFSET_NONE,
573               bufsize, GST_PAD_CAPS (ffmpegdec->srcpad), &buf) != GST_FLOW_OK)
574         return -1;
575       ffmpegdec->last_buffer = buf;
576
577       gst_ffmpeg_avpicture_fill ((AVPicture *) picture,
578           GST_BUFFER_DATA (buf),
579           context->pix_fmt, context->width, context->height);
580       break;
581
582     case CODEC_TYPE_AUDIO:
583     default:
584       g_assert (0);
585       break;
586   }
587
588   /* tell ffmpeg we own this buffer
589    *
590    * we also use an evil hack (keep buffer in base[0])
591    * to keep a reference to the buffer in release_buffer(),
592    * so that we can ref() it here and unref() it there
593    * so that we don't need to copy data */
594   picture->type = FF_BUFFER_TYPE_USER;
595   picture->age = G_MAXINT;
596   picture->opaque = buf;
597   gst_buffer_ref (buf);
598
599   GST_LOG_OBJECT (ffmpegdec, "END");
600
601   return 0;
602 }
603
604 static void
605 gst_ffmpegdec_release_buffer (AVCodecContext * context, AVFrame * picture)
606 {
607   gint i;
608   GstBuffer *buf;
609   GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) context->opaque;
610
611   g_return_if_fail (buf != NULL);
612   g_return_if_fail (picture->type == FF_BUFFER_TYPE_USER);
613
614   buf = GST_BUFFER (picture->opaque);
615
616   if (buf == ffmpegdec->last_buffer)
617     ffmpegdec->last_buffer = NULL;
618   gst_buffer_unref (buf);
619
620   picture->opaque = NULL;
621
622   /* zero out the reference in ffmpeg */
623   for (i = 0; i < 4; i++) {
624     picture->data[i] = NULL;
625     picture->linesize[i] = 0;
626   }
627 }
628
629 static gboolean
630 gst_ffmpegdec_negotiate (GstFFMpegDec * ffmpegdec)
631 {
632   GstFFMpegDecClass *oclass =
633       (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
634   GstCaps *caps;
635
636   switch (oclass->in_plugin->type) {
637     case CODEC_TYPE_VIDEO:
638       if (ffmpegdec->format.video.width == ffmpegdec->context->width &&
639           ffmpegdec->format.video.height == ffmpegdec->context->height &&
640           ffmpegdec->format.video.fps_n == ffmpegdec->format.video.old_fps_n &&
641           ffmpegdec->format.video.fps_d == ffmpegdec->format.video.old_fps_d &&
642           ffmpegdec->format.video.pix_fmt == ffmpegdec->context->pix_fmt)
643         return TRUE;
644       GST_DEBUG ("Renegotiating video from %dx%d@ %d/%d fps to %dx%d@ %d/%d fps",
645           ffmpegdec->format.video.width, ffmpegdec->format.video.height,
646           ffmpegdec->format.video.old_fps_n, ffmpegdec->format.video.old_fps_n,
647           ffmpegdec->context->width, ffmpegdec->context->height, 
648           ffmpegdec->format.video.fps_n, ffmpegdec->format.video.fps_d);
649       ffmpegdec->format.video.width = ffmpegdec->context->width;
650       ffmpegdec->format.video.height = ffmpegdec->context->height;
651       ffmpegdec->format.video.old_fps_n = ffmpegdec->format.video.fps_n;
652       ffmpegdec->format.video.old_fps_d = ffmpegdec->format.video.fps_d;
653       ffmpegdec->format.video.pix_fmt = ffmpegdec->context->pix_fmt;
654       break;
655     case CODEC_TYPE_AUDIO:
656       if (ffmpegdec->format.audio.samplerate ==
657           ffmpegdec->context->sample_rate &&
658           ffmpegdec->format.audio.channels == ffmpegdec->context->channels)
659         return TRUE;
660       GST_DEBUG ("Renegotiating audio from %dHz@%dchannels to %dHz@%dchannels",
661           ffmpegdec->format.audio.samplerate, ffmpegdec->format.audio.channels,
662           ffmpegdec->context->sample_rate, ffmpegdec->context->channels);
663       ffmpegdec->format.audio.samplerate = ffmpegdec->context->sample_rate;
664       ffmpegdec->format.audio.channels = ffmpegdec->context->channels;
665       break;
666     default:
667       break;
668   }
669
670   caps = gst_ffmpeg_codectype_to_caps (oclass->in_plugin->type,
671       ffmpegdec->context);
672
673   if (caps) {
674     /* If a demuxer provided a framerate then use it (#313970) */
675     if (ffmpegdec->format.video.fps_n != -1) {
676       gst_structure_set (gst_caps_get_structure (caps, 0), "framerate",
677           GST_TYPE_FRACTION, ffmpegdec->format.video.fps_n, 
678           ffmpegdec->format.video.fps_d, NULL);
679     }
680
681     /* Add pixel-aspect-ratio if we have it. Prefer
682      * ffmpeg PAR over sink PAR (since it's provided
683      * by the codec, which is more often correct).
684      */
685     if (ffmpegdec->context->sample_aspect_ratio.num &&
686         ffmpegdec->context->sample_aspect_ratio.den) {
687       GST_DEBUG ("setting ffmpeg provided pixel-aspect-ratio");
688       gst_structure_set (gst_caps_get_structure (caps, 0),
689           "pixel-aspect-ratio", GST_TYPE_FRACTION,
690           ffmpegdec->context->sample_aspect_ratio.num,
691           ffmpegdec->context->sample_aspect_ratio.den, NULL);
692     } else if (ffmpegdec->par) {
693       GST_DEBUG ("passing on pixel-aspect-ratio from sink");
694       gst_structure_set (gst_caps_get_structure (caps, 0),
695           "pixel-aspect-ratio", GST_TYPE_FRACTION,
696           gst_value_get_fraction_numerator (ffmpegdec->par),
697           gst_value_get_fraction_denominator (ffmpegdec->par), NULL);
698     }
699   }
700
701   if (caps == NULL || !gst_pad_set_caps (ffmpegdec->srcpad, caps)) {
702     GST_ELEMENT_ERROR (ffmpegdec, CORE, NEGOTIATION, (NULL),
703         ("Failed to link ffmpeg decoder (%s) to next element",
704             oclass->in_plugin->name));
705
706     if (caps != NULL)
707       gst_caps_unref (caps);
708
709     return FALSE;
710   }
711
712   gst_caps_unref (caps);
713
714   return TRUE;
715 }
716
717 static gint
718 gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec,
719     guint8 * data, guint size, gint * got_data, guint64 * in_ts,
720     GstBuffer * inbuf, GstFlowReturn * ret)
721 {
722   GstFFMpegDecClass *oclass =
723       (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
724   GstBuffer *outbuf = NULL;
725   gint have_data = 0, len = 0;
726
727   if (ffmpegdec->context->codec == NULL)
728     return -1;
729
730   GST_DEBUG_OBJECT (ffmpegdec,
731       "data:%p, size:%d, *in_ts:%" GST_TIME_FORMAT " inbuf:%p  inbuf.ts:%"
732       GST_TIME_FORMAT, data, size, GST_TIME_ARGS (*in_ts), inbuf,
733       GST_TIME_ARGS ((inbuf) ? GST_BUFFER_TIMESTAMP (inbuf) : 0));
734
735   ffmpegdec->context->frame_number++;
736
737   switch (oclass->in_plugin->type) {
738     case CODEC_TYPE_VIDEO:
739       ffmpegdec->picture->pict_type = -1;       /* in case we skip frames */
740
741       ffmpegdec->context->opaque = ffmpegdec;
742
743       len = avcodec_decode_video (ffmpegdec->context,
744           ffmpegdec->picture, &have_data, data, size);
745       GST_DEBUG_OBJECT (ffmpegdec,
746           "Decoded video: len=%d, have_data=%d", len, have_data);
747
748       if (ffmpegdec->waiting_for_key) {
749         if (ffmpegdec->picture->pict_type == FF_I_TYPE) {
750           ffmpegdec->waiting_for_key = FALSE;
751         } else {
752           GST_WARNING_OBJECT (ffmpegdec, "Dropping non-keyframe (seek/init)");
753           have_data = 0;
754           break;
755         }
756       }
757
758       /* note that ffmpeg sometimes gets the FPS wrong.
759        * For B-frame containing movies, we get all pictures delayed
760        * except for the I frames, so we synchronize only on I frames
761        * and keep an internal counter based on FPS for the others. */
762       if (!(oclass->in_plugin->capabilities & CODEC_CAP_DELAY) ||
763           ((ffmpegdec->picture->pict_type == FF_I_TYPE ||
764                   !GST_CLOCK_TIME_IS_VALID (ffmpegdec->next_ts)) &&
765               GST_CLOCK_TIME_IS_VALID (*in_ts))) {
766         GST_DEBUG_OBJECT (ffmpegdec, "setting next_ts to %" GST_TIME_FORMAT,
767             GST_TIME_ARGS (*in_ts));
768         ffmpegdec->next_ts = *in_ts;
769         *in_ts = GST_CLOCK_TIME_NONE;
770       }
771
772       /* precise seeking.... */
773       if (GST_CLOCK_TIME_IS_VALID (ffmpegdec->synctime)) {
774         if (ffmpegdec->next_ts >= ffmpegdec->synctime) {
775           ffmpegdec->synctime = GST_CLOCK_TIME_NONE;
776         } else {
777           GST_WARNING_OBJECT (ffmpegdec,
778               "Dropping frame for synctime %" GST_TIME_FORMAT
779               ", expected(next_ts) %" GST_TIME_FORMAT,
780               GST_TIME_ARGS (ffmpegdec->synctime),
781               GST_TIME_ARGS (ffmpegdec->next_ts));
782
783           if (ffmpegdec->picture->opaque != NULL) {
784             outbuf = (GstBuffer *) ffmpegdec->picture->opaque;
785             gst_buffer_unref (outbuf);
786           }
787
788           have_data = 0;
789           /* don´t break here! Timestamps are updated below */
790         }
791       }
792
793       if (ffmpegdec->waiting_for_key &&
794           ffmpegdec->picture->pict_type != FF_I_TYPE) {
795         have_data = 0;
796       } else if (len >= 0 && have_data > 0) {
797         /* libavcodec constantly crashes on stupid buffer allocation
798          * errors inside. This drives me crazy, so we let it allocate
799          * its own buffers and copy to our own buffer afterwards... */
800
801         if (ffmpegdec->picture->opaque != NULL) {
802           outbuf = (GstBuffer *) ffmpegdec->picture->opaque;
803           if (outbuf == ffmpegdec->last_buffer)
804             ffmpegdec->last_buffer = NULL;
805         } else {
806           AVPicture pic;
807           gint fsize =
808               gst_ffmpeg_avpicture_get_size (ffmpegdec->context->pix_fmt,
809               ffmpegdec->context->width, ffmpegdec->context->height);
810
811           if (!gst_ffmpegdec_negotiate (ffmpegdec))
812             return -1;
813
814           if ((*ret =
815                   gst_pad_alloc_buffer (ffmpegdec->srcpad,
816                       GST_BUFFER_OFFSET_NONE, fsize,
817                       GST_PAD_CAPS (ffmpegdec->srcpad),
818                       &outbuf)) != GST_FLOW_OK)
819             return -1;
820
821           /* original ffmpeg code does not handle odd sizes correctly.
822            * This patched up version does */
823           gst_ffmpeg_avpicture_fill (&pic, GST_BUFFER_DATA (outbuf),
824               ffmpegdec->context->pix_fmt,
825               ffmpegdec->context->width, ffmpegdec->context->height);
826
827           /* the original convert function did not do the right thing, this
828            * is a patched up version that adjust widht/height so that the
829            * ffmpeg one works correctly. */
830           gst_ffmpeg_img_convert (&pic, ffmpegdec->context->pix_fmt,
831               (AVPicture *) ffmpegdec->picture,
832               ffmpegdec->context->pix_fmt,
833               ffmpegdec->context->width, ffmpegdec->context->height);
834         }
835
836         ffmpegdec->waiting_for_key = FALSE;
837
838         if (!ffmpegdec->picture->key_frame) {
839           GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
840         }
841
842         /* If we have used the framerate from the demuxer then
843          * also use the demuxer's timestamp information (#317596) */
844         if (ffmpegdec->format.video.fps_n != -1 && inbuf != NULL) {
845           gst_buffer_stamp (outbuf, inbuf);
846         } else {
847           GST_BUFFER_TIMESTAMP (outbuf) = ffmpegdec->next_ts;
848           if (ffmpegdec->context->time_base.num != 0 &&
849               ffmpegdec->context->time_base.den != 0) {
850             GST_BUFFER_DURATION (outbuf) = 
851                 gst_util_clock_time_scale (GST_SECOND, 
852                     ffmpegdec->context->time_base.num, 
853                     ffmpegdec->context->time_base.den);
854
855             /* Take repeat_pict into account */
856             GST_BUFFER_DURATION (outbuf) += GST_BUFFER_DURATION (outbuf)
857                 * ffmpegdec->picture->repeat_pict / 2;
858             GST_DEBUG_OBJECT (ffmpegdec,
859                 "advancing next_ts by duration of %" GST_TIME_FORMAT,
860                 GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)));
861             ffmpegdec->next_ts += GST_BUFFER_DURATION (outbuf);
862           } else {
863             ffmpegdec->next_ts = GST_CLOCK_TIME_NONE;
864           }
865         }
866       } else if (ffmpegdec->picture->pict_type != -1 &&
867           oclass->in_plugin->capabilities & CODEC_CAP_DELAY) {
868         /* update time for skip-frame */
869         if ((!have_data)
870             || (ffmpegdec->picture->pict_type == FF_I_TYPE ||
871                 !GST_CLOCK_TIME_IS_VALID (ffmpegdec->next_ts))
872             && GST_CLOCK_TIME_IS_VALID (*in_ts)) {
873           GST_DEBUG_OBJECT (ffmpegdec, "setting next_ts to *in_ts");
874           ffmpegdec->next_ts = *in_ts;
875           *in_ts = GST_CLOCK_TIME_NONE;
876         }
877
878         if (ffmpegdec->context->time_base.num != 0 &&
879             ffmpegdec->context->time_base.den != 0) {
880           guint64 dur = GST_SECOND *
881               ffmpegdec->context->time_base.num /
882               ffmpegdec->context->time_base.den;
883
884           /* Take repeat_pict into account */
885           dur += dur * ffmpegdec->picture->repeat_pict / 2;
886           GST_DEBUG_OBJECT (ffmpegdec,
887               "Advancing next_ts by dur:%" GST_TIME_FORMAT,
888               GST_TIME_ARGS (dur));
889           ffmpegdec->next_ts += dur;
890         } else {
891           ffmpegdec->next_ts = GST_CLOCK_TIME_NONE;
892         }
893       }
894       break;
895
896     case CODEC_TYPE_AUDIO:
897       if (!ffmpegdec->last_buffer)
898         outbuf = gst_buffer_new_and_alloc (AVCODEC_MAX_AUDIO_FRAME_SIZE);
899       else {
900         outbuf = ffmpegdec->last_buffer;
901         ffmpegdec->last_buffer = NULL;
902       }
903       len = avcodec_decode_audio (ffmpegdec->context,
904           (int16_t *) GST_BUFFER_DATA (outbuf), &have_data, data, size);
905       GST_DEBUG_OBJECT (ffmpegdec,
906           "Decode audio: len=%d, have_data=%d", len, have_data);
907
908       if (len >= 0 && have_data > 0) {
909         if (!gst_ffmpegdec_negotiate (ffmpegdec)) {
910           gst_buffer_unref (outbuf);
911           return -1;
912         }
913
914         GST_BUFFER_SIZE (outbuf) = have_data;
915         if (GST_CLOCK_TIME_IS_VALID (*in_ts)) {
916           ffmpegdec->next_ts = *in_ts;
917         }
918         GST_BUFFER_TIMESTAMP (outbuf) = ffmpegdec->next_ts;
919         GST_BUFFER_DURATION (outbuf) = (have_data * GST_SECOND) /
920             (2 * ffmpegdec->context->channels *
921             ffmpegdec->context->sample_rate);
922         ffmpegdec->next_ts += GST_BUFFER_DURATION (outbuf);
923         if (GST_CLOCK_TIME_IS_VALID (*in_ts))
924           *in_ts += GST_BUFFER_DURATION (outbuf);
925       } else if (len > 0 && have_data == 0) {
926         /* cache output, because it may be used for caching (in-place) */
927         ffmpegdec->last_buffer = outbuf;
928       } else {
929         gst_buffer_unref (outbuf);
930       }
931       break;
932     default:
933       g_assert (0);
934       break;
935   }
936
937   if (len < 0 || have_data < 0) {
938     GST_ERROR_OBJECT (ffmpegdec,
939         "ffdec_%s: decoding error (len: %d, have_data: %d)",
940         oclass->in_plugin->name, len, have_data);
941     *got_data = 0;
942     return len;
943   } else if (len == 0 && have_data == 0) {
944     *got_data = 0;
945     return 0;
946   } else {
947     /* this is where I lost my last clue on ffmpeg... */
948     *got_data = 1;              //(ffmpegdec->pctx || have_data) ? 1 : 0;
949   }
950
951   if (have_data) {
952     GST_DEBUG_OBJECT (ffmpegdec, "Decoded data, now pushing (%"
953         GST_TIME_FORMAT ")", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)));
954
955     gst_buffer_set_caps (outbuf, GST_PAD_CAPS (ffmpegdec->srcpad));
956     *ret = gst_pad_push (ffmpegdec->srcpad, outbuf);
957   }
958
959   return len;
960 }
961
962 static gboolean
963 gst_ffmpegdec_sink_event (GstPad * pad, GstEvent * event)
964 {
965   GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) GST_OBJECT_PARENT (pad);
966   GstFFMpegDecClass *oclass =
967       (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
968   gboolean ret;
969
970   GST_DEBUG_OBJECT (ffmpegdec, "Handling %s event",
971       GST_EVENT_TYPE_NAME (event));
972
973   switch (GST_EVENT_TYPE (event)) {
974     case GST_EVENT_EOS:{
975       if (oclass->in_plugin->capabilities & CODEC_CAP_DELAY) {
976         gint have_data, len, try = 0;
977
978         do {
979           GstFlowReturn ret;
980
981           len = gst_ffmpegdec_frame (ffmpegdec, NULL, 0, &have_data,
982               &ffmpegdec->next_ts, NULL, &ret);
983           if (len < 0 || have_data == 0)
984             break;
985         } while (try++ < 10);
986       }
987       break;
988     }
989     case GST_EVENT_FLUSH_STOP:{
990       if (ffmpegdec->opened) {
991         avcodec_flush_buffers (ffmpegdec->context);
992       }
993       break;
994     }
995     case GST_EVENT_NEWSEGMENT:{
996       gint64 base, start, end;
997       gdouble rate;
998       GstFormat fmt;
999
1000       gst_event_parse_new_segment (event, NULL, &rate, &fmt, &start, &end,
1001           &base);
1002       if (fmt == GST_FORMAT_TIME) {
1003         ffmpegdec->next_ts = start;
1004         GST_DEBUG_OBJECT (ffmpegdec,
1005             "Discont to time (next_ts) %" GST_TIME_FORMAT " -- %"
1006             GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (end));
1007       } else if (ffmpegdec->context->bit_rate && fmt == GST_FORMAT_BYTES) {
1008         ffmpegdec->next_ts = start * GST_SECOND / ffmpegdec->context->bit_rate;
1009         GST_DEBUG_OBJECT (ffmpegdec,
1010             "Newsegment in bytes from byte %" G_GINT64_FORMAT
1011             " (time %" GST_TIME_FORMAT ") to byte % " G_GINT64_FORMAT
1012             " (time %" GST_TIME_FORMAT ")",
1013             start, GST_TIME_ARGS (ffmpegdec->next_ts),
1014             end,
1015             GST_TIME_ARGS (end * GST_SECOND / ffmpegdec->context->bit_rate));
1016         gst_event_unref (event);
1017         event = gst_event_new_new_segment (FALSE, rate, fmt,
1018             start * GST_SECOND / ffmpegdec->context->bit_rate,
1019             end == -1 ? -1 : end * GST_SECOND / ffmpegdec->context->bit_rate,
1020             base * GST_SECOND / ffmpegdec->context->bit_rate);
1021       } else {
1022         GST_WARNING_OBJECT (ffmpegdec,
1023             "Received discont with no useful value...");
1024       }
1025       if (ffmpegdec->opened) {
1026         avcodec_flush_buffers (ffmpegdec->context);
1027
1028         if (ffmpegdec->context->codec_id == CODEC_ID_MPEG2VIDEO ||
1029             ffmpegdec->context->codec_id == CODEC_ID_MPEG4 ||
1030             ffmpegdec->context->codec_id == CODEC_ID_H264) {
1031           ffmpegdec->waiting_for_key = TRUE;
1032         }
1033       }
1034       ffmpegdec->waiting_for_key = TRUE;
1035       ffmpegdec->synctime = ffmpegdec->next_ts;
1036       break;
1037     }
1038     default:
1039       break;
1040   }
1041
1042   ret = gst_pad_event_default (ffmpegdec->sinkpad, event);
1043
1044   return ret;
1045 }
1046
1047 static GstFlowReturn
1048 gst_ffmpegdec_chain (GstPad * pad, GstBuffer * inbuf)
1049 {
1050   GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) (GST_PAD_PARENT (pad));
1051   GstFFMpegDecClass *oclass =
1052       (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
1053   guint8 *bdata, *data;
1054   gint bsize, size, len, have_data;
1055   guint64 in_ts = GST_BUFFER_TIMESTAMP (inbuf);
1056   GstFlowReturn ret = GST_FLOW_OK;
1057
1058   if (!ffmpegdec->opened)
1059     goto not_negotiated;
1060
1061   GST_DEBUG_OBJECT (ffmpegdec,
1062       "Received new data of size %d, time %" GST_TIME_FORMAT " next_ts %"
1063       GST_TIME_FORMAT, GST_BUFFER_SIZE (inbuf),
1064       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)),
1065       GST_TIME_ARGS (ffmpegdec->next_ts));
1066
1067   /* parse cache joining */
1068   if (ffmpegdec->pcache) {
1069     inbuf = gst_buffer_span (ffmpegdec->pcache, 0, inbuf,
1070         GST_BUFFER_SIZE (ffmpegdec->pcache) + GST_BUFFER_SIZE (inbuf));
1071     ffmpegdec->pcache = NULL;
1072     bdata = GST_BUFFER_DATA (inbuf);
1073     bsize = GST_BUFFER_SIZE (inbuf);
1074   }
1075   /* workarounds, functions write to buffers:
1076    *  libavcodec/svq1.c:svq1_decode_frame writes to the given buffer.
1077    *  libavcodec/svq3.c:svq3_decode_slice_header too.
1078    * ffmpeg devs know about it and will fix it (they said). */
1079   else if (oclass->in_plugin->id == CODEC_ID_SVQ1 ||
1080       oclass->in_plugin->id == CODEC_ID_SVQ3) {
1081     inbuf = gst_buffer_make_writable (inbuf);
1082     bdata = GST_BUFFER_DATA (inbuf);
1083     bsize = GST_BUFFER_SIZE (inbuf);
1084   } else {
1085     bdata = GST_BUFFER_DATA (inbuf);
1086     bsize = GST_BUFFER_SIZE (inbuf);
1087   }
1088
1089   do {
1090     /* parse, if at all possible */
1091     if (ffmpegdec->pctx) {
1092       gint res;
1093       gint64 ffpts;
1094
1095       ffpts = gst_ffmpeg_time_gst_to_ff (in_ts, ffmpegdec->context->time_base);
1096       res = av_parser_parse (ffmpegdec->pctx, ffmpegdec->context,
1097           &data, &size, bdata, bsize, ffpts, ffpts);
1098
1099       GST_DEBUG_OBJECT (ffmpegdec, "Parsed video frame, res=%d, size=%d",
1100           res, size);
1101
1102       in_ts = gst_ffmpeg_time_ff_to_gst (ffmpegdec->pctx->pts,
1103           ffmpegdec->context->time_base);
1104       if (res == 0 || size == 0)
1105         break;
1106       else {
1107         bsize -= res;
1108         bdata += res;
1109       }
1110     } else {
1111       data = bdata;
1112       size = bsize;
1113     }
1114
1115     if ((len = gst_ffmpegdec_frame (ffmpegdec, data, size,
1116                 &have_data, &in_ts, inbuf, &ret)) < 0 || ret != GST_FLOW_OK)
1117       break;
1118
1119     if (!ffmpegdec->pctx) {
1120       bsize -= len;
1121       bdata += len;
1122     }
1123
1124     if (!have_data) {
1125       break;
1126     }
1127   } while (bsize > 0);
1128
1129   if ((ffmpegdec->pctx || oclass->in_plugin->id == CODEC_ID_MP3) && bsize > 0) {
1130     GST_DEBUG_OBJECT (ffmpegdec, "Keeping %d bytes of data", bsize);
1131
1132     ffmpegdec->pcache = gst_buffer_create_sub (inbuf,
1133         GST_BUFFER_SIZE (inbuf) - bsize, bsize);
1134   } else if (bsize > 0) {
1135     GST_DEBUG_OBJECT (ffmpegdec, "Dropping %d bytes of data", bsize);
1136   }
1137   gst_buffer_unref (inbuf);
1138
1139   return ret;
1140
1141   /* ERRORS */
1142 not_negotiated:
1143   {
1144     GST_ELEMENT_ERROR (ffmpegdec, CORE, NEGOTIATION, (NULL),
1145         ("ffdec_%s: input format was not set before data start",
1146             oclass->in_plugin->name));
1147     return GST_FLOW_NOT_NEGOTIATED;
1148   }
1149 }
1150
1151 static GstStateChangeReturn
1152 gst_ffmpegdec_change_state (GstElement * element, GstStateChange transition)
1153 {
1154   GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) element;
1155   GstStateChangeReturn ret;
1156
1157   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1158
1159   switch (transition) {
1160     case GST_STATE_CHANGE_PAUSED_TO_READY:
1161       gst_ffmpegdec_close (ffmpegdec);
1162       if (ffmpegdec->last_buffer != NULL) {
1163         gst_buffer_unref (ffmpegdec->last_buffer);
1164         ffmpegdec->last_buffer = NULL;
1165       }
1166       break;
1167     default:
1168       break;
1169   }
1170
1171   return ret;
1172 }
1173
1174 static void
1175 gst_ffmpegdec_set_property (GObject * object,
1176     guint prop_id, const GValue * value, GParamSpec * pspec)
1177 {
1178   GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) object;
1179
1180   switch (prop_id) {
1181     case ARG_LOWRES:
1182       ffmpegdec->lowres = ffmpegdec->context->lowres = g_value_get_enum (value);
1183       break;
1184     case ARG_SKIPFRAME:
1185       ffmpegdec->hurry_up = ffmpegdec->context->hurry_up =
1186           g_value_get_enum (value);
1187       break;
1188     default:
1189       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1190       break;
1191   }
1192 }
1193
1194 static void
1195 gst_ffmpegdec_get_property (GObject * object,
1196     guint prop_id, GValue * value, GParamSpec * pspec)
1197 {
1198   GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) object;
1199
1200   switch (prop_id) {
1201     case ARG_LOWRES:
1202       g_value_set_enum (value, ffmpegdec->context->lowres);
1203       break;
1204     case ARG_SKIPFRAME:
1205       g_value_set_enum (value, ffmpegdec->context->hurry_up);
1206       break;
1207     default:
1208       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1209       break;
1210   }
1211 }
1212
1213 gboolean
1214 gst_ffmpegdec_register (GstPlugin * plugin)
1215 {
1216   GTypeInfo typeinfo = {
1217     sizeof (GstFFMpegDecClass),
1218     (GBaseInitFunc) gst_ffmpegdec_base_init,
1219     NULL,
1220     (GClassInitFunc) gst_ffmpegdec_class_init,
1221     NULL,
1222     NULL,
1223     sizeof (GstFFMpegDec),
1224     0,
1225     (GInstanceInitFunc) gst_ffmpegdec_init,
1226   };
1227   GType type;
1228   AVCodec *in_plugin;
1229   gint rank;
1230
1231   in_plugin = first_avcodec;
1232
1233   global_plugins = g_hash_table_new (NULL, NULL);
1234
1235   while (in_plugin) {
1236     GstFFMpegDecClassParams *params;
1237     GstCaps *srccaps, *sinkcaps;
1238     gchar *type_name;
1239
1240     /* no quasi-codecs, please */
1241     if (in_plugin->id == CODEC_ID_RAWVIDEO ||
1242         (in_plugin->id >= CODEC_ID_PCM_S16LE &&
1243             in_plugin->id <= CODEC_ID_PCM_S24DAUD)) {
1244       goto next;
1245     }
1246
1247     /* only decoders */
1248     if (!in_plugin->decode) {
1249       goto next;
1250     }
1251
1252     /* name */
1253     if (!gst_ffmpeg_get_codecid_longname (in_plugin->id)) {
1254       g_warning ("Add decoder %s (%d) please", in_plugin->name, in_plugin->id);
1255       goto next;
1256     }
1257
1258     /* first make sure we've got a supported type */
1259     sinkcaps = gst_ffmpeg_codecid_to_caps (in_plugin->id, NULL, FALSE);
1260     if (in_plugin->type == CODEC_TYPE_VIDEO) {
1261       srccaps = gst_caps_from_string ("video/x-raw-rgb; video/x-raw-yuv");
1262     } else {
1263       srccaps = gst_ffmpeg_codectype_to_caps (in_plugin->type, NULL);
1264     }
1265     if (!sinkcaps || !srccaps) {
1266       if (sinkcaps)
1267         gst_caps_unref (sinkcaps);
1268       if (srccaps)
1269         gst_caps_unref (srccaps);
1270       goto next;
1271     }
1272
1273     /* construct the type */
1274     type_name = g_strdup_printf ("ffdec_%s", in_plugin->name);
1275
1276     /* if it's already registered, drop it */
1277     if (g_type_from_name (type_name)) {
1278       g_free (type_name);
1279       goto next;
1280     }
1281
1282     params = g_new0 (GstFFMpegDecClassParams, 1);
1283     params->in_plugin = in_plugin;
1284     params->srccaps = srccaps;
1285     params->sinkcaps = sinkcaps;
1286     g_hash_table_insert (global_plugins,
1287         GINT_TO_POINTER (0), (gpointer) params);
1288
1289     /* create the gtype now */
1290     type = g_type_register_static (GST_TYPE_ELEMENT, type_name, &typeinfo, 0);
1291
1292     /* (Ronald) MPEG-4 gets a higher priority because it has been well-
1293      * tested and by far outperforms divxdec/xviddec - so we prefer it.
1294      * msmpeg4v3 same, as it outperforms divxdec for divx3 playback.
1295      * VC1/WMV3 are not working and thus unpreferred for now. */
1296     switch (in_plugin->id) {
1297       case CODEC_ID_MPEG4:
1298       case CODEC_ID_MSMPEG4V3:
1299       case CODEC_ID_H264:
1300         rank = GST_RANK_PRIMARY;
1301         break;
1302       default:
1303         rank = GST_RANK_MARGINAL;
1304         break;
1305       case CODEC_ID_WMV3:
1306       case CODEC_ID_VC9:
1307         /* what's that? */
1308       case CODEC_ID_SP5X:
1309         rank = GST_RANK_NONE;
1310         break;
1311     }
1312     if (!gst_element_register (plugin, type_name, rank, type)) {
1313       g_warning ("Failed to register %s", type_name);
1314       g_free (type_name);
1315       return FALSE;
1316     }
1317
1318     g_free (type_name);
1319
1320     g_hash_table_insert (global_plugins,
1321         GINT_TO_POINTER (type), (gpointer) params);
1322
1323   next:
1324     in_plugin = in_plugin->next;
1325   }
1326   g_hash_table_remove (global_plugins, GINT_TO_POINTER (0));
1327
1328   return TRUE;
1329 }