diff --git a/configure.ac b/configure.ac
index a071358..ea84bf1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -389,6 +389,44 @@ if test x$HAVE_FFMPEG_UNINSTALLED = x1; then
 fi
 AM_CONDITIONAL(HAVE_FFMPEG_UNINSTALLED, test x$HAVE_FFMPEG_UNINSTALLED = x1)
 
+PKG_CHECK_MODULES(VDPAU, vdpau, [HAVE_VDPAU="yes"],
+[
+    AC_CHECK_HEADER([vdpau/vdpau.h], [HAVE_VDPAU_H=yes],
+    [
+      dnl Didn't find VDPAU header straight away.
+      dnl Try /usr/include/nvidia. Need to clear caching vars first
+      AC_MSG_NOTICE([VDPAU header not in standard path. Checking /usr/include/nvidia])
+      unset ac_cv_header_vdpau_vdpau_h
+      unset ac_cv_header_vdpau_vdpau_x11_h
+      VDPAU_CFLAGS="-I/usr/include/nvidia"
+      VDPAU_LIBS="-L/usr/lib/nvidia -lvdpau"
+      saved_CPPFLAGS="$CPPFLAGS"
+      CPPFLAGS="$VDPAU_CFLAGS $saved_CPPFLAGS"
+      AC_CHECK_HEADER([vdpau/vdpau.h], [HAVE_VDPAU_H=yes])
+      CPPFLAGS="$saved_CPPFLAGS"
+    ])
+    
+    AC_CHECK_HEADER([vdpau/vdpau_x11.h], [HAVE_VDPAU_X11_H=yes])
+    if test "x$HAVE_VDPAU_H" = "xyes" -a "x$HAVE_VDPAU_X11_H" = "xyes"; then
+      dnl Found the headers - look for the lib
+      AC_MSG_NOTICE([VDPAU headers found. Checking libraries])
+      saved_LIBS="$LIBS"
+      LIBS="$VDPAU_LIBS $saved_LIBS"
+      AC_CHECK_LIB(vdpau,vdp_device_create_x11,[HAVE_VDPAU="yes"])
+      LIBS="$saved_LIBS"
+    fi
+])
+
+if test "x$HAVE_VDPAU" = "xyes"; then
+  AC_MSG_NOTICE([Found up to date VDPAU installation])
+  
+  VDPAU_LIBS="-lgstvdp-0.10 $VDPAU_LIBS"
+  AC_SUBST(VDPAU_CFLAGS)
+  AC_SUBST(VDPAU_LIBS)
+  AC_DEFINE([HAVE_VDPAU], [1], ["asdasd"])
+  embffmpeg_configure_args="$embffmpeg_configure_args --enable-vdpau"
+fi
+
 SHAVE_INIT([common],[enable])
 
 AC_CONFIG_FILES(
diff --git a/ext/ffmpeg/Makefile.am b/ext/ffmpeg/Makefile.am
index 083f265..a2ac791 100644
--- a/ext/ffmpeg/Makefile.am
+++ b/ext/ffmpeg/Makefile.am
@@ -21,8 +21,8 @@ libgstffmpeg_la_SOURCES = gstffmpeg.c	\
 # 			  gstffmpegscale.c
 
 libgstffmpeg_la_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \
-	$(FFMPEG_CFLAGS)
-libgstffmpeg_la_LIBADD = $(FFMPEG_LIBS) $(GST_BASE_LIBS) $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR) $(LIBM) $(WIN32_LIBS) -lz $(BZ2_LIBS)
+	$(FFMPEG_CFLAGS) $(VDPAU_CFLAGS)
+libgstffmpeg_la_LIBADD = $(FFMPEG_LIBS) $(GST_BASE_LIBS) $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR) $(LIBM) $(WIN32_LIBS) -lz $(BZ2_LIBS) $(VDPAU_LIBS)
 libgstffmpeg_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(DARWIN_LDFLAGS)
 libgstffmpeg_la_LIBTOOLFLAGS = --tag=disable-static
 
