commit f679677babd595777ba30f32448396b1b92a1a6c
Author: Gwenole Beauchesne
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
Date: Tue Sep 22 11:02:33 2009 +0000
Cleanups. Add GnashTextureFormat helper.
commit d601ec0e92b787d80659ea8f0b9acc24f4f69097
Author: Gwenole Beauchesne
Date: Tue Sep 22 11:01:42 2009 +0000
Simplify VaapiSurfaceGLX::update() function.
commit 331bdfefeeaf54709b9addaf7a902b00755a74d6
Author: Gwenole Beauchesne
Date: Tue Sep 22 11:01:18 2009 +0000
Drop obsolete GnashGLImage object.
commit 807037ef15d08ed666be1437b300b88ddd0caea8
Author: Gwenole Beauchesne
Date: Tue Sep 22 11:00:20 2009 +0000
Add GnashVaapiTexture abstraction.
commit ada718d95d36e5ed38b09d756a7093f47e9b0530
Author: Gwenole Beauchesne
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
Date: Tue Sep 22 10:57:33 2009 +0000
Add VA/GLX display abstraction.
commit 007a2b217dbc24b9a20b0a66562cb2b3915b3126
Author: Gwenole Beauchesne
Date: Mon Sep 21 16:36:05 2009 +0000
Add (basic) texture cache.
commit c02aab48f3842e4206c692e98f76daae6855970e
Author: Gwenole Beauchesne
Date: Mon Sep 21 16:33:21 2009 +0000
Return size accessors.
commit 5664bc5fc66b97ed82a6fb74d6d958cea100683e
Author: Gwenole Beauchesne
Date: Mon Sep 21 16:26:15 2009 +0000
Add VA/GLX abstraction.
commit 3fa2f69ee80c94a93c97203b8b7846834d177681
Author: Gwenole Beauchesne
Date: Mon Sep 21 16:24:56 2009 +0000
Add VA/GLX configury.
commit 52b117799811dde1a0efef5fe0f23e36a8114dab
Author: Gwenole Beauchesne
Date: Mon Sep 21 16:05:16 2009 +0000
Rename GnashGLTexture to GnashTexture.
commit e53135df9a2303e30645ffcfdb4023f9452cb5a0
Author: Gwenole Beauchesne
Date: Mon Sep 21 14:22:08 2009 +0000
VaapiSurface now takes care of colorspace conversion.
commit 280bd81be7c6607f26bfd16b5b444a238321fdb2
Author: Gwenole Beauchesne
Date: Mon Sep 21 14:21:35 2009 +0000
Add VaapiSurface::getPixelsRGBA() and ::getPixelsRGB().
commit 895379a9caf855727251a376a21c8d27e773f377
Author: Gwenole Beauchesne
Date: Mon Sep 21 12:02:13 2009 +0000
Use new GnashVaapiImage object.
commit f74a9c5fda1f153141f73a5f57f2450000dfd272
Author: Gwenole Beauchesne
Date: Mon Sep 21 12:00:36 2009 +0000
Add GnashVaapiImage abstraction.
commit 63e3cdfe084a1c4ff2bd78bf2246c112e4b20b12
Author: Gwenole Beauchesne
Date: Mon Sep 21 11:53:47 2009 +0000
Extend GnashImage to record the image data location (CPU, GPU).
commit a754f07eadab142182a1e04636a81c4eb3e8a799
Author: Gwenole Beauchesne
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
Date: Mon Sep 21 00:18:09 2009 +0000
Use new libgnashvaapi library.
commit 891a4e8fb4309a52cafa5fdf72f74d9760684049
Author: Gwenole Beauchesne
Date: Mon Sep 21 00:17:22 2009 +0000
Add new libgnashvaapi library.
commit 7ce5d4f73765e14d33158708df84c2910ae8e65f
Author: Gwenole Beauchesne
Date: Fri Sep 18 15:47:17 2009 +0000
Move vaapi_check_status() to VaapiGlobalContext.{h,cpp}.
commit bacdfd4c4436a05ddc94e82380ca1d3758c08f74
Author: Gwenole Beauchesne
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
Date: Fri Sep 18 12:19:44 2009 +0000
Fix run-time check for VA API acceleration.
commit c2122e92d8070809b1125b93508b72198b423c1e
Author: Gwenole Beauchesne
Date: Fri Sep 18 11:49:58 2009 +0000
Use new VaapiGlobalContext and drop VA VTable, use functions directly.
commit a7bcbe4de204b59be60727d6b0f37b63910edd6d
Author: Gwenole Beauchesne
Date: Fri Sep 18 11:44:03 2009 +0000
Implement global VA context.
commit f31a461cf56c136c76877fdba84ae092d497bdb3
Author: Gwenole Beauchesne
Date: Fri Sep 18 09:05:29 2009 +0000
Rework VA API configury.
commit 5f9680cd2b2bde835d94593d134540d96c71c5c1
Author: Gwenole Beauchesne
Date: Tue Sep 15 11:50:53 2009 +0000
Make it possible to disable VA API at runtime.
commit c8cfc227ae07761472cfcb055128371cd37108f5
Author: Gwenole Beauchesne
Date: Tue Sep 15 11:44:38 2009 +0000
Fix loading of libVA.
commit 6dcd362b71db123bb1593b734dacd90c81fcf4ad
Author: Gwenole Beauchesne
Date: Tue Sep 15 09:22:45 2009 +0000
Add support for VA API 0.31.
commit 483c439e626d49dfe58d8654eaf9ee5be8d19275
Author: Gwenole Beauchesne
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
Date: Mon Jun 15 13:36:12 2009 +0000
Add initial VA API support through decoded frames readback (slow).
commit 6e689e1d71e07755d92e49e950f157d079074321
Author: Gwenole Beauchesne
Date: Mon Jun 15 13:33:45 2009 +0000
Fix buffer allocation in AudioDecoderFfmpeg::decodeFrame().
commit a09dae25a10154e24bcca938e1899c5c119fd71f
Author: Gwenole Beauchesne
Date: Fri Sep 18 07:56:40 2009 +0000
Disable (slow) anti-aliasing code with the accumulation buffer.
commit 417de4ea10411fe5647bb43ccf6869ec600b7e9e
Author: Gwenole Beauchesne
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
Date: Fri Sep 18 07:46:48 2009 +0000
Rewrite drawVideoFrame() with GnashGLImage.
commit c38c06b6e3c241152bd2694bdcdaef95116103b2
Author: Gwenole Beauchesne
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
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
Date: Fri Sep 18 07:15:10 2009 +0000
Fix scaled window mode.
commit b4516b52875647c2b6f3dd66d06c8bd683869fe9
Author: Gwenole Beauchesne
Date: Fri Sep 18 08:07:58 2009 +0000
Update to Gnash bzr rev 11514.
commit aed1793e89615b0ec38695e7d2e2dab51d2fa002
Author: Gwenole Beauchesne
Date: Tue Sep 15 08:11:12 2009 +0000
Update to Gnash bzr rev 11511.
commit 378d16788fc4a0769e1e152db6aaf5d1613c6663
Author: Gwenole Beauchesne
Date: Mon Aug 10 14:54:13 2009 +0000
Update to Gnash bzr rev 11404.
commit dc163c9124fadfee87c506856b32715bf94b65f8
Author: Gwenole Beauchesne
Date: Mon Jun 15 13:31:20 2009 +0000
Update to Gnash bzr rev 11112.
commit 5b67f070f3eba34ca45789b17412ee9281925e38
Author: Gwenole Beauchesne
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
#include
+#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 getCachedTexture(GnashImage *frame)
+ {
+ boost::shared_ptr 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 >::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 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(texture.get())->update(dynamic_cast(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 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 _render_indices;
- std::vector _video_indices;
+ std::vector< boost::shared_ptr > _render_textures;
+ std::list< boost::shared_ptr > _cached_textures;
#ifdef OSMESA_TESTING
std::auto_ptr _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
+
+#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
+
+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
+
+#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 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 GnashVaapiImage::clone()
+{
+ D(bug("GnashVaapiImage::clone(): image %p\n", this));
+
+ return std::auto_ptr(new GnashVaapiImage(*this));
+}
+
+void GnashVaapiImage::update(boost::shared_ptr 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(from.data()));
+ break;
+ case GNASH_IMAGE_GPU:
+ this->update(static_cast(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(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
+
+namespace gnash {
+
+// Forward declarations
+class VaapiSurface;
+class VaapiSurfaceProxy;
+
+/// GnashImage implementation using a VA surface
+class DSOEXPORT GnashVaapiImage : public GnashImage
+{
+ boost::shared_ptr _surface;
+ boost::uint64_t _creation_time;
+
+ /// Transfer (and convert) VA surface to CPU image data
+ bool transfer();
+
+public:
+ GnashVaapiImage(boost::shared_ptr surface, ImageType type);
+ GnashVaapiImage(const GnashVaapiImage& o);
+ ~GnashVaapiImage();
+
+ virtual std::auto_ptr clone();
+ virtual void update(boost::shared_ptr 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 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
+
+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 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 _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 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(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(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(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(newOutput);
+ }
outputSize = outSize;
return reinterpret_cast(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(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
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 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(srcFrame.data),
- const_cast(srcFrame.linesize), 0, height, picture.data,
+ const_cast(srcFrame->data),
+ const_cast(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(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 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(surface);
+ pic->data[3] = reinterpret_cast((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
+#include
+}
+
+namespace gnash {
+namespace media {
+namespace ffmpeg {
+
+/// VA image implementation for FFmpeg
+class VaapiImageFfmpeg {
+ std::auto_ptr _image;
+ AVFrame _frame;
+ PixelFormat _pixel_format;
+
+public:
+ VaapiImageFfmpeg(std::auto_ptr 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 surface,
+ boost::shared_ptr 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(pic->data[0]);
+}
+
+/// VA context implementation for FFmpeg
+class VaapiContextFfmpeg : public vaapi_context {
+ boost::shared_ptr _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 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 VaapiContext::acquireSurface()
+{
+ boost::shared_ptr 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 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
+
+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 VaapiSurfaceSP;
+
+ VADisplay _display;
+ VAConfigID _config;
+ VAContextID _context;
+ VaapiCodec _codec;
+ VAProfile _profile;
+ VAEntrypoint _entrypoint;
+ std::queue _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 acquireSurface();
+
+ /// Release surface
+ void releaseSurface(boost::shared_ptr 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
+#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
+#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
+#include
+
+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 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 vaapi_global_context;
+
+ if (!vaapi_global_context.get()) {
+ std::auto_ptr 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
+#include "VaapiDisplay.h"
+
+namespace gnash {
+
+/// VA API global context
+class DSOEXPORT VaapiGlobalContext {
+ std::auto_ptr _display;
+ std::vector _profiles;
+ std::vector _image_formats;
+
+ bool init();
+
+public:
+ VaapiGlobalContext(std::auto_ptr 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
+
+#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(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
+}
+
+#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 _image;
+ bool _image_rgba;
+ std::auto_ptr _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 _impl;
+
+public:
+ VaapiSurface(unsigned int width, unsigned int height);
+
+ /// Return VA surface id
+ VASurfaceID get() const
+ { return static_cast(_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
+
+#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(VaapiSurfaceImplBase::surface()); }
+
+public:
+ VaapiSurfaceGLXImpl(GLenum target, GLuint texture);
+ ~VaapiSurfaceGLXImpl();
+
+ bool update(boost::shared_ptr 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(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 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 surface)
+{
+ D(bug("VaapiSurfaceGLX::update(): from surface 0x%08x\n", surface->get()));
+
+ return dynamic_cast(_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
+
+namespace gnash {
+
+/// VA/GLX surface abstraction
+class VaapiSurfaceGLX {
+ std::auto_ptr _impl;
+
+public:
+ VaapiSurfaceGLX(GLenum target, GLuint texture);
+
+ /// Return VA surface id
+ void *get() const
+ { return reinterpret_cast(_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 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 surface,
+ boost::shared_ptr 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 VaapiSurfaceProxy::getImage() const
+{
+ std::auto_ptr 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 _context;
+ boost::shared_ptr _surface;
+
+public:
+ VaapiSurfaceProxy(boost::shared_ptr surface,
+ boost::shared_ptr context);
+ ~VaapiSurfaceProxy();
+
+ /// Return VA surface
+ boost::shared_ptr get() const
+ { return _surface; }
+
+ /// Return VA context
+ boost::shared_ptr getContext() const
+ { return _context; }
+
+ /// Return VA image
+ std::auto_ptr 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
+#include
+
+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
+#include
+#include /* XXX: uintptr_t */
+#include
+#include
+#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
+
+#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
+#include
+
+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 */