/*****************************************************************************
* converter_vdpau.c: OpenGL VDPAU opaque converter
*****************************************************************************
* Copyright (C) 2017 VLC authors, VideoLAN and VideoLabs
*
* Author: Victorien Le Couviour--Tuffet <victorien.lecouviour.tuffet@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_window.h>
#include <vlc_xlib.h>
#include <vlc_codec.h>
#include <vlc_plugin.h>
#include "gl_api.h"
#include "gl_util.h"
#include "../../hw/vdpau/vlc_vdpau.h"
#include "interop.h"
#define INTEROP_CALL(sys, fct, ...) \
((sys)->gl.fct(__VA_ARGS__)); \
{ \
GLenum ret = (sys)->gl.GetError(); \
if (ret != GL_NO_ERROR) \
{ \
msg_Err(interop->gl, #fct " failed: 0x%x", ret); \
return VLC_EGENERIC; \
} \
}
typedef struct {
vlc_decoder_device *dec_device;
struct {
PFNGLGETERRORPROC GetError;
PFNGLVDPAUINITNVPROC VDPAUInitNV;
PFNGLVDPAUFININVPROC VDPAUFiniNV;
PFNGLVDPAUREGISTEROUTPUTSURFACENVPROC VDPAURegisterOutputSurfaceNV;
PFNGLVDPAUISSURFACENVPROC VDPAUIsSurfaceNV;
PFNGLVDPAUUNREGISTERSURFACENVPROC VDPAUUnregisterSurfaceNV;
PFNGLVDPAUGETSURFACEIVNVPROC VDPAUGetSurfaceivNV;
PFNGLVDPAUSURFACEACCESSNVPROC VDPAUSurfaceAccessNV;
PFNGLVDPAUMAPSURFACESNVPROC VDPAUMapSurfacesNV;
PFNGLVDPAUUNMAPSURFACESNVPROC VDPAUUnmapSurfacesNV;
} gl;
} converter_sys_t;
static int
tc_vdpau_gl_update(const struct vlc_gl_interop *interop, uint32_t textures[],
int32_t const tex_widths[], int32_t const tex_heights[],
picture_t *pic, size_t const plane_offsets[])
{
VLC_UNUSED(tex_widths);
VLC_UNUSED(tex_heights);
VLC_UNUSED(plane_offsets);
vlc_vdp_output_surface_t *p_sys = pic->p_sys;
converter_sys_t *convsys = interop->priv;
GLvdpauSurfaceNV gl_nv_surface = p_sys->gl_nv_surface;
static_assert (sizeof (gl_nv_surface) <= sizeof (p_sys->gl_nv_surface),
"Type too small");
if (gl_nv_surface)
{
assert(convsys->gl.VDPAUIsSurfaceNV(gl_nv_surface) == GL_TRUE);
GLint state;
GLsizei num_val;
INTEROP_CALL(convsys, VDPAUGetSurfaceivNV, gl_nv_surface,
GL_SURFACE_STATE_NV, 1, &num_val, &state);
assert(num_val == 1); assert(state == GL_SURFACE_MAPPED_NV);
INTEROP_CALL(convsys, VDPAUUnmapSurfacesNV, 1, &gl_nv_surface);
INTEROP_CALL(convsys, VDPAUUnregisterSurfaceNV, gl_nv_surface);
}
gl_nv_surface =
INTEROP_CALL(convsys, VDPAURegisterOutputSurfaceNV,
(void *)(size_t)p_sys->surface,
GL_TEXTURE_2D, interop->tex_count, textures);
INTEROP_CALL(convsys, VDPAUSurfaceAccessNV, gl_nv_surface, GL_READ_ONLY);
INTEROP_CALL(convsys, VDPAUMapSurfacesNV, 1, &gl_nv_surface);
p_sys->gl_nv_surface = gl_nv_surface;
return VLC_SUCCESS;
}
static void
Close(struct vlc_gl_interop *interop)
{
converter_sys_t *sys = interop->priv;
sys->gl.VDPAUFiniNV();
assert(sys->gl.GetError() == GL_NO_ERROR);
vlc_decoder_device *dec_device = sys->dec_device;
vlc_decoder_device_Release(dec_device);
free(sys);
}
static int
Open(struct vlc_gl_interop *interop)
{
if (interop->vctx == NULL)
return VLC_EGENERIC;
struct vlc_gl_extension_vt extension_vt;
vlc_gl_LoadExtensionFunctions(interop->gl, &extension_vt);
vlc_decoder_device *dec_device = vlc_video_context_HoldDevice(interop->vctx);
if (GetVDPAUOpaqueDevice(dec_device) == NULL
|| interop->fmt_in.i_chroma != VLC_CODEC_VDPAU_VIDEO
|| !vlc_gl_HasExtension(&extension_vt, "GL_NV_vdpau_interop"))
{
vlc_decoder_device_Release(dec_device);
return VLC_EGENERIC;
}
converter_sys_t *sys = malloc(sizeof(*sys));
if (unlikely(sys == NULL))
{
vlc_decoder_device_Release(dec_device);
return VLC_ENOMEM;
}
sys->dec_device = dec_device;
sys->gl.GetError = vlc_gl_GetProcAddress(interop->gl, "glGetError");
assert(sys->gl.GetError != NULL);
/* Request to change the input chroma to the core */
interop->fmt_in.i_chroma = VLC_CODEC_VDPAU_OUTPUT;
VdpDevice device;
vdpau_decoder_device_t *vdpau_dev = GetVDPAUOpaqueDevice(dec_device);
vdp_t *vdp = vdpau_dev->vdp;
device = vdpau_dev->device;
void *vdp_gpa;
if (vdp_get_proc_address(vdp, device,
VDP_FUNC_ID_GET_PROC_ADDRESS, &vdp_gpa)
!= VDP_STATUS_OK)
{
vlc_decoder_device_Release(dec_device);
free(sys);
return VLC_EGENERIC;
}
#define SAFE_GPA(fct) \
sys->gl.fct = vlc_gl_GetProcAddress(interop->gl, "gl" #fct); \
if (sys->gl.fct == NULL) \
{ \
vlc_decoder_device_Release(dec_device); \
free(sys); \
return VLC_EGENERIC; \
}
SAFE_GPA(VDPAUInitNV);
SAFE_GPA(VDPAUFiniNV);
SAFE_GPA(VDPAURegisterOutputSurfaceNV);
SAFE_GPA(VDPAUIsSurfaceNV);
SAFE_GPA(VDPAUUnregisterSurfaceNV);
SAFE_GPA(VDPAUGetSurfaceivNV);
SAFE_GPA(VDPAUSurfaceAccessNV);
SAFE_GPA(VDPAUMapSurfacesNV);
SAFE_GPA(VDPAUUnmapSurfacesNV);
#undef SAFE_GPA
sys->gl.VDPAUInitNV((void *)(uintptr_t)device, vdp_gpa);
{
GLenum ret = (sys)->gl.GetError();
if (ret != GL_NO_ERROR)
{
msg_Err(interop->gl, "VDPAUInitNV failed: 0x%x", ret);
vlc_decoder_device_Release(dec_device);
free(sys);
return VLC_EGENERIC;
}
}
/* The pictures are uploaded upside-down */
video_format_TransformBy(&interop->fmt_out, TRANSFORM_VFLIP);
interop->tex_target = GL_TEXTURE_2D;
interop->fmt_out.i_chroma = VLC_CODEC_RGBA;
interop->fmt_out.space = COLOR_SPACE_UNDEF;
interop->tex_count = 1;
interop->texs[0] = (struct vlc_gl_tex_cfg) {
.w = {1, 1},
.h = {1, 1},
.internal = GL_RGBA,
.format = GL_RGBA,
.type = GL_UNSIGNED_BYTE,
};
static const struct vlc_gl_interop_ops ops = {
.update_textures = tc_vdpau_gl_update,
.close = Close,
};
interop->ops = &ops;
interop->priv = sys;
return VLC_SUCCESS;
}
vlc_module_begin ()
set_description("VDPAU OpenGL surface converter")
set_capability("glinterop", 2)
set_callback(Open)
set_subcategory(SUBCAT_VIDEO_VOUT)
add_shortcut("vdpau")
vlc_module_end ()
¤ Dauer der Verarbeitung: 0.5 Sekunden
¤
*© Formatika GbR, Deutschland
|
|