[vlc-devel] [PATCH] opengl: add converter_vdpau
Victorien Le Couviour--Tuffet
victorien.lecouviour.tuffet at gmail.com
Thu Jul 20 16:55:10 CEST 2017
---
modules/hw/vdpau/vlc_vdpau.h | 1 +
modules/video_output/Makefile.am | 7 +
modules/video_output/opengl/converter_vdpau.c | 234 ++++++++++++++++++++++++++
modules/video_output/opengl/internal.h | 5 +
modules/video_output/opengl/vout_helper.c | 3 +
5 files changed, 250 insertions(+)
create mode 100644 modules/video_output/opengl/converter_vdpau.c
diff --git a/modules/hw/vdpau/vlc_vdpau.h b/modules/hw/vdpau/vlc_vdpau.h
index af62bddcc1..01289ffbae 100644
--- a/modules/hw/vdpau/vlc_vdpau.h
+++ b/modules/hw/vdpau/vlc_vdpau.h
@@ -261,6 +261,7 @@ struct picture_sys_t
VdpOutputSurface surface;
VdpDevice device;
vdp_t *vdp;
+ void *gl_nv_surface;
};
typedef struct vlc_vdp_video_frame
diff --git a/modules/video_output/Makefile.am b/modules/video_output/Makefile.am
index 5b5efcfe1f..d9e45f5377 100644
--- a/modules/video_output/Makefile.am
+++ b/modules/video_output/Makefile.am
@@ -46,6 +46,13 @@ OPENGL_COMMONCFLAGS += -DHAVE_VA_DRM
endif
endif
endif
+if HAVE_VDPAU
+OPENGL_COMMONLDFLAGS += $(LIBDL)
+OPENGL_COMMONLIBS += libvlc_vdpau.la
+OPENGL_COMMONSOURCES += video_output/opengl/converter_vdpau.c \
+ hw/vdpau/vlc_vdpau.h
+OPENGL_COMMONCFLAGS += $(VDPAU_CFLAGS) -DVLCGL_CONV_VDPAU
+endif
if HAVE_DECKLINK
libdecklinkoutput_plugin_la_SOURCES = video_output/decklink.cpp
diff --git a/modules/video_output/opengl/converter_vdpau.c b/modules/video_output/opengl/converter_vdpau.c
new file mode 100644
index 0000000000..3e70bc2c5c
--- /dev/null
+++ b/modules/video_output/opengl/converter_vdpau.c
@@ -0,0 +1,234 @@
+/*****************************************************************************
+ * converter_vdpau.c: OpenGL VDPAU opaque converter
+ *****************************************************************************
+ * Copyright (C) 2017 VLC authors, VideoLAN and VideoLabs
+ *
+ * Author: Victorien Le Couviour--Tuffet <victorien.lecouviour.tuffet at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+
+#include <GL/gl.h>
+#include <GL/glext.h>
+
+#include <vlc_common.h>
+#include <vlc_vout_window.h>
+#include <vlc_xlib.h>
+
+#include "../../hw/vdpau/vlc_vdpau.h"
+#include "internal.h"
+
+#define INTEROP_CALL(fct, ...) \
+ _##fct(__VA_ARGS__); \
+ { \
+ GLenum ret = glGetError(); \
+ if (ret != GL_NO_ERROR) \
+ { \
+ msg_Err(tc->gl, #fct " failed: 0x%x\n", ret); \
+ return VLC_EGENERIC; \
+ } \
+ }
+
+struct priv
+{
+ vdp_t *vdp;
+ VdpDevice vdp_device;
+};
+
+static PFNGLVDPAUINITNVPROC _glVDPAUInitNV;
+static PFNGLVDPAUFININVPROC _glVDPAUFiniNV;
+static PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC _glVDPAURegisterOutputSurfaceNV;
+static PFNGLVDPAUISSURFACENVPROC _glVDPAUIsSurfaceNV;
+static PFNGLVDPAUUNREGISTERSURFACENVPROC _glVDPAUUnregisterSurfaceNV;
+static PFNGLVDPAUGETSURFACEIVNVPROC _glVDPAUGetSurfaceivNV;
+static PFNGLVDPAUSURFACEACCESSNVPROC _glVDPAUSurfaceAccessNV;
+static PFNGLVDPAUMAPSURFACESNVPROC _glVDPAUMapSurfacesNV;
+static PFNGLVDPAUUNMAPSURFACESNVPROC _glVDPAUUnmapSurfacesNV;
+
+static void
+pool_pic_destroy_cb(picture_t *pic)
+{
+ vdp_output_surface_destroy(pic->p_sys->vdp, pic->p_sys->surface);
+ vdp_release_x11(pic->p_sys->vdp);
+ free(pic->p_sys);
+ free(pic);
+}
+
+static picture_pool_t *
+tc_vdpau_gl_get_pool(opengl_tex_converter_t const *tc,
+ unsigned int requested_count)
+{
+ struct priv *priv = tc->priv;
+ picture_t *pics[requested_count];
+
+ unsigned int i;
+ for (i = 0; i < requested_count; ++i)
+ {
+ VdpOutputSurface surface;
+
+ VdpStatus st;
+ if ((st = vdp_output_surface_create(priv->vdp, priv->vdp_device,
+ VDP_RGBA_FORMAT_B8G8R8A8,
+ tc->fmt.i_visible_width,
+ tc->fmt.i_visible_height,
+ &surface)) != VDP_STATUS_OK)
+ goto error;
+
+ picture_sys_t *picsys = calloc(1, sizeof(*picsys));
+ if (!picsys)
+ goto error;
+
+ picsys->vdp = vdp_hold_x11(priv->vdp, NULL);
+ picsys->device = priv->vdp_device;
+ picsys->surface = surface;
+
+ picture_resource_t rsc = { .p_sys = picsys,
+ .pf_destroy = pool_pic_destroy_cb };
+
+ pics[i] = picture_NewFromResource(&tc->fmt, &rsc);
+ if (!pics[i])
+ goto error;
+ }
+
+ picture_pool_t *pool = picture_pool_New(requested_count, pics);
+ if (!pool)
+ goto error;
+
+ return pool;
+
+error:
+ while (i--)
+ picture_Release(pics[i]);
+ return NULL;
+}
+
+static int
+tc_vdpau_gl_update(opengl_tex_converter_t const *tc, GLuint textures[],
+ GLsizei const tex_widths[], GLsizei const tex_heights[],
+ picture_t *pic, size_t const plane_offsets[])
+{
+ VLC_UNUSED(tex_widths);
+ VLC_UNUSED(tex_heights);
+ VLC_UNUSED(plane_offsets);
+
+ GLvdpauSurfaceNV *p_gl_nv_surface =
+ (GLvdpauSurfaceNV *)&pic->p_sys->gl_nv_surface;
+
+ if (*p_gl_nv_surface)
+ {
+ assert(_glVDPAUIsSurfaceNV(*p_gl_nv_surface) == GL_TRUE);
+
+ GLint state;
+ GLsizei num_val;
+ INTEROP_CALL(glVDPAUGetSurfaceivNV, *p_gl_nv_surface,
+ GL_SURFACE_STATE_NV, 1, &num_val, &state);
+ assert(num_val == 1); assert(state == GL_SURFACE_MAPPED_NV);
+
+ INTEROP_CALL(glVDPAUUnmapSurfacesNV, 1, p_gl_nv_surface);
+ INTEROP_CALL(glVDPAUUnregisterSurfaceNV, *p_gl_nv_surface);
+ }
+
+ *p_gl_nv_surface =
+ INTEROP_CALL(glVDPAURegisterOutputSurfaceNV,
+ (void *)(size_t)pic->p_sys->surface,
+ GL_TEXTURE_2D, tc->tex_count, textures);
+ INTEROP_CALL(glVDPAUSurfaceAccessNV, *p_gl_nv_surface, GL_READ_ONLY);
+ INTEROP_CALL(glVDPAUMapSurfacesNV, 1, p_gl_nv_surface);
+
+ return VLC_SUCCESS;
+}
+
+static void
+tc_vdpau_gl_release(opengl_tex_converter_t const *tc)
+{
+ _glVDPAUFiniNV(); assert(glGetError() == GL_NO_ERROR);
+ vdp_release_x11(((struct priv *)tc->priv)->vdp);
+ free(tc->priv);
+}
+
+int
+opengl_tex_converter_vdpau_init(opengl_tex_converter_t *tc)
+{
+ if ((tc->fmt.i_chroma != VLC_CODEC_VDPAU_VIDEO_420 &&
+ tc->fmt.i_chroma != VLC_CODEC_VDPAU_VIDEO_422 &&
+ tc->fmt.i_chroma != VLC_CODEC_VDPAU_VIDEO_444) ||
+ !HasExtension(tc->glexts, "GL_NV_vdpau_interop") ||
+ tc->gl->surface->type != VOUT_WINDOW_TYPE_XID)
+ return VLC_EGENERIC;
+
+ tc->fmt.i_chroma = VLC_CODEC_VDPAU_OUTPUT;
+
+ if (!vlc_xlib_init(VLC_OBJECT(tc->gl)))
+ return VLC_EGENERIC;
+
+ struct priv *priv = calloc(1, sizeof(*priv));
+ if (!priv)
+ return VLC_EGENERIC;
+ tc->priv = priv;
+
+ if (vdp_get_x11(tc->gl->surface->display.x11, -1,
+ &priv->vdp, &priv->vdp_device) != VDP_STATUS_OK)
+ {
+ free(priv);
+ return VLC_EGENERIC;
+ }
+
+ void *vdp_gpa;
+ if (vdp_get_proc_address(priv->vdp, priv->vdp_device,
+ VDP_FUNC_ID_GET_PROC_ADDRESS, &vdp_gpa)
+ != VDP_STATUS_OK)
+ {
+ vdp_release_x11(priv->vdp);
+ free(priv);
+ return VLC_EGENERIC;
+ }
+
+#define SAFE_GPA(fct) \
+ if (!(_##fct = vlc_gl_GetProcAddress(tc->gl, #fct))) \
+ return VLC_EGENERIC;
+ SAFE_GPA(glVDPAUInitNV);
+ SAFE_GPA(glVDPAUFiniNV);
+ SAFE_GPA(glVDPAURegisterOutputSurfaceNV);
+ SAFE_GPA(glVDPAUIsSurfaceNV);
+ SAFE_GPA(glVDPAUUnregisterSurfaceNV);
+ SAFE_GPA(glVDPAUGetSurfaceivNV);
+ SAFE_GPA(glVDPAUSurfaceAccessNV);
+ SAFE_GPA(glVDPAUMapSurfacesNV);
+ SAFE_GPA(glVDPAUUnmapSurfacesNV);
+#undef SAFE_GPA
+
+ INTEROP_CALL(glVDPAUInitNV, (void *)(size_t)priv->vdp_device, vdp_gpa);
+
+ tc->fshader = opengl_fragment_shader_init(tc, GL_TEXTURE_2D,
+ VLC_CODEC_RGB32,
+ COLOR_SPACE_UNDEF);
+ if (!tc->fshader)
+ {
+ tc_vdpau_gl_release(tc);
+ return VLC_EGENERIC;
+ }
+
+ tc->pf_get_pool = tc_vdpau_gl_get_pool;
+ tc->pf_update = tc_vdpau_gl_update;
+ tc->pf_release = tc_vdpau_gl_release;
+
+ return VLC_SUCCESS;
+}
diff --git a/modules/video_output/opengl/internal.h b/modules/video_output/opengl/internal.h
index 3c27d49028..c5f9c45100 100644
--- a/modules/video_output/opengl/internal.h
+++ b/modules/video_output/opengl/internal.h
@@ -346,4 +346,9 @@ int
opengl_tex_converter_vaapi_init(opengl_tex_converter_t *tc);
#endif
+#ifdef VLCGL_CONV_VDPAU
+int
+opengl_tex_converter_vdpau_init(opengl_tex_converter_t *tc);
+#endif
+
#endif /* include-guard */
diff --git a/modules/video_output/opengl/vout_helper.c b/modules/video_output/opengl/vout_helper.c
index 075b1c2ee8..ee21a7ea0a 100644
--- a/modules/video_output/opengl/vout_helper.c
+++ b/modules/video_output/opengl/vout_helper.c
@@ -53,6 +53,9 @@ static opengl_tex_converter_init_cb opengl_tex_converter_init_cbs[] =
#ifdef VLCGL_CONV_VA
opengl_tex_converter_vaapi_init,
#endif
+#ifdef VLCGL_CONV_VDPAU
+ opengl_tex_converter_vdpau_init,
+#endif
#ifdef __ANDROID__
opengl_tex_converter_anop_init,
#endif
--
2.13.1
More information about the vlc-devel
mailing list