From 0ec35fa111391b8069640ba2f616746a1b5530a5 Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 17 Nov 2015 21:07:41 +0100 Subject: videotoolbox: make decoder format customizable Because apparently there's no ideal universally working format. The weird OpenGL texture format for kCVPixelFormatType_32BGRA is from: http://stackoverflow.com/questions/22077544/draw-an-iosurface-to-an-opengl-context (Which apparently got it from the linked Apple example code.) --- DOCS/man/options.rst | 8 ++++++++ options/options.c | 4 ++++ options/options.h | 1 + video/decode/videotoolbox.c | 4 ++-- video/out/opengl/hwdec.c | 11 +++++++---- video/out/opengl/hwdec.h | 6 ++++-- video/out/opengl/hwdec_osx.c | 24 ++++++++++++++++++++++-- video/out/vo_opengl.c | 4 ++-- video/out/vo_opengl_cb.c | 5 ++++- 9 files changed, 54 insertions(+), 13 deletions(-) diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index fe76296d5f..cdc0e75094 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -618,6 +618,14 @@ Video to temporarily set the ``hwdec`` option just during OpenGL context initialization with ``mpv_opengl_cb_init_gl()``. +``--videotoolbox-format=`` + Set the internal pixel format used by ``--hwdec=videotoolbox`` on OSX. The + choice of the format can influence performance considerably. On the other + hand, there doesn't appear to be a good way to detect the best format for + the given hardware. ``nv12``, the default works better on modern hardware, + while ``uyvy422`` appears to be better for old hardware. ``rgb0`` also + works. + ``--panscan=<0.0-1.0>`` Enables pan-and-scan functionality (cropping the sides of e.g. a 16:9 video to make it fit a 4:3 display without black bands). The range diff --git a/options/options.c b/options/options.c index a42d818c83..fb9237938c 100644 --- a/options/options.c +++ b/options/options.c @@ -308,6 +308,9 @@ const m_option_t mp_opts[] = { OPT_CHOICE_C("hwdec", hwdec_api, 0, mp_hwdec_names), OPT_CHOICE_C("hwdec-preload", vo.hwdec_preload_api, 0, mp_hwdec_names), OPT_STRING("hwdec-codecs", hwdec_codecs, 0), +#if HAVE_VIDEOTOOLBOX_HWACCEL + OPT_IMAGEFORMAT("videotoolbox-format", videotoolbox_format, 0), +#endif OPT_SUBSTRUCT("sws", vo.sws_opts, sws_conf, 0), @@ -804,6 +807,7 @@ const struct MPOpts mp_default_opts = { .screenshot_template = "mpv-shot%n", .hwdec_codecs = "h264,vc1,wmv3,hevc,mpeg2video", + .videotoolbox_format = IMGFMT_NV12, .index_mode = 1, diff --git a/options/options.h b/options/options.h index 49387f388b..7c9046f50b 100644 --- a/options/options.h +++ b/options/options.h @@ -268,6 +268,7 @@ typedef struct MPOpts { int hwdec_api; char *hwdec_codecs; + int videotoolbox_format; int w32_priority; diff --git a/video/decode/videotoolbox.c b/video/decode/videotoolbox.c index 470f6b6cf3..c5035f3a5b 100644 --- a/video/decode/videotoolbox.c +++ b/video/decode/videotoolbox.c @@ -31,7 +31,7 @@ static int probe(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info, const char *decoder) { hwdec_request_api(info, "videotoolbox"); - if (!info || !info->hwctx) + if (!info || !info->hwctx || info->hwctx->type != HWDEC_VIDEOTOOLBOX) return HWDEC_ERR_NO_CTX; switch (mp_codec_to_av_codec_id(decoder)) { case AV_CODEC_ID_H264: @@ -88,7 +88,7 @@ static int init_decoder(struct lavc_ctx *ctx, int w, int h) av_videotoolbox_default_free(ctx->avctx); AVVideotoolboxContext *vtctx = av_videotoolbox_alloc_context(); - vtctx->cv_pix_fmt_type = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange; + vtctx->cv_pix_fmt_type = (uintptr_t)ctx->hwdec_info->hwctx->priv; int err = av_videotoolbox_default_init2(ctx->avctx, vtctx); if (err < 0) { diff --git a/video/out/opengl/hwdec.c b/video/out/opengl/hwdec.c index 2a8c1eb14b..3c3a9785a6 100644 --- a/video/out/opengl/hwdec.c +++ b/video/out/opengl/hwdec.c @@ -55,6 +55,7 @@ static const struct gl_hwdec_driver *const mpgl_hwdec_drivers[] = { }; static struct gl_hwdec *load_hwdec_driver(struct mp_log *log, GL *gl, + struct mpv_global *global, const struct gl_hwdec_driver *drv, bool is_auto) { @@ -62,6 +63,7 @@ static struct gl_hwdec *load_hwdec_driver(struct mp_log *log, GL *gl, *hwdec = (struct gl_hwdec) { .driver = drv, .log = mp_log_new(hwdec, log, drv->api_name), + .global = global, .gl = gl, .gl_texture_target = GL_TEXTURE_2D, .probing = is_auto, @@ -76,13 +78,13 @@ static struct gl_hwdec *load_hwdec_driver(struct mp_log *log, GL *gl, } struct gl_hwdec *gl_hwdec_load_api(struct mp_log *log, GL *gl, - const char *api_name) + struct mpv_global *g, const char *api_name) { bool is_auto = api_name && strcmp(api_name, "auto") == 0; for (int n = 0; mpgl_hwdec_drivers[n]; n++) { const struct gl_hwdec_driver *drv = mpgl_hwdec_drivers[n]; if (is_auto || (api_name && strcmp(drv->api_name, api_name) == 0)) { - struct gl_hwdec *r = load_hwdec_driver(log, gl, drv, is_auto); + struct gl_hwdec *r = load_hwdec_driver(log, gl, g, drv, is_auto); if (r) return r; } @@ -91,9 +93,10 @@ struct gl_hwdec *gl_hwdec_load_api(struct mp_log *log, GL *gl, } // Like gl_hwdec_load_api(), but use HWDEC_... identifiers. -struct gl_hwdec *gl_hwdec_load_api_id(struct mp_log *log, GL *gl, int id) +struct gl_hwdec *gl_hwdec_load_api_id(struct mp_log *log, GL *gl, + struct mpv_global *g, int id) { - return gl_hwdec_load_api(log, gl, m_opt_choice_str(mp_hwdec_names, id)); + return gl_hwdec_load_api(log, gl, g, m_opt_choice_str(mp_hwdec_names, id)); } void gl_hwdec_uninit(struct gl_hwdec *hwdec) diff --git a/video/out/opengl/hwdec.h b/video/out/opengl/hwdec.h index 6f07536f57..ac1771c28d 100644 --- a/video/out/opengl/hwdec.h +++ b/video/out/opengl/hwdec.h @@ -9,6 +9,7 @@ struct mp_hwdec_info; struct gl_hwdec { const struct gl_hwdec_driver *driver; struct mp_log *log; + struct mpv_global *global; GL *gl; struct mp_hwdec_ctx *hwctx; // For free use by hwdec driver @@ -45,8 +46,9 @@ struct gl_hwdec_driver { }; struct gl_hwdec *gl_hwdec_load_api(struct mp_log *log, GL *gl, - const char *api_name); -struct gl_hwdec *gl_hwdec_load_api_id(struct mp_log *log, GL *gl, int id); + struct mpv_global *g, const char *api_name); +struct gl_hwdec *gl_hwdec_load_api_id(struct mp_log *log, GL *gl, + struct mpv_global *g, int id); void gl_hwdec_uninit(struct gl_hwdec *hwdec); diff --git a/video/out/opengl/hwdec_osx.c b/video/out/opengl/hwdec_osx.c index 84e8abca41..d1212e220f 100644 --- a/video/out/opengl/hwdec_osx.c +++ b/video/out/opengl/hwdec_osx.c @@ -26,6 +26,8 @@ #include "video/mp_image_pool.h" #include "hwdec.h" +#include "common/global.h" +#include "options/options.h" struct vt_gl_plane_format { GLenum gl_format; @@ -55,7 +57,23 @@ static struct vt_format vt_formats[] = { { GL_RED, GL_UNSIGNED_BYTE, GL_RED }, { GL_RG, GL_UNSIGNED_BYTE, GL_RG } , } - } + }, + { + .cvpixfmt = kCVPixelFormatType_422YpCbCr8, + .imgfmt = IMGFMT_UYVY, + .planes = 1, + .gl = { + { GL_RGB_422_APPLE, GL_UNSIGNED_SHORT_8_8_APPLE, GL_RGB } + } + }, + { + .cvpixfmt = kCVPixelFormatType_32BGRA, + .imgfmt = IMGFMT_RGB0, + .planes = 1, + .gl = { + { GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, GL_RGBA } + } + }, }; static struct vt_format *vt_get_gl_format(uint32_t cvpixfmt) @@ -134,7 +152,8 @@ static int create(struct gl_hwdec *hw) return -1; struct priv *p = talloc_zero(hw, struct priv); - struct vt_format *f = vt_get_gl_format_from_imgfmt(IMGFMT_NV12); + struct vt_format *f = + vt_get_gl_format_from_imgfmt(hw->global->opts->videotoolbox_format); if (!f) return -1; @@ -143,6 +162,7 @@ static int create(struct gl_hwdec *hw) hw->hwctx = &p->hwctx; hw->hwctx->download_image = download_image; hw->hwctx->type = HWDEC_VIDEOTOOLBOX; + hw->hwctx->priv = (void *)(uintptr_t)f->cvpixfmt; hw->gl_texture_target = GL_TEXTURE_RECTANGLE; hw->gl->GenTextures(MP_MAX_PLANES, p->gl_planes); diff --git a/video/out/vo_opengl.c b/video/out/vo_opengl.c index 23a22a3f7e..1147aba79a 100644 --- a/video/out/vo_opengl.c +++ b/video/out/vo_opengl.c @@ -205,7 +205,7 @@ static void request_hwdec_api(struct gl_priv *p, const char *api_name) if (p->hwdec) return; - p->hwdec = gl_hwdec_load_api(p->vo->log, p->gl, api_name); + p->hwdec = gl_hwdec_load_api(p->vo->log, p->gl, p->vo->global, api_name); gl_video_set_hwdec(p->renderer, p->hwdec); if (p->hwdec) p->hwdec_info.hwctx = p->hwdec->hwctx; @@ -439,7 +439,7 @@ static int preinit(struct vo *vo) if (hwdec == HWDEC_NONE) hwdec = vo->global->opts->hwdec_api; if (hwdec != HWDEC_NONE) { - p->hwdec = gl_hwdec_load_api_id(p->vo->log, p->gl, hwdec); + p->hwdec = gl_hwdec_load_api_id(p->vo->log, p->gl, vo->global, hwdec); gl_video_set_hwdec(p->renderer, p->hwdec); if (p->hwdec) p->hwdec_info.hwctx = p->hwdec->hwctx; diff --git a/video/out/vo_opengl_cb.c b/video/out/vo_opengl_cb.c index 687b9e3528..b90031d922 100644 --- a/video/out/vo_opengl_cb.c +++ b/video/out/vo_opengl_cb.c @@ -58,6 +58,7 @@ struct vo_priv { struct mpv_opengl_cb_context { struct mp_log *log; + struct mpv_global *global; struct mp_client_api *client_api; pthread_mutex_t lock; @@ -130,6 +131,7 @@ struct mpv_opengl_cb_context *mp_opengl_create(struct mpv_global *g, ctx->gl = talloc_zero(ctx, GL); + ctx->global = g; ctx->log = mp_log_new(ctx, g->log, "opengl-cb"); ctx->client_api = client_api; @@ -178,7 +180,8 @@ int mpv_opengl_cb_init_gl(struct mpv_opengl_cb_context *ctx, const char *exts, if (!ctx->renderer) return MPV_ERROR_UNSUPPORTED; - ctx->hwdec = gl_hwdec_load_api_id(ctx->log, ctx->gl, ctx->hwdec_api); + ctx->hwdec = gl_hwdec_load_api_id(ctx->log, ctx->gl, ctx->global, + ctx->hwdec_api); gl_video_set_hwdec(ctx->renderer, ctx->hwdec); if (ctx->hwdec) ctx->hwdec_info.hwctx = ctx->hwdec->hwctx; -- cgit v1.2.3