commit f679677babd595777ba30f32448396b1b92a1a6c
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Tue Sep 22 11:03:26 2009 +0000

    Implement a real GnashTexture cache. Properly transfer VaapiSurface to the texture for improved performance.

commit c5888e8f93d62497f423cd7153ec1508c46b7af5
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Tue Sep 22 11:02:33 2009 +0000

    Cleanups. Add GnashTextureFormat helper.

commit d601ec0e92b787d80659ea8f0b9acc24f4f69097
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Tue Sep 22 11:01:42 2009 +0000

    Simplify VaapiSurfaceGLX::update() function.

commit 331bdfefeeaf54709b9addaf7a902b00755a74d6
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Tue Sep 22 11:01:18 2009 +0000

    Drop obsolete GnashGLImage object.

commit 807037ef15d08ed666be1437b300b88ddd0caea8
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Tue Sep 22 11:00:20 2009 +0000

    Add GnashVaapiTexture abstraction.

commit ada718d95d36e5ed38b09d756a7093f47e9b0530
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Tue Sep 22 10:57:56 2009 +0000

    Make it possible to enable (default) or disable VA API support from a configure option: --enable-vaapi.

commit bcc8a0d94de14ba61169cd19fab2e9f32b8f3e24
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Tue Sep 22 10:57:33 2009 +0000

    Add VA/GLX display abstraction.

commit 007a2b217dbc24b9a20b0a66562cb2b3915b3126
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Mon Sep 21 16:36:05 2009 +0000

    Add (basic) texture cache.

commit c02aab48f3842e4206c692e98f76daae6855970e
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Mon Sep 21 16:33:21 2009 +0000

    Return size accessors.

commit 5664bc5fc66b97ed82a6fb74d6d958cea100683e
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Mon Sep 21 16:26:15 2009 +0000

    Add VA/GLX abstraction.

commit 3fa2f69ee80c94a93c97203b8b7846834d177681
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Mon Sep 21 16:24:56 2009 +0000

    Add VA/GLX configury.

commit 52b117799811dde1a0efef5fe0f23e36a8114dab
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Mon Sep 21 16:05:16 2009 +0000

    Rename GnashGLTexture to GnashTexture.

commit e53135df9a2303e30645ffcfdb4023f9452cb5a0
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Mon Sep 21 14:22:08 2009 +0000

    VaapiSurface now takes care of colorspace conversion.

commit 280bd81be7c6607f26bfd16b5b444a238321fdb2
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Mon Sep 21 14:21:35 2009 +0000

    Add VaapiSurface::getPixelsRGBA() and ::getPixelsRGB().

commit 895379a9caf855727251a376a21c8d27e773f377
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Mon Sep 21 12:02:13 2009 +0000

    Use new GnashVaapiImage object.

commit f74a9c5fda1f153141f73a5f57f2450000dfd272
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Mon Sep 21 12:00:36 2009 +0000

    Add GnashVaapiImage abstraction.

commit 63e3cdfe084a1c4ff2bd78bf2246c112e4b20b12
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Mon Sep 21 11:53:47 2009 +0000

    Extend GnashImage to record the image data location (CPU, GPU).

commit a754f07eadab142182a1e04636a81c4eb3e8a799
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Mon Sep 21 08:22:35 2009 +0000

    Add VaapiSurfaceProxy object used to automatically relinquish the surface back to the context.

commit 5c254b4a8dfdf12cad81e20e4086ebd21687a938
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Mon Sep 21 00:18:09 2009 +0000

    Use new libgnashvaapi library.

commit 891a4e8fb4309a52cafa5fdf72f74d9760684049
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Mon Sep 21 00:17:22 2009 +0000

    Add new libgnashvaapi library.

commit 7ce5d4f73765e14d33158708df84c2910ae8e65f
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Fri Sep 18 15:47:17 2009 +0000

    Move vaapi_check_status() to VaapiGlobalContext.{h,cpp}.

commit bacdfd4c4436a05ddc94e82380ca1d3758c08f74
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Fri Sep 18 14:10:51 2009 +0000

    Implement GnashGLTexture used to retain a GL texture as long as possible.

commit ba75133bcf5531b6779bde49eeaf68955963215b
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Fri Sep 18 12:19:44 2009 +0000

    Fix run-time check for VA API acceleration.

commit c2122e92d8070809b1125b93508b72198b423c1e
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Fri Sep 18 11:49:58 2009 +0000

    Use new VaapiGlobalContext and drop VA VTable, use functions directly.

commit a7bcbe4de204b59be60727d6b0f37b63910edd6d
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Fri Sep 18 11:44:03 2009 +0000

    Implement global VA context.

commit f31a461cf56c136c76877fdba84ae092d497bdb3
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Fri Sep 18 09:05:29 2009 +0000

    Rework VA API configury.

commit 5f9680cd2b2bde835d94593d134540d96c71c5c1
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Tue Sep 15 11:50:53 2009 +0000

    Make it possible to disable VA API at runtime.

commit c8cfc227ae07761472cfcb055128371cd37108f5
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Tue Sep 15 11:44:38 2009 +0000

    Fix loading of libVA.

commit 6dcd362b71db123bb1593b734dacd90c81fcf4ad
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Tue Sep 15 09:22:45 2009 +0000

    Add support for VA API 0.31.

commit 483c439e626d49dfe58d8654eaf9ee5be8d19275
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Tue Sep 15 09:13:04 2009 +0000

    Fix check for VA API and report it in the configure summary.

commit d539a1c491fec883207562d9b1453d8a3d0f595b
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Mon Jun 15 13:36:12 2009 +0000

    Add initial VA API support through decoded frames readback (slow).

commit 6e689e1d71e07755d92e49e950f157d079074321
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Mon Jun 15 13:33:45 2009 +0000

    Fix buffer allocation in AudioDecoderFfmpeg::decodeFrame().

commit a09dae25a10154e24bcca938e1899c5c119fd71f
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Fri Sep 18 07:56:40 2009 +0000

    Disable (slow) anti-aliasing code with the accumulation buffer.

commit 417de4ea10411fe5647bb43ccf6869ec600b7e9e
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Fri Sep 18 07:49:52 2009 +0000

    Drop _video_indices array now that we use a plain GL texture for video rendering. In other words, further objects can now be rendered above the video frame.

commit 5c8ba32d7dbabf81f6904159c0ab58c5aa010737
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Fri Sep 18 07:46:48 2009 +0000

    Rewrite drawVideoFrame() with GnashGLImage.

commit c38c06b6e3c241152bd2694bdcdaef95116103b2
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Fri Sep 18 07:45:33 2009 +0000

    Add GnashGLImage object. This is a GnashImage wrapper with a texture used to store pixels data.

commit d03196bea880f4e2afba8c40463de869f24d7f77
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Fri Sep 18 07:18:24 2009 +0000

    Fix draw_subshape() to disable environment mapping when we are done with it.

commit 9ba81e7444e1e0627245e9a93de206a67b02d622
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Fri Sep 18 07:15:10 2009 +0000

    Fix scaled window mode.

commit b4516b52875647c2b6f3dd66d06c8bd683869fe9
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Fri Sep 18 08:07:58 2009 +0000

    Update to Gnash bzr rev 11514.

commit aed1793e89615b0ec38695e7d2e2dab51d2fa002
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Tue Sep 15 08:11:12 2009 +0000

    Update to Gnash bzr rev 11511.

commit 378d16788fc4a0769e1e152db6aaf5d1613c6663
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Mon Aug 10 14:54:13 2009 +0000

    Update to Gnash bzr rev 11404.

commit dc163c9124fadfee87c506856b32715bf94b65f8
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Mon Jun 15 13:31:20 2009 +0000

    Update to Gnash bzr rev 11112.

commit 5b67f070f3eba34ca45789b17412ee9281925e38
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Tue Apr 7 07:48:11 2009 +0000

    Initial import of Gnash trunk rev 10778.
diff --git a/Makefile.am b/Makefile.am
index 34f3282..f299cc7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -41,8 +41,14 @@ DISTCHECK_CONFIGURE_FLAGS = \
 	--disable-testsuite
 #--enable-cygnal
 
+STD_DIRS =
 
-STD_DIRS = \
+# XXX: build libgnashvaapi.la first
+if USE_VAAPI
+STD_DIRS += libvaapi
+endif
+
+STD_DIRS += \
 	libbase \
 	libamf \
 	libnet \
diff --git a/backend/Renderer_ogl.cpp b/backend/Renderer_ogl.cpp
index 3c08e7a..6312d9d 100644
--- a/backend/Renderer_ogl.cpp
+++ b/backend/Renderer_ogl.cpp
@@ -27,6 +27,7 @@
 #include "gnash.h"
 #include "RGBA.h"
 #include "GnashImage.h"
+#include "GnashTexture.h"
 #include "GnashNumeric.h"
 #include "log.h"
 #include "utility.h"
@@ -41,6 +42,14 @@
 #include <boost/utility.hpp>
 #include <boost/bind.hpp>
 
+#if USE_VAAPI_GLX
+#  include "GnashVaapiImage.h"
+#  include "GnashVaapiTexture.h"
+#endif
+
+// Defined to 1 to disable (slow) anti-aliasing with the accumulation buffer
+#define NO_ANTIALIASING 1
+
 /// \file Renderer_ogl.cpp
 /// \brief The OpenGL renderer and related code.
 ///
@@ -671,6 +680,73 @@ public:
       }
   }
 
+  boost::shared_ptr<GnashTexture> getCachedTexture(GnashImage *frame)
+  {
+      boost::shared_ptr<GnashTexture> texture;
+      GnashTextureFormat frameFormat(frame->type());
+      unsigned int frameFlags;
+
+      switch (frame->location()) {
+      case GNASH_IMAGE_CPU:
+	  frameFlags = 0;
+	  break;
+#if USE_VAAPI_GLX
+      case GNASH_IMAGE_GPU:
+	  frameFlags = GNASH_TEXTURE_VAAPI;
+	  break;
+#endif
+      default:
+	  assert(0);
+	  return texture;
+      }
+
+      // Look for a texture with the same dimensions and type
+      std::list< boost::shared_ptr<GnashTexture> >::iterator it;
+      for (it = _cached_textures.begin(); it != _cached_textures.end(); it++) {
+	  if ((*it)->width() == frame->width() &&
+	      (*it)->height() == frame->height() &&
+	      (*it)->internal_format() == frameFormat.internal_format() &&
+	      (*it)->format() == frameFormat.format() &&
+	      (*it)->flags() == frameFlags)
+	      break;
+      }
+
+      // Found texture and remove it from cache. It will be pushed
+      // back into the cache when rendering is done, in end_display()
+      if (it != _cached_textures.end()) {
+	  texture = *it;
+	  _cached_textures.erase(it);
+      }
+
+      // Otherwise, create one and empty cache because they may no
+      // longer be referenced
+      else {
+	  _cached_textures.clear();
+
+	  switch (frame->location()) {
+	  case GNASH_IMAGE_CPU:
+	      texture.reset(new GnashTexture(frame->width(),
+					     frame->height(),
+					     frame->type()));
+	      break;
+#if USE_VAAPI_GLX
+	  case GNASH_IMAGE_GPU:
+	      texture.reset(new GnashVaapiTexture(frame->width(),
+						  frame->height(),
+						  frame->type()));
+	      break;
+#endif
+	  }
+      }
+
+      assert(texture->width() == frame->width());
+      assert(texture->height() == frame->height());
+      assert(texture->internal_format() == frameFormat.internal_format());
+      assert(texture->format() == frameFormat.format());
+      assert(texture->flags() == frameFlags);
+      return texture;
+  }
+
   // Since we store drawing operations in display lists, we take special care
   // to store video frame operations in their own display list, lest they be
   // anti-aliased with the rest of the drawing. Since display lists cannot be
@@ -691,14 +767,33 @@ public:
 
     glEndList();
 
+    boost::shared_ptr<GnashTexture> texture = getCachedTexture(frame);
+    if (!texture.get())
+	return;
+
+    switch (frame->location()) {
+    case GNASH_IMAGE_CPU:
+	texture->update(frame->data());
+	break;
+#if USE_VAAPI_GLX
+    case GNASH_IMAGE_GPU:
+	dynamic_cast<GnashVaapiTexture *>(texture.get())->update(dynamic_cast<GnashVaapiImage *>(frame)->surface());
+	break;
+#endif
+    default:
+	assert(0);
+	return;
+    }
+    _render_textures.push_back(texture);
+
     glGenLists(2);
 
     ++index;
 
     glNewList(index, GL_COMPILE);
-    _video_indices.push_back(index);
+    _render_indices.push_back(index);
 
-    reallyDrawVideoFrame(frame, m, bounds);
+    reallyDrawVideoFrame(texture, m, bounds);
 
     glEndList();
 
@@ -707,57 +802,34 @@ public:
     glNewList(index, GL_COMPILE);
     _render_indices.push_back(index);
   }
-  
-  virtual void reallyDrawVideoFrame(GnashImage* frame, const SWFMatrix* m, const rect* bounds)
-  {
-  
-    if (frame->type() == GNASH_IMAGE_RGBA)
-    {
-        LOG_ONCE(log_error(_("Can't render videos with alpha")));
-        return;
-    }
-  
-    assert(frame->type() == GNASH_IMAGE_RGB);
 
+private:  
+  void reallyDrawVideoFrame(boost::shared_ptr<GnashTexture> texture, const SWFMatrix* m, const rect* bounds)
+  {
     glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT);
-
-
-    glMatrixMode(GL_COLOR);
     glPushMatrix();
 
-    glLoadIdentity();
-    glPixelTransferf(GL_GREEN_BIAS, 0.0);
-    glPixelTransferf(GL_BLUE_BIAS, 0.0);
-
-    gnash::point a, b, c, d;
-    m->transform(&a, gnash::point(bounds->get_x_min(), bounds->get_y_min()));
-    m->transform(&b, gnash::point(bounds->get_x_max(), bounds->get_y_min()));
-    m->transform(&c, gnash::point(bounds->get_x_min(), bounds->get_y_max()));
-    d.x = b.x + c.x - a.x;
-    d.y = b.y + c.y - a.y;
-
-    float w_bounds = twipsToPixels(b.x - a.x);
-    float h_bounds = twipsToPixels(c.y - a.y);
-
-    unsigned char*   ptr = frame->data();
-    float xpos = a.x < 0 ? 0.0f : a.x;  //hack
-    float ypos = a.y < 0 ? 0.0f : a.y;  //hack
-    glRasterPos2f(xpos, ypos);  //hack
-
-    size_t height = frame->height();
-    size_t width = frame->width();
-    float zx = w_bounds / (float) width;
-    float zy = h_bounds / (float) height;
-    glPixelZoom(zx,  -zy);  // flip & zoom image
-    glDrawPixels(width, height, GL_RGB, GL_UNSIGNED_BYTE, ptr);
+    gnash::point l, u;
+    m->transform(&l, point(bounds->get_x_min(), bounds->get_y_min()));
+    m->transform(&u, point(bounds->get_x_max(), bounds->get_y_max()));
+    const unsigned int w = u.x - l.x;
+    const unsigned int h = u.y - l.y;
 
-    glPopMatrix();
+    texture->bind();
+    glTranslatef(l.x, l.y, 0.0f);
+    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+    glBegin(GL_QUADS);
+    {
+	glTexCoord2f(0.0f, 0.0f); glVertex2i(0, 0);
+	glTexCoord2f(0.0f, 1.0f); glVertex2i(0, h);
+	glTexCoord2f(1.0f, 1.0f); glVertex2i(w, h);
+	glTexCoord2f(1.0f, 0.0f); glVertex2i(w, 0);
+    }
+    glEnd();
+    texture->release();
 
+    glPopMatrix();
     glPopAttrib();
-
-    // Restore the default SWFMatrix mode.
-    glMatrixMode(GL_MODELVIEW); 
-    
   }
 
   // FIXME
@@ -778,6 +850,7 @@ public:
     return point(pixelsToTwips(x), pixelsToTwips(y));
   }
 
