summaryrefslogtreecommitdiffstats
path: root/options
diff options
context:
space:
mode:
Diffstat (limited to 'options')
-rw-r--r--options/m_config.h2
-rw-r--r--options/m_config_core.c139
-rw-r--r--options/m_config_core.h7
-rw-r--r--options/m_config_frontend.c40
-rw-r--r--options/m_config_frontend.h7
-rw-r--r--options/m_option.c351
-rw-r--r--options/m_option.h66
-rw-r--r--options/m_property.c47
-rw-r--r--options/m_property.h22
-rw-r--r--options/options.c684
-rw-r--r--options/options.h264
-rw-r--r--options/parse_commandline.c11
-rw-r--r--options/parse_configfile.c47
-rw-r--r--options/parse_configfile.h5
-rw-r--r--options/path.c236
-rw-r--r--options/path.h54
16 files changed, 939 insertions, 1043 deletions
diff --git a/options/m_config.h b/options/m_config.h
index d2ce2b4467..a6bade90c9 100644
--- a/options/m_config.h
+++ b/options/m_config.h
@@ -1 +1 @@
-#include "m_config_core.h" \ No newline at end of file
+#include "m_config_core.h"
diff --git a/options/m_config_core.c b/options/m_config_core.c
index 4f8c462db1..328ec6479f 100644
--- a/options/m_config_core.c
+++ b/options/m_config_core.c
@@ -15,29 +15,29 @@
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <stdlib.h>
-#include <stdio.h>
+#include <assert.h>
#include <errno.h>
+#include <stdatomic.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <strings.h>
-#include <assert.h>
-#include <stdbool.h>
-#include <pthread.h>
-#include "m_config_core.h"
-#include "options/m_option.h"
#include "common/common.h"
#include "common/global.h"
-#include "common/msg.h"
#include "common/msg_control.h"
+#include "common/msg.h"
+#include "m_config_core.h"
#include "misc/dispatch.h"
-#include "osdep/atomic.h"
+#include "options/m_option.h"
+#include "osdep/threads.h"
// For use with m_config_cache.
struct m_config_shadow {
- pthread_mutex_t lock;
+ mp_mutex lock;
// Incremented on every option change.
- mp_atomic_uint64 ts;
+ _Atomic uint64_t ts;
// -- immutable after init
// List of m_sub_options instances.
// Index 0 is the top-level and is always present.
@@ -99,14 +99,19 @@ struct config_cache {
void *wakeup_cb_ctx;
};
+struct force_update {
+ char *name;
+ uint64_t ts;
+};
+
// Per m_config_data state for each m_config_group.
struct m_group_data {
- char *udata; // pointer to group user option struct
- uint64_t ts; // timestamp of the data copy
+ char *udata; // pointer to group user option struct
+ uint64_t ts; // timestamp of the data copy
+ struct force_update **force_update; // tracks opts that are written with force update
+ int force_update_len;
};
-static const union m_option_value default_value = {0};
-
static void add_sub_group(struct m_config_shadow *shadow, const char *name_prefix,
int parent_group_index, int parent_ptr,
const struct m_sub_options *subopts);
@@ -241,7 +246,7 @@ const void *m_config_shadow_get_opt_default(struct m_config_shadow *shadow,
if (subopt->defaults)
return (char *)subopt->defaults + opt->offset;
- return &default_value;
+ return &m_option_value_default;
}
void *m_config_cache_get_opt_data(struct m_config_cache *cache, int32_t id)
@@ -419,14 +424,14 @@ static void shadow_destroy(void *p)
assert(shadow->num_listeners == 0);
talloc_free(shadow->data);
- pthread_mutex_destroy(&shadow->lock);
+ mp_mutex_destroy(&shadow->lock);
}
struct m_config_shadow *m_config_shadow_new(const struct m_sub_options *root)
{
struct m_config_shadow *shadow = talloc_zero(NULL, struct m_config_shadow);
talloc_set_destructor(shadow, shadow_destroy);
- pthread_mutex_init(&shadow->lock, NULL);
+ mp_mutex_init(&shadow->lock);
add_sub_group(shadow, NULL, -1, -1, root);
@@ -568,9 +573,9 @@ struct m_config_cache *m_config_cache_from_shadow(void *ta_parent,
in->shadow = shadow;
in->src = shadow->data;
- pthread_mutex_lock(&shadow->lock);
+ mp_mutex_lock(&shadow->lock);
in->data = allocate_option_data(cache, shadow, group_index, in->src);
- pthread_mutex_unlock(&shadow->lock);
+ mp_mutex_unlock(&shadow->lock);
cache->opts = in->data->gdata[0].udata;
@@ -590,6 +595,34 @@ struct m_config_cache *m_config_cache_alloc(void *ta_parent,
return m_config_cache_from_shadow(ta_parent, global->config, group);
}
+static void append_force_update(struct m_config_cache *cache, struct m_group_data *gdata,
+ const char *opt_name)
+{
+ for (int i = 0; i < gdata->force_update_len; ++i) {
+ if (strcmp(opt_name, gdata->force_update[i]->name) == 0) {
+ gdata->force_update[i]->ts = gdata->ts;
+ return;
+ }
+ }
+ struct force_update *new_update = talloc_zero(cache, struct force_update);
+ new_update->name = talloc_strdup(cache, opt_name);
+ new_update->ts = gdata->ts;
+ MP_TARRAY_APPEND(cache, gdata->force_update, gdata->force_update_len, new_update);
+}
+
+static bool check_force_update(struct m_group_data *gdata, const char *opt_name,
+ uint64_t timestamp)
+{
+ for (int i = 0; i < gdata->force_update_len; ++i) {
+ if ((strcmp(opt_name, gdata->force_update[i]->name) == 0) &&
+ gdata->force_update[i]->ts == timestamp)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
static void update_next_option(struct m_config_cache *cache, void **p_opt)
{
struct config_cache *in = cache->internal;
@@ -611,16 +644,18 @@ static void update_next_option(struct m_config_cache *cache, void **p_opt)
while (opts && opts[in->upd_opt].name) {
const struct m_option *opt = &opts[in->upd_opt];
+ void *dsrc = gsrc->udata + opt->offset;
+ void *ddst = gdst->udata + opt->offset;
if (opt->offset >= 0 && opt->type->size) {
- void *dsrc = gsrc->udata + opt->offset;
- void *ddst = gdst->udata + opt->offset;
-
- if (!m_option_equal(opt, ddst, dsrc)) {
+ bool opt_equal = m_option_equal(opt, ddst, dsrc);
+ bool force_update = opt->force_update &&
+ check_force_update(gsrc, opt->name, in->ts);
+ if (!opt_equal || force_update) {
uint64_t ch = get_opt_change_mask(dst->shadow,
in->upd_group, dst->group_index, opt);
- if (cache->debug) {
+ if (cache->debug && !opt_equal) {
char *vdst = m_option_print(opt, ddst);
char *vsrc = m_option_print(opt, dsrc);
mp_warn(cache->debug, "Option '%s' changed from "
@@ -677,7 +712,7 @@ bool m_config_cache_update(struct m_config_cache *cache)
if (!cache_check_update(cache))
return false;
- pthread_mutex_lock(&shadow->lock);
+ mp_mutex_lock(&shadow->lock);
bool res = false;
while (1) {
void *p;
@@ -686,7 +721,7 @@ bool m_config_cache_update(struct m_config_cache *cache)
break;
res = true;
}
- pthread_mutex_unlock(&shadow->lock);
+ mp_mutex_unlock(&shadow->lock);
return res;
}
@@ -699,9 +734,9 @@ bool m_config_cache_get_next_changed(struct m_config_cache *cache, void **opt)
if (!cache_check_update(cache) && in->upd_group < 0)
return false;
- pthread_mutex_lock(&shadow->lock);
+ mp_mutex_lock(&shadow->lock);
update_next_option(cache, opt);
- pthread_mutex_unlock(&shadow->lock);
+ mp_mutex_unlock(&shadow->lock);
return !!*opt;
}
@@ -746,13 +781,14 @@ bool m_config_cache_write_opt(struct m_config_cache *cache, void *ptr)
struct m_config_group *g = &shadow->groups[group_idx];
const struct m_option *opt = &g->group->opts[opt_idx];
- pthread_mutex_lock(&shadow->lock);
+ mp_mutex_lock(&shadow->lock);
struct m_group_data *gdst = m_config_gdata(in->data, group_idx);
struct m_group_data *gsrc = m_config_gdata(in->src, group_idx);
assert(gdst && gsrc);
- bool changed = !m_option_equal(opt, gsrc->udata + opt->offset, ptr);
+ bool changed = !m_option_equal(opt, gsrc->udata + opt->offset, ptr) ||
+ opt->force_update;
if (changed) {
m_option_copy(opt, gsrc->udata + opt->offset, ptr);
@@ -765,7 +801,10 @@ bool m_config_cache_write_opt(struct m_config_cache *cache, void *ptr)
}
}
- pthread_mutex_unlock(&shadow->lock);
+ if (opt->force_update)
+ append_force_update(cache, gsrc, opt->name);
+
+ mp_mutex_unlock(&shadow->lock);
return changed;
}
@@ -776,7 +815,7 @@ void m_config_cache_set_wakeup_cb(struct m_config_cache *cache,
struct config_cache *in = cache->internal;
struct m_config_shadow *shadow = in->shadow;
- pthread_mutex_lock(&shadow->lock);
+ mp_mutex_lock(&shadow->lock);
if (in->in_list) {
for (int n = 0; n < shadow->num_listeners; n++) {
if (shadow->listeners[n] == in) {
@@ -798,7 +837,7 @@ void m_config_cache_set_wakeup_cb(struct m_config_cache *cache,
in->wakeup_cb = cb;
in->wakeup_cb_ctx = cb_ctx;
}
- pthread_mutex_unlock(&shadow->lock);
+ mp_mutex_unlock(&shadow->lock);
}
static void dispatch_notify(void *p)
@@ -850,38 +889,6 @@ void *mp_get_config_group(void *ta_parent, struct mpv_global *global,
return cache->opts;
}
-void mp_read_option_raw(struct mpv_global *global, const char *name,
- const struct m_option_type *type, void *dst)
-{
- struct m_config_shadow *shadow = global->config;
-
- int32_t optid = -1;
- while (m_config_shadow_get_next_opt(shadow, &optid)) {
- char buf[M_CONFIG_MAX_OPT_NAME_LEN];
- const char *opt_name =
- m_config_shadow_get_opt_name(shadow, optid, buf, sizeof(buf));
-
- if (strcmp(name, opt_name) == 0) {
- const struct m_option *opt = m_config_shadow_get_opt(shadow, optid);
-
- int group_index, opt_index;
- get_opt_from_id(shadow, optid, &group_index, &opt_index);
-
- struct m_group_data *gdata = m_config_gdata(shadow->data, group_index);
- assert(gdata);
-
- assert(opt->offset >= 0);
- assert(opt->type == type);
-
- memset(dst, 0, opt->type->size);
- m_option_copy(opt, dst, gdata->udata + opt->offset);
- return;
- }
- }
-
- MP_ASSERT_UNREACHABLE(); // not found
-}
-
static const struct m_config_group *find_group(struct mpv_global *global,
const struct m_option *cfg)
{
diff --git a/options/m_config_core.h b/options/m_config_core.h
index c4902be9d1..a9558423d8 100644
--- a/options/m_config_core.h
+++ b/options/m_config_core.h
@@ -131,13 +131,6 @@ bool m_config_cache_write_opt(struct m_config_cache *cache, void *ptr);
void *mp_get_config_group(void *ta_parent, struct mpv_global *global,
const struct m_sub_options *group);
-// Read a single global option in a thread-safe way. For multiple options,
-// use m_config_cache. The option must exist and match the provided type (the
-// type is used as a sanity check only). Performs semi-expensive lookup.
-// Warning: new code must not use this.
-void mp_read_option_raw(struct mpv_global *global, const char *name,
- const struct m_option_type *type, void *dst);
-
// Allocate a priv struct that is backed by global options (like AOs and VOs,
// anything that uses m_obj_list.use_global_options == true).
// The result contains a snapshot of the current option values of desc->options.
diff --git a/options/m_config_frontend.c b/options/m_config_frontend.c
index 5a6db46d83..d800cdb75d 100644
--- a/options/m_config_frontend.c
+++ b/options/m_config_frontend.c
@@ -15,28 +15,28 @@
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <assert.h>
+#include <errno.h>
#include <float.h>
-#include <stdlib.h>
+#include <stdatomic.h>
+#include <stdbool.h>
#include <stdio.h>
-#include <errno.h>
+#include <stdlib.h>
#include <string.h>
#include <strings.h>
-#include <assert.h>
-#include <stdbool.h>
-#include <pthread.h>
#include "libmpv/client.h"
-#include "m_config.h"
-#include "m_config_frontend.h"
-#include "options/m_option.h"
#include "common/common.h"
#include "common/global.h"
-#include "common/msg.h"
#include "common/msg_control.h"
+#include "common/msg.h"
+#include "m_config_frontend.h"
+#include "m_config.h"
#include "misc/dispatch.h"
#include "misc/node.h"
-#include "osdep/atomic.h"
+#include "options/m_option.h"
+#include "osdep/threads.h"
extern const char mp_help_text[];
@@ -168,18 +168,9 @@ static int m_config_set_obj_params(struct m_config *config, struct mp_log *log,
struct m_config *m_config_from_obj_desc_and_args(void *ta_parent,
struct mp_log *log, struct mpv_global *global, struct m_obj_desc *desc,
- const char *name, struct m_obj_settings *defaults, char **args)
+ char **args)
{
struct m_config *config = m_config_from_obj_desc(ta_parent, log, global, desc);
-
- for (int n = 0; defaults && defaults[n].name; n++) {
- struct m_obj_settings *entry = &defaults[n];
- if (name && strcmp(entry->name, name) == 0) {
- if (m_config_set_obj_params(config, log, global, desc, entry->attribs) < 0)
- goto error;
- }
- }
-
if (m_config_set_obj_params(config, log, global, desc, args) < 0)
goto error;
@@ -758,7 +749,7 @@ int m_config_set_option_cli(struct m_config *config, struct bstr name,
BSTR_P(name), BSTR_P(param), flags);
}
- union m_option_value val = {0};
+ union m_option_value val = m_option_value_default;
// Some option types are "impure" and work on the existing data.
// (Prime examples: --vf-add, --sub-file)
@@ -792,7 +783,7 @@ int m_config_set_option_node(struct m_config *config, bstr name,
// Do this on an "empty" type to make setting the option strictly overwrite
// the old value, as opposed to e.g. appending to lists.
- union m_option_value val = {0};
+ union m_option_value val = m_option_value_default;
if (data->format == MPV_FORMAT_STRING) {
bstr param = bstr0(data->u.string);
@@ -877,11 +868,10 @@ void m_config_print_option_list(const struct m_config *config, const char *name)
}
char *def = NULL;
const void *defptr = m_config_get_co_default(config, co);
- const union m_option_value default_value = {0};
if (!defptr)
- defptr = &default_value;
+ defptr = &m_option_value_default;
if (defptr)
- def = m_option_pretty_print(opt, defptr);
+ def = m_option_pretty_print(opt, defptr, false);
if (def) {
MP_INFO(config, " (default: %s)", def);
talloc_free(def);
diff --git a/options/m_config_frontend.h b/options/m_config_frontend.h
index 2812033b75..6108d9feec 100644
--- a/options/m_config_frontend.h
+++ b/options/m_config_frontend.h
@@ -17,9 +17,10 @@
#pragma once
+#include <stdatomic.h>
+#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
-#include <stdbool.h>
#include "common/common.h"
#include "common/global.h"
@@ -29,7 +30,6 @@
#include "misc/bstr.h"
#include "misc/dispatch.h"
#include "options/m_option.h"
-#include "osdep/atomic.h"
// m_config provides an API to manipulate the config variables in MPlayer.
// It makes use of the Options API to provide a context stack that
@@ -115,10 +115,9 @@ struct m_config *m_config_new(void *talloc_ctx, struct mp_log *log,
// different sub-options for every filter (represented by separate desc
// structs).
// args is an array of key/value pairs (args=[k0, v0, k1, v1, ..., NULL]).
-// name/defaults is only needed for the legacy af-defaults/vf-defaults options.
struct m_config *m_config_from_obj_desc_and_args(void *ta_parent,
struct mp_log *log, struct mpv_global *global, struct m_obj_desc *desc,
- const char *name, struct m_obj_settings *defaults, char **args);
+ char **args);
// Like m_config_from_obj_desc_and_args(), but don't allocate option the
// struct, i.e. m_config.optstruct==NULL. This is used by the sub-option
diff --git a/options/m_option.c b/options/m_option.c
index 898d0da4f6..3d9ae26669 100644
--- a/options/m_option.c
+++ b/options/m_option.c
@@ -270,6 +270,7 @@ static bool flag_equal(const m_option_t *opt, void *a, void *b)
return VAL(a) == VAL(b);
}
+// Only exists for libmpv interopability and should not be used anywhere.
const m_option_type_t m_option_type_flag = {
// need yes or no in config files
.name = "Flag",
@@ -770,7 +771,7 @@ static const struct m_opt_choice_alternatives *get_choice(const m_option_t *opt,
return NULL;
}
}
- abort();
+ MP_ASSERT_UNREACHABLE();
}
static int choice_get(const m_option_t *opt, void *ta_parent,
@@ -1022,12 +1023,12 @@ static char *print_double(const m_option_t *opt, const void *val)
return talloc_asprintf(NULL, "%f", f);
}
-static char *print_double_f3(const m_option_t *opt, const void *val)
+static char *pretty_print_double(const m_option_t *opt, const void *val)
{
double f = VAL(val);
if (isnan(f))
return print_double(opt, val);
- return talloc_asprintf(NULL, "%.3f", f);
+ return mp_format_double(NULL, f, 4, false, false, !(opt->flags & M_OPT_FIXED_LEN_PRINT));
}
static void add_double(const m_option_t *opt, void *val, double add, bool wrap)
@@ -1099,7 +1100,33 @@ const m_option_type_t m_option_type_double = {
.size = sizeof(double),
.parse = parse_double,
.print = print_double,
- .pretty_print = print_double_f3,
+ .pretty_print = pretty_print_double,
+ .copy = copy_opt,
+ .add = add_double,
+ .multiply = multiply_double,
+ .set = double_set,
+ .get = double_get,
+ .equal = double_equal,
+};
+
+static int parse_double_aspect(struct mp_log *log, const m_option_t *opt,
+ struct bstr name, struct bstr param, void *dst)
+{
+ if (bstr_equals0(param, "no")) {
+ if (dst)
+ VAL(dst) = 0.0;
+ return 1;
+ }
+ return parse_double(log, opt, name, param, dst);
+}
+
+const m_option_type_t m_option_type_aspect = {
+ .name = "Aspect",
+ .size = sizeof(double),
+ .flags = M_OPT_TYPE_CHOICE | M_OPT_TYPE_USES_RANGE,
+ .parse = parse_double_aspect,
+ .print = print_double,
+ .pretty_print = pretty_print_double,
.copy = copy_opt,
.add = add_double,
.multiply = multiply_double,
@@ -1127,10 +1154,10 @@ static char *print_float(const m_option_t *opt, const void *val)
return print_double(opt, &tmp);
}
-static char *print_float_f3(const m_option_t *opt, const void *val)
+static char *pretty_print_float(const m_option_t *opt, const void *val)
{
double tmp = VAL(val);
- return print_double_f3(opt, &tmp);
+ return pretty_print_double(opt, &tmp);
}
static void add_float(const m_option_t *opt, void *val, double add, bool wrap)
@@ -1175,33 +1202,7 @@ const m_option_type_t m_option_type_float = {
.size = sizeof(float),
.parse = parse_float,
.print = print_float,
- .pretty_print = print_float_f3,
- .copy = copy_opt,
- .add = add_float,
- .multiply = multiply_float,
- .set = float_set,
- .get = float_get,
- .equal = float_equal,
-};
-
-static int parse_float_aspect(struct mp_log *log, const m_option_t *opt,
- struct bstr name, struct bstr param, void *dst)
-{
- if (bstr_equals0(param, "no")) {
- if (dst)
- VAL(dst) = 0.0f;
- return 1;
- }
- return parse_float(log, opt, name, param, dst);
-}
-
-const m_option_type_t m_option_type_aspect = {
- .name = "Aspect",
- .size = sizeof(float),
- .flags = M_OPT_TYPE_CHOICE | M_OPT_TYPE_USES_RANGE,
- .parse = parse_float_aspect,
- .print = print_float,
- .pretty_print = print_float_f3,
+ .pretty_print = pretty_print_float,
.copy = copy_opt,
.add = add_float,
.multiply = multiply_float,
@@ -1291,11 +1292,10 @@ const m_option_type_t m_option_type_string = {
#define OP_NONE 0
#define OP_ADD 1
#define OP_PRE 2
-#define OP_DEL 3
-#define OP_CLR 4
-#define OP_TOGGLE 5
-#define OP_APPEND 6
-#define OP_REMOVE 7
+#define OP_CLR 3
+#define OP_TOGGLE 4
+#define OP_APPEND 5
+#define OP_REMOVE 6
static void free_str_list(void *dst)
{
@@ -1337,55 +1337,6 @@ static int str_list_add(char **add, int n, void *dst, int pre)
return 1;
}
-static int str_list_del(struct mp_log *log, char **del, int n, void *dst)
-{
- char **lst, *ep;
- int i, ln, s;
- long idx;
-
- lst = VAL(dst);
-
- for (ln = 0; lst && lst[ln]; ln++)
- /**/;
- s = ln;
-
- for (i = 0; del[i] != NULL; i++) {
- idx = strtol(del[i], &ep, 0);
- if (*ep) {
- mp_err(log, "Invalid index: %s\n", del[i]);
- talloc_free(del[i]);
- continue;
- }
- talloc_free(del[i]);
- if (idx < 0 || idx >= ln) {
- mp_err(log, "Index %ld is out of range.\n", idx);
- continue;
- } else if (!lst[idx])
- continue;
- talloc_free(lst[idx]);
- lst[idx] = NULL;
- s--;
- }
- talloc_free(del);
-
- if (s == 0) {
- talloc_free(lst);
- VAL(dst) = NULL;
- return 1;
- }
-
- // Don't bother shrinking the list allocation
- for (i = 0, n = 0; i < ln; i++) {
- if (!lst[i])
- continue;
- lst[n] = lst[i];
- n++;
- }
- lst[s] = NULL;
-
- return 1;
-}
-
static struct bstr get_nextsep(struct bstr *ptr, char sep, bool modify)
{
struct bstr str = *ptr;
@@ -1432,11 +1383,6 @@ static int parse_str_list_impl(struct mp_log *log, const m_option_t *opt,
multi = false;
} else if (bstr_endswith0(name, "-pre")) {
op = OP_PRE;
- } else if (bstr_endswith0(name, "-del")) {
- op = OP_DEL;
- mp_warn(log, "Option %.*s: -del is deprecated! "
- "Use -remove (removes by content instead of by index).\n",
- BSTR_P(name));
} else if (bstr_endswith0(name, "-clr")) {
op = OP_CLR;
} else if (bstr_endswith0(name, "-set")) {
@@ -1450,14 +1396,20 @@ static int parse_str_list_impl(struct mp_log *log, const m_option_t *opt,
if (op == OP_TOGGLE || op == OP_REMOVE) {
if (dst) {
char **list = VAL(dst);
- int index = find_list_bstr(list, param);
- if (index >= 0) {
- char *old = list[index];
- for (int n = index; list[n]; n++)
- list[n] = list[n + 1];
- talloc_free(old);
+ bool found = false;
+ int index = 0;
+ do {
+ index = find_list_bstr(list, param);
+ if (index >= 0) {
+ found = true;
+ char *old = list[index];
+ for (int n = index; list[n]; n++)
+ list[n] = list[n + 1];
+ talloc_free(old);
+ }
+ } while (index >= 0);
+ if (found)
return 1;
- }
}
if (op == OP_REMOVE)
return 1; // ignore if not found
@@ -1518,8 +1470,6 @@ static int parse_str_list_impl(struct mp_log *log, const m_option_t *opt,
return str_list_add(res, n, dst, 0);
case OP_PRE:
return str_list_add(res, n, dst, 1);
- case OP_DEL:
- return str_list_del(log, res, n, dst);
}
if (VAL(dst))
@@ -1562,6 +1512,7 @@ static char *print_str_list(const m_option_t *opt, const void *src)
{
char **lst = NULL;
char *ret = NULL;
+ const char sep = opt->priv ? *(char *)opt->priv : OPTION_LIST_SEPARATOR;
if (!(src && VAL(src)))
return talloc_strdup(NULL, "");
@@ -1569,7 +1520,7 @@ static char *print_str_list(const m_option_t *opt, const void *src)
for (int i = 0; lst[i]; i++) {
if (ret)
- ret = talloc_strdup_append_buffer(ret, ",");
+ ret = talloc_strndup_append_buffer(ret, &sep, 1);
ret = talloc_strdup_append_buffer(ret, lst[i]);
}
return ret;
@@ -1649,7 +1600,6 @@ const m_option_type_t m_option_type_string_list = {
{"add"},
{"append"},
{"clr", M_OPT_TYPE_OPTIONAL_PARAM},
- {"del"},
{"pre"},
{"set"},
{"toggle"},
@@ -1755,7 +1705,7 @@ static int parse_keyvalue_list(struct mp_log *log, const m_option_t *opt,
}
if (param.len) {
- mp_err(log, "Unparseable garbage at end of option value: '%.*s'\n",
+ mp_err(log, "Unparsable garbage at end of option value: '%.*s'\n",
BSTR_P(param));
r = M_OPT_INVALID;
}
@@ -1947,7 +1897,7 @@ const m_option_type_t m_option_type_dummy_flag = {
// Read s sub-option name, or a positional sub-opt value.
// termset is a string containing the set of chars that terminate an option.
-// Return 0 on succes, M_OPT_ error code otherwise.
+// Return 0 on success, M_OPT_ error code otherwise.
// optname is for error reporting.
static int read_subparam(struct mp_log *log, bstr optname, char *termset,
bstr *str, bstr *out_subparam)
@@ -2273,7 +2223,7 @@ void m_geometry_apply(int *xpos, int *ypos, int *widw, int *widh,
*widw = *widh * asp;
}
// Center window after resize. If valid x:y values are passed to
- // geometry, then those values will be overriden.
+ // geometry, then those values will be overridden.
*xpos += prew / 2 - *widw / 2;
*ypos += preh / 2 - *widh / 2;
}
@@ -2380,6 +2330,64 @@ const m_option_type_t m_option_type_size_box = {
.equal = geometry_equal,
};
+void m_rect_apply(struct mp_rect *rc, int w, int h, struct m_geometry *gm)
+{
+ *rc = (struct mp_rect){0, 0, w, h};
+ if (!w || !h)
+ return;
+ m_geometry_apply(&rc->x0, &rc->y0, &rc->x1, &rc->y1, w, h, gm);
+ if (!gm->xy_valid && gm->wh_valid && rc->x1 == 0 && rc->y1 == 0)
+ return;
+ if (!gm->wh_valid || rc->x1 == 0 || rc->x1 == INT_MIN)
+ rc->x1 = w - rc->x0;
+ if (!gm->wh_valid || rc->y1 == 0 || rc->y1 == INT_MIN)
+ rc->y1 = h - rc->y0;
+ if (gm->wh_valid && (gm->w || gm->h))
+ rc->x1 += rc->x0;
+ if (gm->wh_valid && (gm->w || gm->h))
+ rc->y1 += rc->y0;
+}
+
+static int parse_rect(struct mp_log *log, const m_option_t *opt,
+ struct bstr name, struct bstr param, void *dst)
+{
+ bool is_help = bstr_equals0(param, "help");
+ if (is_help)
+ goto exit;
+
+ struct m_geometry gm;
+ if (!parse_geometry_str(&gm, param))
+ goto exit;
+
+ bool invalid = gm.x_sign || gm.y_sign || gm.ws;
+ invalid |= gm.wh_valid && (gm.w < 0 || gm.h < 0);
+ invalid |= gm.wh_valid && !gm.xy_valid && gm.w <= 0 && gm.h <= 0;
+
+ if (invalid)
+ goto exit;
+
+ if (dst)
+ *((struct m_geometry *)dst) = gm;
+
+ return 1;
+
+exit:
+ if (!is_help) {
+ mp_err(log, "Option %.*s: invalid rect: '%.*s'\n",
+ BSTR_P(name), BSTR_P(param));
+ }
+ mp_info(log, "Valid format: W[%%][xH[%%]][+x+y]\n");
+ return is_help ? M_OPT_EXIT : M_OPT_INVALID;
+}
+
+const m_option_type_t m_option_type_rect = {
+ .name = "Video rect",
+ .size = sizeof(struct m_geometry),
+ .parse = parse_rect,
+ .print = print_geometry,
+ .copy = copy_opt,
+ .equal = geometry_equal,
+};
#include "video/img_format.h"
@@ -2647,21 +2655,33 @@ const m_option_type_t m_option_type_channels = {
static int parse_timestring(struct bstr str, double *time, char endchar)
{
- int a, b, len;
- double d;
+ int h, m, len;
+ double s;
*time = 0; /* ensure initialization for error cases */
- if (bstr_sscanf(str, "%d:%d:%lf%n", &a, &b, &d, &len) >= 3)
- *time = 3600 * a + 60 * b + d;
- else if (bstr_sscanf(str, "%d:%lf%n", &a, &d, &len) >= 2)
- *time = 60 * a + d;
- else if (bstr_sscanf(str, "%lf%n", &d, &len) >= 1)
- *time = d;
- else
+ bool neg = bstr_eatstart0(&str, "-");
+ if (!neg)
+ bstr_eatstart0(&str, "+");
+ if (bstrchr(str, '-') >= 0 || bstrchr(str, '+') >= 0)
+ return 0; /* the timestamp shouldn't contain anymore +/- after this point */
+ if (bstr_sscanf(str, "%d:%d:%lf%n", &h, &m, &s, &len) >= 3) {
+ if (m >= 60 || s >= 60)
+ return 0; /* minutes or seconds are out of range */
+ *time = 3600 * h + 60 * m + s;
+ } else if (bstr_sscanf(str, "%d:%lf%n", &m, &s, &len) >= 2) {
+ if (s >= 60)
+ return 0; /* seconds are out of range */
+ *time = 60 * m + s;
+ } else if (bstr_sscanf(str, "%lf%n", &s, &len) >= 1) {
+ *time = s;
+ } else {
return 0; /* unsupported time format */
+ }
if (len < str.len && str.start[len] != endchar)
return 0; /* invalid extra characters at the end */
if (!isfinite(*time))
return 0;
+ if (neg)
+ *time = -*time;
return len;
}
@@ -2802,8 +2822,7 @@ static char *print_rel_time(const m_option_t *opt, const void *val)
case REL_TIME_ABSOLUTE:
return talloc_asprintf(NULL, "%g", t->pos);
case REL_TIME_RELATIVE:
- return talloc_asprintf(NULL, "%s%g",
- (t->pos >= 0) ? "+" : "-", fabs(t->pos));
+ return talloc_asprintf(NULL, "%+g", t->pos);
case REL_TIME_CHAPTER:
return talloc_asprintf(NULL, "#%g", t->pos);
case REL_TIME_PERCENT:
@@ -3147,7 +3166,7 @@ print_help: ;
} else if (list->print_unknown_entry_help) {
list->print_unknown_entry_help(log, mp_tprintf(80, "%.*s", BSTR_P(name)));
} else {
- mp_warn(log, "Option %.*s: item %.*s doesn't exist.\n",
+ mp_warn(log, "Option %.*s: item '%.*s' isn't supported.\n",
BSTR_P(opt_name), BSTR_P(name));
}
r = M_OPT_EXIT;
@@ -3202,7 +3221,7 @@ static int parse_obj_settings(struct mp_log *log, struct bstr opt, int op,
int idx = bstrspn(*pstr, NAMECH);
str = bstr_splice(*pstr, 0, idx);
if (!str.len) {
- mp_err(log, "Option %.*s: filter name expected.\n", BSTR_P(opt));
+ mp_err(log, "Option %.*s: item name expected.\n", BSTR_P(opt));
return M_OPT_INVALID;
}
*pstr = bstr_cut(*pstr, idx);
@@ -3219,7 +3238,7 @@ static int parse_obj_settings(struct mp_log *log, struct bstr opt, int op,
char name[80];
snprintf(name, sizeof(name), "%.*s", BSTR_P(str));
if (list->check_unknown_entry && !list->check_unknown_entry(name)) {
- mp_err(log, "Option %.*s: %.*s doesn't exist.\n",
+ mp_err(log, "Option %.*s: '%.*s' isn't supported.\n",
BSTR_P(opt), BSTR_P(str));
return M_OPT_INVALID;
}
@@ -3252,11 +3271,10 @@ done: ;
return 1;
}
-// Parse a single entry for -vf-del (return 0 if not applicable)
+// Parse a single entry for -vf-remove (return 0 if not applicable)
// mark_del is bounded by the number of items in dst
static int parse_obj_settings_del(struct mp_log *log, struct bstr opt_name,
- struct bstr *param, int op,
- void *dst, bool *mark_del)
+ struct bstr *param, void *dst, bool *mark_del)
{
bstr s = *param;
if (bstr_eatstart0(&s, "@")) {
@@ -3268,7 +3286,8 @@ static int parse_obj_settings_del(struct mp_log *log, struct bstr opt_name,
if (bstr_startswith0(s, ":"))