diff --git a/ext/ffmpeg/gstffmpegdec.c b/ext/ffmpeg/gstffmpegdec.c
index 2a5bd51..3c1f556 100644
--- a/ext/ffmpeg/gstffmpegdec.c
+++ b/ext/ffmpeg/gstffmpegdec.c
@@ -30,6 +30,14 @@
 #include <libavcodec/avcodec.h>
 #endif
 
+#ifdef HAVE_VDPAU
+#include <gst/vdpau/gstvdpdevice.h>
+#include <gst/vdpau/gstvdpvideobuffer.h>
+#include <gst/vdpau/gstvdpvideosrcpad.h>
+#include <vdpau/vdpau.h>
+#include "libavcodec/vdpau.h"
+#endif
+
 #include <gst/gst.h>
 #include <gst/video/video.h>
 
@@ -157,6 +165,12 @@ struct _GstFFMpegDec
 
   /* Can downstream allocate 16bytes aligned data. */
   gboolean can_allocate_aligned;
+
+#ifdef HAVE_VDPAU
+  gboolean is_vdpau_dec;
+  VdpDecoder decoder;
+  gint decoder_max_refs;
+#endif
 };
 
 typedef struct _GstFFMpegDecClass GstFFMpegDecClass;
@@ -223,6 +237,11 @@ static void gst_ffmpegdec_get_property (GObject * object,
 static gboolean gst_ffmpegdec_negotiate (GstFFMpegDec * ffmpegdec,
     gboolean force);
 
+#ifdef HAVE_VDPAU
+static void gst_ffmpegdec_draw_horiz_band (AVCodecContext * context,
+    const AVFrame * picture, int offset[4], int y, int type, int height);
+#endif
+
 /* some sort of bufferpool handling, but different */
 static int gst_ffmpegdec_get_buffer (AVCodecContext * context,
     AVFrame * picture);
@@ -316,11 +335,19 @@ gst_ffmpegdec_base_init (GstFFMpegDecClass * klass)
   /* get the caps */
   sinkcaps = gst_ffmpeg_codecid_to_caps (in_plugin->id, NULL, FALSE);
   if (!sinkcaps) {
-    GST_DEBUG ("Couldn't get sink caps for decoder '%s'", in_plugin->name);
-    sinkcaps = gst_caps_from_string ("unknown/unknown");
+    GST_DEBUG ("Couldn't get sink caps for decoder '%s', skipping codec",
+        in_plugin->name);
+    srccaps = gst_caps_from_string ("unknown/unknown");
   }
   if (in_plugin->type == CODEC_TYPE_VIDEO) {
+#ifdef HAVE_VDPAU
+    if (in_plugin->capabilities & CODEC_CAP_HWACCEL_VDPAU)
+      srccaps = gst_vdp_video_src_pad_get_template_caps ();
+    else
+      srccaps = gst_caps_from_string ("video/x-raw-rgb; video/x-raw-yuv");
+#else
     srccaps = gst_caps_from_string ("video/x-raw-rgb; video/x-raw-yuv");
+#endif
   } else {
     srccaps = gst_ffmpeg_codectype_to_audio_caps (NULL,
         in_plugin->id, FALSE, in_plugin);
@@ -396,6 +423,14 @@ gst_ffmpegdec_init (GstFFMpegDec * ffmpegdec)
 
   oclass = (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec));
 
+  /* check if it's a vdpau decoder */
+#ifdef HAVE_VDPAU
+  if (oclass->in_plugin->capabilities & CODEC_CAP_HWACCEL_VDPAU)
+    ffmpegdec->is_vdpau_dec = TRUE;
+  else
+    ffmpegdec->is_vdpau_dec = FALSE;
+#endif
+
   /* setup pads */
   ffmpegdec->sinkpad = gst_pad_new_from_template (oclass->sinktempl, "sink");
   gst_pad_set_setcaps_function (ffmpegdec->sinkpad,
@@ -406,6 +441,20 @@ gst_ffmpegdec_init (GstFFMpegDec * ffmpegdec)
       GST_DEBUG_FUNCPTR (gst_ffmpegdec_chain));
   gst_element_add_pad (GST_ELEMENT (ffmpegdec), ffmpegdec->sinkpad);
 
+#ifdef HAVE_VDPAU
+  if (ffmpegdec->is_vdpau_dec)
+    ffmpegdec->srcpad = (GstPad *) gst_vdp_video_src_pad_new ();
+  else {
+    ffmpegdec->srcpad = gst_pad_new_from_template (oclass->srctempl, "src");
+    gst_pad_use_fixed_caps (ffmpegdec->srcpad);
+  }
+
+  gst_pad_set_event_function (ffmpegdec->srcpad,
+      GST_DEBUG_FUNCPTR (gst_ffmpegdec_src_event));
+  gst_pad_set_query_function (ffmpegdec->srcpad,
+      GST_DEBUG_FUNCPTR (gst_ffmpegdec_query));
+  gst_element_add_pad (GST_ELEMENT (ffmpegdec), ffmpegdec->srcpad);
+#else
   ffmpegdec->srcpad = gst_pad_new_from_template (oclass->srctempl, "src");
   gst_pad_use_fixed_caps (ffmpegdec->srcpad);
   gst_pad_set_event_function (ffmpegdec->srcpad,
@@ -413,6 +462,7 @@ gst_ffmpegdec_init (GstFFMpegDec * ffmpegdec)
   gst_pad_set_query_function (ffmpegdec->srcpad,
       GST_DEBUG_FUNCPTR (gst_ffmpegdec_query));
   gst_element_add_pad (GST_ELEMENT (ffmpegdec), ffmpegdec->srcpad);
+#endif
 
   /* some ffmpeg data */
   ffmpegdec->context = avcodec_alloc_context ();
@@ -597,6 +647,19 @@ gst_ffmpegdec_close (GstFFMpegDec * ffmpegdec)
   ffmpegdec->format.video.fps_n = -1;
   ffmpegdec->format.video.old_fps_n = -1;
   ffmpegdec->format.video.interlaced = FALSE;
+
+#ifdef HAVE_VDPAU
+  if (ffmpegdec->is_vdpau_dec) {
+    if (ffmpegdec->decoder != VDP_INVALID_HANDLE) {
+      GstVdpDevice *device =
+          gst_vdp_video_src_pad_get_device (GST_VDP_VIDEO_SRC_PAD
+          (ffmpegdec->srcpad));
+
+      if (device)
+        device->vdp_decoder_destroy (ffmpegdec->decoder);
+    }
+  }
+#endif
 }
 
 /* with LOCK */
@@ -675,6 +738,11 @@ gst_ffmpegdec_open (GstFFMpegDec * ffmpegdec)
   ffmpegdec->proportion = 0.0;
   ffmpegdec->earliest_time = -1;
 
+#ifdef HAVE_VDPAU
+  ffmpegdec->decoder = VDP_INVALID_HANDLE;
+  ffmpegdec->decoder_max_refs = -1;
+#endif
+
   return TRUE;
 
   /* ERRORS */
@@ -723,7 +791,14 @@ gst_ffmpegdec_setcaps (GstPad * pad, GstCaps * caps)
   /* set buffer functions */
   ffmpegdec->context->get_buffer = gst_ffmpegdec_get_buffer;
   ffmpegdec->context->release_buffer = gst_ffmpegdec_release_buffer;
+#ifdef HAVE_VDPAU
+  if (ffmpegdec->is_vdpau_dec)
+    ffmpegdec->context->draw_horiz_band = gst_ffmpegdec_draw_horiz_band;
+  else
+    ffmpegdec->context->draw_horiz_band = NULL;
+#else
   ffmpegdec->context->draw_horiz_band = NULL;
+#endif
 
   /* assume PTS as input, we will adapt when we detect timestamp reordering
    * in the output frames. */
@@ -798,6 +873,12 @@ gst_ffmpegdec_setcaps (GstPad * pad, GstCaps * caps)
      * outside of the memory. */
     ffmpegdec->context->flags |= CODEC_FLAG_EMU_EDGE;
   }
