xviddec and xvideenc ported to 0.10

Original commit message from CVS:
xviddec and xvideenc ported to 0.10
diff --git a/ext/xvid/gstxvid.c b/ext/xvid/gstxvid.c
index d09489e..d0339a8 100644
--- a/ext/xvid/gstxvid.c
+++ b/ext/xvid/gstxvid.c
@@ -166,7 +166,6 @@
 
     stride = w * bpp / 8;
   }
-
   if (_stride)
     *_stride = stride;
   if (_bpp)
@@ -176,7 +175,7 @@
 }
 
 GstCaps *
-gst_xvid_csp_to_caps (gint csp, gint w, gint h, gdouble fps)
+gst_xvid_csp_to_caps (gint csp, gint w, gint h, gint fps_n, gint fps_d)
 {
   GstCaps *caps = NULL;
 
@@ -263,7 +262,7 @@
           "red_mask", G_TYPE_INT, r_mask,
           "green_mask", G_TYPE_INT, g_mask,
           "blue_mask", G_TYPE_INT, b_mask,
-          "framerate", G_TYPE_DOUBLE, fps, NULL);
+          "framerate", GST_TYPE_FRACTION, fps_n, fps_d, NULL);
       break;
     }
 
@@ -291,12 +290,11 @@
           fourcc = GST_MAKE_FOURCC ('Y', 'V', '1', '2');
           break;
       }
-
       caps = gst_caps_new_simple ("video/x-raw-yuv",
           "width", G_TYPE_INT, w,
           "height", G_TYPE_INT, h,
           "format", GST_TYPE_FOURCC, fourcc,
-          "framerate", G_TYPE_DOUBLE, fps, NULL);
+          "framerate", GST_TYPE_FRACTION, fps_n, fps_d, NULL);
       break;
     }
   }
diff --git a/ext/xvid/gstxvid.h b/ext/xvid/gstxvid.h
index 5b855b5..ab24088 100644
--- a/ext/xvid/gstxvid.h
+++ b/ext/xvid/gstxvid.h
@@ -42,12 +42,13 @@
   "green_mask = (int) " G_STRINGIFY (g_mask) ", " \
   "blue_mask = (int) " G_STRINGIFY (b_mask)
 
-extern gchar *  gst_xvid_error (int errorcode);
-extern gboolean gst_xvid_init  (void);
+extern gchar *	gst_xvid_error (int errorcode);
+extern gboolean	gst_xvid_init  (void);
 
 extern gint     gst_xvid_structure_to_csp (GstStructure *structure,
-                                           gint w, gint *stride, gint *bpp);
-extern GstCaps *gst_xvid_csp_to_caps      (gint csp, gint w, gint h, gdouble fps);
+					   gint w, gint *stride, gint *bpp);
+extern GstCaps *gst_xvid_csp_to_caps (gint csp, gint w, gint h,
+                       gint fps_n, gint fps_d);
 
 G_END_DECLS
 
diff --git a/ext/xvid/gstxviddec.c b/ext/xvid/gstxviddec.c
index 44d5b26..73601ef 100644
--- a/ext/xvid/gstxviddec.c
+++ b/ext/xvid/gstxviddec.c
@@ -40,7 +40,7 @@
     GST_PAD_ALWAYS,
     GST_STATIC_CAPS ("video/x-xvid, "
         "width = (int) [ 0, MAX ], "
-        "height = (int) [ 0, MAX ], " "framerate = (double) [ 0, MAX ]")
+        "height = (int) [ 0, MAX ], " "framerate = (fraction) [0/1, MAX]")
     );
 
 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
@@ -69,24 +69,19 @@
       /* FILL ME */
 };
 
-static void gst_xviddec_base_init (gpointer g_class);
+static void gst_xviddec_base_init (GstXvidDecClass * klass);
 static void gst_xviddec_class_init (GstXvidDecClass * klass);
 static void gst_xviddec_init (GstXvidDec * xviddec);