+public:
   virtual void  begin_display(
     const rgba& bg_color,
     int viewport_x0, int viewport_y0,
@@ -791,6 +864,9 @@ public:
     
     _width  = fabsf(x1 - x0);
     _height = fabsf(y1 - y0);
+    glScalef((float)twipsToPixels(_width) / (float)viewport_width,
+	     (float)twipsToPixels(_height) / (float)viewport_height,
+	     1.0f);
 
     // Setup the clear color. The actual clearing will happen in end_display.
     if (bg_color.m_a) {
@@ -813,6 +889,12 @@ public:
   {
     glEndList();    
     
+#if NO_ANTIALIASING
+    // Don't use accumulation buffer based anti-aliasing
+    glClear(GL_COLOR_BUFFER_BIT);
+    glCallLists(_render_indices.size(), GL_UNSIGNED_BYTE,
+		&_render_indices.front());
+#else
     // This is a table of randomly generated numbers between -0.5 and 0.5.
     struct {
       GLfloat x;
@@ -856,12 +938,7 @@ public:
     }
     
     glAccum (GL_RETURN, 1.0);
-    
-    if (!_video_indices.empty()) {
-      // there's a video frame (or several) to draw, without anti-aliasing.
-      glCallLists(_video_indices.size(), GL_UNSIGNED_BYTE,
-                  &_video_indices.front());
-    }  
+#endif
   
   #if 0
     GLint box[4];
@@ -875,9 +952,12 @@ public:
     glRectd(x, y - h, x + w, y + h);
   #endif
 
-    glDeleteLists(1, _render_indices.size() + _video_indices.size());
+    glDeleteLists(1, _render_indices.size());
     _render_indices.clear();
-    _video_indices.clear();
+
+    for (int i = 0; i < _render_textures.size(); i++)
+	_cached_textures.push_front(_render_textures[i]);
+    _render_textures.clear();
   
     check_error();
 
@@ -1589,6 +1669,8 @@ public:
         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
       }
       
+      glDisable(GL_TEXTURE_GEN_S);
+      glDisable(GL_TEXTURE_GEN_T);    
       glDisable(GL_TEXTURE_1D);
       glDisable(GL_TEXTURE_2D);      
     }
@@ -1734,7 +1816,8 @@ private:
   bool _drawing_mask;
   
   std::vector<boost::uint8_t> _render_indices;
-  std::vector<boost::uint8_t> _video_indices;
+  std::vector< boost::shared_ptr<GnashTexture> > _render_textures;
+  std::list< boost::shared_ptr<GnashTexture> > _cached_textures;
   
 #ifdef OSMESA_TESTING
   std::auto_ptr<OSRenderMesa> _offscreen;
diff --git a/configure.ac b/configure.ac
index da9895f..3054f3a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -930,6 +930,7 @@ AM_CONDITIONAL(LIBLTDL2, [test $ltmajor -eq 2])
 AM_CONDITIONAL(INSTALL_LTDL, test x"${enable_ltdl_install-no}" != xno)
 AM_CONDITIONAL(CONVENIENCE_LTDL, test x"${enable_ltdl_convenience-no}" != xno)
 
+AC_C_BIGENDIAN
 AC_C_CONST
 AC_C_INLINE
 AC_SUBST([LIBTOOL_DEPS])
@@ -2033,6 +2034,76 @@ if test x"$media_handler" = x"ffmpeg"; then
   fi
 fi
 
+dnl Check for VA API
+AC_ARG_ENABLE(vaapi,
+    AC_HELP_STRING([--enable-vaapi],
+                   [Enable Video Acceleration support (default=yes)]),
+    [], [enable_vaapi="yes"])
+
+GNASH_PKG_FIND([libswscale],
+    [libswscale/swscale.h],
+    [SW Scaler],
+    sws_getContext,
+    [], [-lswscale]
+)
+GNASH_PKG_FIND([libva],
+    [va/va.h],
+    [Video Acceleration API],
+    vaInitialize
+)
+GNASH_PKG_FIND([libva_x11],
+    [va/va_x11.h],
+    [VA API (X11 display)],
+    vaGetDisplay,
+    [], [-lva-x11]
+)
+GNASH_PKG_FIND([libva_glx],
+    [va/va_glx.h],
+    [VA API (GLX display)],
+    vaGetDisplayGLX,
+    [], [-lva-glx]
+)
+
+USE_VAAPI=yes
+USE_VAAPI_GLX=yes
+if test "x$enable_vaapi" != xyes; then
+    USE_VAAPI=no
+    USE_VAAPI_GLX=no
+fi
+if test "x$libswscale" != xyes; then
+    USE_VAAPI=no
+    USE_VAAPI_GLX=no
+fi
+if test "x$libva" != xyes; then
+    USE_VAAPI=no
+    USE_VAAPI_GLX=no
+fi
+if test "x$libva_x11" != xyes; then
+    USE_VAAPI=no
+    USE_VAAPI_GLX=no
+fi
+if test "x$build_ogl" != xyes; then
+    USE_VAAPI_GLX=no
+fi
+if test "x$libva_glx" != xyes; then
+    USE_VAAPI_GLX=no
+fi
+if test "x$USE_VAAPI" = xyes; then
+    use_vaapi=1
+else
+    use_vaapi=0
+fi
+if test "x$USE_VAAPI_GLX" = xyes; then
+    use_vaapi_glx=1
+else
+    use_vaapi_glx=0
+fi
+
+AM_CONDITIONAL(USE_VAAPI, test $use_vaapi = 1)
+AC_DEFINE_UNQUOTED([USE_VAAPI], [$use_vaapi], [Enable VA API])
+AM_CONDITIONAL(USE_VAAPI_GLX, test $use_vaapi_glx = 1)
+AC_DEFINE_UNQUOTED([USE_VAAPI_GLX], [$use_vaapi_glx], [Enable VA API with GLX extensions])
+
 if test x$build_cairo = xyes; then
   GNASH_PKG_FIND(cairo, [cairo.h], [cairo render library], cairo_status)
 dnl   if test x"${CAIRO_CFLAGS}" != x; then
@@ -2368,6 +2439,7 @@ libcore/vm/Makefile
 libcore/parser/Makefile
 libnet/Makefile
 libamf/Makefile
+libvaapi/Makefile
 backend/Makefile
 utilities/Makefile
 doc/Makefile
@@ -2536,6 +2608,7 @@ fi
 echo "        GUI toolkits supported: ${SUPPORTED_GUIS}"
 echo "        Renderers supported: ${add_renderer}"
 echo "        Media handler: "$media_handler
+echo "        Video Acceleration (VA) API support: $USE_VAAPI"
 echo "        Using ${add_sound} for sound handling"
 echo "        Using $with_shm mode for shared memory"
 echo ""
diff --git a/libbase/GnashImage.cpp b/libbase/GnashImage.cpp
index a464cb8..7a3c4f5 100644
--- a/libbase/GnashImage.cpp
+++ b/libbase/GnashImage.cpp
@@ -49,9 +49,10 @@ namespace {
 
 /// Create an image taking ownership of the given buffer height*pitch bytes
 GnashImage::GnashImage(boost::uint8_t* data, int width,
-        int height, int pitch, ImageType type)
+        int height, int pitch, ImageType type, ImageLocation location)
     :
     _type(type),
+    _location(location),
     _size(height*pitch),
     _width(width),
     _height(height),
@@ -62,9 +63,10 @@ GnashImage::GnashImage(boost::uint8_t* data, int width,
 
 /// Create an image allocating a buffer of height*pitch bytes
 GnashImage::GnashImage(int width, int height,
-        int pitch, ImageType type)
+        int pitch, ImageType type, ImageLocation location)
     :
     _type(type),
+    _location(location),
     _size(height*pitch),
     _width(width),
     _height(height),
@@ -84,6 +86,7 @@ void GnashImage::update(const GnashImage& from)
     assert(from._pitch == _pitch);
     assert(_size <= from._size);
     assert(_type == from._type);
+    assert(_location == from._location);
     std::memcpy(data(), from.data(), _size);
 }
 
diff --git a/libbase/GnashImage.h b/libbase/GnashImage.h
index e32018c..b72a877 100644
--- a/libbase/GnashImage.h
+++ b/libbase/GnashImage.h
@@ -56,6 +56,13 @@ enum ImageType
 	GNASH_IMAGE_ALPHA
 };
 
+/// The locations of images handled in Gnash.
+enum ImageLocation
+{
+    GNASH_IMAGE_CPU = 1,
+    GNASH_IMAGE_GPU
+};
+
 
 /// Base class for different types of bitmaps
 //
@@ -70,6 +77,7 @@ public:
     GnashImage(const GnashImage& o) throw (std::bad_alloc)
         :
         _type(o._type),
+        _location(o._location),
         _size(o.size()),
         _width(o.width()),
         _height(o.height()),
@@ -88,7 +96,8 @@ public:
     /// @param pitch    The pitch (rowstride) of the image in bytes.
     /// @param type     The ImageType of the image.
     GnashImage(boost::uint8_t *data, int width, int height,
-            int pitch, ImageType type);
+               int pitch, ImageType type,
+               ImageLocation location = GNASH_IMAGE_CPU);
 
     /// Construct an empty GnashImage
     //
@@ -99,13 +108,19 @@ public:
     /// @param height   The height of the image in pixels.
     /// @param pitch    The pitch (rowstride) of the image in bytes.
     /// @param type     The ImageType of the image.
-    GnashImage(int width, int height, int pitch, ImageType type);
+    GnashImage(int width, int height, int pitch, ImageType type,
+               ImageLocation location = GNASH_IMAGE_CPU);
 
     /// Return the ImageType of the image.
     //
     /// This saves guessing when dynamic_cast is used.
     ImageType type() const { return _type; }
 
+    /// Return the ImageLocation of the image.
+    //
+    /// This saves guessing when dynamic_cast is used.
+    ImageLocation location() const { return _location; }
+
     /// Get the size of the image buffer
     //
     /// @return     The size of the buffer in bytes
@@ -187,6 +202,9 @@ protected:
 
     const ImageType _type;
 
+    /// Image data location (CPU or GPU)
+    const ImageLocation _location;
+
     /// Size of image buffer in bytes.
     const size_t _size;
 