+#ifdef HAVE_VDPAU
+  if (ffmpegdec->is_vdpau_dec) {
+    ffmpegdec->context->slice_flags =
+        ffmpegdec->context->slice_flags | SLICE_FLAG_CODED_ORDER;
+  }
+#endif
 
   /* workaround encoder bugs */
   ffmpegdec->context->workaround_bugs |= FF_BUG_AUTODETECT;
@@ -912,6 +993,136 @@ alloc_failed:
   }
 }
 
+#ifdef HAVE_VDPAU
+static VdpDecoder
+create_vdpau_decoder (GstVdpDevice * device, enum PixelFormat pix_fmt,
+    guint max_refs, guint width, guint height)
+{
+  VdpDecoderProfile profile;
+  VdpStatus status;
+  VdpDecoder decoder;
+
+  switch (pix_fmt) {
+    case PIX_FMT_VDPAU_MPEG1:
+      profile = VDP_DECODER_PROFILE_MPEG1;
+      break;
+    case PIX_FMT_VDPAU_MPEG2:
+      profile = VDP_DECODER_PROFILE_MPEG2_MAIN;
+      break;
+    case PIX_FMT_VDPAU_H264:
+      profile = VDP_DECODER_PROFILE_H264_HIGH;
+      break;
+    case PIX_FMT_VDPAU_VC1:
+      profile = VDP_DECODER_PROFILE_VC1_ADVANCED;
+      break;
+    default:
+      GST_ERROR ("Invalid picture format");
+      return VDP_INVALID_HANDLE;
+  }
+
+  status = device->vdp_decoder_create (device->device, profile, width,
+      height, max_refs, &decoder);
+  if (status != VDP_STATUS_OK) {
+    GST_ERROR
+        ("Couldn't create vdpau decoder, error returned from vdpau was: %s",
+        device->vdp_get_error_string (status));
+    return VDP_INVALID_HANDLE;
+  }
+
+  return decoder;
+
+}
+
+static GstFlowReturn
+gst_ffmpegdec_vdpau_alloc_output_buffer (GstFFMpegDec * ffmpegdec,
+    GstBuffer ** outbuf)
+{
+  GstFlowReturn ret;
+
+  /* see if we need renegotiation */
+  if (G_UNLIKELY (!gst_ffmpegdec_negotiate (ffmpegdec, FALSE)))
+    goto negotiate_failed;
+
+  ret = gst_vdp_video_src_pad_alloc_buffer (
+      (GstVdpVideoSrcPad *) ffmpegdec->srcpad, (GstVdpVideoBuffer **) outbuf);
+  if (G_UNLIKELY (ret != GST_FLOW_OK))
+    return ret;
+
+  return ret;
+
+  /* special cases */
+negotiate_failed:
+  {
+    GST_DEBUG_OBJECT (ffmpegdec, "negotiate failed");
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
+}
+
+static void
+gst_ffmpegdec_draw_horiz_band (AVCodecContext * context,
+    const AVFrame * picture, int offset[4], int y, int type, int height)
+{
+  GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) context->opaque;
+
+  GstVdpDevice *device;
+  struct vdpau_render_state *render;
+  guint max_refs;
+  guint width;
+  VdpStatus status;
+
+  device = gst_vdp_video_src_pad_get_device (
+      (GstVdpVideoSrcPad *) ffmpegdec->srcpad);
+  render = (struct vdpau_render_state *) picture->data[0];
+
+  width = ffmpegdec->context->width;
+  height = ffmpegdec->context->height;
+
+  if (ffmpegdec->context->pix_fmt == PIX_FMT_VDPAU_H264)
+    max_refs = render->info.h264.num_ref_frames;
+  else
+    max_refs = 2;
+
+  if (G_UNLIKELY (ffmpegdec->decoder == VDP_INVALID_HANDLE)) {
+    ffmpegdec->decoder = create_vdpau_decoder (device,
+        ffmpegdec->context->pix_fmt, max_refs, width, height);
+
+    if (G_UNLIKELY (ffmpegdec->decoder == VDP_INVALID_HANDLE))
+      goto create_decoder_failed;
+  } else if (G_UNLIKELY (max_refs != ffmpegdec->decoder_max_refs)) {
+    device->vdp_decoder_destroy (ffmpegdec->decoder);
+
+    ffmpegdec->decoder = create_vdpau_decoder (device,
+        ffmpegdec->context->pix_fmt, max_refs, width, height);
+
+    if (G_UNLIKELY (ffmpegdec->decoder == VDP_INVALID_HANDLE))
+      goto create_decoder_failed;
+
+    ffmpegdec->decoder_max_refs = max_refs;
+  }
+
+  status = device->vdp_decoder_render (ffmpegdec->decoder, render->surface,
+      (void *) &render->info, render->bitstream_buffers_used,
+      render->bitstream_buffers);
+  if (status != VDP_STATUS_OK)
+    goto decode_failed;
+
+  return;
+
+create_decoder_failed:
+  GST_ELEMENT_ERROR (ffmpegdec, RESOURCE, OPEN_READ,
+      ("Couldn't create vdpau decoder."), (NULL));
+  return;
+
+decode_failed:
+  GST_ELEMENT_ERROR (ffmpegdec, RESOURCE, READ,
+      ("Could not decode"),
+      ("Error returned from vdpau was: %s",
+          device->vdp_get_error_string (status)));
+  return;
+
+}
+#endif
+
 static int
 gst_ffmpegdec_get_buffer (AVCodecContext * context, AVFrame * picture)
 {
@@ -942,6 +1153,24 @@ gst_ffmpegdec_get_buffer (AVCodecContext * context, AVFrame * picture)
 
   GST_LOG_OBJECT (ffmpegdec, "dimension %dx%d, coded %dx%d", width, height,
       coded_width, coded_height);
+
+#ifdef HAVE_VDPAU
+  if (ffmpegdec->is_vdpau_dec) {
+    GstFlowReturn ret;
+    struct vdpau_render_state *render;
+
+    ret = gst_ffmpegdec_vdpau_alloc_output_buffer (ffmpegdec, &buf);
+    if (G_UNLIKELY (ret != GST_FLOW_OK))
+      return -1;
+
+    render = g_new0 (struct vdpau_render_state, 1);
+    render->surface = GST_VDP_VIDEO_BUFFER (buf)->surface;
+    picture->data[0] = (void *) render;
+
+    goto beach;
+  }
+#endif
+
   if (!ffmpegdec->current_dr) {
     GST_LOG_OBJECT (ffmpegdec, "direct rendering disabled, fallback alloc");
     res = avcodec_default_get_buffer (context, picture);
@@ -1003,6 +1232,9 @@ gst_ffmpegdec_get_buffer (AVCodecContext * context, AVFrame * picture)
       break;
   }
 
+#ifdef HAVE_VDPAU
+beach:
+#endif
   /* tell ffmpeg we own this buffer, tranfer the ref we have on the buffer to
    * the opaque data. */
   picture->type = FF_BUFFER_TYPE_USER;
@@ -1051,6 +1283,11 @@ gst_ffmpegdec_release_buffer (AVCodecContext * context, AVFrame * picture)
   gst_buffer_unref (buf);
 #endif
 
+#ifdef HAVE_VDPAU
+  if (ffmpegdec->is_vdpau_dec)
+    g_free (picture->data[0]);
+#endif
+
   /* zero out the reference in ffmpeg */
   for (i = 0; i < 4; i++) {
     picture->data[i] = NULL;
@@ -1186,8 +1423,20 @@ gst_ffmpegdec_negotiate (GstFFMpegDec * ffmpegdec, gboolean force)
       break;
   }
 
+#ifdef HAVE_VDPAU
+  if (ffmpegdec->is_vdpau_dec) {
+    caps = gst_pad_get_allowed_caps (ffmpegdec->srcpad);
+    if (caps == NULL)
+      goto no_caps;
+
+    gst_pad_fixate_caps (ffmpegdec->srcpad, caps);
+  } else
+    caps = gst_ffmpeg_codectype_to_caps (oclass->in_plugin->type,
+        ffmpegdec->context, oclass->in_plugin->id, FALSE);
+#else
   caps = gst_ffmpeg_codectype_to_caps (oclass->in_plugin->type,
       ffmpegdec->context, oclass->in_plugin->id, FALSE);
+#endif
 
   if (caps == NULL)
     goto no_caps;
@@ -1229,8 +1478,19 @@ gst_ffmpegdec_negotiate (GstFFMpegDec * ffmpegdec, gboolean force)
       break;
   }
 
