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 */