diff --git a/src/vaapi/SurfaceInteropVAAPI.cpp b/src/vaapi/SurfaceInteropVAAPI.cpp index d00b9fae..8d155ced 100644 --- a/src/vaapi/SurfaceInteropVAAPI.cpp +++ b/src/vaapi/SurfaceInteropVAAPI.cpp @@ -1,5 +1,7 @@ #include "SurfaceInteropVAAPI.h" #include "utils/OpenGLHelper.h" +#include +#include namespace QtAV { namespace vaapi { @@ -23,6 +25,8 @@ void* SurfaceInteropVAAPI::map(SurfaceType type, const VideoFormat &fmt, void *h { if (!fmt.isRGB()) return 0; + QMutexLocker lock(&mutex); + if (!handle) handle = createHandle(type, fmt, plane); if (type == GLTextureSurface) { @@ -37,7 +41,7 @@ void* SurfaceInteropVAAPI::map(SurfaceType type, const VideoFormat &fmt, void *h glx->set(m_surface); if (!glx->copy()) return 0; - glx->sync(); + VAWARN(vaSyncSurface(m_surface->display(), m_surface->get())); return handle; } else if (type == HostMemorySurface) { @@ -78,6 +82,143 @@ void* SurfaceInteropVAAPI::createHandle(SurfaceType type, const VideoFormat &fmt return 0; } +#ifndef QT_OPENGL_ES_2 +VAAPI_X_GLX_Interop::glXReleaseTexImage_t VAAPI_X_GLX_Interop::glXReleaseTexImage = 0; +VAAPI_X_GLX_Interop::glXBindTexImage_t VAAPI_X_GLX_Interop::glXBindTexImage = 0; + +VAAPI_X_GLX_Interop::VAAPI_X_GLX_Interop() + : xdisplay(0) + , fbc(0) + , pixmap(0) + , glxpixmap(0) + , width(0) + , height(0) +{} + +VAAPI_X_GLX_Interop::~VAAPI_X_GLX_Interop() +{ + if (glxpixmap) { + glXReleaseTexImage(xdisplay, glxpixmap, GLX_FRONT_EXT); + XSync((::Display*)xdisplay, False); + glXDestroyPixmap((::Display*)xdisplay, glxpixmap); + } + glxpixmap = 0; + + if (pixmap) + XFreePixmap((::Display*)xdisplay, pixmap); + pixmap = 0; +} + +bool VAAPI_X_GLX_Interop::ensureGLX() +{ + if (fbc) + return true; + xdisplay = (Display*)glXGetCurrentDisplay(); + if (!xdisplay) + return false; + int xscr = DefaultScreen(xdisplay); + const char *glxext = glXQueryExtensionsString((::Display*)xdisplay, xscr); + if (!glxext || !strstr(glxext, "GLX_EXT_texture_from_pixmap")) + return false; + glXBindTexImage = (glXBindTexImage_t)glXGetProcAddressARB((const GLubyte*)"glXBindTexImageEXT"); + if (!glXBindTexImage) { + qWarning("glXBindTexImage not found"); + return false; + } + glXReleaseTexImage = (glXReleaseTexImage_t)glXGetProcAddressARB((const GLubyte*)"glXReleaseTexImageEXT"); + if (!glXReleaseTexImage) { + qWarning("glXReleaseTexImage not found"); + return false; + } + int attribs[] = { + GLX_RENDER_TYPE, GLX_RGBA_BIT, //xbmc + GLX_X_RENDERABLE, True, //xbmc + GLX_BIND_TO_TEXTURE_RGBA_EXT, True, + GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, + GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT, + GLX_Y_INVERTED_EXT, True, + GLX_DOUBLEBUFFER, False, + GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_ALPHA_SIZE, 8, + None + }; + + int fbcount; + GLXFBConfig *fbcs = glXChooseFBConfig((::Display*)xdisplay, xscr, attribs, &fbcount); + if (!fbcount) { + qWarning("No texture-from-pixmap support"); + return false; + } + if (fbcount) + fbc = fbcs[0]; + XFree(fbcs); + return true; +} + +bool VAAPI_X_GLX_Interop::ensurePixmaps(int w, int h) +{ + if (pixmap && width == w && height == h) + return true; + if (!ensureGLX()) { + return false; + } + + pixmap = XCreatePixmap((::Display*)xdisplay, RootWindow((::Display*)xdisplay, DefaultScreen((::Display*)xdisplay)), w, h, 24); + if (!pixmap) { + qWarning("VAAPI_X_GLX_Interop could not create pixmap"); + return false; + } + + int attribs[] = { + GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, + GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT, + GLX_MIPMAP_TEXTURE_EXT, False, + None, + }; + glxpixmap = glXCreatePixmap((::Display*)xdisplay, fbc, pixmap, attribs); + return true; +} + +void* VAAPI_X_GLX_Interop::map(SurfaceType type, const VideoFormat &fmt, void *handle, int plane) +{ + Q_UNUSED(plane); + if (!handle) + return 0; + QMutexLocker lock(&mutex); + if (!m_surface) + return 0; + if (type != GLTextureSurface) + return 0; + if (!fmt.isRGB()) { + return 0; + } + if (!ensurePixmaps(m_surface->width(), m_surface->height())) + return 0; + + VA_ENSURE_TRUE(vaPutSurface(m_surface->display(), m_surface->get(), pixmap + , 0, 0, m_surface->width(), m_surface->height() + , 0, 0, m_surface->width(), m_surface->height() + , NULL, 0, VA_FRAME_PICTURE | VA_SRC_BT709) + , NULL); + XSync((::Display*)xdisplay, False); + VAWARN(vaSyncSurface(m_surface->display(), m_surface->get())); + DYGL(glBindTexture(GL_TEXTURE_2D, *((GLuint*)handle))); + glXBindTexImage(xdisplay, glxpixmap, GLX_FRONT_EXT, NULL); + DYGL(glBindTexture(GL_TEXTURE_2D, 0)); + + return handle; +} + +void VAAPI_X_GLX_Interop::unmap(void *handle) +{ + DYGL(glBindTexture(GL_TEXTURE_2D, *((GLuint*)handle))); + glXReleaseTexImage(xdisplay, glxpixmap, GLX_FRONT_EXT); + DYGL(glBindTexture(GL_TEXTURE_2D, 0)); +} + +#endif //QT_OPENGL_ES_2 } //namespace QtAV } //namespace vaapi diff --git a/src/vaapi/SurfaceInteropVAAPI.h b/src/vaapi/SurfaceInteropVAAPI.h index 4bc82a29..ee170575 100644 --- a/src/vaapi/SurfaceInteropVAAPI.h +++ b/src/vaapi/SurfaceInteropVAAPI.h @@ -3,28 +3,82 @@ #include #include -#include "vaapi_helper.h" +#include #include "QtAV/SurfaceInterop.h" +#include "vaapi_helper.h" + +#if defined(QT_OPENGL_ES_2) +#include +#else +#include +#endif //defined(QT_OPENGL_ES_2) +#ifdef Bool +#undef Bool +#endif //Bool +#ifdef CursorShape +#undef CursorShape //used in qvariant and x11 +#endif //CursorShape +#ifdef Status +#undef Status // qtextstream +#endif //Status namespace QtAV { namespace vaapi { +// TODO: move create glx surface to decoder, interop only map/unmap, 1 interop per frame +// load/resolve symbols only once in decoder and pass a VAAPI_XXX ptr +// or use pool class SurfaceInteropVAAPI : public VideoSurfaceInterop, public VAAPI_GLX { public: SurfaceInteropVAAPI(); - void setSurface(const surface_ptr& surface) { m_surface = surface; } + + void setSurface(const surface_ptr& surface) { + QMutexLocker lock(&mutex); + m_surface = surface; + } // return glx surface surface_glx_ptr createGLXSurface(void* handle); virtual void* map(SurfaceType type, const VideoFormat& fmt, void* handle, int plane); virtual void unmap(void *handle); virtual void* createHandle(SurfaceType type, const VideoFormat& fmt, int plane = 0); private: - surface_ptr m_surface; QMap glx_surfaces, tmp_surfaces; + surface_ptr m_surface; + QMutex mutex; }; typedef QSharedPointer SurfaceInteropVAAPIPtr; +#ifndef QT_OPENGL_ES_2 +class VAAPI_X_GLX_Interop Q_DECL_FINAL: public VideoSurfaceInterop, public VAAPI_X11 +{ +public: + VAAPI_X_GLX_Interop(); + ~VAAPI_X_GLX_Interop(); + void setSurface(const surface_ptr& surface) { + QMutexLocker lock(&mutex); + m_surface = surface; + } + void* map(SurfaceType type, const VideoFormat& fmt, void* handle, int plane) Q_DECL_OVERRIDE; + void unmap(void *handle) Q_DECL_OVERRIDE; +private: + bool ensureGLX(); + bool ensurePixmaps(int w, int h); + Display *xdisplay; + GLXFBConfig fbc; + Pixmap pixmap; + GLXPixmap glxpixmap; + int width, height; + surface_ptr m_surface; + + QMutex mutex; + + typedef void (*glXBindTexImage_t)(Display *dpy, GLXDrawable draw, int buffer, int *a); + typedef void (*glXReleaseTexImage_t)(Display *dpy, GLXDrawable draw, int buffer); + static glXBindTexImage_t glXBindTexImage; + static glXReleaseTexImage_t glXReleaseTexImage; +}; +#endif //QT_OPENGL_ES_2 } //namespace QtAV } //namespace vaapi //Q_DECLARE_METATYPE(QtAV::vaapi::SurfaceInteropVAAPIPtr) diff --git a/src/vaapi/vaapi_helper.h b/src/vaapi/vaapi_helper.h index be5859c1..010b31b4 100644 --- a/src/vaapi/vaapi_helper.h +++ b/src/vaapi/vaapi_helper.h @@ -33,7 +33,9 @@ #elif defined(QT_OPENGL_LIB) #include #else +#if !defined(QT_OPENGL_ES_2) #include +#endif //!defined(QT_OPENGL_ES_2) #endif #include "utils/SharedPtr.h" @@ -117,16 +119,33 @@ private: }; class VAAPI_X11 : public dll_helper { public: + typedef unsigned long Drawable; typedef VADisplay vaGetDisplay_t(Display *); + typedef VAStatus vaPutSurface_t(VADisplay, VASurfaceID, Drawable, + short, short, unsigned short, unsigned short, + short, short, unsigned short, unsigned short, + VARectangle *, unsigned int, unsigned int); VAAPI_X11(): dll_helper("va-x11",1) { fp_vaGetDisplay = (vaGetDisplay_t*)resolve("vaGetDisplay"); + fp_vaPutSurface = (vaPutSurface_t*)resolve("vaPutSurface"); } VADisplay vaGetDisplay(Display *dpy) { assert(fp_vaGetDisplay); return fp_vaGetDisplay(dpy); } + VAStatus vaPutSurface (VADisplay dpy, VASurfaceID surface, Drawable draw, /* X Drawable */ + short srcx, short srcy, unsigned short srcw, unsigned short srch, + short destx, short desty, unsigned short destw, unsigned short desth, + VARectangle *cliprects, /* client supplied destination clip list */ + unsigned int number_cliprects, /* number of clip rects in the clip list */ + unsigned int flags /* PutSurface flags */ + ) { + assert(fp_vaPutSurface); + return fp_vaPutSurface(dpy, surface, draw, srcx, srcy, srcw, srch, destx, desty, destw, desth, cliprects, number_cliprects, flags); + } private: vaGetDisplay_t* fp_vaGetDisplay; + vaPutSurface_t* fp_vaPutSurface; }; class VAAPI_GLX : public dll_helper { public: @@ -244,9 +263,6 @@ public: VA_ENSURE_TRUE(vaCopySurfaceGLX(display(), m_glx, m_surface->get(), VA_FRAME_PICTURE | VA_SRC_BT709), false); return true; } - void sync() { - VAWARN(vaSyncSurface(display(), m_surface->get())); - } VADisplay display() const { return m_surface->display();} surface_t* surface() { return m_surface.get();} void* glxSurface() { return m_glx;}