summaryrefslogtreecommitdiffstats
path: root/video
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-11-04 00:43:06 +0100
committerwm4 <wm4@nowhere>2013-11-04 00:43:06 +0100
commitf7b2d644eff7fae2d74259ae14ec2b05b00c9b9b (patch)
treeca5462391d6a8f7b8e254c51c88f30efea91b90f /video
parent37388ebb0ef9085c841d7f94e665a5a77cfe0e92 (diff)
parent25affdcc886ce010995804553396d81d90a321d3 (diff)
downloadmpv-f7b2d644eff7fae2d74259ae14ec2b05b00c9b9b.tar.bz2
mpv-f7b2d644eff7fae2d74259ae14ec2b05b00c9b9b.tar.xz
Merge branch 'master' into have_configure
Conflicts: configure
Diffstat (limited to 'video')
-rw-r--r--video/decode/dec_video.h5
-rw-r--r--video/decode/lavc.h2
-rw-r--r--video/decode/vaapi.c1
-rw-r--r--video/decode/vd_lavc.c7
-rw-r--r--video/mp_image.c22
-rw-r--r--video/mp_image.h3
-rw-r--r--video/out/gl_common.c9
-rw-r--r--video/out/gl_common.h39
-rw-r--r--video/out/gl_hwdec_vaglx.c140
-rw-r--r--video/out/gl_video.c123
-rw-r--r--video/out/gl_video.h4
-rw-r--r--video/out/vo_opengl.c73
12 files changed, 396 insertions, 32 deletions
diff --git a/video/decode/dec_video.h b/video/decode/dec_video.h
index 549d208f81..03b72907ef 100644
--- a/video/decode/dec_video.h
+++ b/video/decode/dec_video.h
@@ -47,6 +47,11 @@ int vd_control(struct sh_video *sh_video, int cmd, void *arg);
struct mp_hwdec_info {
struct mp_vdpau_ctx *vdpau_ctx;
struct mp_vaapi_ctx *vaapi_ctx;
+ // Can be used to lazily load a requested API.
+ // api_name is e.g. "vdpau" (like the fields above, without "_ctx")
+ // Can be NULL, is idempotent, caller checks _ctx fields for success/access.
+ void (*load_api)(struct mp_hwdec_info *info, const char *api_name);
+ void *load_api_ctx;
};
#endif /* MPLAYER_DEC_VIDEO_H */
diff --git a/video/decode/lavc.h b/video/decode/lavc.h
index 9e2533cbd5..af206bc82a 100644
--- a/video/decode/lavc.h
+++ b/video/decode/lavc.h
@@ -86,6 +86,8 @@ bool hwdec_check_codec_support(const char *decoder,
const struct hwdec_profile_entry *table);
int hwdec_get_max_refs(struct lavc_ctx *ctx);
+void hwdec_request_api(struct mp_hwdec_info *info, const char *api_name);
+
// lavc_dr1.c
int mp_codec_get_buffer(AVCodecContext *s, AVFrame *frame);
void mp_codec_release_buffer(AVCodecContext *s, AVFrame *frame);
diff --git a/video/decode/vaapi.c b/video/decode/vaapi.c
index bb2a6c1049..4603a3c5e1 100644
--- a/video/decode/vaapi.c
+++ b/video/decode/vaapi.c
@@ -421,6 +421,7 @@ static int init(struct lavc_ctx *ctx)
static int probe(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info,
const char *decoder)
{
+ hwdec_request_api(info, "vaapi");
if (!info || !info->vaapi_ctx)
return HWDEC_ERR_NO_CTX;
if (!hwdec_check_codec_support(decoder, profiles))
diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c
index 64542be69d..c6a939ec51 100644
--- a/video/decode/vd_lavc.c
+++ b/video/decode/vd_lavc.c
@@ -46,6 +46,7 @@
#include "video/img_format.h"
#include "video/mp_image_pool.h"
#include "video/filter/vf.h"
+#include "video/decode/dec_video.h"
#include "demux/stheader.h"
#include "demux/demux_packet.h"
#include "osdep/numcores.h"
@@ -195,6 +196,12 @@ int hwdec_get_max_refs(struct lavc_ctx *ctx)
return ctx->avctx->codec_id == AV_CODEC_ID_H264 ? 16 : 2;
}
+void hwdec_request_api(struct mp_hwdec_info *info, const char *api_name)
+{
+ if (info && info->load_api)
+ info->load_api(info, api_name);
+}
+
static int hwdec_probe(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info,
const char *decoder, const char **hw_decoder)
{
diff --git a/video/mp_image.c b/video/mp_image.c
index 3bc76b669e..9b96bab67d 100644
--- a/video/mp_image.c
+++ b/video/mp_image.c
@@ -36,6 +36,8 @@
#include "memcpy_pic.h"
#include "fmt-conversion.h"
+#include "video/filter/vf.h"
+
#if HAVE_PTHREADS
#include <pthread.h>
static pthread_mutex_t refcount_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -468,6 +470,26 @@ void mp_image_set_params(struct mp_image *image,
image->chroma_location = params->chroma_location;
}
+// Set most image parameters, but not image format or size.
+// Display size is used to set the PAR.
+void mp_image_set_attributes(struct mp_image *image,
+ const struct mp_image_params *params)
+{
+ struct mp_image_params nparams = *params;
+ nparams.imgfmt = image->imgfmt;
+ nparams.w = image->w;
+ nparams.h = image->h;
+ if (nparams.imgfmt != params->imgfmt)
+ mp_image_params_guess_csp(&nparams);
+ if (nparams.w != params->w || nparams.h != params->h) {
+ if (nparams.d_w && nparams.d_h) {
+ vf_rescale_dsize(&nparams.d_w, &nparams.d_h,
+ params->w, params->h, nparams.w, nparams.h);
+ }
+ }
+ mp_image_set_params(image, &nparams);
+}
+
void mp_image_set_colorspace_details(struct mp_image *image,
struct mp_csp_details *csp)
{
diff --git a/video/mp_image.h b/video/mp_image.h
index e198c4e547..f7e7353475 100644
--- a/video/mp_image.h
+++ b/video/mp_image.h
@@ -153,6 +153,9 @@ void mp_image_params_from_image(struct mp_image_params *params,
void mp_image_set_params(struct mp_image *image,
const struct mp_image_params *params);
+void mp_image_set_attributes(struct mp_image *image,
+ const struct mp_image_params *params);
+
struct AVFrame;
void mp_image_copy_fields_from_av_frame(struct mp_image *dst,
struct AVFrame *src);
diff --git a/video/out/gl_common.c b/video/out/gl_common.c
index d39a09df16..f3e38a2171 100644
--- a/video/out/gl_common.c
+++ b/video/out/gl_common.c
@@ -1008,3 +1008,12 @@ void mp_log_source(struct mp_log *log, int lev, const char *src)
src = next;
}
}
+
+extern const struct gl_hwdec_driver gl_hwdec_vaglx;
+
+const struct gl_hwdec_driver *mpgl_hwdec_drivers[] = {
+#if HAVE_VAAPI_GLX
+ &gl_hwdec_vaglx,
+#endif
+ NULL
+};
diff --git a/video/out/gl_common.h b/video/out/gl_common.h
index 41d30bb001..4722f3d52e 100644
--- a/video/out/gl_common.h
+++ b/video/out/gl_common.h
@@ -164,6 +164,45 @@ void mpgl_set_backend_w32(MPGLContext *ctx);
void mpgl_set_backend_x11(MPGLContext *ctx);
void mpgl_set_backend_wayland(MPGLContext *ctx);
+struct mp_hwdec_info;
+
+struct gl_hwdec {
+ const struct gl_hwdec_driver *driver;
+ struct mp_log *log;
+ struct MPGLContext *mpgl;
+ struct mp_hwdec_info *info;
+ // For free use by hwdec driver
+ void *priv;
+ // hwdec backends must set this to an IMGFMT_ that has an equivalent
+ // internal representation in gl_video.c as the hardware texture.
+ // It's used to build the rendering chain, and also as screenshot format.
+ int converted_imgfmt;
+};
+
+struct gl_hwdec_driver {
+ // Same name as used by mp_hwdec_info->load_api()
+ const char *api_name;
+ // Test whether the given IMGFMT_ is supported.
+ bool (*query_format)(int imgfmt);
+ // Create the hwdec device. It must fill in hw->info, if applicable.
+ // This also must set hw->converted_imgfmt.
+ int (*create)(struct gl_hwdec *hw);
+ // Prepare for rendering video. (E.g. create textures.)
+ // Called on initialization, and every time the video size changes.
+ int (*reinit)(struct gl_hwdec *hw, int w, int h);
+ // Return textures that contain the given hw_image.
+ // Note that the caller keeps a reference to hw_image until unbind_image
+ // is called, so the callee doesn't need to do that.
+ int (*load_image)(struct gl_hwdec *hw, struct mp_image *hw_image,
+ GLuint *out_textures);
+ // Undo load_image(). The user of load_image() calls this when the textures
+ // are not needed anymore.
+ void (*unload_image)(struct gl_hwdec *hw);
+ void (*destroy)(struct gl_hwdec *hw);
+};
+
+extern const struct gl_hwdec_driver *mpgl_hwdec_drivers[];
+
void *mp_getdladdr(const char *s);
void mpgl_load_functions(GL *gl, void *(*getProcAddress)(const GLubyte *),
diff --git a/video/out/gl_hwdec_vaglx.c b/video/out/gl_hwdec_vaglx.c
new file mode 100644
index 0000000000..9e1030fe49
--- /dev/null
+++ b/video/out/gl_hwdec_vaglx.c
@@ -0,0 +1,140 @@
+/*
+ * 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_common.h"
+#include "video/vaapi.h"
+#include "video/decode/dec_video.h"
+
+struct priv {
+ struct mp_vaapi_ctx *ctx;
+ VADisplay *display;
+ GLuint gl_texture;
+ void *vaglx_surface;
+};
+
+static bool query_format(int imgfmt)
+{
+ return imgfmt == IMGFMT_VAAPI;
+}
+
+static void destroy_texture(struct gl_hwdec *hw)
+{
+ struct priv *p = hw->priv;
+ VAStatus status;
+
+ if (p->vaglx_surface) {
+ status = vaDestroySurfaceGLX(p->display, p->vaglx_surface);
+ check_va_status(status, "vaDestroySurfaceGLX()");
+ p->vaglx_surface = NULL;
+ }
+
+ glDeleteTextures(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);
+}
+
+static int create(struct gl_hwdec *hw)
+{
+ if (hw->info->vaapi_ctx)
+ return -1;
+ if (!hw->mpgl->vo->x11 || !glXGetCurrentContext())
+ return -1;
+ struct priv *p = talloc_zero(hw, struct priv);
+ hw->priv = p;
+ p->display = vaGetDisplayGLX(hw->mpgl->vo->x11->display);
+ if (!p->display)
+ return -1;
+ p->ctx = va_initialize(p->display);
+ if (!p->ctx) {
+ vaTerminate(p->display);
+ return -1;
+ }
+ hw->info->vaapi_ctx = p->ctx;
+ hw->converted_imgfmt = IMGFMT_RGBA;
+ return 0;
+}
+
+static int reinit(struct gl_hwdec *hw, int w, int h)
+{
+ struct priv *p = hw->priv;
+ GL *gl = hw->mpgl->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, w, h, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ gl->BindTexture(GL_TEXTURE_2D, 0);
+
+ status = vaCreateSurfaceGLX(p->display, GL_TEXTURE_2D,
+ p->gl_texture, &p->vaglx_surface);
+ return check_va_status(status, "vaCreateSurfaceGLX()") ? 0 : -1;
+}
+
+static int load_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;
+
+ status = vaCopySurfaceGLX(p->display, p->vaglx_surface,
+ va_surface_id_in_mp_image(hw_image),
+ va_get_colorspace_flag(hw_image->colorspace));
+ if (!check_va_status(status, "vaCopySurfaceGLX()"))
+ return -1;
+
+ out_textures[0] = p->gl_texture;
+ return 0;
+}
+
+static void unload_image(struct gl_hwdec *hw)
+{
+}
+
+const struct gl_hwdec_driver gl_hwdec_vaglx = {
+ .api_name = "vaapi",
+ .query_format = query_format,
+ .create = create,
+ .reinit = reinit,
+ .load_image = load_image,
+ .unload_image = unload_image,
+ .destroy = destroy,
+};
diff --git a/video/out/gl_video.c b/video/out/gl_video.c
index 3151927be6..bcab017133 100644
--- a/video/out/gl_video.c
+++ b/video/out/gl_video.c
@@ -114,6 +114,7 @@ struct texplane {
struct video_image {
struct texplane planes[4];
bool image_flipped;
+ struct mp_image *hwimage; // if hw decoding is active
};
struct scaler {
@@ -202,6 +203,9 @@ struct gl_video {
int last_dither_matrix_size;
float *last_dither_matrix;
+ struct gl_hwdec *hwdec;
+ bool hwdec_active;
+
void *scratch;
};
@@ -1129,7 +1133,7 @@ static void reinit_rendering(struct gl_video *p)
uninit_rendering(p);
- if (!p->image.planes[0].gl_texture)
+ if (!p->image_format)
return;
for (int n = 0; n < 2; n++)
@@ -1196,17 +1200,41 @@ void gl_video_set_lut3d(struct gl_video *p, struct lut3d *lut3d)
debug_check_gl(p, "after 3d lut creation");
}
-static void set_image_textures(struct gl_video *p, struct video_image *vimg)
+static void set_image_textures(struct gl_video *p, struct video_image *vimg,
+ GLuint imgtex[4])
{
GL *gl = p->gl;
+ GLuint dummy[4];
+ if (!imgtex)
+ imgtex = dummy;
- for (int n = 0; n < p->plane_count; n++) {
- struct texplane *plane = &vimg->planes[n];
+ if (p->hwdec_active) {
+ assert(vimg->hwimage);
+ p->hwdec->driver->load_image(p->hwdec, vimg->hwimage, imgtex);
+ } else {
+ for (int n = 0; n < p->plane_count; n++)
+ imgtex[n] = vimg->planes[n].gl_texture;
+ }
+ for (int n = 0; n < 4; n++) {
gl->ActiveTexture(GL_TEXTURE0 + n);
- gl->BindTexture(GL_TEXTURE_2D, plane->gl_texture);
+ gl->BindTexture(GL_TEXTURE_2D, imgtex[n]);
+ }
+ gl->ActiveTexture(GL_TEXTURE0);
+}
+
+static void unset_image_textures(struct gl_video *p)
+{
+ GL *gl = p->gl;
+
+ for (int n = 0; n < 4; n++) {
+ gl->ActiveTexture(GL_TEXTURE0 + n);
+ gl->BindTexture(GL_TEXTURE_2D, 0);
}
gl->ActiveTexture(GL_TEXTURE0);
+
+ if (p->hwdec_active)
+ p->hwdec->driver->unload_image(p->hwdec);
}
static void init_video(struct gl_video *p)
@@ -1243,21 +1271,27 @@ static void init_video(struct gl_video *p)
plane->w = full_w >> p->image_desc.xs[n];
plane->h = full_h >> p->image_desc.ys[n];
- texture_size(p, plane->w, plane->h,
- &plane->tex_w, &plane->tex_h);
+ if (p->hwdec_active) {
+ // We expect hwdec backends to allocate exact size
+ plane->tex_w = plane->w;
+ plane->tex_h = plane->h;
+ } else {
+ texture_size(p, plane->w, plane->h,
+ &plane->tex_w, &plane->tex_h);
- MP_VERBOSE(p, "Texture for plane %d: %dx%d\n",
- n, plane->tex_w, plane->tex_h);
+ gl->ActiveTexture(GL_TEXTURE0 + n);
+ gl->GenTextures(1, &plane->gl_texture);
+ gl->BindTexture(GL_TEXTURE_2D, plane->gl_texture);
- gl->ActiveTexture(GL_TEXTURE0 + n);
- gl->GenTextures(1, &plane->gl_texture);
- gl->BindTexture(GL_TEXTURE_2D, plane->gl_texture);
+ gl->TexImage2D(GL_TEXTURE_2D, 0, plane->gl_internal_format,
+ plane->tex_w, plane->tex_h, 0,
+ plane->gl_format, plane->gl_type, NULL);
- gl->TexImage2D(GL_TEXTURE_2D, 0, plane->gl_internal_format,
- plane->tex_w, plane->tex_h, 0,
- plane->gl_format, plane->gl_type, NULL);
+ default_tex_params(gl, GL_TEXTURE_2D, GL_LINEAR);
+ }
- default_tex_params(gl, GL_TEXTURE_2D, GL_LINEAR);
+ MP_VERBOSE(p, "Texture for plane %d: %dx%d\n",
+ n, plane->tex_w, plane->tex_h);
}
gl->ActiveTexture(GL_TEXTURE0);
@@ -1266,6 +1300,11 @@ static void init_video(struct gl_video *p)
debug_check_gl(p, "after video texture creation");
+ if (p->hwdec_active) {
+ if (p->hwdec->driver->reinit(p->hwdec, p->image_w, p->image_h) < 0)
+ MP_ERR(p, "Initializing hardware ddecoding video texture failed.\n");
+ }
+
reinit_rendering(p);
}
@@ -1287,6 +1326,7 @@ static void uninit_video(struct gl_video *p)
plane->buffer_ptr = NULL;
plane->buffer_size = 0;
}
+ mp_image_unrefp(&vimg->hwimage);
fbotex_uninit(p, &p->indirect_fbo);
fbotex_uninit(p, &p->scale_sep_fbo);
@@ -1373,14 +1413,15 @@ void gl_video_render_frame(struct gl_video *p)
// Order of processing:
// [indirect -> [scale_sep ->]] final
- set_image_textures(p, vimg);
+ GLuint imgtex[4] = {0};
+ set_image_textures(p, vimg, imgtex);
struct fbotex chain = {
.vp_w = p->image_w,
.vp_h = p->image_h,
.tex_w = p->texture_w,
.tex_h = p->texture_h,
- .texture = vimg->planes[0].gl_texture,
+ .texture = imgtex[0],
};
handle_pass(p, &chain, &p->indirect_fbo, p->indirect_program);
@@ -1441,6 +1482,8 @@ void gl_video_render_frame(struct gl_video *p)
gl->UseProgram(0);
+ unset_image_textures(p);
+
p->frames_rendered++;
debug_check_gl(p, "after video rendering");
@@ -1552,16 +1595,21 @@ static bool get_image(struct gl_video *p, struct mp_image *mpi)
void gl_video_upload_image(struct gl_video *p, struct mp_image *mpi)
{
GL *gl = p->gl;
- int n;
-
- assert(mpi->num_planes == p->plane_count);
struct video_image *vimg = &p->image;
+ if (p->hwdec_active) {
+ mp_image_setrefp(&vimg->hwimage, mpi);
+ p->have_image = true;
+ return;
+ }
+
+ assert(mpi->num_planes == p->plane_count);
+
mp_image_t mpi2 = *mpi;
bool pbo = false;
if (!vimg->planes[0].buffer_ptr && get_image(p, &mpi2)) {
- for (n = 0; n < p->plane_count; n++) {
+ for (int n = 0; n < p->plane_count; n++) {
int line_bytes = mpi->plane_w[n] * p->image_desc.bytes[n];
memcpy_pic(mpi2.planes[n], mpi->planes[n], line_bytes, mpi->plane_h[n],
mpi2.stride[n], mpi->stride[n]);
@@ -1570,7 +1618,7 @@ void gl_video_upload_image(struct gl_video *p, struct mp_image *mpi)
pbo = true;
}
vimg->image_flipped = mpi->stride[0] < 0;
- for (n = 0; n < p->plane_count; n++) {
+ for (int n = 0; n < p->plane_count; n++) {
struct texplane *plane = &vimg->planes[n];
void *plane_ptr = mpi->planes[n];
if (pbo) {
@@ -1598,10 +1646,11 @@ struct mp_image *gl_video_download_image(struct gl_video *p)
struct video_image *vimg = &p->image;
- if (!p->have_image || !vimg->planes[0].gl_texture)
+ if (!p->have_image)
return NULL;
- assert(p->image_format == p->image_params.imgfmt);
+ set_image_textures(p, vimg, NULL);
+
assert(p->texture_w >= p->image_params.w);
assert(p->texture_h >= p->image_params.h);
@@ -1611,12 +1660,12 @@ struct mp_image *gl_video_download_image(struct gl_video *p)
for (int n = 0; n < p->plane_count; n++) {
struct texplane *plane = &vimg->planes[n];
gl->ActiveTexture(GL_TEXTURE0 + n);
- gl->BindTexture(GL_TEXTURE_2D, plane->gl_texture);
glDownloadTex(gl, GL_TEXTURE_2D, plane->gl_format, plane->gl_type,
image->planes[n], image->stride[n]);
}
- gl->ActiveTexture(GL_TEXTURE0);
- mp_image_set_params(image, &p->image_params);
+ mp_image_set_attributes(image, &p->image_params);
+
+ unset_image_textures(p);
return image;
}
@@ -1884,6 +1933,12 @@ static bool init_format(int fmt, struct gl_video *init)
if (!init)
init = &dummy;
+ init->hwdec_active = false;
+ if (init->hwdec && init->hwdec->driver->query_format(fmt)) {
+ fmt = init->hwdec->converted_imgfmt;
+ init->hwdec_active = true;
+ }
+
struct mp_imgfmt_desc desc = mp_imgfmt_get_desc(fmt);
if (!desc.id)
return false;
@@ -1985,9 +2040,10 @@ static bool init_format(int fmt, struct gl_video *init)
return true;
}
-bool gl_video_check_format(int mp_format)
+bool gl_video_check_format(struct gl_video *p, int mp_format)
{
- return init_format(mp_format, NULL);
+ struct gl_video tmp = *p;
+ return init_format(mp_format, &tmp);
}
void gl_video_config(struct gl_video *p, struct mp_image_params *params)
@@ -2012,6 +2068,7 @@ void gl_video_config(struct gl_video *p, struct mp_image_params *params)
p->colorspace = csp;
p->have_image = false;
+ mp_image_unrefp(&p->image.hwimage);
}
void gl_video_set_output_depth(struct gl_video *p, int r, int g, int b)
@@ -2132,3 +2189,9 @@ void gl_video_resize_redraw(struct gl_video *p, int w, int h)
gl_video_render_frame(p);
mpgl_osd_redraw_cb(p->osd, draw_osd_cb, p);
}
+
+void gl_video_set_hwdec(struct gl_video *p, struct gl_hwdec *hwdec)
+{
+ p->hwdec = hwdec;
+ mp_image_unrefp(&p->image.hwimage);
+}
diff --git a/video/out/gl_video.h b/video/out/gl_video.h
index dcec9f3888..cab5f0f077 100644
--- a/video/out/gl_video.h
+++ b/video/out/gl_video.h
@@ -56,6 +56,7 @@ struct gl_video;
struct gl_video *gl_video_init(GL *gl, struct mp_log *log);
void gl_video_uninit(struct gl_video *p);
void gl_video_set_options(struct gl_video *p, struct gl_video_opts *opts);
+bool gl_video_check_format(struct gl_video *p, int mp_format);
void gl_video_config(struct gl_video *p, struct mp_image_params *params);
void gl_video_set_output_depth(struct gl_video *p, int r, int g, int b);
void gl_video_set_lut3d(struct gl_video *p, struct lut3d *lut3d);
@@ -73,6 +74,7 @@ bool gl_video_get_equalizer(struct gl_video *p, const char *name, int *val);
void gl_video_set_debug(struct gl_video *p, bool enable);
void gl_video_resize_redraw(struct gl_video *p, int w, int h);
-bool gl_video_check_format(int mp_format);
+struct gl_hwdec;
+void gl_video_set_hwdec(struct gl_video *p, struct gl_hwdec *hwdec);
#endif
diff --git a/video/out/vo_opengl.c b/video/out/vo_opengl.c
index cf1b3b3400..8572f587a4 100644
--- a/video/out/vo_opengl.c
+++ b/video/out/vo_opengl.c
@@ -48,6 +48,7 @@
#include "gl_osd.h"
#include "filter_kernels.h"
#include "video/memcpy_pic.h"
+#include "video/decode/dec_video.h"
#include "gl_video.h"
#include "gl_lcms.h"
@@ -58,6 +59,8 @@ struct gl_priv {
struct gl_video *renderer;
+ struct gl_hwdec *hwdec;
+
// Options
struct gl_video_opts *renderer_opts;
struct mp_icc_opts *icc_opts;
@@ -134,8 +137,9 @@ static void draw_image(struct vo *vo, mp_image_t *mpi)
static int query_format(struct vo *vo, uint32_t format)
{
+ struct gl_priv *p = vo->priv;
int caps = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_FLIP;
- if (!gl_video_check_format(format))
+ if (!gl_video_check_format(p->renderer, format))
return 0;
return caps;
}
@@ -191,6 +195,68 @@ static int reconfig(struct vo *vo, struct mp_image_params *params, int flags)
return 0;
}
+
+static void load_hwdec_driver(struct gl_priv *p,
+ const struct gl_hwdec_driver *drv)
+{
+ assert(!p->hwdec);
+ struct gl_hwdec *hwdec = talloc(NULL, struct gl_hwdec);
+ *hwdec = (struct gl_hwdec) {
+ .driver = drv,
+ .log = mp_log_new(hwdec, p->vo->log, drv->api_name),
+ .mpgl = p->glctx,
+ .info = talloc_zero(hwdec, struct mp_hwdec_info),
+ };
+ mpgl_lock(p->glctx);
+ if (hwdec->driver->create(hwdec) < 0) {
+ mpgl_unlock(p->glctx);
+ talloc_free(hwdec);
+ MP_ERR(p->vo, "Couldn't load hwdec driver '%s'\n", drv->api_name);
+ return;
+ }
+ p->hwdec = hwdec;
+ gl_video_set_hwdec(p->renderer, p->hwdec);
+ mpgl_unlock(p->glctx);
+}
+
+static void request_hwdec_api(struct mp_hwdec_info *info, const char *api_name)
+{
+ struct gl_priv *p = info->load_api_ctx;
+ // Load at most one hwdec API
+ if (p->hwdec)
+ return;
+ for (int n = 0; mpgl_hwdec_drivers[n]; n++) {
+ const struct gl_hwdec_driver *drv = mpgl_hwdec_drivers[n];
+ if (api_name && strcmp(drv->api_name, api_name) == 0) {
+ load_hwdec_driver(p, drv);
+ if (p->hwdec) {
+ *info = *p->hwdec->info;
+ return;
+ }
+ }
+ }
+}
+
+static void get_hwdec_info(struct gl_priv *p, struct mp_hwdec_info *info)
+{
+ info->load_api = request_hwdec_api;
+ info->load_api_ctx = p;
+ if (p->hwdec)
+ *info = *p->hwdec->info;
+}
+
+static void unload_hwdec_driver(struct gl_priv *p)
+{
+ if (p->hwdec) {
+ mpgl_lock(p->glctx);
+ gl_video_set_hwdec(p->renderer, NULL);
+ p->hwdec->driver->destroy(p->hwdec);
+ talloc_free(p->hwdec);
+ p->hwdec = NULL;
+ mpgl_unlock(p->glctx);
+ }
+}
+
static bool reparse_cmdline(struct gl_priv *p, char *args)
{
struct m_config *cfg = NULL;
@@ -263,6 +329,10 @@ static int control(struct vo *vo, uint32_t request, void *data)
mpgl_unlock(p->glctx);
return true;
}
+ case VOCTRL_GET_HWDEC_INFO: {
+ get_hwdec_info(p, data);
+ return true;
+ }
case VOCTRL_REDRAW_FRAME:
mpgl_lock(p->glctx);
gl_video_render_frame(p->renderer);
@@ -291,6 +361,7 @@ static void uninit(struct vo *vo)
struct gl_priv *p = vo->priv;
if (p->glctx) {
+ unload_hwdec_driver(p);
if (p->renderer)
gl_video_uninit(p->renderer);
mpgl_uninit(p->glctx);