From 380f01567d183a4dd5c4f86a58470145a29f578d Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 24 Dec 2019 09:24:22 +0100 Subject: vd_lavc: more hwdec autoselect nonsense Add an "auto-safe" mode, mostly triggered by Ubuntu's nonsense to force hwdec=vaapi in the global config file in their mpv package. But to be honest it's probably something more people want. This is implemented as explicit whitelist. On Windows, HEVC/Intel is sometimes broken, but it's still whitelisted, and in theory we'd need a detailed whitelist of device names etc. (like for example browsers tend to do). On OSX, videotoolbox is a pretty bad choice, but unfortunately the only one, so it's whitelisted too. There may be a larger number of hwdec wrappers that work anyway, and I'm for example ignoring Android. --- DOCS/man/options.rst | 40 +++++++++++++++++++++++++++--- video/decode/vd_lavc.c | 66 +++++++++++++++++++++++++++++++++++++------------- 2 files changed, 85 insertions(+), 21 deletions(-) diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index 8ff149d86d..522656625d 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -998,7 +998,10 @@ Video Always enabling HW decoding by putting it into the config file is discouraged. If you use the Ubuntu package, delete ``/etc/mpv/mpv.conf``, - as the package tries to enable HW decoding by default. + as the package tries to enable HW decoding by default by setting + ``hwdec=vaapi`` (which is less than ideal, and may even cause + sub-optimal wrappers to be used). Or at least change it to + ``hwdec=auto-safe``. Use one of the auto modes if you want to enable hardware decoding. Explicitly selecting the mode is mostly meant for testing and debugging. @@ -1010,11 +1013,25 @@ Video Even if enabled, hardware decoding is still only white-listed for some codecs. See ``--hwdec-codecs`` to enable hardware decoding in more cases. + .. admonition:: Which method to choose? + + - If you only want to enable hardware decoding at runtime, don't set the + parameter, or put ``hwdec=no`` into your ``mpv.conf`` (relevant on + distros which force-enable it by default, such as on Ubuntu). Use the + ``Ctrl+h`` default binding to enable it at runtime. + - If you're not sure, but want hardware decoding always enabled by + default, put ``hwdec=auto-safe`` into your ``mpv.conf``, and + acknowledge that this use case is not "really" supported and may cause + problems. + - If you want to test available hardware decoding methods, pass + ``--hwdec=auto --hwdec-codecs`` and look at the terminal output. + ```` can be one of the following: :no: always use software decoding (default) - :auto: enable best hw decoder (see below) + :auto: forcibly enable any hw decoder found (see below) :yes: exactly the same as ``auto`` + :auto-safe: enable any whitelisted hw decoder (see below) :auto-copy: enable best hw decoder with copy-back (see below) :vdpau: requires ``--vo=gpu`` with X11, or ``--vo=vdpau`` (Linux only) :vdpau-copy: copies video back into system RAM (Linux with some GPUs only) @@ -1048,6 +1065,20 @@ Video work, it will always fall back to software decoding, instead of trying the next method (might matter on some Linux systems). + ``auto-safe`` is similar to ``auto``, but allows only whitelisted methods + that are considered "safe". This is supposed to be a reasonable way to + enable hardware decdoding by default in a config file (even though you + shouldn't do that anyway; prefer runtime enabling with ``Ctrl+h``). Unlike + ``auto``, this will not try to enable unknown or known-to-be-bad methods. In + addition, this may disable hardware decoding in other situations when it's + known to cause problems, but currently this mechanism is quite primitive. + (As an example for something that still causes problems: certain + combinations of HEVC and Intel chips on Windows tend to cause mpv to crash, + most likely due to driver bugs.) + + ``auto-copy-safe`` selects the union of methods selected with ``auto-safe`` + and ``auto-copy``. + ``auto-copy`` selects only modes that copy the video data back to system memory after decoding. This selects modes like ``vaapi-copy`` (and so on). If none of these work, hardware decoding is disabled. This mode is usually @@ -1074,8 +1105,9 @@ Video output path. To use this deinterlacing you must pass the option: ``vd-lavc-o=deint=[weave|bob|adaptive]``. Pass ``weave`` (or leave the option unset) to not attempt any - deinterlacing. ``cuda`` should always be preferred unless the ``gpu`` - vo is not being used or filters are required. + deinterlacing. ``cuda`` should always be preferred over ``cuda-copy`` unless + the ``gpu`` vo is not being used or filters are required. Using ``nvdec`` + should be preferred on Nvidia hardware. ``nvdec`` is a newer implementation of CUVID/CUDA decoding, which uses the FFmpeg decoders for file parsing. Experimental, is known not to correctly diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c index 3f0eedc47c..985a2b6d2e 100644 --- a/video/decode/vd_lavc.c +++ b/video/decode/vd_lavc.c @@ -155,6 +155,7 @@ struct hwdec_info { enum AVPixelFormat pix_fmt; // if not NONE, select in get_format bool use_hw_frames; // set AVCodecContext.hw_frames_ctx bool use_hw_device; // set AVCodecContext.hw_device_ctx + unsigned int flags; // HWDEC_FLAG_* // for internal sorting int auto_pos; @@ -216,19 +217,33 @@ typedef struct lavc_ctx { struct mp_decoder public; } vd_ffmpeg_ctx; +enum { + HWDEC_FLAG_AUTO = (1 << 0), // prioritize in autoprobe order + HWDEC_FLAG_WHITELIST = (1 << 1), // whitelist for auto-safe +}; + +struct autoprobe_info { + const char *method_name; + unsigned int flags; // HWDEC_FLAG_* +}; + // Things not included in this list will be tried last, in random order. -static const char *const hwdec_autoprobe_order[] = { - "d3d11va", - "dxva2", - "dxva2-copy", - "d3d11va-copy", - "nvdec", - "nvdec-copy", - "vaapi", - "vaapi-copy", - "vdpau", - "vdpau-copy", - 0 +const struct autoprobe_info hwdec_autoprobe_info[] = { + {"d3d11va", HWDEC_FLAG_AUTO | HWDEC_FLAG_WHITELIST}, + {"dxva2", HWDEC_FLAG_AUTO}, + {"dxva2-copy", HWDEC_FLAG_AUTO | HWDEC_FLAG_WHITELIST}, + {"d3d11va-copy", HWDEC_FLAG_AUTO | HWDEC_FLAG_WHITELIST}, + {"nvdec", HWDEC_FLAG_AUTO | HWDEC_FLAG_WHITELIST}, + {"nvdec-copy", HWDEC_FLAG_AUTO | HWDEC_FLAG_WHITELIST}, + {"vaapi", HWDEC_FLAG_AUTO | HWDEC_FLAG_WHITELIST}, + {"vaapi-copy", HWDEC_FLAG_AUTO | HWDEC_FLAG_WHITELIST}, + {"vdpau", HWDEC_FLAG_AUTO}, + {"vdpau-copy", HWDEC_FLAG_AUTO | HWDEC_FLAG_WHITELIST}, + {"mmal", HWDEC_FLAG_AUTO}, + {"mmal-copy", HWDEC_FLAG_AUTO | HWDEC_FLAG_WHITELIST}, + {"videotoolbox", HWDEC_FLAG_AUTO | HWDEC_FLAG_WHITELIST}, + {"videotoolbox-copy", HWDEC_FLAG_AUTO | HWDEC_FLAG_WHITELIST}, + {0} }; static int hwdec_compare(const void *p1, const void *p2) @@ -266,9 +281,14 @@ static void add_hwdec_item(struct hwdec_info **infos, int *num_infos, info.rank = *num_infos; info.auto_pos = INT_MAX; - for (int x = 0; hwdec_autoprobe_order[x]; x++) { - if (strcmp(hwdec_autoprobe_order[x], info.method_name) == 0) - info.auto_pos = x; + + for (int x = 0; hwdec_autoprobe_info[x].method_name; x++) { + const struct autoprobe_info *entry = &hwdec_autoprobe_info[x]; + if (strcmp(entry->method_name, info.method_name) == 0) { + info.flags |= entry->flags; + if (info.flags & HWDEC_FLAG_AUTO) + info.auto_pos = x; + } } MP_TARRAY_APPEND(NULL, *infos, *num_infos, info); @@ -434,8 +454,11 @@ static void select_and_set_hwdec(struct mp_filter *vd) bool hwdec_auto_all = bstr_equals0(opt, "auto") || bstr_equals0(opt, "yes") || bstr_equals0(opt, ""); - bool hwdec_auto_copy = bstr_equals0(opt, "auto-copy"); - bool hwdec_auto = hwdec_auto_all || hwdec_auto_copy; + bool hwdec_auto_safe = bstr_equals0(opt, "auto-safe") || + bstr_equals0(opt, "auto-copy-safe"); + bool hwdec_auto_copy = bstr_equals0(opt, "auto-copy") || + bstr_equals0(opt, "auto-copy-safe"); + bool hwdec_auto = hwdec_auto_all || hwdec_auto_copy || hwdec_auto_safe; if (!hwdec_requested) { MP_VERBOSE(vd, "No hardware decoding requested.\n"); @@ -460,6 +483,9 @@ static void select_and_set_hwdec(struct mp_filter *vd) bstr_equals0(opt, hwdec->name))) continue; + if (hwdec_auto_safe && !(hwdec->flags & HWDEC_FLAG_WHITELIST)) + continue; + MP_VERBOSE(vd, "Looking at hwdec %s...\n", hwdec->name); if (hwdec_auto_copy && !hwdec->copying) { @@ -530,6 +556,12 @@ static int hwdec_validate_opt(struct mp_log *log, const m_option_t *opt, talloc_free(hwdecs); + mp_info(log, " auto (yes '')\n"); + mp_info(log, " no\n"); + mp_info(log, " auto-safe\n"); + mp_info(log, " auto-copy\n"); + mp_info(log, " auto-copy-safe\n"); + return M_OPT_EXIT; } return 0; -- cgit v1.2.3