File indexing completed on 2025-01-19 03:57:04
0001 /********************************************************* 0002 * Copyright (C) 2020, Val Doroshchuk <valbok@gmail.com> * 0003 * * 0004 * This file is part of QtAVPlayer. * 0005 * Free Qt Media Player based on FFmpeg. * 0006 *********************************************************/ 0007 0008 #include "qavhwdevice_vaapi_x11_glx_p.h" 0009 #include "qavvideocodec_p.h" 0010 #include "qavstream.h" 0011 #include "qavvideobuffer_gpu_p.h" 0012 #include <QDebug> 0013 0014 #include <GL/glx.h> 0015 #include <va/va_x11.h> 0016 0017 extern "C" { 0018 #include <libavutil/hwcontext_vaapi.h> 0019 #include <libavcodec/avcodec.h> 0020 } 0021 0022 typedef void (*glXBindTexImageEXT_)(Display *dpy, GLXDrawable drawable, int buffer, const int *attrib_list); 0023 typedef void (*glXReleaseTexImageEXT_)(Display *dpy, GLXDrawable draw, int buffer); 0024 static glXBindTexImageEXT_ s_glXBindTexImageEXT = nullptr; 0025 static glXReleaseTexImageEXT_ s_glXReleaseTexImageEXT = nullptr; 0026 0027 QT_BEGIN_NAMESPACE 0028 0029 class QAVHWDevice_VAAPI_X11_GLXPrivate 0030 { 0031 public: 0032 Pixmap pixmap = 0; 0033 GLXPixmap glxpixmap = 0; 0034 Display *display = nullptr; 0035 GLuint texture = 0; 0036 }; 0037 0038 QAVHWDevice_VAAPI_X11_GLX::QAVHWDevice_VAAPI_X11_GLX() 0039 : d_ptr(new QAVHWDevice_VAAPI_X11_GLXPrivate) 0040 { 0041 } 0042 0043 QAVHWDevice_VAAPI_X11_GLX::~QAVHWDevice_VAAPI_X11_GLX() 0044 { 0045 Q_D(QAVHWDevice_VAAPI_X11_GLX); 0046 0047 if (d->glxpixmap) { 0048 s_glXReleaseTexImageEXT(d->display, d->glxpixmap, GLX_FRONT_EXT); 0049 glXDestroyPixmap(d->display, d->glxpixmap); 0050 } 0051 if (d->pixmap) 0052 XFreePixmap(d->display, d->pixmap); 0053 0054 if (d->texture) 0055 glDeleteTextures(1, &d->texture); 0056 } 0057 0058 AVPixelFormat QAVHWDevice_VAAPI_X11_GLX::format() const 0059 { 0060 return AV_PIX_FMT_VAAPI; 0061 } 0062 0063 AVHWDeviceType QAVHWDevice_VAAPI_X11_GLX::type() const 0064 { 0065 return AV_HWDEVICE_TYPE_VAAPI; 0066 } 0067 0068 class VideoBuffer_GLX : public QAVVideoBuffer_GPU 0069 { 0070 public: 0071 VideoBuffer_GLX(QAVHWDevice_VAAPI_X11_GLXPrivate *hw, const QAVVideoFrame &frame) 0072 : QAVVideoBuffer_GPU(frame) 0073 , m_hw(hw) 0074 { 0075 if (!s_glXBindTexImageEXT) { 0076 s_glXBindTexImageEXT = (glXBindTexImageEXT_) glXGetProcAddressARB((const GLubyte *)"glXBindTexImageEXT"); 0077 s_glXReleaseTexImageEXT = (glXReleaseTexImageEXT_) glXGetProcAddressARB((const GLubyte *)"glXReleaseTexImageEXT"); 0078 } 0079 } 0080 0081 QAVVideoFrame::HandleType handleType() const override 0082 { 0083 return QAVVideoFrame::GLTextureHandle; 0084 } 0085 0086 QVariant handle(QRhi */*rhi*/) const override 0087 { 0088 if (!s_glXBindTexImageEXT) { 0089 qWarning() << "Could not get proc address: s_glXBindTexImageEXT"; 0090 return 0; 0091 } 0092 0093 auto av_frame = frame().frame(); 0094 AVHWDeviceContext *hwctx = (AVHWDeviceContext *)frame().stream().codec()->avctx()->hw_device_ctx->data; 0095 AVVAAPIDeviceContext *vactx = (AVVAAPIDeviceContext *)hwctx->hwctx; 0096 VADisplay va_display = vactx->display; 0097 VASurfaceID va_surface = (VASurfaceID)(uintptr_t)av_frame->data[3]; 0098 0099 int w = av_frame->width; 0100 int h = av_frame->height; 0101 0102 if (!m_hw->display) { 0103 glGenTextures(1, &m_hw->texture); 0104 auto display = (Display *)glXGetCurrentDisplay(); 0105 m_hw->display = display; 0106 int xscr = DefaultScreen(display); 0107 const char *glxext = glXQueryExtensionsString(display, xscr); 0108 if (!glxext || !strstr(glxext, "GLX_EXT_texture_from_pixmap")) { 0109 qWarning() << "GLX_EXT_texture_from_pixmap is not supported"; 0110 return 0; 0111 } 0112 0113 int attribs[] = { 0114 GLX_RENDER_TYPE, GLX_RGBA_BIT, 0115 GLX_X_RENDERABLE, True, 0116 GLX_BIND_TO_TEXTURE_RGBA_EXT, True, 0117 GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, 0118 GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT, 0119 GLX_Y_INVERTED_EXT, True, 0120 GLX_DOUBLEBUFFER, False, 0121 GLX_RED_SIZE, 8, 0122 GLX_GREEN_SIZE, 8, 0123 GLX_BLUE_SIZE, 8, 0124 GLX_ALPHA_SIZE, 8, 0125 None 0126 }; 0127 0128 int fbcount; 0129 GLXFBConfig *fbcs = glXChooseFBConfig(display, xscr, attribs, &fbcount); 0130 if (!fbcount) { 0131 XFree(fbcs); 0132 qWarning() << "No texture-from-pixmap support"; 0133 return 0; 0134 } 0135 0136 GLXFBConfig fbc = fbcs[0]; 0137 XFree(fbcs); 0138 0139 XWindowAttributes xwa; 0140 XGetWindowAttributes(display, DefaultRootWindow(display), &xwa); 0141 0142 m_hw->pixmap = XCreatePixmap(display, DefaultRootWindow(display), w, h, xwa.depth); 0143 0144 const int attribs_pixmap[] = { 0145 GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, 0146 GLX_TEXTURE_FORMAT_EXT, xwa.depth == 32 ? GLX_TEXTURE_FORMAT_RGBA_EXT : GLX_TEXTURE_FORMAT_RGB_EXT, 0147 GLX_MIPMAP_TEXTURE_EXT, False, 0148 None, 0149 }; 0150 0151 m_hw->glxpixmap = glXCreatePixmap(display, fbc, m_hw->pixmap, attribs_pixmap); 0152 } 0153 0154 vaSyncSurface(va_display, va_surface); 0155 auto status = vaPutSurface(va_display, va_surface, m_hw->pixmap, 0156 0, 0, w, h, 0157 0, 0, w, h, 0158 NULL, 0, VA_FRAME_PICTURE | VA_SRC_BT709); 0159 if (status != VA_STATUS_SUCCESS) { 0160 qWarning() << "vaPutSurface failed" << status; 0161 return 0; 0162 } 0163 0164 XSync(m_hw->display, False); 0165 glBindTexture(GL_TEXTURE_2D, m_hw->texture); 0166 s_glXBindTexImageEXT(m_hw->display, m_hw->glxpixmap, GLX_FRONT_EXT, NULL); 0167 glBindTexture(GL_TEXTURE_2D, 0); 0168 0169 return m_hw->texture; 0170 } 0171 0172 QAVHWDevice_VAAPI_X11_GLXPrivate *m_hw = nullptr; 0173 }; 0174 0175 QAVVideoBuffer *QAVHWDevice_VAAPI_X11_GLX::videoBuffer(const QAVVideoFrame &frame) const 0176 { 0177 return new VideoBuffer_GLX(d_ptr.get(), frame); 0178 } 0179 0180 QT_END_NAMESPACE