diff --git a/libbase/GnashTexture.cpp b/libbase/GnashTexture.cpp
new file mode 100644
index 0000000..5c75a0b
--- /dev/null
+++ b/libbase/GnashTexture.cpp
@@ -0,0 +1,234 @@
+// GnashTexture.cpp: GnashImage class used for OpenGL rendering
+// 
+//   Copyright (C) 2009 Splitted-Desktop Systems
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "GnashTexture.h"
+#include <GL/gl.h>
+
+#define GL_DEBUG 0
+
+#if GL_DEBUG
+#  define D(x) x
+#else
+#  define D(x)
+#endif
+#define bug printf
+
+namespace gnash {
+
+// Returns a string representation of an OpenGL error
+static const char *gl_get_error_string(GLenum error)
+{
+    static const struct {
+        GLenum val;
+        const char *str;
+    }
+    gl_errors[] = {
+        { GL_NO_ERROR,          "no error" },
+        { GL_INVALID_ENUM,      "invalid enumerant" },
+        { GL_INVALID_VALUE,     "invalid value" },
+        { GL_INVALID_OPERATION, "invalid operation" },
+        { GL_STACK_OVERFLOW,    "stack overflow" },
+        { GL_STACK_UNDERFLOW,   "stack underflow" },
+        { GL_OUT_OF_MEMORY,     "out of memory" },
+#ifdef GL_INVALID_FRAMEBUFFER_OPERATION_EXT
+        { GL_INVALID_FRAMEBUFFER_OPERATION_EXT, "invalid framebuffer operation" },
+#endif
+        { ~0, NULL }
+    };
+
+    int i;
+    for (i = 0; gl_errors[i].str; i++) {
+        if (gl_errors[i].val == error)
+            return gl_errors[i].str;
+    }
+    return "unknown";
+}
+
+static inline bool gl_do_check_error(int report)
+{
+    GLenum error;
+    bool is_error = false;
+    while ((error = glGetError()) != GL_NO_ERROR) {
+        if (report)
+            log_error("glError: %s caught\n", gl_get_error_string(error));
+        is_error = true;
+    }
+    return is_error;
+}
+
+static inline void gl_purge_errors(void)
+{
+    gl_do_check_error(0);
+}
+
+static inline bool gl_check_error(void)
+{
+    return gl_do_check_error(1);
+}
+
+// glGetIntegerv() wrapper
+static bool gl_get_param(GLenum param, unsigned int *pval)
+{
+    GLint val;
+
+    gl_purge_errors();
+    glGetIntegerv(param, &val);
+    if (gl_check_error())
+        return false;
+    if (pval)
+        *pval = val;
+    return true;
+}
+
+// Check for GLX extensions (TFP, FBO)
+static bool check_extension(const char *name, const char *ext)
+{
+    const char *end;
+    int name_len, n;
+
+    if (name == NULL || ext == NULL)
+        return false;
+
+    end = ext + strlen(ext);
+    name_len = strlen(name);
+    while (ext < end) {
+        n = strcspn(ext, " ");
+        if (n == name_len && strncmp(name, ext, n) == 0)
+            return true;
+        ext += (n + 1);
+    }
+    return false;
+}
+
+GnashTextureFormat::GnashTextureFormat(ImageType type)
+{
+    switch (type) {
+    case GNASH_IMAGE_RGB:
+	_internal_format = GL_RGB;
+	_format = GL_RGB;
+	break;
+    case GNASH_IMAGE_RGBA:
+	_internal_format = GL_RGBA;
+	_format = GL_BGRA;
+	break;
+    default:
+	assert(0);
+	break;
+    }
+}
+
+GnashTexture::GnashTexture(unsigned int width, unsigned int height, ImageType type)
+    : _width(width), _height(height), _texture(0), _format(type), _flags(0)
+{
+    D(bug("GnashTexture::GnashTexture()\n"));
+
+    init();
+}
+
+GnashTexture::~GnashTexture()
+{
+    D(bug("GnashTexture::~GnashTexture()\n"));
+
+    if (_texture) {
+	glDeleteTextures(1, &_texture);
+	_texture = 0;
+    }
+}
+
+bool GnashTexture::init()
+{
+    // XXX: we only support NPOT textures
+    const char *gl_extensions = (const char *)glGetString(GL_EXTENSIONS);
+    if (!check_extension("GL_ARB_texture_non_power_of_two", gl_extensions))
+        return false;
+
+    assert(_width > 0);
+    assert(_height > 0);
+    if (_width == 0 || _height == 0)
+	return false;
+
+    glGenTextures(1, &_texture);
+    if (!_texture)
+	return false;
+
+    if (!bind()) {
+	glDeleteTextures(1, &_texture);
+	return false;
+    }
+
+    glPixelStorei(GL_UNPACK_ALIGNMENT, internal_format() == GL_RGBA ? 4 : 1);
+    glTexImage2D(GL_TEXTURE_2D, 0, internal_format(), _width, _height, 0,
+                 format(), GL_UNSIGNED_BYTE, NULL);
+    release();
+    return true;
+}
+
+// Bind texture, preserve previous texture state
+bool GnashTexture::bind()
+{
+    TextureState * const ts = &_texture_state;
+    ts->old_texture = 0;
+    ts->was_bound   = 0;
+    ts->was_enabled = glIsEnabled(GL_TEXTURE_2D);
+
+    if (!ts->was_enabled)
+        glEnable(GL_TEXTURE_2D);
+    else if (gl_get_param(GL_TEXTURE_BINDING_2D, &ts->old_texture))
+	ts->was_bound = _texture == ts->old_texture;
+    else
+        return false;
+
+    if (!ts->was_bound) {
+        gl_purge_errors();
+        glBindTexture(GL_TEXTURE_2D, _texture);
+        if (gl_check_error())
+            return false;
+    }
+
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    return true;
+}
+
+// Release texture, restore previous texture state
+void GnashTexture::release()
+{
+    TextureState * const ts = &_texture_state;
+    if (!ts->was_bound && ts->old_texture)
+        glBindTexture(GL_TEXTURE_2D, ts->old_texture);
+    if (!ts->was_enabled)
+	glDisable(GL_TEXTURE_2D);
+    gl_check_error();
+}
+
+// Update texture with data
+void GnashTexture::update(const boost::uint8_t *data)
+{
+    D(bug("GnashTexture::update(): data %p, size %dx%d\n", data, _width, _height));
+
+    bind();
+    glTexSubImage2D(GL_TEXTURE_2D, 0,
+		    0, 0, _width, _height,
+		    format(), GL_UNSIGNED_BYTE, data);
+    release();
+}
+
+} // gnash namespace
diff --git a/libbase/GnashTexture.h b/libbase/GnashTexture.h
new file mode 100644
index 0000000..de46119
--- /dev/null
+++ b/libbase/GnashTexture.h
@@ -0,0 +1,116 @@
+// GnashTexture.h: GnashImage class used for OpenGL rendering
+// 
+//   Copyright (C) 2009 Splitted-Desktop Systems
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef GNASH_GNASHTEXTURE_H
+#define GNASH_GNASHTEXTURE_H
+
+#include "GnashImage.h"
+#include <boost/shared_ptr.hpp>
+
+namespace gnash {
+
+/// Texture flags
+enum {
+    GNASH_TEXTURE_VAAPI	= 1 << 0,
+};
+
+/// OpenGL texture format
+class DSOEXPORT GnashTextureFormat {
+    unsigned int	_internal_format;
+    unsigned int	_format;
+
+public:
+    GnashTextureFormat(ImageType type);
+
+    /// Return GL internal format
+    unsigned int internal_format() const
+	{ return _internal_format; }
+
+    /// Return GL format
+    unsigned int format() const
+	{ return _format; }
+};
+
+/// OpenGL texture abstraction
+class DSOEXPORT GnashTexture {
+    unsigned int	_width;
+    unsigned int	_height;
+    unsigned int	_texture;
+    GnashTextureFormat	_format;
+
+    /// OpenGL texture state
+    struct TextureState {
+	unsigned int	old_texture;
+	unsigned int	was_enabled : 1;
+	unsigned int	was_bound   : 1;
+    }			_texture_state;
+
+protected:
+    unsigned int	_flags;
+
+private:
+    bool init();
+
+public:
+    GnashTexture(unsigned int width, unsigned int height, ImageType type);
+    virtual ~GnashTexture();
+
+    /// Return texture flags
+    unsigned int flags() const
+	{ return _flags; }
+
+    /// Return texture width
+    unsigned int width() const
+	{ return _width; }
+
+    /// Return texture height
+    unsigned int height() const
+	{ return _height; }
+
+    /// Return GL texture
+    unsigned int texture() const
+	{ return _texture; }
+
+    /// Return GL internal format
+    unsigned int internal_format() const
+	{ return _format.internal_format(); }
+
+    /// Return GL format
+    unsigned int format() const
+	{ return _format.format(); }
+
+    /// Bind texture to a texturing target
+    bool bind();
+
+    /// Release texture
+    void release();
+
+    /// Copy texture data from a buffer.
+    //
+    /// Note that this buffer MUST have the same _pitch, or unexpected things
+    /// will happen. In general, it is only safe to copy from another GnashImage
+    /// (or derivative thereof) or unexpected things will happen. 
+    ///
+    /// @param data buffer to copy data from.
+    void update(const boost::uint8_t *data);
+};
+
+} // gnash namespace
+
+#endif /* GNASH_GNASHTEXTURE_H */
diff --git a/libbase/GnashVaapiImage.cpp b/libbase/GnashVaapiImage.cpp
new file mode 100644
index 0000000..f059671
--- /dev/null
+++ b/libbase/GnashVaapiImage.cpp
@@ -0,0 +1,181 @@
+// GnashVaapiImage.cpp: GnashImage class used with VA API
+// 
+//   Copyright (C) 2009 Splitted-Desktop Systems
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "GnashVaapiImage.h"
+#include "vaapi.h"
+#include <time.h>
+
+#define DEBUG 0
+#include "vaapi_debug.h"
+
+namespace gnash {
+
+/// Get current value of microsecond timer
+static boost::uint64_t get_ticks_usec(void)
+{
+#ifdef HAVE_CLOCK_GETTIME
+    struct timespec t;
+    clock_gettime(CLOCK_REALTIME, &t);
+    return (boost::uint64_t)t.tv_sec * 1000000 + t.tv_nsec / 1000;
+#else
+    struct timeval t;
+    gettimeofday(&t, NULL);
+    return (boost::uint64_t)t.tv_sec * 1000000 + t.tv_usec;
+#endif
+}
+
+/// Get scanline pitch for the specified image type
+static inline int get_pitch(int width, ImageType type)
+{
+    int bytes_per_pixel;
+
+    switch (type) {
+    case GNASH_IMAGE_RGB:
+	bytes_per_pixel = 3;
+	break;
+    case GNASH_IMAGE_RGBA:
+	bytes_per_pixel = 4;
+	break;
+    default:
+	assert(0);
+	bytes_per_pixel = 0;
+	break;
+    }
+    return width * bytes_per_pixel;
+}
+
+GnashVaapiImage::GnashVaapiImage(boost::shared_ptr<VaapiSurface> surface, ImageType type)
+    : GnashImage(NULL, surface->width(), surface->height(), get_pitch(surface->width(), type),
+		 type, GNASH_IMAGE_GPU)
+    , _surface(surface)
+    , _creation_time(get_ticks_usec())
+{
+    D(bug("GnashVaapiImage::GnashVaapiImage(): surface 0x%08x, size %dx%d\n",
+	  _surface->get(), _width, _height));
+}
+
+GnashVaapiImage::GnashVaapiImage(const GnashVaapiImage& o)
+    : GnashImage(NULL, o.width(), o.height(), get_pitch(o.width(), o.type()),
+		 o.type(), GNASH_IMAGE_GPU)
+    , _surface(o.surface())
+    , _creation_time(get_ticks_usec())
+{
+    D(bug("GnashVaapiImage::GnashVaapiImage(): VA image %p\n", &o));
+
+    update(o);
+}
+
+GnashVaapiImage::~GnashVaapiImage()
+{
+    D(bug("GnashVaapiImage::~GnashVaapiImage(): surface 0x%08x\n",
+	  _surface->get()));
+}
+
+std::auto_ptr<GnashImage> GnashVaapiImage::clone()
+{
+    D(bug("GnashVaapiImage::clone(): image %p\n", this));
+
+    return std::auto_ptr<GnashImage>(new GnashVaapiImage(*this));
+}
+
+void GnashVaapiImage::update(boost::shared_ptr<VaapiSurface> surface)
+{
+    _surface = surface;
+    _creation_time = get_ticks_usec();
+}
+
+void GnashVaapiImage::update(boost::uint8_t* data)
+{
+    D(bug("GnashVaapi::update(): data %p\n", data));
+
+    /* XXX: use vaPutImage() */
+    _creation_time = get_ticks_usec();
+}
+
+void GnashVaapiImage::update(const GnashImage& from)
+{
+    assert(_pitch == from.pitch());
+    assert(_size <= from.size());
+    assert(_type == from.type());
+
+    switch (from.location()) {
+    case GNASH_IMAGE_CPU:
+	this->update(const_cast<boost::uint8_t *>(from.data()));
+	break;
+    case GNASH_IMAGE_GPU:
+	this->update(static_cast<const GnashVaapiImage &>(from).surface());
+	break;
+    default:
+	assert(0);
+	break;
+    }
+}
+
+// Transfer (and convert) VA surface to CPU image data
+bool GnashVaapiImage::transfer()
+{
+    boost::uint8_t *pixels;
+
+    switch (_type) {
+    case GNASH_IMAGE_RGB:
+	pixels = _surface->getPixelsRGB();
+	break;
+    case GNASH_IMAGE_RGBA:
+	pixels = _surface->getPixelsRGBA();
+	break;
+    default:
+	assert(0);
+	pixels = NULL;
+    }
+
+    if (!pixels)
+	return false;
+
+    _data.reset(pixels);
+    return true;
+}
+
+// Get access to the underlying data
+boost::uint8_t* GnashVaapiImage::data()
+{
+    D(bug("GnashVaapiImage::data(): surface 0x%08x\n", _surface->get()));
+    D(bug("  -> %u usec from creation\n",
+	  (boost::uint32_t)(get_ticks_usec() - _creation_time)));
+
+    if (!transfer())
+	return NULL;
+
+    return _data.get();
+}
+
+// Get read-only access to the underlying data
+const boost::uint8_t* GnashVaapiImage::data() const
+{
+    D(bug("GnashVaapiImage::data() const: surface 0x%08x\n", _surface->get()));
+    D(bug("  -> %u usec from creation\n",
+	  (boost::uint32_t)(get_ticks_usec() - _creation_time)));
+
+    /* XXX: awful hack... */
+    if (!const_cast<GnashVaapiImage *>(this)->transfer())
+	return NULL;
+
+    return _data.get();
+}
+
+} // gnash namespace
diff --git a/libbase/GnashVaapiImage.h b/libbase/GnashVaapiImage.h
new file mode 100644
index 0000000..8fcfd6d
--- /dev/null
+++ b/libbase/GnashVaapiImage.h
@@ -0,0 +1,72 @@
+// GnashVaapiImage.h: GnashImage class used with VA API
+// 
+//   Copyright (C) 2009 Splitted-Desktop Systems
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef GNASH_GNASHVAAPIIMAGE_H
+#define GNASH_GNASHVAAPIIMAGE_H
+
+#include "GnashImage.h"
+#include <boost/shared_ptr.hpp>
+
+namespace gnash {
+
+// Forward declarations
+class VaapiSurface;
+class VaapiSurfaceProxy;
+
+/// GnashImage implementation using a VA surface
+class DSOEXPORT GnashVaapiImage : public GnashImage
+{
+    boost::shared_ptr<VaapiSurface> _surface;
+    boost::uint64_t _creation_time;
+
+    /// Transfer (and convert) VA surface to CPU image data
+    bool transfer();
+
+public:
+    GnashVaapiImage(boost::shared_ptr<VaapiSurface> surface, ImageType type);
+    GnashVaapiImage(const GnashVaapiImage& o);
+    ~GnashVaapiImage();
+
+    virtual std::auto_ptr<GnashImage> clone();
+    virtual void update(boost::shared_ptr<VaapiSurface> surface);
+    virtual void update(boost::uint8_t* data);
+    virtual void update(const GnashImage& from);
+
+    /// Get access to the underlying surface
+    //
+    /// @return     A pointer to the VA surface.
+    boost::shared_ptr<VaapiSurface> surface() const
+	{ return _surface; }
+
+    /// Get access to the underlying data
+    //
+    /// NOTE: This function shall not be used
+    //
+    /// @return     NULL.
+    virtual boost::uint8_t* data();
+
+    /// Get read-only access to the underlying data
+    //
+    /// @return     A read-only pointer to the raw image data.
+    virtual const boost::uint8_t* data() const;
+};
+
+} // gnash namespace
+
+#endif /* GNASH_GNASHVAAPIIMAGE_H */
diff --git a/libbase/GnashVaapiTexture.cpp b/libbase/GnashVaapiTexture.cpp
new file mode 100644
index 0000000..f92b4d0
--- /dev/null
+++ b/libbase/GnashVaapiTexture.cpp
@@ -0,0 +1,44 @@
+// GnashVaapiTexture.cpp: GnashImage class used for VA/GLX rendering
+// 
+//   Copyright (C) 2009 Splitted-Desktop Systems
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "GnashVaapiTexture.h"
+#include "libvaapi/VaapiSurface.h"
+#include "libvaapi/VaapiSurfaceGLX.h"
+#include <GL/gl.h>
+
+namespace gnash {
+
+GnashVaapiTexture::GnashVaapiTexture(unsigned int width, unsigned int height, ImageType type)
+    : GnashTexture(width, height, type)
+{
+    _flags |= GNASH_TEXTURE_VAAPI;
+
+    _surface.reset(new VaapiSurfaceGLX(GL_TEXTURE_2D, texture()));
+}
+
+GnashVaapiTexture::~GnashVaapiTexture()
+{
+}
+
+void GnashVaapiTexture::update(boost::shared_ptr<VaapiSurface> surface)
+{
+    _surface->update(surface);
+}
+
+} // gnash namespace
diff --git a/libbase/GnashVaapiTexture.h b/libbase/GnashVaapiTexture.h
new file mode 100644
index 0000000..8ea17a4
--- /dev/null
+++ b/libbase/GnashVaapiTexture.h
@@ -0,0 +1,50 @@
+// GnashVaapiTexture.h: GnashImage class used for VA/GLX rendering
+// 
+//   Copyright (C) 2009 Splitted-Desktop Systems
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef GNASH_GNASHVAAPITEXTURE_H
+#define GNASH_GNASHVAAPITEXTURE_H
+
+#include "GnashTexture.h"
+
+namespace gnash {
+
+// Forward declarations
+class VaapiSurface;
+class VaapiSurfaceGLX;
+
+/// OpenGL texture abstraction
+class DSOEXPORT GnashVaapiTexture : public GnashTexture {
+    std::auto_ptr<VaapiSurfaceGLX> _surface;
+
+public:
+    GnashVaapiTexture(unsigned int width, unsigned int height, ImageType type);
+    ~GnashVaapiTexture();
+
+    /// Copy texture data from a VA surface.
+    //
+    /// Note that this surface MUST have the same _pitch, or
+    /// unexpected things will happen.
+    ///
+    /// @param surface VA surface to copy data from.
+    void update(boost::shared_ptr<VaapiSurface> surface);
+};
+
+} // gnash namespace
+
+#endif /* GNASH_GNASHVAAPITEXTURE_H */
diff --git a/libbase/Makefile.am b/libbase/Makefile.am
index 338fcb7..bb5bb06 100644
--- a/libbase/Makefile.am
+++ b/libbase/Makefile.am
@@ -201,6 +201,48 @@ endif
 libgnashbase_la_LDFLAGS = -release $(VERSION) 
 libgnashbase_la_DEPENDENCIES = $(LIBLTDLLIB)
 
+if BUILD_OGL_RENDERER
+   libgnashbase_la_SOURCES += \
+	GnashTexture.cpp \
+	$(NULL)
+
+   noinst_HEADERS += \
+	GnashTexture.h \
+	$(NULL)
+endif
+
+if USE_VAAPI
+   libgnashbase_la_SOURCES += \
+	GnashVaapiImage.cpp \
+	$(NULL)
+
+   noinst_HEADERS += \
+	GnashVaapiImage.h \
+	$(NULL)
+
+if USE_VAAPI_GLX
+   libgnashbase_la_SOURCES += \
+	GnashVaapiTexture.cpp \
+	$(NULL)
+
+   noinst_HEADERS += \
+	GnashVaapiTexture.h \
+	$(NULL)
+endif
+
+   libgnashbase_la_CPPFLAGS += \
+	-I$(top_srcdir)/libvaapi \
+	$(NULL)
+
+   libgnashbase_la_LIBADD += \
+	$(top_builddir)/libvaapi/libgnashvaapi.la \
+	$(NULL)
+
+   libgnashbase_la_DEPENDENCIES += \
+	$(top_srcdir)/libvaapi/libgnashvaapi.la \
+	$(NULL)
+endif
+
 if WIN32
   libgnashbase_la_LDFLAGS += -no-undefined
   libgnashbase_la_LIBADD += -lws2_32 -lwinmm
diff --git a/libmedia/Makefile.am b/libmedia/Makefile.am
index 44f7249..8f1a9c0 100644
--- a/libmedia/Makefile.am
+++ b/libmedia/Makefile.am
@@ -161,6 +161,16 @@ if USE_FFMPEG_ENGINE
    libgnashmedia_la_CPPFLAGS += \
 		$(FFMPEG_CFLAGS) \
 		$(NULL)
+
+if USE_VAAPI
+   libgnashmedia_la_SOURCES += \
+		ffmpeg/vaapi.cpp \
+		$(NULL)
+
+   noinst_HEADERS += \
+		ffmpeg/vaapi.h \
+		$(NULL)
+endif
 endif
 
 if HAVE_SPEEX
@@ -178,6 +188,16 @@ endif
 
 libgnashmedia_la_LDFLAGS = -release $(VERSION)
 