-static void gst_xviddec_chain (GstPad * pad, GstData * data);
-static GstPadLinkReturn
-gst_xviddec_sink_link (GstPad * pad, const GstCaps * vscapslist);
-static GstPadLinkReturn
-gst_xviddec_src_link (GstPad * pad, const GstCaps * vscapslist);
-static GstCaps *gst_xviddec_src_getcaps (GstPad * pad);
+static GstFlowReturn gst_xviddec_chain (GstPad * pad, GstBuffer * buf);
+static gboolean gst_xviddec_setcaps (GstPad * pad, GstCaps * caps);
+static gboolean gst_xviddec_negotiate (GstXvidDec * xviddec);
 static GstStateChangeReturn gst_xviddec_change_state (GstElement * element,
     GstStateChange transition);
 
-
 static GstElementClass *parent_class = NULL;
 
 /* static guint gst_xviddec_signals[LAST_SIGNAL] = { 0 }; */
 
-
 GType
 gst_xviddec_get_type (void)
 {
@@ -95,7 +90,7 @@
   if (!xviddec_type) {
     static const GTypeInfo xviddec_info = {
       sizeof (GstXvidDecClass),
-      gst_xviddec_base_init,
+      (GBaseInitFunc) gst_xviddec_base_init,
       NULL,
       (GClassInitFunc) gst_xviddec_class_init,
       NULL,
@@ -112,9 +107,9 @@
 }
 
 static void
-gst_xviddec_base_init (gpointer g_class)
+gst_xviddec_base_init (GstXvidDecClass * klass)
 {
-  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
 
   gst_element_class_add_pad_template (element_class,
       gst_static_pad_template_get (&sink_template));
@@ -127,14 +122,13 @@
 static void
 gst_xviddec_class_init (GstXvidDecClass * klass)
 {
-  GstElementClass *gstelement_class = (GstElementClass *) klass;
+  GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
 
-  parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
+  parent_class = g_type_class_peek_parent (klass);
 
   gstelement_class->change_state = gst_xviddec_change_state;
 }
 
-
 static void
 gst_xviddec_init (GstXvidDec * xviddec)
 {
@@ -145,18 +139,15 @@
       gst_pad_new_from_template (gst_static_pad_template_get (&sink_template),
       "sink");
   gst_element_add_pad (GST_ELEMENT (xviddec), xviddec->sinkpad);
-
   gst_pad_set_chain_function (xviddec->sinkpad, gst_xviddec_chain);
-  gst_pad_set_link_function (xviddec->sinkpad, gst_xviddec_sink_link);
+  gst_pad_set_setcaps_function (xviddec->sinkpad, gst_xviddec_setcaps);
 
   /* create the src pad */
   xviddec->srcpad =
       gst_pad_new_from_template (gst_static_pad_template_get (&src_template),
       "src");
   gst_element_add_pad (GST_ELEMENT (xviddec), xviddec->srcpad);
-
-  gst_pad_set_getcaps_function (xviddec->srcpad, gst_xviddec_src_getcaps);
-  gst_pad_set_link_function (xviddec->srcpad, gst_xviddec_src_link);
+  gst_pad_use_fixed_caps (xviddec->srcpad);
 
   /* size, etc. */
   xviddec->width = xviddec->height = xviddec->csp = -1;
@@ -196,36 +187,30 @@
   }
 
   xviddec->handle = xdec.handle;
-
   return TRUE;
 }
 
-
-static void
-gst_xviddec_chain (GstPad * pad, GstData * _data)
+static GstFlowReturn
+gst_xviddec_chain (GstPad * pad, GstBuffer * buf)
 {
-  GstBuffer *buf = GST_BUFFER (_data);
-  GstXvidDec *xviddec = GST_XVIDDEC (GST_OBJECT_PARENT (pad));
-  GstBuffer *outbuf;
+  GstXvidDec *xviddec = GST_XVIDDEC (gst_pad_get_parent (pad));
+  GstBuffer *outbuf = NULL;
   xvid_dec_frame_t xframe;
-  int ret;
+  GstFlowReturn ret = GST_FLOW_OK;
+  int error = 0;
 
-  g_return_if_fail (pad != NULL);
-  g_return_if_fail (GST_IS_PAD (pad));
-
-  if (!xviddec->handle) {
-    GST_ELEMENT_ERROR (xviddec, CORE, NEGOTIATION, (NULL),
-        ("format wasn't negotiated before chain function"));
-    gst_buffer_unref (buf);
-    return;
+  if (xviddec->handle == NULL) {
+    if (!gst_xviddec_negotiate (xviddec))
+      goto not_negotiated;
   }
 
-  outbuf = gst_buffer_new_and_alloc (xviddec->width *
-      xviddec->height * xviddec->bpp / 8);
+  guint bufsize = (xviddec->width * xviddec->height * xviddec->bpp / 8);
+
+  outbuf = gst_buffer_new_and_alloc (bufsize);
+
   GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
   GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
-  GST_BUFFER_SIZE (outbuf) = xviddec->width *
-      xviddec->height * xviddec->bpp / 8;
+  GST_BUFFER_SIZE (outbuf) = bufsize;
 
   /* decode and so ... */
   gst_xvid_init_struct (xframe);
@@ -247,23 +232,39 @@
     xframe.output.stride[0] = xviddec->stride;
   }
 
-  if ((ret = xvid_decore (xviddec->handle, XVID_DEC_DECODE, &xframe, NULL)) < 0) {
-    GST_ELEMENT_ERROR (xviddec, STREAM, DECODE, (NULL),
-        ("Error decoding xvid frame: %s (%d)\n", gst_xvid_error (ret), ret));
-    gst_buffer_unref (buf);
-    gst_buffer_unref (outbuf);
-    return;
+  if ((error =
+          xvid_decore (xviddec->handle, XVID_DEC_DECODE, &xframe, NULL)) < 0) {
+    goto not_decoding;
   }
 
-  gst_pad_push (xviddec->srcpad, GST_DATA (outbuf));
+  gst_buffer_set_caps (outbuf, GST_PAD_CAPS (xviddec->srcpad));
+  gst_pad_push (xviddec->srcpad, outbuf);
   gst_buffer_unref (buf);
+  return ret;
+
+not_negotiated:
+  {
+    GST_ELEMENT_ERROR (xviddec, CORE, NEGOTIATION, (NULL),
+        ("format wasn't negotiated before chain function"));
+    gst_buffer_unref (buf);
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
+
+not_decoding:
+  {
+    GST_ELEMENT_ERROR (xviddec, STREAM, DECODE, (NULL),
+        ("Error decoding xvid frame: %s (%d)\n", gst_xvid_error (error),
+            error));
+    gst_buffer_unref (buf);
+    gst_buffer_unref (outbuf);
+    return GST_FLOW_ERROR;
+  }
 }
 
-static GstCaps *
-gst_xviddec_src_getcaps (GstPad * pad)
+static gboolean
+gst_xviddec_negotiate (GstXvidDec * xviddec)
 {
-  GstXvidDec *xviddec = GST_XVIDDEC (gst_pad_get_parent (pad));
-  GstCaps *caps;
+  GstCaps *caps = NULL;
   gint csp[] = {
     XVID_CSP_I420,
     XVID_CSP_YV12,
@@ -282,92 +283,93 @@
     0
   }, i;
 
-  if (!GST_PAD_CAPS (xviddec->sinkpad)) {
-    GstPadTemplate *templ = gst_static_pad_template_get (&src_template);
-
-    return gst_caps_copy (gst_pad_template_get_caps (templ));
-  }
-
   caps = gst_caps_new_empty ();
   for (i = 0; csp[i] != 0; i++) {
     GstCaps *one = gst_xvid_csp_to_caps (csp[i], xviddec->width,
-        xviddec->height, xviddec->fps);
+        xviddec->height, xviddec->fps_n, xviddec->fps_d);
 
-    gst_caps_append (caps, one);
+    if (gst_pad_set_caps (xviddec->srcpad, one)) {
+      GstStructure *structure = gst_caps_get_structure (one, 0);
+
+      xviddec->csp = gst_xvid_structure_to_csp (structure, xviddec->width,
+          &xviddec->stride, &xviddec->bpp);
+
+      if (xviddec->csp < 0) {
+        return FALSE;
+      }
+
+      break;
+    }
   }
 
-  return caps;
+  gst_xviddec_setup (xviddec);
+  return TRUE;
 }
 
-static GstPadLinkReturn
-gst_xviddec_src_link (GstPad * pad, const GstCaps * vscaps)
-{
-  GstXvidDec *xviddec = GST_XVIDDEC (gst_pad_get_parent (pad));
-  GstStructure *structure = gst_caps_get_structure (vscaps, 0);
-
-  if (!GST_PAD_CAPS (xviddec->sinkpad))
-    return GST_PAD_LINK_DELAYED;
-
-  /* if there's something old around, remove it */
-  if (xviddec->handle) {
-    gst_xviddec_unset (xviddec);
-  }
-  xviddec->csp = gst_xvid_structure_to_csp (structure, xviddec->width,
-      &xviddec->stride, &xviddec->bpp);
-
-  if (xviddec->csp < 0)
-    return GST_PAD_LINK_REFUSED;
-
-  if (!gst_xviddec_setup (xviddec))
-    return GST_PAD_LINK_REFUSED;
-
-  return GST_PAD_LINK_OK;
-}
-
-static GstPadLinkReturn
-gst_xviddec_sink_link (GstPad * pad, const GstCaps * vscaps)
+static gboolean
+gst_xviddec_setcaps (GstPad * pad, GstCaps * caps)
 {
   GstXvidDec *xviddec = GST_XVIDDEC (gst_pad_get_parent (pad));
   GstStructure *structure;
-  GstPadLinkReturn ret;
+  const GValue *fps;
 
   /* if there's something old around, remove it */
   if (xviddec->handle) {
     gst_xviddec_unset (xviddec);
   }
 
+  if (!gst_pad_set_caps (xviddec->srcpad, caps)) {
+    return FALSE;
+  }
+
   /* if we get here, we know the input is xvid. we
    * only need to bother with the output colorspace,
    * which the src_link function takes care of. */
-  structure = gst_caps_get_structure (vscaps, 0);
+  structure = gst_caps_get_structure (caps, 0);
   gst_structure_get_int (structure, "width", &xviddec->width);
   gst_structure_get_int (structure, "height", &xviddec->height);
-  gst_structure_get_double (structure, "framerate", &xviddec->fps);
 
-  ret = gst_pad_renegotiate (xviddec->srcpad);
-  if (ret == GST_PAD_LINK_DELAYED)
-    ret = GST_PAD_LINK_OK;
+  fps = gst_structure_get_value (structure, "framerate");
+  if (fps != NULL && GST_VALUE_HOLDS_FRACTION (fps)) {
+    xviddec->fps_n = gst_value_get_fraction_numerator (fps);
+    xviddec->fps_d = gst_value_get_fraction_denominator (fps);
+  } else {
+    xviddec->fps_n = -1;
+  }
 
-  return ret;
+  return gst_xviddec_negotiate (xviddec);
 }
 
 static GstStateChangeReturn
 gst_xviddec_change_state (GstElement * element, GstStateChange transition)
 {
   GstXvidDec *xviddec = GST_XVIDDEC (element);
+  GstStateChangeReturn ret;
 
-  switch (GST_STATE_PENDING (element)) {
-    case GST_STATE_CHANGE_PAUSED_TO_READY:
-      if (xviddec->handle) {
-        gst_xviddec_unset (xviddec);
-      }
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
       break;
     default:
       break;
   }
 
-  if (parent_class->change_state)
-    return parent_class->change_state (element, transition);
+  ret = parent_class->change_state (element, transition);
 
-  return GST_STATE_CHANGE_SUCCESS;
+  switch (transition) {
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      if (xviddec->handle) {
+        gst_xviddec_unset (xviddec);
+      }
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
+    default:
+      break;
+  }
+
+  return ret;
 }
diff --git a/ext/xvid/gstxviddec.h b/ext/xvid/gstxviddec.h
index fa90d06..e574145 100644
--- a/ext/xvid/gstxviddec.h
+++ b/ext/xvid/gstxviddec.h
@@ -54,7 +54,7 @@
   /* video (output) settings */
   gint csp, bpp, stride;
   gint width, height;
-  double fps;
+  gint fps_n, fps_d;
 };
 
 struct _GstXvidDecClass {
diff --git a/ext/xvid/gstxvidenc.c b/ext/xvid/gstxvidenc.c
index 4fc4c0c..26f4d6c 100644
--- a/ext/xvid/gstxvidenc.c
+++ b/ext/xvid/gstxvidenc.c
@@ -53,7 +53,7 @@
     GST_PAD_ALWAYS,
     GST_STATIC_CAPS ("video/x-xvid, "
         "width = (int) [ 0, MAX ], "
-        "height = (int) [ 0, MAX ], " "framerate = (double) [ 0.0, MAX ]")
+        "height = (int) [ 0, MAX ], " "framerate = (fraction) [0/1, MAX]")
     );
 
 
@@ -83,9 +83,9 @@
 static void gst_xvidenc_base_init (gpointer g_class);
 static void gst_xvidenc_class_init (GstXvidEncClass * klass);
 static void gst_xvidenc_init (GstXvidEnc * xvidenc);
-static void gst_xvidenc_chain (GstPad * pad, GstData * data);
-static GstPadLinkReturn
-gst_xvidenc_link (GstPad * pad, const GstCaps * vscapslist);
+static GstFlowReturn gst_xvidenc_chain (GstPad * pad, GstBuffer * buf);
+static gboolean gst_xvidenc_setcaps (GstPad * pad, GstCaps * caps);
+
 
 /* properties */
 static void gst_xvidenc_set_property (GObject * object,
@@ -173,13 +173,13 @@
 static void
 gst_xvidenc_class_init (GstXvidEncClass * klass)
 {
-  GstElementClass *gstelement_class;
-  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+  GObjectClass *gobject_class = (GObjectClass *) klass;
 
-  gobject_class = (GObjectClass *) klass;
-  gstelement_class = (GstElementClass *) klass;
+  parent_class = g_type_class_peek_parent (klass);
 
-  parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
+  gobject_class->set_property = gst_xvidenc_set_property;
+  gobject_class->get_property = gst_xvidenc_get_property;
 
   /* encoding profile */
   g_object_class_install_property (gobject_class, ARG_PROFILE,
@@ -201,8 +201,6 @@
       g_param_spec_ulong ("buffer_size", "Buffer Size",
           "Size of the video buffers", 0, G_MAXULONG, 0, G_PARAM_READWRITE));
 
-  gobject_class->set_property = gst_xvidenc_set_property;
-  gobject_class->get_property = gst_xvidenc_get_property;
   gstelement_class->change_state = gst_xvidenc_change_state;
 
   gst_xvidenc_signals[FRAME_ENCODED] =
@@ -222,10 +220,9 @@
   xvidenc->sinkpad =
       gst_pad_new_from_template (gst_static_pad_template_get (&sink_template),
       "sink");
-  gst_element_add_pad (GST_ELEMENT (xvidenc), xvidenc->sinkpad);
-
   gst_pad_set_chain_function (xvidenc->sinkpad, gst_xvidenc_chain);
-  gst_pad_set_link_function (xvidenc->sinkpad, gst_xvidenc_link);
+  gst_pad_set_setcaps_function (xvidenc->sinkpad, gst_xvidenc_setcaps);
+  gst_element_add_pad (GST_ELEMENT (xvidenc), xvidenc->sinkpad);
 
   /* create the src pad */
   xvidenc->srcpad =
@@ -263,7 +260,7 @@
   xenc.global = XVID_GLOBAL_PACKED;
 
   xenc.fbase = 1000000;
-  xenc.fincr = (int) (xenc.fbase / xvidenc->fps);
+  xenc.fincr = (int) (xenc.fbase / xvidenc->fps_n / xvidenc->fps_d);    /* FIX? */
   xenc.max_key_interval = (xvidenc->max_key_interval == -1) ?
       (2 * xenc.fbase / xenc.fincr) : xvidenc->max_key_interval;
   xenc.handle = NULL;
@@ -293,19 +290,15 @@
 }
 
 
-static void
-gst_xvidenc_chain (GstPad * pad, GstData * _data)
+static GstFlowReturn
+gst_xvidenc_chain (GstPad * pad, GstBuffer * buf)
 {
-  GstBuffer *buf = GST_BUFFER (_data);
-  GstXvidEnc *xvidenc = GST_XVIDENC (GST_OBJECT_PARENT (pad));
+  GstXvidEnc *xvidenc = GST_XVIDENC (gst_pad_get_parent (pad));
   GstBuffer *outbuf;
   xvid_enc_frame_t xframe;
   xvid_enc_stats_t xstats;
   gint ret;
 
-  g_return_if_fail (pad != NULL);
-  g_return_if_fail (GST_IS_PAD (pad));
-
   outbuf = gst_buffer_new_and_alloc (xvidenc->buffer_size << 10);
   GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
   GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
@@ -332,7 +325,7 @@
   }
   xframe.type = XVID_TYPE_AUTO;
   xframe.bitstream = (void *) GST_BUFFER_DATA (outbuf);
-  xframe.length = GST_BUFFER_MAXSIZE (outbuf);
+  xframe.length = GST_BUFFER_SIZE (outbuf);     /* GST_BUFFER_MAXSIZE */
   gst_xvid_init_struct (xstats);
 
   if ((ret = xvid_encore (xvidenc->handle, XVID_ENC_ENCODE,
@@ -341,32 +334,32 @@
         ("Error encoding xvid frame: %s (%d)", gst_xvid_error (ret), ret));
     gst_buffer_unref (buf);
     gst_buffer_unref (outbuf);
-    return;
+    return GST_FLOW_ERROR;
   }
 
   GST_BUFFER_SIZE (outbuf) = xstats.length;
-  if (xframe.out_flags & XVID_KEYFRAME)
-    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_KEY_UNIT);
 
   /* go out, multiply! */
-  gst_pad_push (xvidenc->srcpad, GST_DATA (outbuf));
+  gst_buffer_set_caps (outbuf, GST_PAD_CAPS (xvidenc->srcpad));
+  gst_pad_push (xvidenc->srcpad, outbuf);
 
   /* proclaim destiny */
   g_signal_emit (G_OBJECT (xvidenc), gst_xvidenc_signals[FRAME_ENCODED], 0);
 
   /* until the final judgement */
   gst_buffer_unref (buf);
+  return GST_FLOW_OK;
 }
 
 
-static GstPadLinkReturn
-gst_xvidenc_link (GstPad * pad, const GstCaps * vscaps)
+static gboolean
+gst_xvidenc_setcaps (GstPad * pad, GstCaps * caps)
 {
   GstXvidEnc *xvidenc;
-  GstStructure *structure;
+  GstStructure *structure = gst_caps_get_structure (caps, 0);
   const gchar *mime;
   gint w, h;
-  double fps;
+  const GValue *fps;
   gint xvid_cs = -1, stride = -1;
 
   xvidenc = GST_XVIDENC (gst_pad_get_parent (pad));
@@ -377,43 +370,43 @@
     xvidenc->handle = NULL;
   }
 
-  g_return_val_if_fail (gst_caps_get_size (vscaps) == 1, GST_PAD_LINK_REFUSED);
-  structure = gst_caps_get_structure (vscaps, 0);
-
   gst_structure_get_int (structure, "width", &w);
   gst_structure_get_int (structure, "height", &h);
-  gst_structure_get_double (structure, "framerate", &fps);
+
+  fps = gst_structure_get_value (structure, "framerate");
+  if (fps != NULL && GST_VALUE_HOLDS_FRACTION (fps)) {
+    xvidenc->fps_n = gst_value_get_fraction_numerator (fps);
+    xvidenc->fps_d = gst_value_get_fraction_denominator (fps);
+  } else {
+    xvidenc->fps_n = -1;
+  }
+
   mime = gst_structure_get_name (structure);
-
   xvid_cs = gst_xvid_structure_to_csp (structure, w, &stride, NULL);
-  g_return_val_if_fail (xvid_cs != -1, GST_PAD_LINK_REFUSED);
-
   xvidenc->csp = xvid_cs;
   xvidenc->width = w;
   xvidenc->height = h;
   xvidenc->stride = stride;
-  xvidenc->fps = fps;
 
   if (gst_xvidenc_setup (xvidenc)) {
-    GstPadLinkReturn ret;
-    GstCaps *new_caps;
+    GstCaps *new_caps = NULL;
 
     new_caps = gst_caps_new_simple ("video/x-xvid",
         "width", G_TYPE_INT, w,
-        "height", G_TYPE_INT, h, "framerate", G_TYPE_DOUBLE, fps, NULL);
-    ret = gst_pad_try_set_caps (xvidenc->srcpad, new_caps);
-    if (GST_PAD_LINK_FAILED (ret)) {
+        "height", G_TYPE_INT, h,
+        "framerate", GST_TYPE_FRACTION, xvidenc->fps_n, xvidenc->fps_d, NULL);
+    if (!gst_pad_set_caps (xvidenc->srcpad, new_caps)) {
       if (xvidenc->handle) {
         xvid_encore (xvidenc->handle, XVID_ENC_DESTROY, NULL, NULL);
         xvidenc->handle = NULL;
       }
+      return FALSE;
     }
-
-    return ret;
+    return TRUE;
   }
 
   /* if we got here - it's not good */
-  return GST_PAD_LINK_REFUSED;
+  return FALSE;
 }
 
 
