stream_ffmpeg: handle rtsp:// URLs by default, add lavf://
[mplayer.git] / m_property.c
blob762ad73b7dd1a8550a6da57e0e12d2bc0daa7ef7
1 /*
2 * This file is part of MPlayer.
4 * MPlayer is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * MPlayer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 /// \file
20 /// \ingroup Properties
22 #include "config.h"
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <inttypes.h>
28 #include <unistd.h>
30 #include "talloc.h"
31 #include "m_option.h"
32 #include "m_property.h"
33 #include "mp_msg.h"
34 #include "mpcommon.h"
36 static int do_action(const m_option_t *prop_list, const char *name,
37 int action, void *arg, void *ctx)
39 const char *sep;
40 const m_option_t *prop;
41 m_property_action_t ka;
42 int r;
43 if ((sep = strchr(name, '/')) && sep[1]) {
44 int len = sep - name;
45 char base[len + 1];
46 memcpy(base, name, len);
47 base[len] = 0;
48 prop = m_option_list_find(prop_list, base);
49 ka.key = sep + 1;
50 ka.action = action;
51 ka.arg = arg;
52 action = M_PROPERTY_KEY_ACTION;
53 arg = &ka;
54 } else
55 prop = m_option_list_find(prop_list, name);
56 if (!prop)
57 return M_PROPERTY_UNKNOWN;
58 r = ((m_property_ctrl_f)prop->p)(prop, action, arg, ctx);
59 if (action == M_PROPERTY_GET_TYPE && r < 0) {
60 if (!arg)
61 return M_PROPERTY_ERROR;
62 *(const m_option_t **)arg = prop;
63 return M_PROPERTY_OK;
65 return r;
68 int m_property_do(const m_option_t *prop_list, const char *name,
69 int action, void *arg, void *ctx)
71 const m_option_t *opt;
72 void *val;
73 int r;
75 switch (action) {
76 case M_PROPERTY_PRINT:
77 if ((r = do_action(prop_list, name, M_PROPERTY_PRINT, arg, ctx)) >= 0)
78 return r;
79 // fallback on the default print for this type
80 case M_PROPERTY_TO_STRING:
81 if ((r = do_action(prop_list, name, M_PROPERTY_TO_STRING, arg, ctx)) !=
82 M_PROPERTY_NOT_IMPLEMENTED)
83 return r;
84 // fallback on the options API. Get the type, value and print.
85 if ((r =
86 do_action(prop_list, name, M_PROPERTY_GET_TYPE, &opt, ctx)) <= 0)
87 return r;
88 val = calloc(1, opt->type->size);
89 if ((r = do_action(prop_list, name, M_PROPERTY_GET, val, ctx)) <= 0) {
90 free(val);
91 return r;
93 if (!arg)
94 return M_PROPERTY_ERROR;
95 char *str = m_option_print(opt, val);
96 free(val);
97 *(char **)arg = str;
98 return str != NULL;
99 case M_PROPERTY_PARSE:
100 // try the property own parsing func
101 if ((r = do_action(prop_list, name, M_PROPERTY_PARSE, arg, ctx)) !=
102 M_PROPERTY_NOT_IMPLEMENTED)
103 return r;
104 // fallback on the options API, get the type and parse.
105 if ((r =
106 do_action(prop_list, name, M_PROPERTY_GET_TYPE, &opt, ctx)) <= 0)
107 return r;
108 if (!arg)
109 return M_PROPERTY_ERROR;
110 val = calloc(1, opt->type->size);
111 if ((r = m_option_parse(opt, bstr(opt->name), bstr(arg), false,
112 val)) <= 0) {
113 free(val);
114 return r;
116 r = do_action(prop_list, name, M_PROPERTY_SET, val, ctx);
117 m_option_free(opt, val);
118 free(val);
119 return r;
121 return do_action(prop_list, name, action, arg, ctx);
124 char *m_properties_expand_string(const m_option_t *prop_list, char *str,
125 void *ctx)
127 int l, fr = 0, pos = 0, size = strlen(str) + 512;
128 char *p = NULL, *e, *ret = malloc(size), num_val;
129 int skip = 0, lvl = 0, skip_lvl = 0;
131 while (str[0]) {
132 if (str[0] == '\\') {
133 int sl = 1;
134 switch (str[1]) {
135 case 'e':
136 p = "\x1b", l = 1; break;
137 case 'n':
138 p = "\n", l = 1; break;
139 case 'r':
140 p = "\r", l = 1; break;
141 case 't':
142 p = "\t", l = 1; break;
143 case 'x':
144 if (str[2]) {
145 char num[3] = { str[2], str[3], 0 };
146 char *end = num;
147 num_val = strtol(num, &end, 16);
148 sl = end - num + 1;
149 l = 1;
150 p = &num_val;
151 } else
152 l = 0;
153 break;
154 default:
155 p = str + 1, l = 1;
157 str += 1 + sl;
158 } else if (lvl > 0 && str[0] == ')') {
159 if (skip && lvl <= skip_lvl)
160 skip = 0;
161 lvl--, str++, l = 0;
162 } else if (str[0] == '$' && str[1] == '{'
163 && (e = strchr(str + 2, '}'))) {
164 int pl = e - str - 2;
165 char pname[pl + 1];
166 memcpy(pname, str + 2, pl);
167 pname[pl] = 0;
168 if (m_property_do(prop_list, pname,
169 M_PROPERTY_PRINT, &p, ctx) >= 0 && p)
170 l = strlen(p), fr = 1;
171 else
172 l = 0;
173 str = e + 1;
174 } else if (str[0] == '?' && str[1] == '('
175 && (e = strchr(str + 2, ':'))) {
176 lvl++;
177 if (!skip) {
178 int is_not = str[2] == '!';
179 int pl = e - str - (is_not ? 3 : 2);
180 char pname[pl + 1];
181 memcpy(pname, str + (is_not ? 3 : 2), pl);
182 pname[pl] = 0;
183 if (m_property_do(prop_list, pname, M_PROPERTY_GET, NULL, ctx) < 0) {
184 if (!is_not)
185 skip = 1, skip_lvl = lvl;
186 } else if (is_not)
187 skip = 1, skip_lvl = lvl;
189 str = e + 1, l = 0;
190 } else
191 p = str, l = 1, str++;
193 if (skip || l <= 0)
194 continue;
196 if (pos + l + 1 > size) {
197 size = pos + l + 512;
198 ret = realloc(ret, size);
200 memcpy(ret + pos, p, l);
201 pos += l;
202 if (fr)
203 talloc_free(p), fr = 0;
206 ret[pos] = 0;
207 return ret;
210 void m_properties_print_help_list(const m_option_t *list)
212 char min[50], max[50];
213 int i, count = 0;
215 mp_tmsg(MSGT_CFGPARSER, MSGL_INFO,
216 "\n Name Type Min Max\n\n");
217 for (i = 0; list[i].name; i++) {
218 const m_option_t *opt = &list[i];
219 if (opt->flags & M_OPT_MIN)
220 sprintf(min, "%-8.0f", opt->min);
221 else
222 strcpy(min, "No");
223 if (opt->flags & M_OPT_MAX)
224 sprintf(max, "%-8.0f", opt->max);
225 else
226 strcpy(max, "No");
227 mp_msg(MSGT_CFGPARSER, MSGL_INFO,
228 " %-20.20s %-15.15s %-10.10s %-10.10s\n",
229 opt->name,
230 opt->type->name,
231 min,
232 max);
233 count++;
235 mp_tmsg(MSGT_CFGPARSER, MSGL_INFO, "\nTotal: %d properties\n", count);
238 // Some generic property implementations
240 int m_property_int_ro(const m_option_t *prop, int action,
241 void *arg, int var)
243 switch (action) {
244 case M_PROPERTY_GET:
245 if (!arg)
246 return 0;
247 *(int *)arg = var;
248 return 1;
250 return M_PROPERTY_NOT_IMPLEMENTED;
253 int m_property_int_range(const m_option_t *prop, int action,
254 void *arg, int *var)
256 switch (action) {
257 case M_PROPERTY_SET:
258 if (!arg)
259 return 0;
260 M_PROPERTY_CLAMP(prop, *(int *)arg);
261 *var = *(int *)arg;
262 return 1;
263 case M_PROPERTY_STEP_UP:
264 case M_PROPERTY_STEP_DOWN:
265 *var += (arg ? *(int *)arg : 1) *
266 (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
267 M_PROPERTY_CLAMP(prop, *var);
268 return 1;
270 return m_property_int_ro(prop, action, arg, *var);
273 int m_property_choice(const m_option_t *prop, int action,
274 void *arg, int *var)
276 switch (action) {
277 case M_PROPERTY_STEP_UP:
278 case M_PROPERTY_STEP_DOWN:
279 *var += action == M_PROPERTY_STEP_UP ? 1 : prop->max;
280 *var %= (int)prop->max + 1;
281 return 1;
283 return m_property_int_range(prop, action, arg, var);
286 int m_property_flag_ro(const m_option_t *prop, int action,
287 void *arg, int var)
289 switch (action) {
290 case M_PROPERTY_PRINT:
291 if (!arg)
292 return 0;
293 *(char **)arg = talloc_strdup(NULL, (var > prop->min) ?
294 mp_gtext("enabled") : mp_gtext("disabled"));
295 return 1;
297 return m_property_int_ro(prop, action, arg, var);
300 int m_property_flag(const m_option_t *prop, int action,
301 void *arg, int *var)
303 switch (action) {
304 case M_PROPERTY_STEP_UP:
305 case M_PROPERTY_STEP_DOWN:
306 *var = *var == prop->min ? prop->max : prop->min;
307 return 1;
308 case M_PROPERTY_PRINT:
309 return m_property_flag_ro(prop, action, arg, *var);
311 return m_property_int_range(prop, action, arg, var);
314 int m_property_float_ro(const m_option_t *prop, int action,
315 void *arg, float var)
317 switch (action) {
318 case M_PROPERTY_GET:
319 if (!arg)
320 return 0;
321 *(float *)arg = var;
322 return 1;
323 case M_PROPERTY_PRINT:
324 if (!arg)
325 return 0;
326 *(char **)arg = talloc_asprintf(NULL, "%.2f", var);
327 return 1;
329 return M_PROPERTY_NOT_IMPLEMENTED;
332 int m_property_float_range(const m_option_t *prop, int action,
333 void *arg, float *var)
335 switch (action) {
336 case M_PROPERTY_SET:
337 if (!arg)
338 return 0;
339 M_PROPERTY_CLAMP(prop, *(float *)arg);
340 *var = *(float *)arg;
341 return 1;
342 case M_PROPERTY_STEP_UP:
343 case M_PROPERTY_STEP_DOWN:
344 *var += (arg ? *(float *)arg : 0.1) *
345 (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
346 M_PROPERTY_CLAMP(prop, *var);
347 return 1;
349 return m_property_float_ro(prop, action, arg, *var);
352 int m_property_delay(const m_option_t *prop, int action,
353 void *arg, float *var)
355 switch (action) {
356 case M_PROPERTY_PRINT:
357 if (!arg)
358 return 0;
359 *(char **)arg = talloc_asprintf(NULL, "%d ms", ROUND((*var) * 1000));
360 return 1;
361 default:
362 return m_property_float_range(prop, action, arg, var);
366 int m_property_double_ro(const m_option_t *prop, int action,
367 void *arg, double var)
369 switch (action) {
370 case M_PROPERTY_GET:
371 if (!arg)
372 return 0;
373 *(double *)arg = var;
374 return 1;
375 case M_PROPERTY_PRINT:
376 if (!arg)
377 return 0;
378 *(char **)arg = talloc_asprintf(NULL, "%.2f", var);
379 return 1;
381 return M_PROPERTY_NOT_IMPLEMENTED;
384 static char *format_time(double time)
386 int h, m, s = time;
387 h = s / 3600;
388 s -= h * 3600;
389 m = s / 60;
390 s -= m * 60;
391 return talloc_asprintf(NULL, "%02d:%02d:%02d", h, m, s);
394 int m_property_time_ro(const m_option_t *prop, int action,
395 void *arg, double var)
397 switch (action) {
398 case M_PROPERTY_PRINT:
399 if (!arg)
400 return M_PROPERTY_ERROR;
401 else {
402 *(char **)arg = format_time(var);
403 return M_PROPERTY_OK;
406 return m_property_double_ro(prop, action, arg, var);
409 int m_property_string_ro(const m_option_t *prop, int action, void *arg,
410 char *str)
412 switch (action) {
413 case M_PROPERTY_GET:
414 if (!arg)
415 return 0;
416 *(char **)arg = str;
417 return 1;
418 case M_PROPERTY_PRINT:
419 if (!arg)
420 return 0;
421 *(char **)arg = talloc_strdup(NULL, str);
422 return 1;
424 return M_PROPERTY_NOT_IMPLEMENTED;
427 int m_property_bitrate(const m_option_t *prop, int action, void *arg, int rate)
429 switch (action) {
430 case M_PROPERTY_PRINT:
431 if (!arg)
432 return M_PROPERTY_ERROR;
433 *(char **)arg = talloc_asprintf(NULL, "%d kbps", rate * 8 / 1000);
434 return M_PROPERTY_OK;
436 return m_property_int_ro(prop, action, arg, rate);