Update to MPlayer SVN rev 29319 and FFmpeg SVN rev 18938.
[vaapi:athaifas-mplayer.git] / m_property.c
1
2 /// \file
3 /// \ingroup Properties
4
5 #include "config.h"
6
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <inttypes.h>
11 #include <unistd.h>
12
13 #include "m_option.h"
14 #include "m_property.h"
15 #include "mp_msg.h"
16 #include "help_mp.h"
17
18 #define ROUND(x) ((int)((x)<0 ? (x)-0.5 : (x)+0.5))
19
20 static int do_action(const m_option_t* prop_list, const char* name,
21                      int action, void* arg, void *ctx) {
22     const char* sep;
23     const m_option_t* prop;
24     m_property_action_t ka;
25     int r;
26     if((sep = strchr(name,'/')) && sep[1]) {
27         int len = sep-name;
28         char base[len+1];
29         memcpy(base,name,len);
30         base[len] = 0;
31         prop = m_option_list_find(prop_list, base);
32         ka.key = sep+1;
33         ka.action = action;
34         ka.arg = arg;
35         action = M_PROPERTY_KEY_ACTION;
36         arg = &ka;
37     } else
38         prop = m_option_list_find(prop_list, name);
39     if(!prop) return M_PROPERTY_UNKNOWN;
40     r = ((m_property_ctrl_f)prop->p)(prop,action,arg,ctx);
41     if(action == M_PROPERTY_GET_TYPE && r < 0) {
42         if(!arg) return M_PROPERTY_ERROR;
43         *(const m_option_t**)arg = prop;
44         return M_PROPERTY_OK;
45     }
46     return r;
47 }
48
49 int m_property_do(const m_option_t* prop_list, const char* name,
50                   int action, void* arg, void *ctx) {
51     const m_option_t* opt;
52     void* val;
53     char* str;
54     int r;
55
56     switch(action) {
57     case M_PROPERTY_PRINT:
58         if((r = do_action(prop_list,name,M_PROPERTY_PRINT,arg,ctx)) >= 0)
59             return r;
60         // fallback on the default print for this type
61     case M_PROPERTY_TO_STRING:
62         if((r = do_action(prop_list,name,M_PROPERTY_TO_STRING,arg,ctx)) !=
63            M_PROPERTY_NOT_IMPLEMENTED)
64             return r;
65         // fallback on the options API. Get the type, value and print.
66         if((r = do_action(prop_list,name,M_PROPERTY_GET_TYPE,&opt,ctx)) <= 0)
67             return r;
68         val = calloc(1,opt->type->size);
69         if((r = do_action(prop_list,name,M_PROPERTY_GET,val,ctx)) <= 0) {
70             free(val);
71             return r;
72         }
73         if(!arg) return M_PROPERTY_ERROR;
74         str = m_option_print(opt,val);
75         free(val);
76         *(char**)arg = str == (char*)-1 ? NULL : str;
77         return str != (char*)-1;
78     case M_PROPERTY_PARSE:
79         // try the property own parsing func
80         if((r = do_action(prop_list,name,M_PROPERTY_PARSE,arg,ctx)) !=
81            M_PROPERTY_NOT_IMPLEMENTED)
82             return r;
83         // fallback on the options API, get the type and parse.
84         if((r = do_action(prop_list,name,M_PROPERTY_GET_TYPE,&opt,ctx)) <= 0)
85             return r;
86         if(!arg) return M_PROPERTY_ERROR;
87         val = calloc(1,opt->type->size);
88         if((r = m_option_parse(opt,opt->name,arg,val,M_CONFIG_FILE)) <= 0) {
89             free(val);
90             return r;
91         }
92         r = do_action(prop_list,name,M_PROPERTY_SET,val,ctx);
93         m_option_free(opt,val);
94         free(val);
95         return r;
96     }
97     return do_action(prop_list,name,action,arg,ctx);
98 }
99
100 char* m_properties_expand_string(const m_option_t* prop_list,char* str, void *ctx) {
101     int l,fr=0,pos=0,size=strlen(str)+512;
102     char *p = NULL,*e,*ret = malloc(size), num_val;
103     int skip = 0, lvl = 0, skip_lvl = 0;
104
105     while(str[0]) {
106         if(str[0] == '\\') {
107             int sl = 1;
108             switch(str[1]) {
109             case 'e':
110                 p = "\x1b", l = 1; break;
111             case 'n':
112                 p = "\n", l = 1; break;
113             case 'r':
114                 p = "\r", l = 1; break;
115             case 't':
116                 p = "\t", l = 1; break;
117             case 'x':
118                 if(str[2]) {
119                     char num[3] = { str[2], str[3], 0 };
120                     char* end = num;
121                     num_val = strtol(num,&end,16);
122                     sl = end-num;
123                     l = 1;
124                     p = &num_val;
125                 } else
126                     l = 0;
127                 break;
128             default:
129                 p = str+1, l = 1;
130             }
131             str+=1+sl;
132         } else if(lvl > 0 && str[0] == ')') {
133             if(skip && lvl <= skip_lvl) skip = 0;
134             lvl--, str++, l = 0;
135         } else if(str[0] == '$' && str[1] == '{' && (e = strchr(str+2,'}'))) {
136             int pl = e-str-2;
137             char pname[pl+1];
138             memcpy(pname,str+2,pl);
139             pname[pl] = 0;
140             if(m_property_do(prop_list, pname,
141                              M_PROPERTY_PRINT, &p, ctx) >= 0 && p)
142                 l = strlen(p), fr = 1;
143             else
144                 l = 0;
145             str = e+1;
146         } else if(str[0] == '?' && str[1] == '(' && (e = strchr(str+2,':'))) {
147             lvl++;
148             if(!skip) {
149                 int is_not = str[2] == '!';
150                 int pl = e - str - (is_not ? 3 : 2);
151                 char pname[pl+1];
152                 memcpy(pname, str + (is_not ? 3 : 2), pl);
153                 pname[pl] = 0;
154                 if(m_property_do(prop_list,pname,M_PROPERTY_GET,NULL,ctx) < 0) {
155                     if (!is_not)
156                         skip = 1, skip_lvl = lvl;
157                 }
158                 else if (is_not)
159                     skip = 1, skip_lvl = lvl;
160             }
161             str = e+1, l = 0;
162         } else
163             p = str, l = 1, str++;
164
165         if(skip || l <= 0) continue;
166
167         if(pos+l+1 > size) {
168             size = pos+l+512;
169             ret = realloc(ret,size);
170         }
171         memcpy(ret+pos,p,l);
172         pos += l;
173         if(fr) free(p), fr = 0;
174     }
175
176     ret[pos] = 0;
177     return ret;
178 }
179
180 void m_properties_print_help_list(const m_option_t* list) {
181     char min[50],max[50];
182     int i,count = 0;
183
184     mp_msg(MSGT_CFGPARSER, MSGL_INFO, MSGTR_PropertyListHeader);
185     for(i = 0 ; list[i].name ; i++) {
186         const m_option_t* opt = &list[i];
187         if(opt->flags & M_OPT_MIN)
188             sprintf(min,"%-8.0f",opt->min);
189         else
190             strcpy(min,"No");
191         if(opt->flags & M_OPT_MAX)
192             sprintf(max,"%-8.0f",opt->max);
193         else
194             strcpy(max,"No");
195         mp_msg(MSGT_CFGPARSER, MSGL_INFO, " %-20.20s %-15.15s %-10.10s %-10.10s\n",
196                opt->name,
197                opt->type->name,
198                min,
199                max);
200         count++;
201     }
202     mp_msg(MSGT_CFGPARSER, MSGL_INFO, MSGTR_TotalProperties, count);
203 }
204
205 // Some generic property implementations
206
207 int m_property_int_ro(const m_option_t* prop,int action,
208                       void* arg,int var) {
209     switch(action) {
210     case M_PROPERTY_GET:
211         if(!arg) return 0;
212         *(int*)arg = var;
213         return 1;
214     }
215     return M_PROPERTY_NOT_IMPLEMENTED;
216 }
217
218 int m_property_int_range(const m_option_t* prop,int action,
219                          void* arg,int* var) {
220     switch(action) {
221     case M_PROPERTY_SET:
222         if(!arg) return 0;
223         M_PROPERTY_CLAMP(prop,*(int*)arg);
224         *var = *(int*)arg;
225         return 1;
226     case M_PROPERTY_STEP_UP:
227     case M_PROPERTY_STEP_DOWN:
228         *var += (arg ? *(int*)arg : 1) *
229             (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
230         M_PROPERTY_CLAMP(prop,*var);
231         return 1;
232     }
233     return m_property_int_ro(prop,action,arg,*var);
234 }
235
236 int m_property_choice(const m_option_t* prop,int action,
237                       void* arg,int* var) {
238     switch(action) {
239     case M_PROPERTY_STEP_UP:
240     case M_PROPERTY_STEP_DOWN:
241         *var += action == M_PROPERTY_STEP_UP ? 1 : prop->max;
242         *var %= (int)prop->max+1;
243         return 1;
244     }
245     return m_property_int_range(prop,action,arg,var);
246 }
247
248 int m_property_flag_ro(const m_option_t* prop,int action,
249                        void* arg,int var) {
250     switch(action) {
251     case M_PROPERTY_PRINT:
252         if(!arg) return 0;
253         *(char**)arg = strdup((var > prop->min) ? MSGTR_Enabled : MSGTR_Disabled);
254         return 1;
255     }
256     return m_property_int_ro(prop,action,arg,var);
257 }
258
259 int m_property_flag(const m_option_t* prop,int action,
260                     void* arg,int* var) {
261     switch(action) {
262     case M_PROPERTY_STEP_UP:
263     case M_PROPERTY_STEP_DOWN:
264         *var = *var == prop->min ? prop->max : prop->min;
265         return 1;
266     case M_PROPERTY_PRINT:
267         return m_property_flag_ro(prop, action, arg, *var);
268     }
269     return m_property_int_range(prop,action,arg,var);
270 }
271
272 int m_property_float_ro(const m_option_t* prop,int action,
273                         void* arg,float var) {
274     switch(action) {
275     case M_PROPERTY_GET:
276         if(!arg) return 0;
277         *(float*)arg = var;
278         return 1;
279     case M_PROPERTY_PRINT:
280         if(!arg) return 0;
281         *(char**)arg = malloc(20);
282         sprintf(*(char**)arg,"%.2f",var);
283         return 1;
284     }
285     return M_PROPERTY_NOT_IMPLEMENTED;
286 }
287
288 int m_property_float_range(const m_option_t* prop,int action,
289                            void* arg,float* var) {
290     switch(action) {
291     case M_PROPERTY_SET:
292         if(!arg) return 0;
293         M_PROPERTY_CLAMP(prop,*(float*)arg);
294         *var = *(float*)arg;
295         return 1;
296     case M_PROPERTY_STEP_UP:
297     case M_PROPERTY_STEP_DOWN:
298         *var += (arg ? *(float*)arg : 0.1) *
299             (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
300         M_PROPERTY_CLAMP(prop,*var);
301         return 1;
302     }
303     return m_property_float_ro(prop,action,arg,*var);
304 }
305
306 int m_property_delay(const m_option_t* prop,int action,
307                      void* arg,float* var) {
308     switch(action) {
309     case M_PROPERTY_PRINT:
310         if(!arg) return 0;
311         *(char**)arg = malloc(20);
312         sprintf(*(char**)arg,"%d ms",ROUND((*var)*1000));
313         return 1;
314     default:
315         return m_property_float_range(prop,action,arg,var);
316     }
317 }
318
319 int m_property_double_ro(const m_option_t* prop,int action,
320                          void* arg,double var) {
321     switch(action) {
322     case M_PROPERTY_GET:
323         if(!arg) return 0;
324         *(double*)arg = var;
325         return 1;
326     case M_PROPERTY_PRINT:
327         if(!arg) return 0;
328         *(char**)arg = malloc(20);
329         sprintf(*(char**)arg,"%.2f",var);
330         return 1;
331     }
332     return M_PROPERTY_NOT_IMPLEMENTED;
333 }
334
335 int m_property_time_ro(const m_option_t* prop,int action,
336                        void* arg,double var) {
337     switch(action) {
338     case M_PROPERTY_PRINT:
339         if (!arg)
340             return M_PROPERTY_ERROR;
341         else {
342             int h, m, s = var;
343             h = s / 3600;
344             s -= h * 3600;
345             m = s / 60;
346             s -= m * 60;
347             *(char **) arg = malloc(20);
348             if (h > 0)
349                 sprintf(*(char **) arg, "%d:%02d:%02d", h, m, s);
350             else if (m > 0)
351                 sprintf(*(char **) arg, "%d:%02d", m, s);
352             else
353                 sprintf(*(char **) arg, "%d", s);
354             return M_PROPERTY_OK;
355         }
356     }
357     return m_property_double_ro(prop,action,arg,var);
358 }
359
360 int m_property_string_ro(const m_option_t* prop,int action,void* arg,char* str) {
361     switch(action) {
362     case M_PROPERTY_GET:
363         if(!arg) return 0;
364         *(char**)arg = str;
365         return 1;
366     case M_PROPERTY_PRINT:
367         if(!arg) return 0;
368         *(char**)arg = str ? strdup(str) : NULL;
369         return 1;
370     }
371     return M_PROPERTY_NOT_IMPLEMENTED;
372 }
373
374 int m_property_bitrate(const m_option_t* prop,int action,void* arg,int rate) {
375     switch(action) {
376     case M_PROPERTY_PRINT:
377         if (!arg)
378             return M_PROPERTY_ERROR;
379         *(char**)arg = malloc (16);
380         sprintf(*(char**)arg, "%d kbps", rate*8/1000);
381         return M_PROPERTY_OK;
382     }
383     return m_property_int_ro(prop, action, arg, rate);
384 }