1
0
mirror of https://github.com/mpv-player/mpv synced 2024-12-27 09:32:40 +00:00
mpv/video/out/gl_hwdec_vaglx.c
wm4 fb855b8659 client API: expose OpenGL renderer
This adds API to libmpv that lets host applications use the mpv opengl
renderer. This is a more flexible (and possibly more portable) option to
foreign window embedding (via --wid).

This assumes that methods like context sharing and multithreaded OpenGL
rendering are infeasible, and that a way is needed to integrate it with
an application that uses a single thread to render everything.

Add an example that does this with QtQuick/qml. The example is
relatively lazy, but still shows how relatively simple the integration
is. The FBO indirection could probably be avoided, but would require
more work (and would probably lead to worse QtQuick integration, because
it would have to ignore transformations like rotation).

Because this makes mpv directly use the host application's OpenGL
context, there is no platform specific code involved in mpv, except
for hw decoding interop.

main.qml is derived from some Qt example.

The following things are still missing:
- a way to do better video timing
- expose GL renderer options, allow changing them at runtime
- support for color equalizer controls
- support for screenshots
2014-12-09 17:59:04 +01:00

151 lines
4.0 KiB
C

/*
* This file is part of mpv.
*
* Parts based on the MPlayer VA-API patch (see vo_vaapi.c).
*
* mpv 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 2 of the License, or
* (at your option) any later version.
*
* mpv 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 mpv. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stddef.h>
#include <assert.h>
#include <GL/glx.h>
#include <va/va_glx.h>
#include "x11_common.h"
#include "gl_hwdec.h"
#include "video/vaapi.h"
struct priv {
struct mp_log *log;
struct mp_vaapi_ctx *ctx;
VADisplay *display;
GLuint gl_texture;
void *vaglx_surface;
};
static void destroy_texture(struct gl_hwdec *hw)
{
struct priv *p = hw->priv;
GL *gl = hw->gl;
VAStatus status;
if (p->vaglx_surface) {
va_lock(p->ctx);
status = vaDestroySurfaceGLX(p->display, p->vaglx_surface);
va_unlock(p->ctx);
CHECK_VA_STATUS(p, "vaDestroySurfaceGLX()");
p->vaglx_surface = NULL;
}
gl->DeleteTextures(1, &p->gl_texture);
p->gl_texture = 0;
}
static void destroy(struct gl_hwdec *hw)
{
struct priv *p = hw->priv;
destroy_texture(hw);
va_destroy(p->ctx);
hw->info->vaapi_ctx = NULL;
}
static int create(struct gl_hwdec *hw)
{
if (hw->info->vaapi_ctx)
return -1;
Display *x11disp = glXGetCurrentDisplay();
if (!x11disp)
return -1;
struct priv *p = talloc_zero(hw, struct priv);
hw->priv = p;
p->log = hw->log;
p->display = vaGetDisplayGLX(x11disp);
if (!p->display)
return -1;
p->ctx = va_initialize(p->display, p->log);
if (!p->ctx) {
vaTerminate(p->display);
return -1;
}
if (hw->reject_emulated && va_guess_if_emulated(p->ctx)) {
destroy(hw);
return -1;
}
hw->info->vaapi_ctx = p->ctx;
hw->converted_imgfmt = IMGFMT_RGB0;
return 0;
}
static int reinit(struct gl_hwdec *hw, const struct mp_image_params *params)
{
struct priv *p = hw->priv;
GL *gl = hw->gl;
VAStatus status;
destroy_texture(hw);
gl->GenTextures(1, &p->gl_texture);
gl->BindTexture(GL_TEXTURE_2D, p->gl_texture);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, params->w, params->h, 0,
GL_RGBA, GL_UNSIGNED_BYTE, NULL);
gl->BindTexture(GL_TEXTURE_2D, 0);
va_lock(p->ctx);
status = vaCreateSurfaceGLX(p->display, GL_TEXTURE_2D,
p->gl_texture, &p->vaglx_surface);
va_unlock(p->ctx);
return CHECK_VA_STATUS(p, "vaCreateSurfaceGLX()") ? 0 : -1;
}
static int map_image(struct gl_hwdec *hw, struct mp_image *hw_image,
GLuint *out_textures)
{
struct priv *p = hw->priv;
VAStatus status;
if (!p->vaglx_surface)
return -1;
va_lock(p->ctx);
status = vaCopySurfaceGLX(p->display, p->vaglx_surface,
va_surface_id(hw_image),
va_get_colorspace_flag(hw_image->params.colorspace));
va_unlock(p->ctx);
if (!CHECK_VA_STATUS(p, "vaCopySurfaceGLX()"))
return -1;
out_textures[0] = p->gl_texture;
return 0;
}
static void unmap_image(struct gl_hwdec *hw)
{
}
const struct gl_hwdec_driver gl_hwdec_vaglx = {
.api_name = "vaapi",
.imgfmt = IMGFMT_VAAPI,
.create = create,
.reinit = reinit,
.map_image = map_image,
.unmap_image = unmap_image,
.destroy = destroy,
};