From 6f17410f88fd3765b6598b4e706b1d03ee85efe8 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 3 Nov 2013 23:55:16 +0100 Subject: mp_image: add helper for copying image attributes This enw function is similar to mp_image_set_params(), but doesn't force setting "hard" parameters like image size and format. --- video/mp_image.c | 22 ++++++++++++++++++++++ video/mp_image.h | 3 +++ 2 files changed, 25 insertions(+) (limited to 'video') 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 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); -- cgit v1.2.3 From 571e697a7c557d10bcc9130915c431829981d877 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 4 Nov 2013 00:00:18 +0100 Subject: vo_opengl: add infrastructure for hardware decoding OpenGL interop Most hardware decoding APIs provide some OpenGL interop. This allows using vo_opengl, without having to read the video data back from GPU. This requires adding a backend for each hardware decoding API. (Each backend is an entry in gl_hwdec_vaglx[].) The backends expose video data as a set of OpenGL textures. Add infrastructure to support this. The next commit will add support for VA-API. --- video/decode/dec_video.h | 5 ++ video/decode/lavc.h | 2 + video/decode/vd_lavc.c | 7 +++ video/out/gl_common.c | 4 ++ video/out/gl_common.h | 38 +++++++++++++++ video/out/gl_video.c | 123 +++++++++++++++++++++++++++++++++++------------ video/out/gl_video.h | 4 +- video/out/vo_opengl.c | 73 +++++++++++++++++++++++++++- 8 files changed, 224 insertions(+), 32 deletions(-) (limited to 'video') 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/vd_lavc.c b/video/decode/vd_lavc.c index ebfd986a95..47bfd96e84 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" @@ -196,6 +197,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/out/gl_common.c b/video/out/gl_common.c index 10e806dc8d..9482f9de55 100644 --- a/video/out/gl_common.c +++ b/video/out/gl_common.c @@ -1008,3 +1008,7 @@ void mp_log_source(struct mp_log *log, int lev, const char *src) src = next; } } + +const struct gl_hwdec_driver *mpgl_hwdec_drivers[] = { + NULL +}; diff --git a/video/out/gl_common.h b/video/out/gl_common.h index ecff698ac8..d8d07de06a 100644 --- a/video/out/gl_common.h +++ b/video/out/gl_common.h @@ -164,6 +164,44 @@ 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. + 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_video.c b/video/out/gl_video.c index d4b4b507c3..b376fead36 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); -- cgit v1.2.3 From 2d58fb3b8e7e87a939220f50a51294f8efdc51e1 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 4 Nov 2013 00:02:21 +0100 Subject: vo_opengl: add support for VA-API OpenGL interop VA-API's OpenGL/GLX interop is pretty bad and perhaps slow (renders a X11 pixmap into a FBO, and has to go over X11, probably involves one or more copies), and this code serves more as an example, rather than for serious use. On the other hand, this might be work much better than vo_vaapi, even if slightly slower. --- video/decode/vaapi.c | 1 + video/out/gl_common.c | 5 ++ video/out/gl_common.h | 1 + video/out/gl_hwdec_vaglx.c | 140 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 147 insertions(+) create mode 100644 video/out/gl_hwdec_vaglx.c (limited to 'video') 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/out/gl_common.c b/video/out/gl_common.c index 9482f9de55..3216b0037e 100644 --- a/video/out/gl_common.c +++ b/video/out/gl_common.c @@ -1009,6 +1009,11 @@ void mp_log_source(struct mp_log *log, int lev, const char *src) } } +extern const struct gl_hwdec_driver gl_hwdec_vaglx; + const struct gl_hwdec_driver *mpgl_hwdec_drivers[] = { +#if CONFIG_VAAPI_GLX + &gl_hwdec_vaglx, +#endif NULL }; diff --git a/video/out/gl_common.h b/video/out/gl_common.h index d8d07de06a..8d318a7c1f 100644 --- a/video/out/gl_common.h +++ b/video/out/gl_common.h @@ -185,6 +185,7 @@ struct gl_hwdec_driver { // 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. 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 . + */ + +#include +#include + +#include +#include + +#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, +}; -- cgit v1.2.3