commit ec714b1defbf8810de9f905d748020193f02de3b
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 f6e96e78ea71506ad794cd8cc1569badc7d92db7
Author: Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>
Date:   Mon Jun 15 13:33:45 2009 +0000

    Fix buffer allocation in AudioDecoderFfmpeg::decodeFrame().

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/configure.ac b/configure.ac
index 6603f37..9208bcf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -923,6 +923,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])
@@ -2010,6 +2011,12 @@ if test x"$media_handler" = x"ffmpeg"; then
   fi
 fi
 
+GNASH_PKG_FIND([libva], [va/va_x11.h], [Video Acceleration API], vaGetDisplay)
+AM_CONDITIONAL(USE_VAAPI, test "x$libva" = xyes)
+if test "x$libva" = xyes; then
+  AC_DEFINE([USE_VAAPI], 1, [Enable VA API])
+fi
+
 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
diff --git a/libmedia/Makefile.am b/libmedia/Makefile.am
index 93c2c08..df316b2 100644
--- a/libmedia/Makefile.am
+++ b/libmedia/Makefile.am
@@ -142,6 +142,12 @@ if USE_FFMPEG_ENGINE
 		ffmpeg/VideoConverterFfmpeg.cpp \
 		$(NULL)
 
+if USE_VAAPI
+   libgnashmedia_la_SOURCES += \
+		ffmpeg/vaapi.cpp \
+		$(NULL)
+endif
+
    noinst_HEADERS += \
 		ffmpeg/MediaHandlerFfmpeg.h \
 		ffmpeg/MediaParserFfmpeg.h \
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..9a6900a 100644
--- a/libmedia/ffmpeg/VideoDecoderFfmpeg.cpp
+++ b/libmedia/ffmpeg/VideoDecoderFfmpeg.cpp
@@ -45,10 +45,29 @@ extern "C" {
 
 #include "FLVParser.h"
 
+#if USE_VAAPI
+#include "vaapi.h"
+#endif
+
 namespace gnash {
 namespace media {
 namespace ffmpeg {
 
+#if USE_VAAPI
+/// A wrapper around a VAAPIImage that ensures it's free'd on destruction.
+class VAAPIImageWrapper {
+    VAAPIImage *_image;
+public:
+    VAAPIImageWrapper(VAAPIImage *image)
+	: _image(image)
+	{ }
+    ~VAAPIImageWrapper()
+	{ delete _image; }
+    VAAPIImage *getImage() const
+	{ return _image; }
+};
+#endif
+
 #ifdef HAVE_SWSCALE_H
 /// A wrapper round an SwsContext that ensures it's
 /// freed on destruction.
@@ -99,6 +118,113 @@ private:
     AVCodecContext* _codecCtx;
 };
 
+static inline VAAPIContext *get_vaapi_context(AVCodecContext *avctx)
+{
+    return static_cast<VAAPIContext *>(avctx->hwaccel_context);
+}
+
+static inline void set_vaapi_context(AVCodecContext *avctx, VAAPIContext *vactx)
+{
+    avctx->hwaccel_context = vactx;
+}
+
+static void reset_context(AVCodecContext *avctx, VAAPIContext *vactx = NULL);
+
+/// AVCodecContext.get_format() implementation
+static enum PixelFormat get_format(AVCodecContext *avctx, const enum PixelFormat *fmt)
+{
+#if USE_VAAPI
+    VAAPIContext * const vactx = get_vaapi_context(avctx);
+
+    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)) {
+	    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)
+{
+    VAAPIContext * 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;
+
+    VAAPISurface * 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->pic_num;
+    surface->pic_num	= pic_num;
+    return 0;
+#endif
+    return -1;
+}
+
+/// AVCodecContext.reget_buffer() implementation
+static int reget_buffer(AVCodecContext *avctx, AVFrame *pic)
+{
+    VAAPIContext * 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)
+{
+    VAAPIContext * const vactx = get_vaapi_context(avctx);
+    if (!vactx) {
+	avcodec_default_release_buffer(avctx, pic);
+	return;
+    }
+
+#if USE_VAAPI
+    VAAPISurface * const surface = vaapi_get_surface(pic);
+    if (surface)
+	surface->unref();
+
+    pic->data[0]	= NULL;
+    pic->data[1]	= NULL;
+    pic->data[2]	= NULL;
+    pic->data[3]	= NULL;
+#endif
+}
+
+/// (Re)set AVCodecContext to sane values for 
+static void reset_context(AVCodecContext *avctx, VAAPIContext *vactx)
+{
+#if USE_VAAPI
+    VAAPIContext * const old_vactx = get_vaapi_context(avctx);
+    if (old_vactx)
+	delete old_vactx;
+#endif
+
+    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;
+}
 
 VideoDecoderFfmpeg::VideoDecoderFfmpeg(videoCodecType format, int width, int height)
     :
@@ -178,6 +304,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
+    VAAPIContext *vactx = vaapi_create_context(codecId);
+    if (vactx)
+	reset_context(ctx, vactx);
+#endif
+
     int ret = avcodec_open(ctx, _videoCodec);
     if (ret < 0) {
         boost::format msg = boost::format(_("libavcodec"
@@ -195,6 +332,8 @@ VideoDecoderFfmpeg::init(enum CodecID codecId, int /*width*/, int /*height*/,
 
 VideoDecoderFfmpeg::~VideoDecoderFfmpeg()
 {
+    if (_videoCodecCtx.get())
+	reset_context(_videoCodecCtx->getContext());
 }
 
 int
@@ -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
+    std::auto_ptr<VAAPIImageWrapper> vaImage;
+    VAAPIContext * const vactx = get_vaapi_context(srcCtx);
+    if (vactx) {
+	vaImage.reset(new VAAPIImageWrapper(vaapi_get_image(vactx, srcFrame)));
+	if (!vaImage.get() || !(srcFrame = vaImage->getImage()->getFrame())) {
+	    im.reset();
+	    return im;
+	}
+	srcPixFmt = vaImage->getImage()->getPixelFormat();
+    }
+#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/VideoDecoderFfmpeg.h b/libmedia/ffmpeg/VideoDecoderFfmpeg.h
index 29a49ce..d855eb7 100644
--- a/libmedia/ffmpeg/VideoDecoderFfmpeg.h
+++ b/libmedia/ffmpeg/VideoDecoderFfmpeg.h
@@ -42,6 +42,7 @@ class CodecContextWrapper;
 #ifdef HAVE_SWSCALE_H
 class SwsContextWrapper;
 #endif
+class VAAPIContext;
 
 
 /// FFMPEG based VideoDecoder
diff --git a/libmedia/ffmpeg/vaapi.cpp b/libmedia/ffmpeg/vaapi.cpp
new file mode 100644
index 0000000..0aa1966
--- /dev/null
+++ b/libmedia/ffmpeg/vaapi.cpp
@@ -0,0 +1,735 @@
+// 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 <dlfcn.h>
+#include <algorithm>
+
+namespace gnash {
+namespace media {
+namespace ffmpeg {
+
+/* ====================================================================== */
+/* === VA API Hooks                                                   === */
+/* ====================================================================== */
+
+class VAAPIVTable {
+    void *xHandle;
+    void *vaHandle;
+
+    int load(void *handle, void (**func)(), const char *func_name);
+public:
+    VAAPIVTable();
+    ~VAAPIVTable();
+    bool load();
+
+    static VAAPIVTable *get();
+
+    void *	(*XOpenDisplay)(const char *);
+    int		(*XCloseDisplay)(void *);
+    const char *(*vaErrorStr)(VAStatus);
+    VADisplay	(*vaGetDisplay)(void *);
+    VAStatus	(*vaInitialize)(VADisplay, int *, int *);
+    VAStatus	(*vaTerminate)(VADisplay);
+    int		(*vaMaxNumProfiles)(VADisplay);
+    VAStatus	(*vaQueryConfigProfiles)(VADisplay, VAProfile *, unsigned int *);
+    int		(*vaMaxNumEntrypoints)(VADisplay);
+    VAStatus	(*vaQueryConfigEntrypoints)(VADisplay, VAProfile, VAEntrypoint *, unsigned int *);
+    int		(*vaMaxNumImageFormats)(VADisplay);
+    VAStatus	(*vaQueryImageFormats)(VADisplay, VAImageFormat *, unsigned int *);
+    VAStatus	(*vaGetConfigAttributes)(VADisplay, VAProfile, VAEntrypoint, VAConfigAttrib *, int);
+    VAStatus	(*vaCreateConfig)(VADisplay, VAProfile, VAEntrypoint, VAConfigAttrib *, int, VAConfigID *);
+    VAStatus	(*vaDestroyConfig)(VADisplay, VAConfigID);
+    VAStatus	(*vaCreateSurfaces)(VADisplay, int, int, int, int, VASurfaceID *);
+    VAStatus	(*vaDestroySurfaces)(VADisplay, VASurfaceID *, int);
+    VAStatus	(*vaCreateContext)(VADisplay, VAConfigID, int, int, int, VASurfaceID *, int, VAContextID *);
+    VAStatus	(*vaDestroyContext)(VADisplay, VAContextID);
+    VAStatus	(*vaMapBuffer)(VADisplay, VABufferID, void **);
+    VAStatus	(*vaUnmapBuffer)(VADisplay, VABufferID);
+    VAStatus	(*vaSyncSurface)(VADisplay, VAContextID, VASurfaceID);
+    VAStatus	(*vaCreateImage)(VADisplay, VAImageFormat *, int, int, VAImage *);
+    VAStatus	(*vaDestroyImage)(VADisplay, VAImageID);
+    VAStatus	(*vaGetImage)(VADisplay, VASurfaceID, int, int, unsigned int, unsigned int, VAImageID);
+    VAStatus	(*vaDeriveImage)(VADisplay, VASurfaceID, VAImage *);
+};
+
+VAAPIVTable::VAAPIVTable()
+    : xHandle(NULL), vaHandle(NULL)
+{
+}
+
+VAAPIVTable::~VAAPIVTable()
+{
+    if (vaHandle)
+	dlclose(vaHandle);
+    if (xHandle)
+	dlclose(xHandle);
+}
+
+int VAAPIVTable::load(void *handle, void (**func)(), const char *func_name)
+{
+    dlerror();
+    *func = reinterpret_cast<void (*)()>(dlsym(handle, func_name));
+    return dlerror() != NULL;
+}
+
+bool VAAPIVTable::load()
+{
+    int n_errors = 0;
+
+#define LOAD(HANDLE, FUNC)						\
+    n_errors += load(HANDLE##Handle,					\
+		     reinterpret_cast<void (**)()>(&this->FUNC), #FUNC)
+
+    xHandle = dlopen("libX11.so.6", RTLD_LAZY);
+    if (!xHandle)
+	return false;
+
+    LOAD(x, XOpenDisplay);
+    LOAD(x, XCloseDisplay);
+
+    vaHandle = dlopen("libva-x11.so.0", RTLD_LAZY);
+    if (!vaHandle) {
+	vaHandle = dlopen("libva.so.0", RTLD_LAZY);
+	if (!vaHandle)
+	    return false;
+    }
+
+    LOAD(va, vaErrorStr);
+    LOAD(va, vaGetDisplay);
+    LOAD(va, vaInitialize);
+    LOAD(va, vaTerminate);
+    LOAD(va, vaMaxNumProfiles);
+    LOAD(va, vaQueryConfigProfiles);
+    LOAD(va, vaMaxNumEntrypoints);
+    LOAD(va, vaQueryConfigEntrypoints);
+    LOAD(va, vaMaxNumImageFormats);
+    LOAD(va, vaQueryImageFormats);
+    LOAD(va, vaGetConfigAttributes);
+    LOAD(va, vaCreateConfig);
+    LOAD(va, vaDestroyConfig);
+    LOAD(va, vaCreateSurfaces);
+    LOAD(va, vaDestroySurfaces);
+    LOAD(va, vaCreateContext);
+    LOAD(va, vaDestroyContext);
+    LOAD(va, vaMapBuffer);
+    LOAD(va, vaUnmapBuffer);
+    LOAD(va, vaSyncSurface);
+    LOAD(va, vaCreateImage);
+    LOAD(va, vaDestroyImage);
+    LOAD(va, vaGetImage);
+    LOAD(va, vaDeriveImage);
+
+#undef LOAD
+
+    return n_errors == 0;
+}
+
+/// A wrapper around a VAAPIVTable that ensures it's free'd on destruction.
+class VAAPIVTableWrapper {
+    VAAPIVTable *_vtable;
+public:
+    VAAPIVTableWrapper(VAAPIVTable *vtable)
+	: _vtable(vtable)
+	{ }
+    ~VAAPIVTableWrapper()
+	{ delete _vtable; }
+    VAAPIVTable *get() const
+	{ return _vtable; }
+};
+
+static std::auto_ptr<VAAPIVTableWrapper> vaapi_vtable;
+
+VAAPIVTable *VAAPIVTable::get()
+{
+    VAAPIVTable *vtable = NULL;
+    if (!vaapi_vtable.get() || (vtable = vaapi_vtable->get()) == NULL) {
+	vtable = new VAAPIVTable;
+	if (vtable->load())
+	    vaapi_vtable.reset(new VAAPIVTableWrapper(vtable));
+	else {
+	    delete vtable;
+	    vtable = NULL;
+	}
+    }
+    return vtable;
+}
+
+static bool vaapi_check_status(VAStatus status, const char *msg)
+{
+    if (status != VA_STATUS_SUCCESS) {
+	VAAPIVTable * const vaapi = VAAPIVTable::get();
+	if (vaapi)
+	    fprintf(stderr, "[vaapi] %s: %s\n", msg, vaapi->vaErrorStr(status));
+	return false;
+    }
+    return true;
+}
+
+/* ====================================================================== */
+/* === VA API Global Context                                          === */
+/* ====================================================================== */
+
+class VAAPIGlobalContext {
+    void	       *_xdisplay;
+    VADisplay		_display;
+    VAProfile	       *_profiles;
+    unsigned int        _num_profiles;
+    VAImageFormat      *_image_formats;
+    unsigned int        _num_image_formats;
+
+public:
+    VAAPIGlobalContext();
+    ~VAAPIGlobalContext();
+
+    bool init();
+
+    bool hasProfile(VAProfile profile) const;
+    VAImageFormat *getImageFormat(uint32_t fourcc) const;
+
+    VADisplay display() const
+	{ return _display; }
+
+    static VAAPIGlobalContext *get();
+};
+
+VAAPIGlobalContext::VAAPIGlobalContext()
+    : _xdisplay(NULL), _display(NULL),
+      _profiles(NULL), _num_profiles(0),
+      _image_formats(NULL), _num_image_formats(0)
+{
+}
+
+VAAPIGlobalContext::~VAAPIGlobalContext()
+{
+    if (_profiles)
+	delete[] _profiles;
+    if (_image_formats)
+	delete[] _image_formats;
+
+    VAAPIVTable * const vaapi = VAAPIVTable::get();
+
+    if (vaapi) {
+	if (_display)
+	    vaapi->vaTerminate(_display);
+	if (_xdisplay)
+	    vaapi->XCloseDisplay(_xdisplay);
+    }
+}
+
+bool VAAPIGlobalContext::init()
+{
+    VAAPIVTable * const vaapi = VAAPIVTable::get();
+    if (!vaapi)
+	return false;
+
+    _xdisplay = vaapi->XOpenDisplay(NULL);
+    if (!_xdisplay)
+	return false;
+    _display = vaapi->vaGetDisplay(_xdisplay);
+    if (!_display)
+	return false;
+
+    VAStatus status;
+    int major_version, minor_version;
+    status = vaapi->vaInitialize(_display, &major_version, &minor_version);
+    if (!vaapi_check_status(status, "vaInitialize()"))
+	return false;
+
+    _profiles = new(std::nothrow) VAProfile[vaapi->vaMaxNumProfiles(_display)];
+    if (!_profiles)
+	return false;
+
+    status = vaapi->vaQueryConfigProfiles(_display, _profiles, &_num_profiles);
+    if (!vaapi_check_status(status, "vaQueryConfigProfiles()"))
+	return false;
+
+    _image_formats = new(std::nothrow) VAImageFormat[vaapi->vaMaxNumImageFormats(_display)];
+    if (!_image_formats)
+	return false;
+
+    status = vaapi->vaQueryImageFormats(_display, _image_formats, &_num_image_formats);
+    if (!vaapi_check_status(status, "vaQueryImageFormats()"))
+	return false;
+
+    return true;
+}
+
+bool VAAPIGlobalContext::hasProfile(VAProfile profile) const
+{
+    for (unsigned int i = 0; i < _num_profiles; i++) {
+        if (_profiles[i] == profile)
+            return true;
+    }
+    return false;
+}
+
+VAImageFormat *VAAPIGlobalContext::getImageFormat(uint32_t fourcc) const
+{
+    for (unsigned int i = 0; i < _num_image_formats; i++) {
+        if (_image_formats[i].fourcc == fourcc)
+            return &_image_formats[i];
+    }
+    return NULL;
+}
+
+/// A wrapper around a VAAPIGlobalContext that ensures it's free'd on destruction.
+class VAAPIGlobalContextWrapper {
+    VAAPIGlobalContext *_gctx;
+public:
+    VAAPIGlobalContextWrapper(VAAPIGlobalContext *gctx)
+	: _gctx(gctx)
+	{ }
+    ~VAAPIGlobalContextWrapper()
+	{ delete _gctx; }
+    VAAPIGlobalContext *get() const
+	{ return _gctx; }
+};
+
+static std::auto_ptr<VAAPIGlobalContextWrapper> vaapi_global_context;
+
+VAAPIGlobalContext *VAAPIGlobalContext::get()
+{
+    VAAPIGlobalContext *gctx = NULL;
+    if (!vaapi_global_context.get() || (gctx = vaapi_global_context->get()) == NULL) {
+	gctx = new VAAPIGlobalContext;
+	if (gctx->init())
+	    vaapi_global_context.reset(new VAAPIGlobalContextWrapper(gctx));
+	else {
+	    delete gctx;
+	    gctx = NULL;
+	}
+    }
+    return gctx;
+}
+
+/* ====================================================================== */
+/* === VA API Utilities                                               === */
+/* ====================================================================== */
+
+static int VAProfile_from_CodecID(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 gctx = VAAPIGlobalContext::get();
+	if (!gctx)
+	    return -1;
+        for (int i = 0; profiles[i] != -1; i++) {
+            if (gctx->hasProfile((VAProfile)profiles[i]))
+                return profiles[i];
+        }
+    }
+    return -1;
+}
+
+static PixelFormat PixelFormat_from_VAImageFormat(VAImageFormat const &imgfmt)
+{
+    switch (imgfmt.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 (imgfmt.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 == imgfmt.byte_order &&
+		pix_fmt_map[i].bits_per_pixel == imgfmt.bits_per_pixel &&
+		pix_fmt_map[i].red_mask == imgfmt.red_mask &&
+		pix_fmt_map[i].green_mask == imgfmt.green_mask &&
+		pix_fmt_map[i].blue_mask == imgfmt.blue_mask)
+		return pix_fmt_map[i].pix_fmt;
+	}
+    }
+    return PIX_FMT_NONE;
+}
+
+/* ====================================================================== */
+/* === VA API Image                                                   === */
+/* ====================================================================== */
+
+VAAPIImage::VAAPIImage(VAAPIContext *vactx, VAAPISurface *surface)
+    : _vactx(vactx), _imageBytes(0), _isOK(false)
+{
+    _image.image_id = 0;
+    _image.buf = 0;
+    for (int i = 0; i < 4; i++) {
+	_frame.data[i] = NULL;
+	_frame.linesize[i] = NULL;
+    }
+
+    VAStatus status;
+
+    VAAPIVTable * const vaapi = VAAPIVTable::get();
+    if (!vaapi)
+	return;
+
+    VAAPIGlobalContext * const gvactx = VAAPIGlobalContext::get();
+    if (!gvactx)
+	return;
+
+    static const uint32_t image_formats[] = {
+	VA_FOURCC('Y','V','1','2'),
+	VA_FOURCC('N','V','1','2'),
+	VA_FOURCC('U','Y','V','Y'),
+	VA_FOURCC('Y','U','Y','V'),
+	VA_FOURCC('R','G','B','A'),
+	0
+    };
+    VAImageFormat *image_format;
+
+    status = vaapi->vaSyncSurface(_vactx->display,_vactx->context_id, surface->id);
+    if (!vaapi_check_status(status, "vaSyncSurface()"))
+	return;
+
+    status = vaapi->vaDeriveImage(_vactx->display, surface->id, &_image);
+
+    if (status != VA_STATUS_SUCCESS) {
+        image_format = NULL;
+        for (int i = 0; image_formats[i] != 0; i++) {
+            VAImageFormat *imgfmt = gvactx->getImageFormat(image_formats[i]);
+	    if (imgfmt) {
+		image_format = imgfmt;
+                break;
+            }
+        }
+	if (!image_format)
+	    return;
+
+        status = vaapi->vaCreateImage(_vactx->display, image_format,
+				      _vactx->width(), _vactx->height(),
+				      &_image);
+        if (!vaapi_check_status(status, "vaCreateImage()"))
+	    return;
+
+        status = vaapi->vaGetImage(_vactx->display, surface->id,
+				   0, 0, _vactx->width(), _vactx->height(),
+				   _image.image_id);
+        if (!vaapi_check_status(status, "vaGetImage()"))
+	    return;
+    }
+    else
+        image_format = &_image.format;
+
+    status = vaapi->vaMapBuffer(_vactx->display, _image.buf, (void **)&_imageBytes);
+    if (!vaapi_check_status(status, "vaMapBuffer()"))
+        return;
+
+    for (unsigned int i = 0; i < _image.num_planes; i++) {
+	_frame.data[i] = _imageBytes + _image.offsets[i];
+	_frame.linesize[i] = _image.pitches[i];
+    }
+    _isOK = true;
+}
+
+VAAPIImage::~VAAPIImage()
+{
+    VAAPIVTable * const vaapi = VAAPIVTable::get();
+    VAStatus status;
+
+    if (_imageBytes) {
+	status = vaapi->vaUnmapBuffer(_vactx->display, _image.buf);
+        vaapi_check_status(status, "vaUnmapBuffer()");
+    }
+
+    if (_image.image_id) {
+	status = vaapi->vaDestroyImage(_vactx->display, _image.image_id);
+	vaapi_check_status(status, "vaDestroyImage()");
+    }
+}
+
+const AVFrame *VAAPIImage::getFrame()
+{
+    if (!_isOK)
+	return NULL;
+    return &_frame;
+}
+
+PixelFormat VAAPIImage::getPixelFormat() const
+{
+    if (!_isOK)
+	return PIX_FMT_NONE;
+    return PixelFormat_from_VAImageFormat(_image.format);
+}
+
+VAAPIImage *vaapi_get_image(VAAPIContext *vactx, const AVFrame *pic)
+{
+    VAAPISurface * const surface = vaapi_get_surface(pic);
+    if (!surface)
+	return NULL;
+    return new VAAPIImage(vactx, surface);
+}
+
+/* ====================================================================== */
+/* === VA API Surface                                                 === */
+/* ====================================================================== */
+
+void vaapi_set_surface(AVFrame *pic, VAAPISurface *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->id);
+    }
+}
+
+/* ====================================================================== */
+/* === VA API Context                                                 === */
+/* ====================================================================== */
+
+VAAPIContext::VAAPIContext(VAProfile profile, VAEntrypoint entrypoint)
+    : _profile(profile), _entrypoint(entrypoint),
+      _entrypoints(NULL), _num_entrypoints(0),
+      _surface_ids(NULL), _surfaces(NULL), _num_surfaces(0),
+      _picture_width(0), _picture_height(0)
+{
+    // FFmpeg's vaapi_context must be zero-initialized
+    memset(this, 0, sizeof(struct vaapi_context));
+}
+
+VAAPIContext::~VAAPIContext()
+{
+    destroySurfaces();
+
+    VAAPIVTable * const vaapi = VAAPIVTable::get();
+    if (!vaapi)
+	return;
+
+    if (context_id)
+	vaapi->vaDestroyContext(display, context_id);
+
+    if (config_id)
+	vaapi->vaDestroyConfig(display, config_id);
+}
+
+bool VAAPIContext::createSurfaces(unsigned int width, unsigned int height)
+{
+    VAStatus status;
+
+    VAAPIVTable * const vaapi = VAAPIVTable::get();
+    if (!vaapi)
+	return false;
+
+    switch (_profile) {
+    case VAProfileH264High:
+    case VAProfileH264Main:
+    case VAProfileH264Baseline:
+	_num_surfaces = 16;
+	break;
+    default:
+	_num_surfaces = 2;
+	break;
+    }
+
+    _surface_ids = new(std::nothrow) VASurfaceID[_num_surfaces];
+    if (!_surface_ids)
+	return false;
+
+    _surfaces = new(std::nothrow) VAAPISurface[_num_surfaces];
+    if (!_surfaces)
+	return false;
+
+    status = vaapi->vaCreateSurfaces(display, width, height,
+				     VA_RT_FORMAT_YUV420,
+				     _num_surfaces, _surface_ids);
+    if (!vaapi_check_status(status, "vaCreateSurfaces()"))
+	return false;
+
+    for (unsigned int i = 0; i < _num_surfaces; i++)
+	_surfaces[i].id = _surface_ids[i];
+
+    _picture_width  = width;
+    _picture_height = height;
+    return true;
+}
+
+void VAAPIContext::destroySurfaces()
+{
+
+    if (_surfaces) {
+	delete[] _surfaces;
+	_surfaces = NULL;
+    }
+
+    VAAPIVTable * const vaapi = VAAPIVTable::get();
+    if (!vaapi)
+	return;
+
+    if (_surface_ids) {
+	if (vaapi)
+	    vaapi->vaDestroySurfaces(display, _surface_ids, _num_surfaces);
+	delete[] _surface_ids;
+	_surface_ids = NULL;
+    }
+
+    _num_surfaces = 0;
+}
+
+bool VAAPIContext::initContext()
+{
+    VAAPIGlobalContext * const gctx = VAAPIGlobalContext::get();
+    if (!gctx)
+	return false;
+
+    display = gctx->display();
+    if (!display)
+	return false;
+
+    VAAPIVTable * const vaapi = VAAPIVTable::get();
+    if (!vaapi)
+	return false;
+
+    VAStatus status;
+    VAConfigAttrib attrib;
+    attrib.type = VAConfigAttribRTFormat;
+    status = vaapi->vaGetConfigAttributes(display, _profile, _entrypoint, &attrib, 1);
+    if (!vaapi_check_status(status, "vaGetConfigAttributes()"))
+        return false;
+    if ((attrib.value & VA_RT_FORMAT_YUV420) == 0)
+        return false;
+
+    status = vaapi->vaCreateConfig(display, _profile, _entrypoint, &attrib, 1, &config_id);
+    if (!vaapi_check_status(status, "vaCreateConfig()"))
+	return false;
+
+    return true;
+}
+
+bool VAAPIContext::initDecoder(unsigned int width, unsigned int height)
+{
+    VAStatus status;
+
+    VAAPIVTable * const vaapi = VAAPIVTable::get();
+    if (!vaapi)
+	return false;
+
+    if (_picture_width != width || _picture_height != height) {
+	destroySurfaces();
+	if (!createSurfaces(width, height))
+	    return false;
+
+	if (context_id)
+	    vaapi->vaDestroyContext(display, context_id);
+
+	status = vaapi->vaCreateContext(display, config_id,
+					width, height,
+					VA_PROGRESSIVE,
+					_surface_ids, _num_surfaces,
+					&context_id);
+	if (!vaapi_check_status(status, "vaCreateContext"))
+	    return false;
+    }
+    return true;
+}
+
+VAAPISurface *VAAPIContext::getSurface(int id) const
+{
+    if (id < 0) {
+	// Find a free surface
+	for (unsigned int i = 0; i < _num_surfaces; i++) {
+	    VAAPISurface * const surface = &_surfaces[i];
+	    if (surface->refcount == 0)
+		return surface->ref();
+	}
+	return NULL;
+    }
+
+    if (id < _num_surfaces)
+	return &_surfaces[id];
+
+    return NULL;
+}
+
+VAAPIContext *vaapi_create_context(enum CodecID codec_id)
+{
+    int profile = VAProfile_from_CodecID(codec_id);
+    if (profile < 0)
+	return NULL;
+    VAAPIContext * const vactx = new VAAPIContext((VAProfile)profile, VAEntrypointVLD);
+    if (!vactx->initContext())
+	return NULL;
+    return vactx;
+}
+
+void vaapi_destroy_context(VAAPIContext *vactx)
+{
+    delete 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..ed21079
--- /dev/null
+++ b/libmedia/ffmpeg/vaapi.h
@@ -0,0 +1,129 @@
+// 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_VAAPI_H
+#define GNASH_VAAPI_H
+
+#include <va/va.h>
+
+extern "C" {
+#include <libavcodec/avcodec.h>
+#include <libavcodec/vaapi.h>
+}
+
+namespace gnash {
+namespace media {
+namespace ffmpeg {
+
+class VAAPIImage;
+class VAAPISurface;
+class VAAPIContext;
+
+class VAAPIImage {
+
+    VAAPIContext *      _vactx;
+    uint8_t *           _imageBytes;
+    VAImage             _image;
+    AVFrame             _frame;
+    bool                _isOK;
+
+protected:
+
+    // Force creation through vaapi_get_image()
+    VAAPIImage(VAAPIContext *vactx, VAAPISurface *surface);
+    friend VAAPIImage *vaapi_get_image(VAAPIContext *vactx, const AVFrame *pic);
+
+public:
+
+    ~VAAPIImage();
+
+    const AVFrame *getFrame();
+    PixelFormat getPixelFormat() const;
+};
+
+VAAPIImage *vaapi_get_image(VAAPIContext *vactx, const AVFrame *pic);
+
+struct VAAPISurface {
+
+    VASurfaceID         id;
+    unsigned int        pic_num;
+    unsigned int        refcount;
+
+    VAAPISurface()
+        : id(0), pic_num(0), refcount(0)
+        { }
+
+    VAAPISurface *ref()
+        { ++refcount; return this; }
+
+    void unref()
+        { --refcount; }
+};
+
+void vaapi_set_surface(AVFrame *pic, VAAPISurface *surface);
+
+static inline VAAPISurface *vaapi_get_surface(const AVFrame *pic)
+{
+    return reinterpret_cast<VAAPISurface *>(pic->data[0]);
+}
+
+class VAAPIContext : public vaapi_context {
+
+    VAProfile           _profile;
+    VAEntrypoint        _entrypoint;
+    VAEntrypoint       *_entrypoints;
+    unsigned int        _num_entrypoints;
+    VASurfaceID        *_surface_ids;
+    VAAPISurface       *_surfaces;
+    unsigned int        _num_surfaces;
+    unsigned int        _picture_width;
+    unsigned int        _picture_height;
+
+protected:
+
+    // Force creation through vaapi_create_context()
+    VAAPIContext(VAProfile profile, VAEntrypoint entrypoint);
+    friend VAAPIContext *vaapi_create_context(enum CodecID codec_id);
+
+    bool createSurfaces(unsigned int width, unsigned int height);
+    void destroySurfaces();
+
+public:
+
+    ~VAAPIContext();
+
+    bool initContext();
+    bool initDecoder(unsigned int width, unsigned int height);
+
+    // Finds a free surface if id == -1
+    VAAPISurface *getSurface(int id = -1) const;
+
+    unsigned int width() const
+        { return _picture_width; }
+    unsigned int height() const
+        { return _picture_height; }
+};
+
+VAAPIContext *vaapi_create_context(enum CodecID codec_id);
+void vaapi_destroy_context(VAAPIContext *vactx);
+    
+} // gnash.media.ffmpeg namespace 
+} // gnash.media namespace 
+} // gnash namespace
+
+#endif /* GNASH_VAAPI_H */