+#ifdef HAVE_VDPAU
+  if (ffmpegdec->is_vdpau_dec) {
+    if (!gst_vdp_video_src_pad_set_caps
+        (GST_VDP_VIDEO_SRC_PAD (ffmpegdec->srcpad), caps))
+      goto caps_failed;
+  } else {
+    if (!gst_pad_set_caps (ffmpegdec->srcpad, caps))
+      goto caps_failed;
+  }
+#else
   if (!gst_pad_set_caps (ffmpegdec->srcpad, caps))
     goto caps_failed;
+#endif
 
   gst_caps_unref (caps);
 
@@ -1506,6 +1766,7 @@ get_output_buffer (GstFFMpegDec * ffmpegdec, GstBuffer ** outbuf)
 
     av_picture_copy (&pic, outpic, ffmpegdec->context->pix_fmt, width, height);
   }
+
   ffmpegdec->picture->pts = -1;
 
   return ret;
@@ -1542,7 +1803,15 @@ flush_queued (GstFFMpegDec * ffmpegdec)
         GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
 
     /* iterate ouput queue an push downstream */
+#ifdef HAVE_VDPAU
+    if (ffmpegdec->is_vdpau_dec)
+      res = gst_vdp_video_src_pad_push (
+          (GstVdpVideoSrcPad *) ffmpegdec->srcpad, (GstVdpVideoBuffer *) buf);
+    else
+      res = gst_pad_push (ffmpegdec->srcpad, buf);
+#else
     res = gst_pad_push (ffmpegdec->srcpad, buf);