@@ -421,10 +414,9 @@
 gst_xvidenc_set_property (GObject * object,
     guint prop_id, const GValue * value, GParamSpec * pspec)
 {
-  GstXvidEnc *xvidenc;
+  GstXvidEnc *xvidenc = GST_XVIDENC (object);
 
-  g_return_if_fail (GST_IS_XVIDENC (object));
-  xvidenc = GST_XVIDENC (object);
+  GST_OBJECT_LOCK (xvidenc);
 
   switch (prop_id) {
     case ARG_PROFILE:
@@ -443,17 +435,18 @@
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
   }
-}
 
+  GST_OBJECT_UNLOCK (xvidenc);
+
+}
 
 static void
 gst_xvidenc_get_property (GObject * object,
     guint prop_id, GValue * value, GParamSpec * pspec)
 {
-  GstXvidEnc *xvidenc;
+  GstXvidEnc *xvidenc = GST_XVIDENC (object);
 
-  g_return_if_fail (GST_IS_XVIDENC (object));
-  xvidenc = GST_XVIDENC (object);
+  GST_OBJECT_LOCK (xvidenc);
 
   switch (prop_id) {
     case ARG_PROFILE:
@@ -472,26 +465,41 @@
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
   }
+
+  GST_OBJECT_UNLOCK (xvidenc);
 }
 
 static GstStateChangeReturn
 gst_xvidenc_change_state (GstElement * element, GstStateChange transition)
 {
   GstXvidEnc *xvidenc = GST_XVIDENC (element);
+  GstStateChangeReturn ret;
 
-  switch (GST_STATE_PENDING (element)) {
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+      break;
+    default:
+      break;
+  }
+
+  ret = parent_class->change_state (element, transition);
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      break;
     case GST_STATE_CHANGE_PAUSED_TO_READY:
       if (xvidenc->handle) {
         xvid_encore (xvidenc->handle, XVID_ENC_DESTROY, NULL, NULL);
         xvidenc->handle = NULL;
       }
       break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      break;
     default:
       break;
   }
 
-  if (parent_class->change_state)
-    return parent_class->change_state (element, transition);
-
-  return GST_STATE_CHANGE_SUCCESS;
+  return ret;
 }
diff --git a/ext/xvid/gstxvidenc.h b/ext/xvid/gstxvidenc.h
index 356ce53..f016c62 100644
--- a/ext/xvid/gstxvidenc.h
+++ b/ext/xvid/gstxvidenc.h
@@ -65,7 +65,7 @@
   void *handle;
   gint csp;
   gint width, height, stride;
-  gdouble fps;
+  gint fps_n, fps_d;
 };
 
 struct _GstXvidEncClass {