+if USE_VAAPI
+   libgnashmedia_la_CPPFLAGS += \
+	-I$(top_srcdir)/libvaapi \
+	$(NULL)
+
+   libgnashmedia_la_LIBADD += \
+	$(top_builddir)/libvaapi/libgnashvaapi.la \
+	$(NULL)
+endif
+
 if WIN32
   libgnashmedia_la_LDFLAGS += -no-undefined
   libgnashmedia_la_LIBADD += \
diff --git a/libmedia/ffmpeg/AudioDecoderFfmpeg.cpp b/libmedia/ffmpeg/AudioDecoderFfmpeg.cpp
index 8d93545..e54948d 100644
--- a/libmedia/ffmpeg/AudioDecoderFfmpeg.cpp
+++ b/libmedia/ffmpeg/AudioDecoderFfmpeg.cpp
@@ -29,6 +29,10 @@
 
 //#define GNASH_DEBUG_AUDIO_DECODING
 
+/* SIMD versions of DSPContext.float_to_int16_interleave() needs input
+   and output buffers aligned to 16-byte boundaries */
+#define NEEDS_ALIGNED_MEMORY 1
+
 #ifdef FFMPEG_AUDIO2
 # define AVCODEC_DECODE_AUDIO avcodec_decode_audio2
 #else
@@ -525,7 +529,23 @@ AudioDecoderFfmpeg::decodeFrame(const boost::uint8_t* input,
     static const unsigned int bufsize = AVCODEC_MAX_AUDIO_FRAME_SIZE;
 
 	// TODO: make this a private member, to reuse (see NetStreamFfmpeg in 0.8.3)
-	boost::uint8_t* output = new boost::uint8_t[bufsize];
+    boost::uint8_t* output;
+
+    if (NEEDS_ALIGNED_MEMORY)
+    {
+	output = reinterpret_cast<boost::uint8_t*>(av_malloc(bufsize));
+	if (output == NULL)
+	{
+	    log_error(_("failed to allocate audio buffer."));
+	    outputSize = 0;
+	    return NULL;
+	}
+    }
+    else
+    {
+	output = new boost::uint8_t[bufsize];
+    }
+
     boost::int16_t* outPtr = reinterpret_cast<boost::int16_t*>(output);
 
 	// We initialize output size to the full size
@@ -554,7 +574,11 @@ AudioDecoderFfmpeg::decodeFrame(const boost::uint8_t* input,
 		log_error(_("avcodec_decode_audio returned %d. Upgrading "
                     "ffmpeg/libavcodec might fix this issue."), tmp);
 		outputSize = 0;
-		delete [] output;
+
+		if (output)
+		    av_free(output);
+		else
+		    delete [] output;
 		return NULL;
 	}
 
@@ -564,7 +588,11 @@ AudioDecoderFfmpeg::decodeFrame(const boost::uint8_t* input,
                     "data. Upgrading ffmpeg/libavcodec might fix this issue."),
 			        outputSize, inputSize);
 		outputSize = 0;
-		delete [] output;
+
+		if (output)
+		    av_free(output);
+		else
+		    delete [] output;
 		return NULL;
 	}
 