+#endif
 
     ffmpegdec->queued =
         g_list_delete_link (ffmpegdec->queued, ffmpegdec->queued);
@@ -2196,8 +2465,16 @@ gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec,
     gst_buffer_set_caps (outbuf, GST_PAD_CAPS (ffmpegdec->srcpad));
 
     if (ffmpegdec->segment.rate > 0.0) {
-      /* and off we go */
+#ifdef HAVE_VDPAU
+      if (ffmpegdec->is_vdpau_dec)
+        *ret = gst_vdp_video_src_pad_push (
+            (GstVdpVideoSrcPad *) ffmpegdec->srcpad,
+            (GstVdpVideoBuffer *) outbuf);
+      else
+        *ret = gst_pad_push (ffmpegdec->srcpad, outbuf);
+#else
       *ret = gst_pad_push (ffmpegdec->srcpad, outbuf);
+#endif
     } else {
       /* reverse playback, queue frame till later when we get a discont. */
       GST_DEBUG_OBJECT (ffmpegdec, "queued frame");
@@ -2786,9 +3063,7 @@ gst_ffmpegdec_register (GstPlugin * plugin)
           in_plugin->name);
       goto next;
     }
-
-    /* No vdpau plugins until we can figure out how to properly use them
-     * outside of ffmpeg. */
+#ifndef HAVE_VDPAU
     if (!strcmp (in_plugin->name, "h264_vdpau") ||
         !strcmp (in_plugin->name, "mpeg_vdpau") ||
         !strcmp (in_plugin->name, "mpeg1_vdpau") ||
@@ -2797,10 +3072,11 @@ gst_ffmpegdec_register (GstPlugin * plugin)
         !strcmp (in_plugin->name, "vc1_vdpau") ||
         !strcmp (in_plugin->name, "wmv3_vdpau")) {
       GST_DEBUG
-          ("Ignoring VDPAU decoder %s. We can't handle this outside of ffmpeg",
+          ("Ignoring VDPAU decoder %s, since we don't have the vdpau plugins",
           in_plugin->name);
       goto next;
     }
+#endif
 
     GST_DEBUG ("Trying plugin %s [%s]", in_plugin->name, in_plugin->long_name);
 
