summaryrefslogtreecommitdiffstats
path: root/video/decode
diff options
context:
space:
mode:
authorPhilip Langdale <philipl@overt.org>2023-06-18 12:07:30 -0700
committerPhilip Langdale <github.philipl@overt.org>2023-06-29 11:58:51 -0700
commit9ff8c9e78020bcda19f3435ed88ebd6a302d2cc2 (patch)
treec18526a8689fb2ac6aa80b1bc3a200c117dcba34 /video/decode
parenta61b784d90148bcd0e8e9c366dcc563c81c74026 (diff)
downloadmpv-9ff8c9e78020bcda19f3435ed88ebd6a302d2cc2.tar.bz2
mpv-9ff8c9e78020bcda19f3435ed88ebd6a302d2cc2.tar.xz
vd_lavc: let the user provide a priority list of hwdecs to consider
Today, the only way to make mpv consider multiple hwdecs and pick the first one that works is to use one of the `auto` modes. But the list that is considered in those cases is hard-coded. If the user wants to provide their own list, they are out of luck. And I think that there is now a significant reason to support this - the new Vulkan hwdec is definitely not ready to be in the auto list, but if you want to use it by default, it will not work with many codecs that are normally hardware decodable (only h.264, hevc and av1 if you are very lucky). Everything else will fall back to software decoding. Instead, what you really want to say is: use Vulkan for whatever it supports, and fall back to my old hwdec for everything else. One side-effect of this implementation is that you can freely mix hwdec names and special values like `auto` and `no`. The behaviour will be correct, so I didn't try and prohibit any combinations. However, some combinations will be silly - eg: sticking any further values after `no` will result in them being ignored. On the other hand, a combination like `vulkan,auto` could be very useful as that will use Vulkan if possible, and if not, run the normal auto routine. Fixes #11797
Diffstat (limited to 'video/decode')
-rw-r--r--video/decode/vd_lavc.c157
1 files changed, 81 insertions, 76 deletions
diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c
index a39a37aad3..d8dc3daa73 100644
--- a/video/decode/vd_lavc.c
+++ b/video/decode/vd_lavc.c
@@ -84,7 +84,7 @@ struct vd_lavc_params {
int software_fallback;
char **avopts;
int dr;
- char *hwdec_api;
+ char **hwdec_api;
char *hwdec_codecs;
int hwdec_image_format;
int hwdec_extra_frames;
@@ -101,6 +101,8 @@ static const struct m_opt_choice_alternatives discard_names[] = {
};
#define OPT_DISCARD(field) OPT_CHOICE_C(field, discard_names)
+static char *default_hwdec_api[] = { "no", NULL, };
+
const struct m_sub_options vd_lavc_conf = {
.opts = (const m_option_t[]){
{"vd-lavc-fast", OPT_BOOL(fast)},
@@ -120,7 +122,7 @@ const struct m_sub_options vd_lavc_conf = {
{"vd-lavc-o", OPT_KEYVALUELIST(avopts)},
{"vd-lavc-dr", OPT_CHOICE(dr,
{"auto", -1}, {"no", 0}, {"yes", 1})},
- {"hwdec", OPT_STRING(hwdec_api),
+ {"hwdec", OPT_STRINGLIST(hwdec_api),
.help = hwdec_opt_help,
.flags = M_OPT_OPTIONAL_PARAM | UPDATE_HWDEC},
{"hwdec-codecs", OPT_STRING(hwdec_codecs)},
@@ -138,7 +140,7 @@ const struct m_sub_options vd_lavc_conf = {
.skip_frame = AVDISCARD_DEFAULT,
.framedrop = AVDISCARD_NONREF,
.dr = -1,
- .hwdec_api = "no",
+ .hwdec_api = default_hwdec_api,
.hwdec_codecs = "h264,vc1,hevc,vp8,vp9,av1,prores",
// Maximum number of surfaces the player wants to buffer. This number
// might require adjustment depending on whatever the player does;
@@ -465,94 +467,97 @@ static void select_and_set_hwdec(struct mp_filter *vd)
m_config_cache_update(ctx->opts_cache);
- bstr opt = bstr0(ctx->opts->hwdec_api);
-
- bool hwdec_requested = !bstr_equals0(opt, "no");
- bool hwdec_auto_all = bstr_equals0(opt, "auto") ||
- bstr_equals0(opt, "yes") ||
- bstr_equals0(opt, "");
- 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");
- } else if (!hwdec_codec_allowed(vd, codec)) {
- MP_VERBOSE(vd, "Not trying to use hardware decoding: codec %s is not "
- "on whitelist.\n", codec);
- } else {
- bool hwdec_name_supported = false; // relevant only if !hwdec_auto
- struct hwdec_info *hwdecs = NULL;
- int num_hwdecs = 0;
- add_all_hwdec_methods(&hwdecs, &num_hwdecs);
-
- for (int n = 0; n < num_hwdecs; n++) {
- struct hwdec_info *hwdec = &hwdecs[n];
+ struct hwdec_info *hwdecs = NULL;
+ int num_hwdecs = 0;
+ add_all_hwdec_methods(&hwdecs, &num_hwdecs);
- if (!hwdec_auto && !(bstr_equals0(opt, hwdec->method_name) ||
- bstr_equals0(opt, hwdec->name)))
- continue;
- hwdec_name_supported = true;
+ char **hwdec_api = ctx->opts->hwdec_api;
+ for (int i = 0; hwdec_api[i]; i++) {
+ bstr opt = bstr0(hwdec_api[i]);
+
+ bool hwdec_requested = !bstr_equals0(opt, "no");
+ bool hwdec_auto_all = bstr_equals0(opt, "auto") ||
+ bstr_equals0(opt, "yes") ||
+ bstr_equals0(opt, "");
+ 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");
+ break;
+ } else if (!hwdec_codec_allowed(vd, codec)) {
+ MP_VERBOSE(vd, "Not trying to use hardware decoding: codec %s is not "
+ "on whitelist.\n", codec);
+ break;
+ } else {
+ bool hwdec_name_supported = false; // relevant only if !hwdec_auto
+ for (int n = 0; n < num_hwdecs; n++) {
+ struct hwdec_info *hwdec = &hwdecs[n];
- const char *hw_codec = mp_codec_from_av_codec_id(hwdec->codec->id);
- if (!hw_codec || strcmp(hw_codec, codec) != 0)
- continue;
+ if (!hwdec_auto && !(bstr_equals0(opt, hwdec->method_name) ||
+ bstr_equals0(opt, hwdec->name)))
+ continue;
+ hwdec_name_supported = true;
- if (hwdec_auto_safe && !(hwdec->flags & HWDEC_FLAG_WHITELIST))
- continue;
+ const char *hw_codec = mp_codec_from_av_codec_id(hwdec->codec->id);
+ if (!hw_codec || strcmp(hw_codec, codec) != 0)
+ continue;
- MP_VERBOSE(vd, "Looking at hwdec %s...\n", hwdec->name);
+ if (hwdec_auto_safe && !(hwdec->flags & HWDEC_FLAG_WHITELIST))
+ continue;
- if (hwdec_auto_copy && !hwdec->copying) {
- MP_VERBOSE(vd, "Not using this for auto-copy.\n");
- continue;
- }
+ MP_VERBOSE(vd, "Looking at hwdec %s...\n", hwdec->name);
- if (hwdec->lavc_device) {
- ctx->hwdec_dev = hwdec_create_dev(vd, hwdec, hwdec_auto);
- if (!ctx->hwdec_dev) {
- MP_VERBOSE(vd, "Could not create device.\n");
+ if (hwdec_auto_copy && !hwdec->copying) {
+ MP_VERBOSE(vd, "Not using this for auto-copy.\n");
continue;
}
- const struct hwcontext_fns *fns =
- hwdec_get_hwcontext_fns(hwdec->lavc_device);
- if (fns && fns->is_emulated && fns->is_emulated(ctx->hwdec_dev)) {
- if (hwdec_auto) {
- MP_VERBOSE(vd, "Not using emulated API.\n");
- av_buffer_unref(&ctx->hwdec_dev);
+ if (hwdec->lavc_device) {
+ ctx->hwdec_dev = hwdec_create_dev(vd, hwdec, hwdec_auto);
+ if (!ctx->hwdec_dev) {
+ MP_VERBOSE(vd, "Could not create device.\n");
continue;
}
- MP_WARN(vd, "Using emulated hardware decoding API.\n");
- }
- } else if (!hwdec->copying) {
- // Most likely METHOD_INTERNAL, which often use delay-loaded
- // VO support as well.
- if (ctx->hwdec_devs) {
- struct hwdec_imgfmt_request params = {
- .imgfmt = pixfmt2imgfmt(hwdec->pix_fmt),
- .probing = hwdec_auto,
- };
- hwdec_devices_request_for_img_fmt(
- ctx->hwdec_devs, &params);
- }
- }
- ctx->use_hwdec = true;
- ctx->hwdec = *hwdec;
- break;
- }
-
- talloc_free(hwdecs);
+ const struct hwcontext_fns *fns =
+ hwdec_get_hwcontext_fns(hwdec->lavc_device);
+ if (fns && fns->is_emulated && fns->is_emulated(ctx->hwdec_dev)) {
+ if (hwdec_auto) {
+ MP_VERBOSE(vd, "Not using emulated API.\n");
+ av_buffer_unref(&ctx->hwdec_dev);
+ continue;
+ }
+ MP_WARN(vd, "Using emulated hardware decoding API.\n");
+ }
+ } else if (!hwdec->copying) {
+ // Most likely METHOD_INTERNAL, which often use delay-loaded
+ // VO support as well.
+ if (ctx->hwdec_devs) {
+ struct hwdec_imgfmt_request params = {
+ .imgfmt = pixfmt2imgfmt(hwdec->pix_fmt),
+ .probing = hwdec_auto,
+ };
+ hwdec_devices_request_for_img_fmt(
+ ctx->hwdec_devs, &params);
+ }
+ }
- if (!ctx->use_hwdec) {
- if (!hwdec_auto && !hwdec_name_supported)
- MP_WARN(vd, "Unsupported hwdec: %s\n", ctx->opts->hwdec_api);
- MP_VERBOSE(vd, "No hardware decoding available for this codec.\n");
+ ctx->use_hwdec = true;
+ ctx->hwdec = *hwdec;
+ break;
+ }
+ if (ctx->use_hwdec)
+ break;
+ else if (!hwdec_auto && !hwdec_name_supported)
+ MP_WARN(vd, "Unsupported hwdec: %.*s\n", BSTR_P(opt));
}
}
+ talloc_free(hwdecs);
+
if (ctx->use_hwdec) {
MP_VERBOSE(vd, "Trying hardware decoding via %s.\n", ctx->hwdec.name);