@@ -606,7 +634,11 @@ AudioDecoderFfmpeg::decodeFrame(const boost::uint8_t* input,
 
 		// make sure to set outPtr *after* we use it as input to the resampler
         	outPtr = reinterpret_cast<boost::int16_t*>(resampledOutput);
-		delete [] output;
+
+		if (NEEDS_ALIGNED_MEMORY)
+		    av_free(output);
+		else
+		    delete [] output;
 
 		if (expectedMaxOutSamples < outSamples)
 		{
@@ -632,6 +664,12 @@ AudioDecoderFfmpeg::decodeFrame(const boost::uint8_t* input,
 		outSize = outSamples * 2 * 2;
 
 	}
+	else if (NEEDS_ALIGNED_MEMORY)
+	{
+	    boost::uint8_t* newOutput = new boost::uint8_t[outSize];
+	    memcpy(newOutput, output, outSize);
+	    outPtr = reinterpret_cast<boost::int16_t*>(newOutput);
+	}
 
 	outputSize = outSize;
 	return reinterpret_cast<uint8_t*>(outPtr);
diff --git a/libmedia/ffmpeg/VideoDecoderFfmpeg.cpp b/libmedia/ffmpeg/VideoDecoderFfmpeg.cpp
index 5749598..6f58bc6 100644
--- a/libmedia/ffmpeg/VideoDecoderFfmpeg.cpp
+++ b/libmedia/ffmpeg/VideoDecoderFfmpeg.cpp
@@ -45,6 +45,11 @@ extern "C" {
 
 #include "FLVParser.h"
 
+#if USE_VAAPI
+#  include "vaapi.h"
+#  include "GnashVaapiImage.h"
+#endif
+
 namespace gnash {
 namespace media {
 namespace ffmpeg {
@@ -74,6 +79,33 @@ private:
 };
 #endif
 
+class VaapiContextFfmpeg;
+
+static inline VaapiContextFfmpeg *
+get_vaapi_context(AVCodecContext *avctx)
+{
+    return static_cast<VaapiContextFfmpeg *>(avctx->hwaccel_context);
+}
+
+static inline void
+set_vaapi_context(AVCodecContext *avctx, VaapiContextFfmpeg *vactx)
+{
+    avctx->hwaccel_context = vactx;
+}
+
+static inline void
+clear_vaapi_context(AVCodecContext *avctx)
+{
+#if USE_VAAPI
+    VaapiContextFfmpeg * const vactx = get_vaapi_context(avctx);
+    if (!vactx)
+	return;
+
+    delete vactx;
+    set_vaapi_context(avctx, NULL);
+#endif
+}
+
 // A Wrapper ensuring an AVCodecContext is closed and freed
 // on destruction.
 class CodecContextWrapper
@@ -89,6 +121,7 @@ public:
         if (_codecCtx)
         {
             avcodec_close(_codecCtx);
+            clear_vaapi_context(_codecCtx);
             av_free(_codecCtx);
         }
     }
@@ -99,6 +132,101 @@ private:
     AVCodecContext* _codecCtx;
 };
 
+/// (Re)set AVCodecContext to sane values 
+static void
+reset_context(AVCodecContext *avctx, VaapiContextFfmpeg *vactx = NULL)
+{
+    clear_vaapi_context(avctx);
+    set_vaapi_context(avctx, vactx);
+
+    avctx->thread_count = 1;
+    avctx->draw_horiz_band = NULL;
+    if (vactx)
+	avctx->slice_flags = SLICE_FLAG_CODED_ORDER|SLICE_FLAG_ALLOW_FIELD;
+    else
+	avctx->slice_flags = 0;
+}
+
+/// AVCodecContext.get_format() implementation
+static enum PixelFormat
+get_format(AVCodecContext *avctx, const enum PixelFormat *fmt)
+{
+#if USE_VAAPI
+    VaapiContextFfmpeg * const vactx = get_vaapi_context(avctx);
+
+    if (vactx) {
+	for (int i = 0; fmt[i] != PIX_FMT_NONE; i++) {
+	    if (fmt[i] != PIX_FMT_VAAPI_VLD)
+		continue;
+	    if (vactx->initDecoder(avctx->width, avctx->height))
+		return fmt[i];
+	}
+    }
+#endif
+
+    reset_context(avctx);
+    return avcodec_default_get_format(avctx, fmt);
+}
+
+/// AVCodecContext.get_buffer() implementation
+static int
+get_buffer(AVCodecContext *avctx, AVFrame *pic)
+{
+    VaapiContextFfmpeg * const vactx = get_vaapi_context(avctx);
+    if (!vactx)
+	return avcodec_default_get_buffer(avctx, pic);
+
+#if USE_VAAPI
+    if (!vactx->initDecoder(avctx->width, avctx->height))
+	return -1;
+
+    VaapiSurfaceFfmpeg * const surface = vactx->getSurface();
+    if (!surface)
+	return -1;
+    vaapi_set_surface(pic, surface);
+
+    static unsigned int pic_num = 0;
+    pic->type = FF_BUFFER_TYPE_USER;
+    pic->age  = ++pic_num - surface->getPicNum();
+    surface->setPicNum(pic_num);
+    return 0;
+#endif
+    return -1;
+}
+
+/// AVCodecContext.reget_buffer() implementation
+static int
+reget_buffer(AVCodecContext *avctx, AVFrame *pic)
+{
+    VaapiContextFfmpeg * const vactx = get_vaapi_context(avctx);
+
+    if (!vactx)
+	return avcodec_default_reget_buffer(avctx, pic);
+
+    return get_buffer(avctx, pic);
+}
+
+/// AVCodecContext.release_buffer() implementation
+static void
+release_buffer(AVCodecContext *avctx, AVFrame *pic)
+{
+    VaapiContextFfmpeg * const vactx = get_vaapi_context(avctx);
+    if (!vactx) {
+	avcodec_default_release_buffer(avctx, pic);
+	return;
+    }
+
+#if USE_VAAPI
+    VaapiSurfaceFfmpeg * const surface = vaapi_get_surface(pic);
+    if (surface)
+	delete surface;
+
+    pic->data[0] = NULL;
+    pic->data[1] = NULL;
+    pic->data[2] = NULL;
+    pic->data[3] = NULL;
+#endif
+}
 
 VideoDecoderFfmpeg::VideoDecoderFfmpeg(videoCodecType format, int width, int height)
     :
@@ -178,6 +306,17 @@ VideoDecoderFfmpeg::init(enum CodecID codecId, int /*width*/, int /*height*/,
     ctx->extradata = extradata;
     ctx->extradata_size = extradataSize;
 
+    ctx->get_format	= get_format;
+    ctx->get_buffer	= get_buffer;
+    ctx->reget_buffer	= reget_buffer;
+    ctx->release_buffer	= release_buffer;
+
+#if USE_VAAPI
+    VaapiContextFfmpeg *vactx = VaapiContextFfmpeg::create(codecId);
+    if (vactx)
+	reset_context(ctx, vactx);
+#endif
+
     int ret = avcodec_open(ctx, _videoCodec);
     if (ret < 0) {
         boost::format msg = boost::format(_("libavcodec"
@@ -213,8 +352,10 @@ VideoDecoderFfmpeg::height() const
 
 std::auto_ptr<GnashImage>
 VideoDecoderFfmpeg::frameToImage(AVCodecContext* srcCtx,
-                                 const AVFrame& srcFrame)
+                                 const AVFrame& srcFrameRef)
 {
+    const AVFrame *srcFrame = &srcFrameRef;
+    PixelFormat srcPixFmt = srcCtx->pix_fmt;
 
     const int width = srcCtx->width;
     const int height = srcCtx->height;
@@ -228,13 +369,26 @@ VideoDecoderFfmpeg::frameToImage(AVCodecContext* srcCtx,
 
     std::auto_ptr<GnashImage> im;
 
+#if USE_VAAPI
+    VaapiContextFfmpeg * const vactx = get_vaapi_context(srcCtx);
+    if (vactx) {
+	VaapiSurfaceFfmpeg * const vaSurface = vaapi_get_surface(&srcFrameRef);
+	if (!vaSurface) {
+	    im.reset();
+	    return im;
+	}
+	im.reset(new GnashVaapiImage(vaSurface->get(), GNASH_IMAGE_RGBA));
+	return im;
+    }
+#endif
+
 #ifdef HAVE_SWSCALE_H
     // Check whether the context wrapper exists
     // already.
     if (!_swsContext.get()) {
 
         _swsContext.reset(new SwsContextWrapper(
-            sws_getContext(width, height, srcCtx->pix_fmt, width, height,
+            sws_getContext(width, height, srcPixFmt, width, height,
                 pixFmt, SWS_BILINEAR, NULL, NULL, NULL)
         ));
         
@@ -279,8 +433,8 @@ VideoDecoderFfmpeg::frameToImage(AVCodecContext* srcCtx,
     avpicture_fill(&picture, im->data(), pixFmt, width, height);
 
 #ifndef HAVE_SWSCALE_H
-    img_convert(&picture, PIX_FMT_RGB24, (AVPicture*) &srcFrame,
-            srcCtx->pix_fmt, width, height);
+    img_convert(&picture, PIX_FMT_RGB24, (AVPicture*)srcFrame,
+            srcPixFmt, width, height);
 #else
 
     // Is it possible for the context to be reset
@@ -288,8 +442,8 @@ VideoDecoderFfmpeg::frameToImage(AVCodecContext* srcCtx,
     assert(_swsContext->getContext());
 
     int rv = sws_scale(_swsContext->getContext(), 
-            const_cast<uint8_t**>(srcFrame.data),
-            const_cast<int*>(srcFrame.linesize), 0, height, picture.data,
+            const_cast<uint8_t**>(srcFrame->data),
+            const_cast<int*>(srcFrame->linesize), 0, height, picture.data,
             picture.linesize);
 
     if (rv == -1) {
diff --git a/libmedia/ffmpeg/vaapi.cpp b/libmedia/ffmpeg/vaapi.cpp
new file mode 100644
index 0000000..031983a
--- /dev/null
+++ b/libmedia/ffmpeg/vaapi.cpp
@@ -0,0 +1,187 @@
+// vaapi.cpp: VA API acceleration.
+// 
+//     Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA    02110-1301    USA
+
+#include "vaapi.h"
+#include "GnashException.h"
+
+namespace gnash {
+namespace media {
+namespace ffmpeg {
+
+/// Translates FFmpeg Codec ID to VAProfile
+static VAProfile get_profile(enum CodecID codec_id)
+{
+    static const int mpeg2_profiles[] =
+        { VAProfileMPEG2Main, VAProfileMPEG2Simple, -1 };
+    static const int mpeg4_profiles[] =
+        { VAProfileMPEG4Main, VAProfileMPEG4AdvancedSimple, VAProfileMPEG4Simple, -1 };
+    static const int h264_profiles[] =
+        { VAProfileH264High, VAProfileH264Main, VAProfileH264Baseline, -1 };
+    static const int wmv3_profiles[] =
+        { VAProfileVC1Main, VAProfileVC1Simple, -1 };
+    static const int vc1_profiles[] =
+        { VAProfileVC1Advanced, -1 };
+
+    const int *profiles;
+    switch (codec_id) {
+    case CODEC_ID_MPEG2VIDEO:
+	profiles = mpeg2_profiles;
+	break;
+    case CODEC_ID_MPEG4:
+    case CODEC_ID_H263:
+	profiles = mpeg4_profiles;
+	break;
+    case CODEC_ID_H264:
+	profiles = h264_profiles;
+	break;
+    case CODEC_ID_WMV3:
+	profiles = wmv3_profiles;
+	break;
+    case CODEC_ID_VC1:
+	profiles = vc1_profiles;
+	break;
+    default:
+	profiles = NULL;
+	break;
+    }
+
+    if (profiles) {
+	VaapiGlobalContext * const gvactx = VaapiGlobalContext::get();
+	if (gvactx) {
+	    for (int i = 0; profiles[i] != -1; i++) {
+		VAProfile profile = static_cast<VAProfile>(profiles[i]);
+		if (gvactx->hasProfile(profile))
+		    return profile;
+	    }
+	}
+    }
+    return (VAProfile)-1;
+}
+
+/// Translates VA image format to FFmpeg PixelFormat
+static PixelFormat get_pixel_format(VAImageFormat const &image_format)
+{
+    switch (image_format.fourcc) {
+    case VA_FOURCC('N','V','1','2'): return PIX_FMT_NV12;
+    case VA_FOURCC('Y','V','1','2'): return PIX_FMT_YUV420P;
+    case VA_FOURCC('U','Y','V','Y'): return PIX_FMT_UYVY422;
+    case VA_FOURCC('Y','U','Y','V'): return PIX_FMT_YUYV422;
+    }
+    if (image_format.fourcc == VA_FOURCC('R','G','B','A')) {
+	enum {
+#ifdef WORDS_BIGENDIAN
+	    BO_NATIVE = VA_MSB_FIRST,
+	    BO_NONNAT = VA_LSB_FIRST,
+#else
+	    BO_NATIVE = VA_LSB_FIRST,
+	    BO_NONNAT = VA_MSB_FIRST,
+#endif
+	};
+	static const struct {
+	    enum PixelFormat	pix_fmt;
+	    unsigned char	byte_order;
+	    unsigned char	bits_per_pixel;
+	    unsigned int	red_mask;
+	    unsigned int	green_mask;
+	    unsigned int	blue_mask;
+	}
+	pix_fmt_map[] = {
+	    { PIX_FMT_BGR32, BO_NATIVE, 32, 0x000000ff, 0x0000ff00, 0x00ff0000 },
+	    { PIX_FMT_BGR32, BO_NONNAT, 32, 0xff000000, 0x00ff0000, 0x0000ff00 },
+	    { PIX_FMT_RGB32, BO_NATIVE, 32, 0x00ff0000, 0x0000ff00, 0x000000ff },
+	    { PIX_FMT_RGB32, BO_NONNAT, 32, 0x0000ff00, 0x00ff0000, 0xff000000 },
+	    { PIX_FMT_NONE, 0, 0, 0, 0, 0 }
+	};
+	for (int i = 0; pix_fmt_map[i].pix_fmt != PIX_FMT_NONE; i++) {
+	    if (pix_fmt_map[i].byte_order == image_format.byte_order &&
+		pix_fmt_map[i].bits_per_pixel == image_format.bits_per_pixel &&
+		pix_fmt_map[i].red_mask == image_format.red_mask &&
+		pix_fmt_map[i].green_mask == image_format.green_mask &&
+		pix_fmt_map[i].blue_mask == image_format.blue_mask)
+		return pix_fmt_map[i].pix_fmt;
+	}
+    }
+    return PIX_FMT_NONE;
+}
+
+/// Build VA image
+VaapiImageFfmpeg::VaapiImageFfmpeg(std::auto_ptr<VaapiImage> image)
+    : _image(image)
+{
+    _pixel_format = get_pixel_format(_image->format());
+
+    memset(&_frame, 0, sizeof(_frame));
+    for (unsigned int i = 0; i < _image->getPlaneCount(); i++) {
+	_frame.data[i]     = _image->getPlane(i);
+	_frame.linesize[i] = _image->getPitch(i);
+    }
+}
+
+/// Attach VA surface to FFmpeg picture
+void vaapi_set_surface(AVFrame *pic, VaapiSurfaceFfmpeg *surface)
+{
+    for (int i = 0; i < 4; i++) {
+        pic->data[i]     = NULL;
+        pic->linesize[i] = 0;
+    }
+
+    if (surface) {
+        pic->data[0] = reinterpret_cast<uint8_t *>(surface);
+        pic->data[3] = reinterpret_cast<uint8_t *>((uintptr_t)surface->get()->get());
+    }
+}
+
+VaapiContextFfmpeg::VaapiContextFfmpeg(enum CodecID codec_id)
+    : _context(new VaapiContext(get_profile(codec_id), VAEntrypointVLD))
+{
+    // FFmpeg's vaapi_context must be zero-initialized
+    memset(this, 0, sizeof(struct vaapi_context));
+}
+
+bool VaapiContextFfmpeg::initDecoder(unsigned int width, unsigned int height)
+{
+    VaapiGlobalContext * const gvactx = VaapiGlobalContext::get();
+    if (!gvactx)
+	return false;
+
+    if (!_context->initDecoder(width, height))
+	return false;
+
+    this->display    = gvactx->display();
+    this->context_id = _context->get();
+    return true;
+}
+
+VaapiContextFfmpeg *VaapiContextFfmpeg::create(enum CodecID codec_id)
+{
+    if (!vaapi_is_enabled())
+	return NULL;
+
+    VaapiContextFfmpeg *vactx;
+    try {
+	vactx = new VaapiContextFfmpeg(codec_id);
+    }
+    catch (...) {
+	vactx = NULL;
+    }
+    return vactx;
+}
+
+} // gnash.media.ffmpeg namespace 
+} // gnash.media namespace 
+} // gnash namespace
diff --git a/libmedia/ffmpeg/vaapi.h b/libmedia/ffmpeg/vaapi.h
new file mode 100644
index 0000000..7a666da
--- /dev/null
+++ b/libmedia/ffmpeg/vaapi.h
@@ -0,0 +1,92 @@
+// vaapi.h: VA API acceleration.
+// 
+//     Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc.
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA    02110-1301    USA
+
+#ifndef GNASH_MEDIA_VAAPI_H
+#define GNASH_MEDIA_VAAPI_H
+
+#include "libvaapi/vaapi.h"
+
+extern "C" {
+#include <libavcodec/avcodec.h>
+#include <libavcodec/vaapi.h>
+}
+
+namespace gnash {
+namespace media {
+namespace ffmpeg {
+
+/// VA image implementation for FFmpeg
+class VaapiImageFfmpeg {
+    std::auto_ptr<VaapiImage>	_image;
+    AVFrame			_frame;
+    PixelFormat			_pixel_format;
+
+public:
+    VaapiImageFfmpeg(std::auto_ptr<VaapiImage> image);
+
+    const AVFrame *getFrame() const
+	{ return _image->getPlane(0) ? &_frame : NULL; }
+
+    PixelFormat getPixelFormat() const
+	{ return _image->getPlane(0) ? _pixel_format : PIX_FMT_NONE; }
+};
+
+/// VA surface implementation for FFmpeg
+class VaapiSurfaceFfmpeg : public VaapiSurfaceProxy {
+    unsigned int _pic_num;
+
+public:
+    VaapiSurfaceFfmpeg(boost::shared_ptr<VaapiSurface> surface,
+		       boost::shared_ptr<VaapiContext> context)
+	: VaapiSurfaceProxy(surface, context), _pic_num(0)
+	{ }
+
+    unsigned int getPicNum() const
+	{ return _pic_num; }
+
+    void setPicNum(unsigned int pic_num)
+	{ _pic_num = pic_num; }
+};
+
+void vaapi_set_surface(AVFrame *pic, VaapiSurfaceFfmpeg *surface);
+
+static inline VaapiSurfaceFfmpeg *vaapi_get_surface(const AVFrame *pic)
+{
+    return reinterpret_cast<VaapiSurfaceFfmpeg *>(pic->data[0]);
+}
+
+/// VA context implementation for FFmpeg
+class VaapiContextFfmpeg : public vaapi_context {
+    boost::shared_ptr<VaapiContext> _context;
+
+public:
+    VaapiContextFfmpeg(enum CodecID codec_id);
+
+    bool initDecoder(unsigned int width, unsigned int height);
+
+    VaapiSurfaceFfmpeg *getSurface()
+	{ return new VaapiSurfaceFfmpeg(_context->acquireSurface(), _context); }
+
+    static VaapiContextFfmpeg *create(enum CodecID codec_id);
+};
+    
+} // gnash.media.ffmpeg namespace 
+} // gnash.media namespace 
+} // gnash namespace
+
+#endif /* GNASH_MEDIA_VAAPI_H */
diff --git a/libvaapi/Makefile.am b/libvaapi/Makefile.am
new file mode 100644
index 0000000..7958409
--- /dev/null
+++ b/libvaapi/Makefile.am
@@ -0,0 +1,85 @@
+# 
+#   Copyright (C) 2009 Splitted-Desktop Systems
+# 
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+# 
+# This program 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 General Public License for more details.
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+AUTOMAKE_OPTIONS = foreign
+
+pkglib_LTLIBRARIES = libgnashvaapi.la
+
+libgnashvaapi_la_CPPFLAGS =	\
+	$(BOOST_CFLAGS)		\
+	$(LIBSWSCALE_CFLAGS)	\
+	$(LIBVA_CFLAGS)		\
+	$(LIBVA_X11_CFLAGS)	\
+	$(NULL)
+
+libgnashvaapi_la_LIBADD =	\
+	$(BOOST_LIBS)		\
+	$(LIBSWSCALE_LIBS)	\
+	$(LIBVA_LIBS)		\
+	$(LIBVA_X11_LIBS)	\
+	$(NULL)
+
+libgnashvaapi_la_SOURCES =	\
+	vaapi.cpp		\
+	vaapi_utils.cpp		\
+	VaapiContext.cpp	\
+	VaapiDisplay.cpp	\
+	VaapiGlobalContext.cpp	\
+	VaapiImage.cpp		\
+	VaapiSurface.cpp	\
+	VaapiSurfaceProxy.cpp	\
+	$(NULL)
+
+noinst_HEADERS =		\
+	vaapi.h			\
+	vaapi_common.h		\
+	vaapi_debug.h		\
+	vaapi_utils.h		\
+	VaapiContext.h		\
+	VaapiDisplay.h		\
+	VaapiDisplayX11.h	\
+	VaapiDisplayGLX.h	\
+	VaapiException.h	\
+	VaapiGlobalContext.h	\
+	VaapiImage.h		\
+	VaapiSurface.h		\
+	VaapiSurfaceGLX.h	\
+	VaapiSurfaceProxy.h	\
+	$(NULL)
+
+if USE_VAAPI_GLX
+libgnashvaapi_la_CPPFLAGS +=	\
+	$(LIBVA_GLX_CFLAGS)	\
+	$(NULL)
+
+libgnashvaapi_la_LIBADD +=	\
+	$(LIBVA_GLX_LIBS)	\
+	$(NULL)
+
+libgnashvaapi_la_SOURCES +=	\
+	VaapiSurfaceGLX.cpp	\
+	$(NULL)
+endif
+
+libgnashvaapi_la_LDFLAGS = -release $(VERSION)
+
+# Rebuild with GCC 4.x Mudflap support
+mudflap:
+	@echo "Rebuilding with GCC Mudflap support"
+	$(MAKE) CXXFLAGS="$(CXXFLAGS) -fmudflap" LDFLAGS="$(LDFLAGS) -lmudflap"
+
+clean-hook:
+	-rm -f core.* *.obj
diff --git a/libvaapi/VaapiContext.cpp b/libvaapi/VaapiContext.cpp
new file mode 100644
index 0000000..3a667b9
--- /dev/null
+++ b/libvaapi/VaapiContext.cpp
@@ -0,0 +1,206 @@
+// VaapiContext.cpp: VA context abstraction
+// 
+//   Copyright (C) 2009 Splitted-Desktop Systems
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "VaapiContext.h"
+#include "VaapiGlobalContext.h"
+#include "VaapiDisplay.h"
+#include "VaapiSurface.h"
+#include "vaapi_utils.h"
+
+#define DEBUG 0
+#include "vaapi_debug.h"
+
+namespace gnash {
+
+/// Translates VAProfile to VaapiCodec
+static VaapiCodec get_codec(VAProfile profile)
+{
+    switch (profile) {
+    case VAProfileMPEG2Simple:
+    case VAProfileMPEG2Main:
+	return VAAPI_CODEC_MPEG2;
+    case VAProfileMPEG4Simple:
+    case VAProfileMPEG4AdvancedSimple:
+    case VAProfileMPEG4Main:
+	return VAAPI_CODEC_MPEG4;
+    case VAProfileH264Baseline:
+    case VAProfileH264Main:
+    case VAProfileH264High:
+	return VAAPI_CODEC_H264;
+    case VAProfileVC1Simple:
+    case VAProfileVC1Main:
+    case VAProfileVC1Advanced:
+	return VAAPI_CODEC_VC1;
+    default:
+	break;
+    }
+    abort();
+    return VAAPI_CODEC_UNKNOWN;
+}
+
+/// Returns number of VA surfaces to create for a specified codec
+static unsigned int get_max_surfaces(VaapiCodec codec)
+{
+    // Number of scratch surfaces beyond those used as reference
+    const unsigned int SCRATCH_SURFACES_COUNT = 8;
+
+    // Make sure pool of created surfaces for H.264 is under 64 MB for 1080p
+    const unsigned int MAX_SURFACE_SIZE   = (1920 * 1080 * 3) / 2;
+    const unsigned int MAX_VIDEO_MEM_SIZE = 64 * 1024 * 1024;
+    const unsigned int MAX_SURFACES_COUNT = MAX_VIDEO_MEM_SIZE / MAX_SURFACE_SIZE;
+
+    unsigned int max_surfaces;
+    max_surfaces = (codec == VAAPI_CODEC_H264 ? 16 : 2) + SCRATCH_SURFACES_COUNT;
+    if (max_surfaces > MAX_SURFACES_COUNT)
+	max_surfaces = MAX_SURFACES_COUNT;
+
+    return max_surfaces;
+}
+
+VaapiContext::VaapiContext(VAProfile profile, VAEntrypoint entrypoint)
+    : _config(VA_INVALID_ID)
+    , _context(VA_INVALID_ID)
+    , _codec(get_codec(profile))
+    , _profile(profile)
+    , _entrypoint(entrypoint)
+    , _picture_width(0), _picture_height(0)
+{
+    D(bug("VaapiContext::VaapiContext(): profile %d, entrypoint %d\n", profile, entrypoint));
+    construct();
+}
+
+VaapiContext::~VaapiContext()
+{
+    D(bug("VaapiContext::~VaapiContext(): context 0x%08x\n", _context));
+    destruct();
+}
+
+bool VaapiContext::construct()
+{
+    VaapiGlobalContext * const gvactx = VaapiGlobalContext::get();
+    if (!gvactx)
+	return false;
+
+    _display = gvactx->display();
+    if (!_display)
+	return false;
+
+    VAStatus status;
+    VAConfigAttrib attrib;
+    attrib.type = VAConfigAttribRTFormat;
+    status = vaGetConfigAttributes(_display, _profile, _entrypoint, &attrib, 1);
+    if (!vaapi_check_status(status, "vaGetConfigAttributes()"))
+        return false;
+    if ((attrib.value & VA_RT_FORMAT_YUV420) == 0)
+        return false;
+
+    VAConfigID config;
+    status = vaCreateConfig(_display, _profile, _entrypoint, &attrib, 1, &config);
+    if (!vaapi_check_status(status, "vaCreateConfig()"))
+	return false;
+
+    _config = config;
+    return true;
+}
+
+void VaapiContext::destruct()
+{
+    destroyContext();
+
+    if (_config != VA_INVALID_ID) {
+	VAStatus status = vaDestroyConfig(_display, _config);
+	vaapi_check_status(status, "vaDestroyConfig()");
+    }
+}
+
+bool VaapiContext::createContext(unsigned int width, unsigned int height)
+{
+    if (_config == VA_INVALID_ID)
+	return false;
+
+    const unsigned int num_surfaces = get_max_surfaces(_codec);
+    std::vector<VASurfaceID> surface_ids;
+    surface_ids.reserve(num_surfaces);
+    for (unsigned int i = 0; i < num_surfaces; i++) {
+	VaapiSurfaceSP surface(new VaapiSurface(width, height));
+	_surfaces.push(surface);
+	surface_ids.push_back(surface->get());
+    }
+
+    VAStatus status;
+    VAContextID context;
+    status = vaCreateContext(_display,
+			     _config,
+			     width, height,
+			     VA_PROGRESSIVE,
+			     &surface_ids[0], surface_ids.size(),
+			     &context);
+    if (!vaapi_check_status(status, "vaCreateContext()"))
+	return false;
+
+    _context		= context;
+    _picture_width	= width;
+    _picture_height	= height;
+    D(bug("  -> context 0x%08x\n", _context));
+    return true;
+}
+
+void VaapiContext::destroyContext()
+{
+    VAStatus status;
+
+    if (_context != VA_INVALID_ID) {
+	status = vaDestroyContext(_display,_context);
+	if (!vaapi_check_status(status, "vaDestroyContext()"))
+	    return;
+	_context = VA_INVALID_ID;
+    }
+
+    for (unsigned int i = 0; i < _surfaces.size(); i++)
+	_surfaces.pop();
+    _picture_width  = 0;
+    _picture_height = 0;
+}
+
+bool VaapiContext::initDecoder(unsigned int width, unsigned int height)
+{
+    if (_picture_width == width && _picture_height == height)
+	return true;
+
+    destroyContext();
+    return createContext(width, height);
+}
+
+/// Get a free surface
+boost::shared_ptr<VaapiSurface> VaapiContext::acquireSurface()
+{
+    boost::shared_ptr<VaapiSurface> surface = _surfaces.front();
+    _surfaces.pop();
+    D(bug("VaapiContext::acquireSurface(): surface 0x%08x\n", surface->get()));
+    return surface;
+}
+
+/// Release surface
+void VaapiContext::releaseSurface(boost::shared_ptr<VaapiSurface> surface)
+{
+    D(bug("VaapiContext::releaseSurface(): surface 0x%08x\n", surface->get()));
+    _surfaces.push(surface);
+}
+
+} // gnash namespace
diff --git a/libvaapi/VaapiContext.h b/libvaapi/VaapiContext.h
new file mode 100644
index 0000000..2a3d66a
--- /dev/null
+++ b/libvaapi/VaapiContext.h
@@ -0,0 +1,79 @@
+// VaapiContext.h: VA context abstraction
+// 
+//   Copyright (C) 2009 Splitted-Desktop Systems
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef GNASH_VAAPICONTEXT_H
+#define GNASH_VAAPICONTEXT_H
+
+#include "vaapi_common.h"
+#include <queue>
+
+namespace gnash {
+
+// Forward declarations
+class VaapiSurface;
+
+/// VA codec
+enum VaapiCodec {
+    VAAPI_CODEC_UNKNOWN,
+    VAAPI_CODEC_MPEG2,
+    VAAPI_CODEC_MPEG4,
+    VAAPI_CODEC_H264,
+    VAAPI_CODEC_VC1
+};
+
+/// VA context abstraction
+class VaapiContext {
+    typedef boost::shared_ptr<VaapiSurface> VaapiSurfaceSP;
+
+    VADisplay                   _display;
+    VAConfigID			_config;
+    VAContextID			_context;
+    VaapiCodec			_codec;
+    VAProfile			_profile;
+    VAEntrypoint		_entrypoint;
+    std::queue<VaapiSurfaceSP>	_surfaces;
+    unsigned int		_picture_width;
+    unsigned int		_picture_height;
+
+    bool construct();
+    void destruct();
+    bool createContext(unsigned int width, unsigned int height);
+    void destroyContext();
+
+public:
+    VaapiContext(VAProfile profile, VAEntrypoint entrypoint);
+    ~VaapiContext();
+
+    /// Initialize VA decoder for the specified picture dimensions
+    bool initDecoder(unsigned int width, unsigned int height);
+
+    /// Return VA context
+    VAContextID get() const
+        { return _context; }
+
+    /// Get a free surface
+    boost::shared_ptr<VaapiSurface> acquireSurface();
+
+    /// Release surface
+    void releaseSurface(boost::shared_ptr<VaapiSurface> surface);
+};
+
+} // gnash namespace
+
+#endif /* GNASH_VAAPICONTEXT_H */
diff --git a/libvaapi/VaapiDisplay.cpp b/libvaapi/VaapiDisplay.cpp
new file mode 100644
index 0000000..c79689f
--- /dev/null
+++ b/libvaapi/VaapiDisplay.cpp
@@ -0,0 +1,53 @@
+// VaapiDisplay.cpp: VA display abstraction
+// 
+//   Copyright (C) 2009 Splitted-Desktop Systems
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "VaapiDisplay.h"
+#include "vaapi_utils.h"
+
+namespace gnash {
+
+VaapiDisplay::VaapiDisplay(VADisplay display)
+    : _display(display)
+{
+    init();
+}
+
+VaapiDisplay::~VaapiDisplay()
+{
+    if (_display)
+	vaTerminate(_display);
+}
+
+bool VaapiDisplay::init()
+{
+    VAStatus status;
+    int major_version, minor_version;
+
+    if (!_display)
+	return false;
+
+    status = vaInitialize(_display, &major_version, &minor_version);
+    if (!vaapi_check_status(status, "vaInitialize()"))
+      return false;
+
+    vaapi_dprintf("VA API version %d.%d\n", major_version, minor_version);
+    return true;
+}
+
+} // gnash namespace
diff --git a/libvaapi/VaapiDisplay.h b/libvaapi/VaapiDisplay.h
new file mode 100644
index 0000000..35c69bf
--- /dev/null
+++ b/libvaapi/VaapiDisplay.h
@@ -0,0 +1,43 @@
+// VaapiDisplay.h: VA display abstraction
+// 
+//   Copyright (C) 2009 Splitted-Desktop Systems
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef GNASH_VAAPIDISPLAY_H
+#define GNASH_VAAPIDISPLAY_H
+
+#include "vaapi_common.h"
+
+namespace gnash {
+
+/// VA display abstraction
+class VaapiDisplay {
+    VADisplay _display;
+
+    bool init();
+
+public:
+    explicit VaapiDisplay(VADisplay display);
+    virtual ~VaapiDisplay();
+
+    VADisplay get() const
+        { return _display; }
+};
+
+} // gnash namespace
+
+#endif /* GNASH_VAAPIDISPLAY_H */
diff --git a/libvaapi/VaapiDisplayGLX.h b/libvaapi/VaapiDisplayGLX.h
new file mode 100644
index 0000000..db17804
--- /dev/null
+++ b/libvaapi/VaapiDisplayGLX.h
@@ -0,0 +1,37 @@
+// VaapiDisplayGLX.h: VA/GLX display representation
+// 
+//   Copyright (C) 2009 Splitted-Desktop Systems
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef GNASH_VAAPIDISPLAYGLX_H
+#define GNASH_VAAPIDISPLAYGLX_H
+
+#include <va/va_glx.h>
+#include "VaapiDisplayX11.h"
+
+namespace gnash {
+
+/// VA/GLX display representation
+struct VaapiDisplayGLX : public X11Display, VaapiDisplay {
+    VaapiDisplayGLX()
+	: VaapiDisplay(vaGetDisplayGLX(X11Display::get()))
+	{ }
+};
+
+} // gnash namespace
+
+#endif /* GNASH_VAAPIDISPLAY_H */
diff --git a/libvaapi/VaapiDisplayX11.h b/libvaapi/VaapiDisplayX11.h
new file mode 100644
index 0000000..8849a07
--- /dev/null
+++ b/libvaapi/VaapiDisplayX11.h
@@ -0,0 +1,52 @@
+// VaapiDisplayX11.h: VA/X11 display representation
+// 
+//   Copyright (C) 2009 Splitted-Desktop Systems
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef GNASH_VAAPIDISPLAYX11_H
+#define GNASH_VAAPIDISPLAYX11_H
+
+#include <va/va_x11.h>
+#include "VaapiDisplay.h"
+
+namespace gnash {
+
+/// X11 display
+class X11Display {
+    Display *_x_display;
+
+public:
+    X11Display()
+	{ _x_display = XOpenDisplay(NULL); }
+
+    ~X11Display()
+	{ if (_x_display) XCloseDisplay(_x_display); }
+
+    Display *get() const
+	{ return _x_display; }
+};
+
+/// VA/X11 display representation
+struct VaapiDisplayX11 : public X11Display, VaapiDisplay {
+    VaapiDisplayX11()
+	: VaapiDisplay(vaGetDisplay(X11Display::get()))
+	{ }
+};
+
+} // gnash namespace
+
+#endif /* GNASH_VAAPIDISPLAY_H */
diff --git a/libvaapi/VaapiException.h b/libvaapi/VaapiException.h
new file mode 100644
index 0000000..ba77977
--- /dev/null
+++ b/libvaapi/VaapiException.h
@@ -0,0 +1,44 @@
+// VaapiException.h: VA exception abstraction
+// 
+//   Copyright (C) 2009 Splitted-Desktop Systems
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef GNASH_VAAPIEXCEPTION_H
+#define GNASH_VAAPIEXCEPTION_H
+
+#include <stdexcept>
+#include <string>
+
+namespace gnash {
+
+/// VA exception abstraction
+struct VaapiException: public std::runtime_error {
+    VaapiException(const std::string & str)
+	: std::runtime_error(str)
+	{ }
+
+    VaapiException()
+	: std::runtime_error("Video Acceleration error")
+	{ }
+
+    virtual ~VaapiException() throw()
+	{ }
+};
+
+} // gnash namespace
+
+#endif /* GNASH_VAAPIEXCEPTION_H */
diff --git a/libvaapi/VaapiGlobalContext.cpp b/libvaapi/VaapiGlobalContext.cpp
new file mode 100644
index 0000000..5751b35
--- /dev/null
+++ b/libvaapi/VaapiGlobalContext.cpp
@@ -0,0 +1,101 @@
+// VaapiGlobalContext.cpp: VA API global context
+// 
+//   Copyright (C) 2009 Splitted-Desktop Systems
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "VaapiGlobalContext.h"
+#include "VaapiDisplayX11.h"
+#if USE_VAAPI_GLX
+#include "VaapiDisplayGLX.h"
+#endif
+#include "vaapi_utils.h"
+
+namespace gnash {
+
+VaapiGlobalContext::VaapiGlobalContext(std::auto_ptr<VaapiDisplay> display)
+    : _display(display)
+{
+    init();
+}
+
+VaapiGlobalContext::~VaapiGlobalContext()
+{
+}
+
+bool
+VaapiGlobalContext::init()
+{
+    VADisplay dpy = display();
+    VAStatus status;
+
+    int num_profiles = 0;
+    _profiles.resize(vaMaxNumProfiles(dpy));
+    status = vaQueryConfigProfiles(dpy, &_profiles[0], &num_profiles);
+    if (!vaapi_check_status(status, "vaQueryConfigProfiles()"))
+	return false;
+    _profiles.resize(num_profiles);
+
+    int num_image_formats = 0;
+    _image_formats.resize(vaMaxNumImageFormats(dpy));
+    status = vaQueryImageFormats(dpy, &_image_formats[0], &num_image_formats);
+    if (!vaapi_check_status(status, "vaQueryImageFormats()"))
+	return false;
+    _image_formats.resize(num_image_formats);
+    return true;
+}
+
+bool
+VaapiGlobalContext::hasProfile(VAProfile profile) const
+{
+    for (unsigned int i = 0; i < _profiles.size(); i++) {
+	if (_profiles[i] == profile)
+	    return true;
+    }
+    return false;
+}
+
+const VAImageFormat *
+VaapiGlobalContext::getImageFormat(boost::uint32_t fourcc) const
+{
+    for (unsigned int i = 0; i < _image_formats.size(); i++) {
+	if (_image_formats[i].fourcc == fourcc)
+	    return &_image_formats[i];
+    }
+    return NULL;
+}
+
+/// A wrapper around a VaapiGlobalContext to ensure it's free'd on destruction.
+VaapiGlobalContext *VaapiGlobalContext::get()
+{
+    static std::auto_ptr<VaapiGlobalContext> vaapi_global_context;
+
+    if (!vaapi_global_context.get()) {
+	std::auto_ptr<VaapiDisplay> dpy;
+	/* XXX: this won't work with multiple renders built-in */
+#if USE_VAAPI_GLX
+	dpy.reset(new VaapiDisplayGLX());
+#else
+	dpy.reset(new VaapiDisplayX11());
+#endif
+	if (!dpy.get())
+	    return NULL;
+	vaapi_global_context.reset(new VaapiGlobalContext(dpy));
+    }
+    return vaapi_global_context.get();
+}
+
+} // gnash namespace
diff --git a/libvaapi/VaapiGlobalContext.h b/libvaapi/VaapiGlobalContext.h
new file mode 100644
index 0000000..b053223
--- /dev/null
+++ b/libvaapi/VaapiGlobalContext.h
@@ -0,0 +1,63 @@
+// VaapiGlobalContext.h: VA API global context
+// 
+//   Copyright (C) 2009 Splitted-Desktop Systems
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef GNASH_VAAPIGLOBALCONTEXT_H
+#define GNASH_VAAPIGLOBALCONTEXT_H
+
+#include "vaapi_common.h"
+#include <vector>
+#include "VaapiDisplay.h"
+
+namespace gnash {
+
+/// VA API global context
+class DSOEXPORT VaapiGlobalContext {
+    std::auto_ptr<VaapiDisplay>	_display;
+    std::vector<VAProfile>	_profiles;
+    std::vector<VAImageFormat>	_image_formats;
+
+    bool init();
+
+public:
+    VaapiGlobalContext(std::auto_ptr<VaapiDisplay> display);
+    ~VaapiGlobalContext();
+
+    /// Get the unique global VA context
+    //
+    /// @return     The global VA context
+    static VaapiGlobalContext *get();
+
+    /// Check VA profile is supported
+    bool hasProfile(VAProfile profile) const;
+
+    /// Get the VA image format matching FOURCC
+    //
+    /// @return     The VA image format
+    const VAImageFormat *getImageFormat(boost::uint32_t fourcc) const;
+
+    /// Get the VA display
+    //
+    /// @return     The VA display
+    VADisplay display() const
+	{ return _display->get(); }
+};
+
+} // gnash namespace
+
+#endif /* GNASH_VAAPIGLOBALCONTEXT_H */
diff --git a/libvaapi/VaapiImage.cpp b/libvaapi/VaapiImage.cpp
new file mode 100644
index 0000000..48f886c
--- /dev/null
+++ b/libvaapi/VaapiImage.cpp
@@ -0,0 +1,167 @@
+// VaapiImage.cpp: VA image abstraction
+// 
+//   Copyright (C) 2009 Splitted-Desktop Systems
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "VaapiImage.h"
+#include "VaapiSurface.h"
+#include "VaapiGlobalContext.h"
+#include "VaapiException.h"
+#include "vaapi_utils.h"
+#include <string.h>
+
+#define DEBUG 0
+#include "vaapi_debug.h"
+
+namespace gnash {
+
+VaapiImage::VaapiImage(const VaapiSurface *surface)
+    : _data(NULL)
+{
+    D(bug("VaapiImage::VaapiImage(): surface 0x%08x\n", surface.get()));
+
+    memset(&_image, 0, sizeof(_image));
+    _image.image_id = VA_INVALID_ID;
+
+    update(surface);
+}
+
+VaapiImage::~VaapiImage()
+{
+    D(bug("VaapiImage::~VaapiImage()\n"));
+
+    destroy();
+}
+
+bool VaapiImage::map()
+{
+    VaapiGlobalContext * const gvactx = VaapiGlobalContext::get();
+    if (!gvactx)
+	return false;
+
+    VAStatus status;
+    status = vaMapBuffer(gvactx->display(), _image.buf, (void **)&_data);
+    return vaapi_check_status(status, "vaMapBuffer()");
+}
+
+bool VaapiImage::unmap()
+{
+    if (!_data)
+	return true;
+
+    _data = NULL;
+
+    VaapiGlobalContext * const gvactx = VaapiGlobalContext::get();
+    if (!gvactx)
+	return false;
+
+    VAStatus status;
+    status = vaUnmapBuffer(gvactx->display(), _image.buf);
+    return vaapi_check_status(status, "vaUnmapBuffer()");
+}
+
+void VaapiImage::destroy()
+{
+    unmap();
+
+    if (_image.image_id == VA_INVALID_ID)
+	return;
+
+    VaapiGlobalContext * const gvactx = VaapiGlobalContext::get();
+    if (!gvactx)
+	return;
+
+    VAStatus status;
+    status = vaDestroyImage(gvactx->display(), _image.image_id);
+    if (!vaapi_check_status(status, "vaDestroyImage()"))
+	return;
+
+    _image.image_id = VA_INVALID_ID;
+}
+
+bool VaapiImage::update(const VaapiSurface *surface)
+{
+    VaapiGlobalContext * const gvactx = VaapiGlobalContext::get();
+    if (!gvactx)
+	return false;
+
+    VAStatus status;
+    status = vaSyncSurface(gvactx->display(), surface->get());
+    if (!vaapi_check_status(status, "vaSyncSurface()"))
+	return false;
+
+    static const boost::uint32_t image_formats[] = {
+	VA_FOURCC('N','V','1','2'),
+	VA_FOURCC('Y','V','1','2'),
+	VA_FOURCC('U','Y','V','Y'),
+	VA_FOURCC('Y','U','Y','V'),
+	VA_FOURCC('R','G','B','A'),
+	0
+    };
+
+    const VAImageFormat *image_format = NULL;
+    for (int i = 0; image_formats[i] != 0; i++) {
+	const VAImageFormat *m = gvactx->getImageFormat(image_formats[i]);
+	if (m) {
+	    image_format = m;
+	    break;
+	}
+    }
+    if (!image_format)
+	return false;
+
+    unmap();
+
+    if (_image.width != surface->width() ||
+	_image.height != surface->height() ||
+	_image.format.fourcc != image_format->fourcc) {
+	/* XXX: check RGBA formats further */
+
+	destroy();
+
+	status = vaCreateImage(gvactx->display(),
+			       const_cast<VAImageFormat *>(image_format),
+			       surface->width(), surface->height(),
+			       &_image);
+	if (!vaapi_check_status(status, "vaCreateImage()"))
+	    return false;
+    }
+
+    status = vaGetImage(gvactx->display(), surface->get(),
+			0, 0, surface->width(), surface->height(),
+			_image.image_id);
+    if (!vaapi_check_status(status, "vaGetImage()"))
+	return false;
+
+    return map();
+}
+
+// Get pixels for the specified plane
+boost::uint8_t *VaapiImage::getPlane(int plane) const
+{
+    assert(_image.image_id != VA_INVALID_ID);
+    return _data ? &_data[_image.offsets[plane]] : NULL;
+}
+
+// Get scanline pitch for the specified plane
+unsigned int VaapiImage::getPitch(int plane) const
+{   
+    assert(_image.image_id != VA_INVALID_ID);
+    return _image.pitches[plane];
+}
+
+} // gnash namespace
diff --git a/libvaapi/VaapiImage.h b/libvaapi/VaapiImage.h
new file mode 100644
index 0000000..00960f0
--- /dev/null
+++ b/libvaapi/VaapiImage.h
@@ -0,0 +1,67 @@
+// VaapiImage.h: VA image abstraction
+// 
+//   Copyright (C) 2009 Splitted-Desktop Systems
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef GNASH_VAAPIIMAGE_H
+#define GNASH_VAAPIIMAGE_H
+
+#include "vaapi_common.h"
+
+namespace gnash {
+
+// Forward declarations
+class VaapiSurface;
+
+/// VA image data
+class VaapiImage {
+    VAImage		_image;
+    boost::uint8_t *	_data;
+
+    bool map();
+    bool unmap();
+    void destroy();
+
+public:
+    VaapiImage(const VaapiSurface *surface);
+    ~VaapiImage();
+
+    /// Update VA image with surface
+    bool update(const VaapiSurface *surface);
+
+    /// Get image type (FOURCC)
+    boost::uint32_t fourcc() const
+	{ return _image.format.fourcc; }
+
+    /// Get VA image format
+    const VAImageFormat &format() const
+	{ return _image.format; }
+
+    /// Get number of planes
+    unsigned int getPlaneCount() const
+	{ return _image.num_planes; }
+
+    /// Get pixels for the specified plane
+    boost::uint8_t *getPlane(int plane) const;
+
+    /// Get scanline pitch for the specified plane
+    unsigned int getPitch(int plane) const;
+};
+
+} // gnash namespace
+
+#endif /* GNASH_VAAPIIMAGE_H */
diff --git a/libvaapi/VaapiSurface.cpp b/libvaapi/VaapiSurface.cpp
new file mode 100644
index 0000000..d458c7d
--- /dev/null
+++ b/libvaapi/VaapiSurface.cpp
@@ -0,0 +1,211 @@
+// VaapiSurface.cpp: VA surface abstraction
+// 
+//   Copyright (C) 2009 Splitted-Desktop Systems
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "VaapiSurface.h"
+#include "VaapiGlobalContext.h"
+#include "VaapiImage.h"
+#include "vaapi_utils.h"
+
+extern "C" {
+#include <libswscale/swscale.h>
+}
+
+#define DEBUG 0
+#include "vaapi_debug.h"
+
+namespace gnash {
+
+/// A wrapper around an SwsContet that ensures it's freed on destruction.
+class SwsContextWrapper {
+    SwsContext *_context;
+
+public:
+    SwsContextWrapper(SwsContext *context)
+	: _context(context)
+	{ }
+
+    ~SwsContextWrapper()
+	{ sws_freeContext(_context); }
+
+    SwsContext *get() const
+	{ return _context; }
+};
+
+/// Get scanline pitch for the specified image type
+static inline int get_pitch(int width, bool rgba)
+{
+    return (rgba ? 4 : 3) * width;
+}
+
+/// Translates VA image format to FFmpeg PixelFormat
+static PixelFormat get_pixel_format(VAImageFormat const &image_format)
+{
+    switch (image_format.fourcc) {
+    case VA_FOURCC('N','V','1','2'): return PIX_FMT_NV12;
+    case VA_FOURCC('Y','V','1','2'): return PIX_FMT_YUV420P;
+    case VA_FOURCC('U','Y','V','Y'): return PIX_FMT_UYVY422;
+    case VA_FOURCC('Y','U','Y','V'): return PIX_FMT_YUYV422;
+    }
+    if (image_format.fourcc == VA_FOURCC('R','G','B','A')) {
+	enum {
+#ifdef WORDS_BIGENDIAN
+	    BO_NATIVE = VA_MSB_FIRST,
+	    BO_NONNAT = VA_LSB_FIRST,
+#else
+	    BO_NATIVE = VA_LSB_FIRST,
+	    BO_NONNAT = VA_MSB_FIRST,
+#endif
+	};
+	static const struct {
+	    enum PixelFormat	pix_fmt;
+	    unsigned char	byte_order;
+	    unsigned char	bits_per_pixel;
+	    unsigned int	red_mask;
+	    unsigned int	green_mask;
+	    unsigned int	blue_mask;
+	}
+	pix_fmt_map[] = {
+	    { PIX_FMT_BGR32, BO_NATIVE, 32, 0x000000ff, 0x0000ff00, 0x00ff0000 },
+	    { PIX_FMT_BGR32, BO_NONNAT, 32, 0xff000000, 0x00ff0000, 0x0000ff00 },
+	    { PIX_FMT_RGB32, BO_NATIVE, 32, 0x00ff0000, 0x0000ff00, 0x000000ff },
+	    { PIX_FMT_RGB32, BO_NONNAT, 32, 0x0000ff00, 0x00ff0000, 0xff000000 },
+	    { PIX_FMT_NONE, 0, 0, 0, 0, 0 }
+	};
+	for (int i = 0; pix_fmt_map[i].pix_fmt != PIX_FMT_NONE; i++) {
+	    if (pix_fmt_map[i].byte_order == image_format.byte_order &&
+		pix_fmt_map[i].bits_per_pixel == image_format.bits_per_pixel &&
+		pix_fmt_map[i].red_mask == image_format.red_mask &&
+		pix_fmt_map[i].green_mask == image_format.green_mask &&
+		pix_fmt_map[i].blue_mask == image_format.blue_mask)
+		return pix_fmt_map[i].pix_fmt;
+	}
+    }
+    return PIX_FMT_NONE;
+}
+
+VaapiSurfaceImplBase::VaapiSurfaceImplBase(unsigned int width, unsigned int height)
+    : _surface(VA_INVALID_SURFACE), _width(width), _height(height)
+{
+}
+
+class VaapiSurfaceImpl: public VaapiSurfaceImplBase {
+    const VaapiSurface *		_surface;
+    std::auto_ptr<VaapiImage>		_image;
+    bool				_image_rgba;
+    std::auto_ptr<SwsContextWrapper>	_swsContext;
+
+public:
+    VaapiSurfaceImpl(const VaapiSurface *surface, unsigned int width, unsigned int height);
+    ~VaapiSurfaceImpl();
+
+    /// Get surface pixels in RGB or RGBA format
+    //
+    /// NOTE: data array is allocated with new[] and shall be freed
+    virtual boost::uint8_t *getPixels(bool rgba);
+};
+
+VaapiSurfaceImpl::VaapiSurfaceImpl(const VaapiSurface *surface,
+				   unsigned int width, unsigned int height)
+    : VaapiSurfaceImplBase(width, height)
+    , _surface(surface)
+{
+    D(bug("VaapiSurface::VaapiSurface()\n"));
+
+    if (width == 0 || height == 0)
+	return;
+
+    VaapiGlobalContext * gvactx = VaapiGlobalContext::get();
+    if (!gvactx)
+	return;
+
+    VAStatus status;
+    VASurfaceID surface_id;
+    status = vaCreateSurfaces(gvactx->display(),
+			      width, height, VA_RT_FORMAT_YUV420,
+			      1, &surface_id);
+    if (!vaapi_check_status(status, "vaCreateSurfaces()"))
+	return;
+
+    reset(surface_id);
+    D(bug("  -> surface 0x%08x\n", surface()));
+}
+
+VaapiSurfaceImpl::~VaapiSurfaceImpl()
+{
+    D(bug("VaapiSurface::~VaapiSurface(): surface 0x%08x\n", surface()));
+
+    if (surface() == VA_INVALID_SURFACE)
+	return;
+
+    VaapiGlobalContext * gvactx = VaapiGlobalContext::get();
+    if (!gvactx)
+	return;
+
+    VAStatus status;
+    VASurfaceID surface_id = surface();
+    status = vaDestroySurfaces(gvactx->display(), &surface_id, 1);
+    if (!vaapi_check_status(status, "vaDestroySurfaces()"))
+	return;
+
+    reset(VA_INVALID_SURFACE);
+}
+
+boost::uint8_t *VaapiSurfaceImpl::getPixels(bool rgba)
+{
+    if (_image.get())
+	_image->update(_surface);
+    else
+	_image.reset(new VaapiImage(_surface));
+
+    const PixelFormat srcPixFmt = get_pixel_format(_image->format());
+    const PixelFormat dstPixFmt = rgba ? PIX_FMT_RGBA : PIX_FMT_RGB24;
+
+    if (!_swsContext.get() || (_image_rgba ^ rgba) != 0)
+	_swsContext.reset(new SwsContextWrapper(
+			      sws_getContext(width(), height(), srcPixFmt,
+					     width(), height(), dstPixFmt,
+					     SWS_BILINEAR,
+					     NULL, NULL, NULL)));
+    _image_rgba = rgba;
+
+    boost::int32_t srcPitch[4];
+    boost::uint8_t *srcData[4];
+
+    for (unsigned int i = 0; i < _image->getPlaneCount(); i++) {
+	srcData[i]  = _image->getPlane(i);
+	srcPitch[i] = _image->getPitch(i);
+    }
+
+    boost::int32_t dstPitch = get_pitch(width(), rgba);
+    boost::uint8_t *dstData = new boost::uint8_t[height() * dstPitch];
+
+    if (sws_scale(_swsContext->get(),
+		  srcData, srcPitch, 0, height(),
+		  &dstData, &dstPitch) < 0)
+	return NULL;
+
+    return dstData;
+}
+
+VaapiSurface::VaapiSurface(unsigned width, unsigned int height)
+    : _impl(new VaapiSurfaceImpl(this, width, height))
+{
+}
+
+} // gnash namespace
diff --git a/libvaapi/VaapiSurface.h b/libvaapi/VaapiSurface.h
new file mode 100644
index 0000000..b254aa0
--- /dev/null
+++ b/libvaapi/VaapiSurface.h
@@ -0,0 +1,97 @@
+// VaapiSurface.h: VA surface abstraction
+// 
+//   Copyright (C) 2009 Splitted-Desktop Systems
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef GNASH_VAAPISURFACE_H
+#define GNASH_VAAPISURFACE_H
+
+#include "vaapi_common.h"
+
+namespace gnash {
+
+// Forward declarations
+class VaapiImage;
+
+/// VA surface base representation
+class VaapiSurfaceImplBase {
+    uintptr_t		_surface;
+    unsigned int	_width;
+    unsigned int	_height;
+
+protected:
+    void reset(uintptr_t surface)
+	{ _surface = surface; }
+
+public:
+    VaapiSurfaceImplBase(unsigned int width, unsigned int height);
+    virtual ~VaapiSurfaceImplBase() { }
+
+    /// Get VA surface
+    uintptr_t surface() const
+        { return _surface; }
+
+    /// Get surface width
+    unsigned int width() const
+        { return _width; }
+
+    /// Get surface height
+    unsigned int height() const
+        { return _height; }
+
+    /// Get surface pixels in RGB or RGBA format
+    //
+    /// NOTE: data array is allocated with new[] and shall be freed
+    virtual boost::uint8_t *getPixels(bool rgba = true)
+	{ return NULL; }
+};
+
+/// VA surface abstraction
+class VaapiSurface {
+    std::auto_ptr<VaapiSurfaceImplBase> _impl;
+
+public:
+    VaapiSurface(unsigned int width, unsigned int height);
+
+    /// Return VA surface id
+    VASurfaceID get() const
+        { return static_cast<VASurfaceID>(_impl->surface()); }
+
+    /// Get surface width
+    unsigned int width() const
+        { return _impl->width(); }
+
+    /// Get surface height
+    unsigned int height() const
+        { return _impl->height(); }
+
+    /// Get surface pixels in RGB format
+    //
+    /// NOTE: data array is allocated with new[] and shall be freed
+    boost::uint8_t *getPixelsRGB()
+	{ return _impl->getPixels(false); }
+
+    /// Get surface pixels in RGBA format
+    //
+    /// NOTE: data array is allocated with new[] and shall be freed
+    boost::uint8_t *getPixelsRGBA()
+	{ return _impl->getPixels(true); }
+};
+
+} // gnash namespace
+
+#endif /* GNASH_VAAPISURFACE_H */
diff --git a/libvaapi/VaapiSurfaceGLX.cpp b/libvaapi/VaapiSurfaceGLX.cpp
new file mode 100644
index 0000000..d1fbbb3
--- /dev/null
+++ b/libvaapi/VaapiSurfaceGLX.cpp
@@ -0,0 +1,244 @@
+// VaapiSurfaceGLX.cpp: VA/GLX surface abstraction
+// 
+//   Copyright (C) 2009 Splitted-Desktop Systems
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "VaapiSurfaceGLX.h"
+#include "VaapiGlobalContext.h"
+#include "vaapi_utils.h"
+#include <va/va_glx.h>
+
+#define DEBUG 0
+#include "vaapi_debug.h"
+
+namespace gnash {
+
+// Returns a string representation of an OpenGL error
+static const char *gl_get_error_string(GLenum error)
+{
+    static const struct {
+        GLenum val;
+        const char *str;
+    }
+    gl_errors[] = {
+        { GL_NO_ERROR,          "no error" },
+        { GL_INVALID_ENUM,      "invalid enumerant" },
+        { GL_INVALID_VALUE,     "invalid value" },
+        { GL_INVALID_OPERATION, "invalid operation" },
+        { GL_STACK_OVERFLOW,    "stack overflow" },
+        { GL_STACK_UNDERFLOW,   "stack underflow" },
+        { GL_OUT_OF_MEMORY,     "out of memory" },
+#ifdef GL_INVALID_FRAMEBUFFER_OPERATION_EXT
+        { GL_INVALID_FRAMEBUFFER_OPERATION_EXT, "invalid framebuffer operation" },
+#endif
+        { ~0, NULL }
+    };
+
+    int i;
+    for (i = 0; gl_errors[i].str; i++) {
+        if (gl_errors[i].val == error)
+            return gl_errors[i].str;
+    }
+    return "unknown";
+}
+
+static inline bool gl_do_check_error(int report)
+{
+    GLenum error;
+    bool is_error = false;
+    while ((error = glGetError()) != GL_NO_ERROR) {
+        if (report)
+            vaapi_dprintf("glError: %s caught\n", gl_get_error_string(error));
+        is_error = true;
+    }
+    return is_error;
+}
+
+static inline void gl_purge_errors(void)
+{
+    gl_do_check_error(0);
+}
+
+static inline bool gl_check_error(void)
+{
+    return gl_do_check_error(1);
+}
+
+// glGetIntegerv() wrapper
+static bool gl_get_param(GLenum param, unsigned int *pval)
+{
+    GLint val;
+
+    gl_purge_errors();
+    glGetIntegerv(param, &val);
+    if (gl_check_error())
+        return false;
+    if (pval)
+        *pval = val;
+    return true;
+}
+
+/// OpenGL texture state
+struct TextureState {
+    unsigned int target;
+    unsigned int old_texture;
+    unsigned int was_enabled : 1;
+    unsigned int was_bound   : 1;
+};
+
+/// Bind texture, preserve previous texture state
+static bool bind_texture(TextureState *ts, GLenum target, GLuint texture)
+{
+    ts->target      = target;
+    ts->old_texture = 0;
+    ts->was_bound   = 0;
+    ts->was_enabled = glIsEnabled(target);
+
+    GLenum texture_binding;
+    switch (target) {
+    case GL_TEXTURE_1D:
+        texture_binding = GL_TEXTURE_BINDING_1D;
+        break;
+    case GL_TEXTURE_2D:
+        texture_binding = GL_TEXTURE_BINDING_2D;
+        break;
+    case GL_TEXTURE_3D:
+        texture_binding = GL_TEXTURE_BINDING_3D;
+        break;
+    case GL_TEXTURE_RECTANGLE_ARB:
+        texture_binding = GL_TEXTURE_BINDING_RECTANGLE_ARB;
+        break;
+    default:
+        assert(!target);
+        return false;
+    }
+
+    if (!ts->was_enabled)
+        glEnable(target);
+    else if (gl_get_param(texture_binding, &ts->old_texture))
+	ts->was_bound = texture == ts->old_texture;
+    else
+        return false;
+
+    if (!ts->was_bound) {
+        gl_purge_errors();
+        glBindTexture(target, texture);
+        if (gl_check_error())
+            return false;
+    }
+    return true;
+}
+
+/// Release texture, restore previous texture state
+static void unbind_texture(TextureState *ts)
+{
+    if (!ts->was_bound && ts->old_texture)
+        glBindTexture(ts->target, ts->old_texture);
+    if (!ts->was_enabled)
+	glDisable(ts->target);
+    gl_check_error();
+}
+
+class VaapiSurfaceGLXImpl: public VaapiSurfaceImplBase {
+    void *surface() const
+	{ return reinterpret_cast<void *>(VaapiSurfaceImplBase::surface()); }
+
+public:
+    VaapiSurfaceGLXImpl(GLenum target, GLuint texture);
+    ~VaapiSurfaceGLXImpl();
+
+    bool update(boost::shared_ptr<VaapiSurface> surface);
+};
+
+VaapiSurfaceGLXImpl::VaapiSurfaceGLXImpl(GLenum target, GLuint texture)
+    : VaapiSurfaceImplBase(0, 0)
+{
+    D(bug("VaapiSurfaceGLX::VaapiSurfaceGLX()\n"));
+
+    reset(0);
+
+    if (target == 0 || texture == 0)
+	return;
+
+    VaapiGlobalContext * gvactx = VaapiGlobalContext::get();
+    if (!gvactx)
+	return;
+
+    VAStatus status;
+    void *surface = NULL;
+    status = vaCreateSurfaceGLX(gvactx->display(), target, texture, &surface);
+    if (!vaapi_check_status(status, "vaCreateSurfaceGLX()"))
+	return;
+
+    reset(reinterpret_cast<uintptr_t>(surface));
+    D(bug("  -> surface %p\n", this->surface()));
+}
+
+VaapiSurfaceGLXImpl::~VaapiSurfaceGLXImpl()
+{
+    D(bug("VaapiSurface::~VaapiSurface(): surface %p\n", surface()));
+
+    if (!surface())
+	return;
+
+    VaapiGlobalContext * gvactx = VaapiGlobalContext::get();
+    if (!gvactx)
+	return;
+
+    VAStatus status;
+    status = vaDestroySurfaceGLX(gvactx->display(), surface());
+    if (!vaapi_check_status(status, "vaDestroySurfaceGLX()"))
+	return;
+
+    reset(0);
+}
+
+bool VaapiSurfaceGLXImpl::update(boost::shared_ptr<VaapiSurface> surface)
+{
+    if (!this->surface())
+	return false;
+
+    VaapiGlobalContext * gvactx = VaapiGlobalContext::get();
+    if (!gvactx)
+	return false;
+
+    VAStatus status;
+    status = vaSyncSurface(gvactx->display(), surface->get());
+    if (!vaapi_check_status(status, "vaSyncSurface()"))
+	return false;
+
+    status = vaCopySurfaceGLX(gvactx->display(), this->surface(),
+			      surface->get(), VA_FRAME_PICTURE);
+    if (!vaapi_check_status(status, "vaCopySurfaceGLX()"))
+	return false;
+
+    return true;
+}
+
+VaapiSurfaceGLX::VaapiSurfaceGLX(GLenum target, GLuint texture)
+    : _impl(new VaapiSurfaceGLXImpl(target, texture))
+{
+}
+
+bool VaapiSurfaceGLX::update(boost::shared_ptr<VaapiSurface> surface)
+{
+    D(bug("VaapiSurfaceGLX::update(): from surface 0x%08x\n", surface->get()));
+
+    return dynamic_cast<VaapiSurfaceGLXImpl *>(_impl.get())->update(surface);
+}
+
+} // gnash namespace
diff --git a/libvaapi/VaapiSurfaceGLX.h b/libvaapi/VaapiSurfaceGLX.h
new file mode 100644
index 0000000..c74d7e2
--- /dev/null
+++ b/libvaapi/VaapiSurfaceGLX.h
@@ -0,0 +1,54 @@
+// VaapiSurfaceGLX.h: VA/GLX surface abstraction
+// 
+//   Copyright (C) 2009 Splitted-Desktop Systems
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef GNASH_VAAPISURFACEGLX_H
+#define GNASH_VAAPISURFACEGLX_H
+
+#include "vaapi_common.h"
+#include "VaapiSurface.h"
+#include <GL/gl.h>
+
+namespace gnash {
+
+/// VA/GLX surface abstraction
+class VaapiSurfaceGLX {
+    std::auto_ptr<VaapiSurfaceImplBase> _impl;
+
+public:
+    VaapiSurfaceGLX(GLenum target, GLuint texture);
+
+    /// Return VA surface id
+    void *get() const
+        { return reinterpret_cast<void *>(_impl->surface()); }
+
+    /// Get surface width
+    unsigned int width() const
+        { return _impl->width(); }
+
+    /// Get surface height
+    unsigned int height() const
+        { return _impl->height(); }
+
+    /// Update VA/GLX surface from VA surface
+    bool update(boost::shared_ptr<VaapiSurface> surface);
+};
+
+} // gnash namespace
+
+#endif /* GNASH_VAAPISURFACEGLX_H */
diff --git a/libvaapi/VaapiSurfaceProxy.cpp b/libvaapi/VaapiSurfaceProxy.cpp
new file mode 100644
index 0000000..c4624bd
--- /dev/null
+++ b/libvaapi/VaapiSurfaceProxy.cpp
@@ -0,0 +1,50 @@
+// VaapiSurfaceProxy.cpp: VA surface proxy
+// 
+//   Copyright (C) 2009 Splitted-Desktop Systems
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "VaapiSurfaceProxy.h"
+#include "VaapiSurface.h"
+#include "VaapiImage.h"
+#include "VaapiContext.h"
+
+#define DEBUG 0
+#include "vaapi_debug.h"
+
+namespace gnash {
+
+VaapiSurfaceProxy::VaapiSurfaceProxy(boost::shared_ptr<VaapiSurface> surface,
+				     boost::shared_ptr<VaapiContext> context)
+    : _context(context), _surface(surface)
+{
+    D(bug("VaapiSurfaceProxy::VaapiSurfaceProxy(): surface 0x%08x\n", _surface->get()));
+}
+
+VaapiSurfaceProxy::~VaapiSurfaceProxy()
+{
+    D(bug("VaapiSurfaceProxy::~VaapiSurfaceProxy(): surface 0x%08x\n", _surface->get()));
+    _context->releaseSurface(_surface);
+}
+
+// Return VA image
+std::auto_ptr<VaapiImage> VaapiSurfaceProxy::getImage() const
+{
+    std::auto_ptr<VaapiImage> image(new VaapiImage(_surface.get()));
+    return image;
+}
+
+} // gnash namespace
diff --git a/libvaapi/VaapiSurfaceProxy.h b/libvaapi/VaapiSurfaceProxy.h
new file mode 100644
index 0000000..269c056
--- /dev/null
+++ b/libvaapi/VaapiSurfaceProxy.h
@@ -0,0 +1,56 @@
+// VaapiSurfaceProxy.h: VA surface proxy
+// 
+//   Copyright (C) 2009 Splitted-Desktop Systems
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef GNASH_VAAPISURFACEPROXY_H
+#define GNASH_VAAPISURFACEPROXY_H
+
+#include "vaapi_common.h"
+
+namespace gnash {
+
+// Forward declarations
+class VaapiContext;
+class VaapiSurface;
+class VaapiImage;
+
+/// VA surface proxy used to release surface to context
+class VaapiSurfaceProxy {
+    boost::shared_ptr<VaapiContext> _context;
+    boost::shared_ptr<VaapiSurface> _surface;
+
+public:
+    VaapiSurfaceProxy(boost::shared_ptr<VaapiSurface> surface,
+		      boost::shared_ptr<VaapiContext> context);
+    ~VaapiSurfaceProxy();
+
+    /// Return VA surface
+    boost::shared_ptr<VaapiSurface> get() const
+	{ return _surface; }
+
+    /// Return VA context
+    boost::shared_ptr<VaapiContext> getContext() const
+	{ return _context; }
+
+    /// Return VA image
+    std::auto_ptr<VaapiImage> getImage() const;
+};
+
+} // gnash namespace
+
+#endif /* GNASH_VAAPISURFACEPROXY_H */
diff --git a/libvaapi/vaapi.cpp b/libvaapi/vaapi.cpp
new file mode 100644
index 0000000..248ac20
--- /dev/null
+++ b/libvaapi/vaapi.cpp
@@ -0,0 +1,71 @@
+// vaapi.c: VA API wrapper
+// 
+//   Copyright (C) 2009 Splitted-Desktop Systems
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "vaapi.h"
+#include <stdlib.h>
+#include <string.h>
+
+namespace gnash {
+
+/// Parse ENV environment variable expecting "yes" | "no" values
+static bool
+getenv_yesno(const char *env, int *pval)
+{
+    const char *env_str = getenv(env);
+    if (!env_str)
+	return false;
+
+    int val;
+    if (strcmp(env_str, "1") == 0 || strcmp(env_str, "yes") == 0)
+	val = 1;
+    else if (strcmp(env_str, "0") == 0 || strcmp(env_str, "no") == 0)
+	val = 0;
+    else
+	return false;
+
+    if (pval)
+	*pval = val;
+    return true;
+}
+
+static int g_vaapi_is_enabled = -1;
+
+// Enable video acceleration (with VA API)
+void vaapi_enable()
+{
+    g_vaapi_is_enabled = 1;
+}
+
+// Disable video acceleration (with VA API)
+void vaapi_disable()
+{
+    g_vaapi_is_enabled = 0;
+}
+
+// Check whether video acceleration is enabled
+bool vaapi_is_enabled()
+{
+    if (g_vaapi_is_enabled < 0) {
+	if (!getenv_yesno("GNASH_VAAPI", &g_vaapi_is_enabled))
+	    g_vaapi_is_enabled = 1;
+    }
+    return g_vaapi_is_enabled;
+}
+
+} // gnash namespace
diff --git a/libvaapi/vaapi.h b/libvaapi/vaapi.h
new file mode 100644
index 0000000..2ff1f2b
--- /dev/null
+++ b/libvaapi/vaapi.h
@@ -0,0 +1,45 @@
+// vaapi.h: VA API wrapper
+// 
+//   Copyright (C) 2009 Splitted-Desktop Systems
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef GNASH_VAAPI_H
+#define GNASH_VAAPI_H
+
+#include "vaapi_common.h"
+#include "vaapi_utils.h"
+#include "VaapiGlobalContext.h"
+#include "VaapiContext.h"
+#include "VaapiSurface.h"
+#include "VaapiSurfaceProxy.h"
+#include "VaapiImage.h"
+#include "VaapiException.h"
+
+namespace gnash {
+
+/// Enable video acceleration (with VA API)
+void DSOEXPORT vaapi_enable();
+
+/// Disable video acceleration (with VA API)
+void DSOEXPORT vaapi_disable();
+
+/// Check whether video acceleration is enabled
+bool DSOEXPORT vaapi_is_enabled();
+
+} // gnash namespace
+
+#endif /* GNASH_VAAPI_H */
diff --git a/libvaapi/vaapi_common.h b/libvaapi/vaapi_common.h
new file mode 100644
index 0000000..dba08b8
--- /dev/null
+++ b/libvaapi/vaapi_common.h
@@ -0,0 +1,34 @@
+// vaapi_common.h: VA API common (internal) includes and definitions
+// 
+//   Copyright (C) 2009 Splitted-Desktop Systems
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef GNASH_VAAPI_COMMON_H
+#define GNASH_VAAPI_COMMON_H
+
+#ifdef HAVE_CONFIG_H
+#include "gnashconfig.h"
+#endif
+
+#include <va/va.h>
+#include <memory>
+#include <stdint.h> /* XXX: uintptr_t */
+#include <boost/cstdint.hpp>
+#include <boost/shared_ptr.hpp>
+#include "libbase/dsodefs.h"
+
+#endif /* GNASH_VAAPI_COMMON_H */
diff --git a/libvaapi/vaapi_debug.h b/libvaapi/vaapi_debug.h
new file mode 100644
index 0000000..66a9040
--- /dev/null
+++ b/libvaapi/vaapi_debug.h
@@ -0,0 +1,32 @@
+// vaapi_debug.h: Debugging utilities
+// 
+//   Copyright (C) 2009 Splitted-Desktop Systems
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef GNASH_VAAPI_DEBUG_H
+#define GNASH_VAAPI_DEBUG_H
+
+#include <stdio.h>
+
+#if DEBUG
+#  define D(x) x
+#else
+#  define D(x)
+#endif
+#define bug printf
+
+#endif /* GNASH_VAAPI_DEBUG_H */
diff --git a/libvaapi/vaapi_utils.cpp b/libvaapi/vaapi_utils.cpp
new file mode 100644
index 0000000..ba93208
--- /dev/null
+++ b/libvaapi/vaapi_utils.cpp
@@ -0,0 +1,46 @@
+// vaapi_utils.cpp: VA API utilities
+// 
+//   Copyright (C) 2009 Splitted-Desktop Systems
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "vaapi_utils.h"
+#include <stdio.h>
+#include <stdarg.h>
+
+namespace gnash {
+
+// Debug output
+void DSOEXPORT vaapi_dprintf(const char *format, ...)
+{
+    va_list args;
+    va_start(args, format);
+    fprintf(stdout, "[GnashVaapi] ");
+    vfprintf(stdout, format, args);
+    va_end(args);
+}
+
+// Check VA status for success or print out an error
+bool vaapi_check_status(VAStatus status, const char *msg)
+{
+    if (status != VA_STATUS_SUCCESS) {
+	vaapi_dprintf("%s: %s\n", msg, vaErrorStr(status));
+	return false;
+    }
+    return true;
+}
+
+} // gnash namespace
diff --git a/libvaapi/vaapi_utils.h b/libvaapi/vaapi_utils.h
new file mode 100644
index 0000000..edd2c48
--- /dev/null
+++ b/libvaapi/vaapi_utils.h
@@ -0,0 +1,35 @@
+// vaapi_utils.h: VA API utilities
+// 
+//   Copyright (C) 2009 Splitted-Desktop Systems
+// 
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program 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 General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef GNASH_VAAPI_UTILS_H
+#define GNASH_VAAPI_UTILS_H
+
+#include "vaapi_common.h"
+
+namespace gnash {
+
+/// Debug output
+void DSOEXPORT vaapi_dprintf(const char *format, ...);
+
+/// Check VA status for success or print out an error
+bool DSOEXPORT vaapi_check_status(VAStatus status, const char *msg);
+
+} // gnash namespace
+
+#endif /* GNASH_VAAPI_UTILS_H */
