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.
This commit is contained in:
wm4 2019-12-24 09:24:22 +01:00
parent e7add205d8
commit 380f01567d
2 changed files with 85 additions and 21 deletions

View File

@ -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.
``<api>`` 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

View File

@ -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;