Statistics
| Branch: | Revision:

ffmpeg / libavfilter / parseutils.c @ 7d132c54

History | View | Annotate | Download (16.8 KB)

1
/*
2
 * copyright (c) 2009 Stefano Sabatini
3
 * This file is part of FFmpeg.
4
 *
5
 * FFmpeg is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Lesser General Public
7
 * License as published by the Free Software Foundation; either
8
 * version 2.1 of the License, or (at your option) any later version.
9
 *
10
 * FFmpeg is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 * Lesser General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Lesser General Public
16
 * License along with FFmpeg; if not, write to the Free Software
17
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
 */
19

    
20
/**
21
 * @file libavfilter/parseutils.c
22
 * parsing utils
23
 */
24

    
25
#include <strings.h>
26
#include "libavutil/avutil.h"
27
#include "libavutil/random_seed.h"
28
#include "parseutils.h"
29

    
30
#define WHITESPACES " \n\t"
31

    
32
char *av_get_token(const char **buf, const char *term)
33
{
34
    char *out = av_malloc(strlen(*buf) + 1);
35
    char *ret= out, *end= out;
36
    const char *p = *buf;
37
    p += strspn(p, WHITESPACES);
38

    
39
    while(*p && !strspn(p, term)) {
40
        char c = *p++;
41
        if(c == '\\' && *p){
42
            *out++ = *p++;
43
            end= out;
44
        }else if(c == '\''){
45
            while(*p && *p != '\'')
46
                *out++ = *p++;
47
            if(*p){
48
                p++;
49
                end= out;
50
            }
51
        }else{
52
            *out++ = c;
53
        }
54
    }
55

    
56
    do{
57
        *out-- = 0;
58
    }while(out >= end && strspn(out, WHITESPACES));
59

    
60
    *buf = p;
61

    
62
    return ret;
63
}
64

    
65
typedef struct {
66
    const char *name;            ///< a string representing the name of the color
67
    uint8_t     rgba_color[4];   ///< RGBA values for the color
68
} ColorEntry;
69

    
70
static ColorEntry color_table[] = {
71
    { "AliceBlue",            { 0xF0, 0xF8, 0xFF } },
72
    { "AntiqueWhite",         { 0xFA, 0xEB, 0xD7 } },
73
    { "Aqua",                 { 0x00, 0xFF, 0xFF } },
74
    { "Aquamarine",           { 0x7F, 0xFF, 0xD4 } },
75
    { "Azure",                { 0xF0, 0xFF, 0xFF } },
76
    { "Beige",                { 0xF5, 0xF5, 0xDC } },
77
    { "Bisque",               { 0xFF, 0xE4, 0xC4 } },
78
    { "Black",                { 0x00, 0x00, 0x00 } },
79
    { "BlanchedAlmond",       { 0xFF, 0xEB, 0xCD } },
80
    { "Blue",                 { 0x00, 0x00, 0xFF } },
81
    { "BlueViolet",           { 0x8A, 0x2B, 0xE2 } },
82
    { "Brown",                { 0xA5, 0x2A, 0x2A } },
83
    { "BurlyWood",            { 0xDE, 0xB8, 0x87 } },
84
    { "CadetBlue",            { 0x5F, 0x9E, 0xA0 } },
85
    { "Chartreuse",           { 0x7F, 0xFF, 0x00 } },
86
    { "Chocolate",            { 0xD2, 0x69, 0x1E } },
87
    { "Coral",                { 0xFF, 0x7F, 0x50 } },
88
    { "CornflowerBlue",       { 0x64, 0x95, 0xED } },
89
    { "Cornsilk",             { 0xFF, 0xF8, 0xDC } },
90
    { "Crimson",              { 0xDC, 0x14, 0x3C } },
91
    { "Cyan",                 { 0x00, 0xFF, 0xFF } },
92
    { "DarkBlue",             { 0x00, 0x00, 0x8B } },
93
    { "DarkCyan",             { 0x00, 0x8B, 0x8B } },
94
    { "DarkGoldenRod",        { 0xB8, 0x86, 0x0B } },
95
    { "DarkGray",             { 0xA9, 0xA9, 0xA9 } },
96
    { "DarkGreen",            { 0x00, 0x64, 0x00 } },
97
    { "DarkKhaki",            { 0xBD, 0xB7, 0x6B } },
98
    { "DarkMagenta",          { 0x8B, 0x00, 0x8B } },
99
    { "DarkOliveGreen",       { 0x55, 0x6B, 0x2F } },
100
    { "Darkorange",           { 0xFF, 0x8C, 0x00 } },
101
    { "DarkOrchid",           { 0x99, 0x32, 0xCC } },
102
    { "DarkRed",              { 0x8B, 0x00, 0x00 } },
103
    { "DarkSalmon",           { 0xE9, 0x96, 0x7A } },
104
    { "DarkSeaGreen",         { 0x8F, 0xBC, 0x8F } },
105
    { "DarkSlateBlue",        { 0x48, 0x3D, 0x8B } },
106
    { "DarkSlateGray",        { 0x2F, 0x4F, 0x4F } },
107
    { "DarkTurquoise",        { 0x00, 0xCE, 0xD1 } },
108
    { "DarkViolet",           { 0x94, 0x00, 0xD3 } },
109
    { "DeepPink",             { 0xFF, 0x14, 0x93 } },
110
    { "DeepSkyBlue",          { 0x00, 0xBF, 0xFF } },
111
    { "DimGray",              { 0x69, 0x69, 0x69 } },
112
    { "DodgerBlue",           { 0x1E, 0x90, 0xFF } },
113
    { "FireBrick",            { 0xB2, 0x22, 0x22 } },
114
    { "FloralWhite",          { 0xFF, 0xFA, 0xF0 } },
115
    { "ForestGreen",          { 0x22, 0x8B, 0x22 } },
116
    { "Fuchsia",              { 0xFF, 0x00, 0xFF } },
117
    { "Gainsboro",            { 0xDC, 0xDC, 0xDC } },
118
    { "GhostWhite",           { 0xF8, 0xF8, 0xFF } },
119
    { "Gold",                 { 0xFF, 0xD7, 0x00 } },
120
    { "GoldenRod",            { 0xDA, 0xA5, 0x20 } },
121
    { "Gray",                 { 0x80, 0x80, 0x80 } },
122
    { "Green",                { 0x00, 0x80, 0x00 } },
123
    { "GreenYellow",          { 0xAD, 0xFF, 0x2F } },
124
    { "HoneyDew",             { 0xF0, 0xFF, 0xF0 } },
125
    { "HotPink",              { 0xFF, 0x69, 0xB4 } },
126
    { "IndianRed",            { 0xCD, 0x5C, 0x5C } },
127
    { "Indigo",               { 0x4B, 0x00, 0x82 } },
128
    { "Ivory",                { 0xFF, 0xFF, 0xF0 } },
129
    { "Khaki",                { 0xF0, 0xE6, 0x8C } },
130
    { "Lavender",             { 0xE6, 0xE6, 0xFA } },
131
    { "LavenderBlush",        { 0xFF, 0xF0, 0xF5 } },
132
    { "LawnGreen",            { 0x7C, 0xFC, 0x00 } },
133
    { "LemonChiffon",         { 0xFF, 0xFA, 0xCD } },
134
    { "LightBlue",            { 0xAD, 0xD8, 0xE6 } },
135
    { "LightCoral",           { 0xF0, 0x80, 0x80 } },
136
    { "LightCyan",            { 0xE0, 0xFF, 0xFF } },
137
    { "LightGoldenRodYellow", { 0xFA, 0xFA, 0xD2 } },
138
    { "LightGrey",            { 0xD3, 0xD3, 0xD3 } },
139
    { "LightGreen",           { 0x90, 0xEE, 0x90 } },
140
    { "LightPink",            { 0xFF, 0xB6, 0xC1 } },
141
    { "LightSalmon",          { 0xFF, 0xA0, 0x7A } },
142
    { "LightSeaGreen",        { 0x20, 0xB2, 0xAA } },
143
    { "LightSkyBlue",         { 0x87, 0xCE, 0xFA } },
144
    { "LightSlateGray",       { 0x77, 0x88, 0x99 } },
145
    { "LightSteelBlue",       { 0xB0, 0xC4, 0xDE } },
146
    { "LightYellow",          { 0xFF, 0xFF, 0xE0 } },
147
    { "Lime",                 { 0x00, 0xFF, 0x00 } },
148
    { "LimeGreen",            { 0x32, 0xCD, 0x32 } },
149
    { "Linen",                { 0xFA, 0xF0, 0xE6 } },
150
    { "Magenta",              { 0xFF, 0x00, 0xFF } },
151
    { "Maroon",               { 0x80, 0x00, 0x00 } },
152
    { "MediumAquaMarine",     { 0x66, 0xCD, 0xAA } },
153
    { "MediumBlue",           { 0x00, 0x00, 0xCD } },
154
    { "MediumOrchid",         { 0xBA, 0x55, 0xD3 } },
155
    { "MediumPurple",         { 0x93, 0x70, 0xD8 } },
156
    { "MediumSeaGreen",       { 0x3C, 0xB3, 0x71 } },
157
    { "MediumSlateBlue",      { 0x7B, 0x68, 0xEE } },
158
    { "MediumSpringGreen",    { 0x00, 0xFA, 0x9A } },
159
    { "MediumTurquoise",      { 0x48, 0xD1, 0xCC } },
160
    { "MediumVioletRed",      { 0xC7, 0x15, 0x85 } },
161
    { "MidnightBlue",         { 0x19, 0x19, 0x70 } },
162
    { "MintCream",            { 0xF5, 0xFF, 0xFA } },
163
    { "MistyRose",            { 0xFF, 0xE4, 0xE1 } },
164
    { "Moccasin",             { 0xFF, 0xE4, 0xB5 } },
165
    { "NavajoWhite",          { 0xFF, 0xDE, 0xAD } },
166
    { "Navy",                 { 0x00, 0x00, 0x80 } },
167
    { "OldLace",              { 0xFD, 0xF5, 0xE6 } },
168
    { "Olive",                { 0x80, 0x80, 0x00 } },
169
    { "OliveDrab",            { 0x6B, 0x8E, 0x23 } },
170
    { "Orange",               { 0xFF, 0xA5, 0x00 } },
171
    { "OrangeRed",            { 0xFF, 0x45, 0x00 } },
172
    { "Orchid",               { 0xDA, 0x70, 0xD6 } },
173
    { "PaleGoldenRod",        { 0xEE, 0xE8, 0xAA } },
174
    { "PaleGreen",            { 0x98, 0xFB, 0x98 } },
175
    { "PaleTurquoise",        { 0xAF, 0xEE, 0xEE } },
176
    { "PaleVioletRed",        { 0xD8, 0x70, 0x93 } },
177
    { "PapayaWhip",           { 0xFF, 0xEF, 0xD5 } },
178
    { "PeachPuff",            { 0xFF, 0xDA, 0xB9 } },
179
    { "Peru",                 { 0xCD, 0x85, 0x3F } },
180
    { "Pink",                 { 0xFF, 0xC0, 0xCB } },
181
    { "Plum",                 { 0xDD, 0xA0, 0xDD } },
182
    { "PowderBlue",           { 0xB0, 0xE0, 0xE6 } },
183
    { "Purple",               { 0x80, 0x00, 0x80 } },
184
    { "Red",                  { 0xFF, 0x00, 0x00 } },
185
    { "RosyBrown",            { 0xBC, 0x8F, 0x8F } },
186
    { "RoyalBlue",            { 0x41, 0x69, 0xE1 } },
187
    { "SaddleBrown",          { 0x8B, 0x45, 0x13 } },
188
    { "Salmon",               { 0xFA, 0x80, 0x72 } },
189
    { "SandyBrown",           { 0xF4, 0xA4, 0x60 } },
190
    { "SeaGreen",             { 0x2E, 0x8B, 0x57 } },
191
    { "SeaShell",             { 0xFF, 0xF5, 0xEE } },
192
    { "Sienna",               { 0xA0, 0x52, 0x2D } },
193
    { "Silver",               { 0xC0, 0xC0, 0xC0 } },
194
    { "SkyBlue",              { 0x87, 0xCE, 0xEB } },
195
    { "SlateBlue",            { 0x6A, 0x5A, 0xCD } },
196
    { "SlateGray",            { 0x70, 0x80, 0x90 } },
197
    { "Snow",                 { 0xFF, 0xFA, 0xFA } },
198
    { "SpringGreen",          { 0x00, 0xFF, 0x7F } },
199
    { "SteelBlue",            { 0x46, 0x82, 0xB4 } },
200
    { "Tan",                  { 0xD2, 0xB4, 0x8C } },
201
    { "Teal",                 { 0x00, 0x80, 0x80 } },
202
    { "Thistle",              { 0xD8, 0xBF, 0xD8 } },
203
    { "Tomato",               { 0xFF, 0x63, 0x47 } },
204
    { "Turquoise",            { 0x40, 0xE0, 0xD0 } },
205
    { "Violet",               { 0xEE, 0x82, 0xEE } },
206
    { "Wheat",                { 0xF5, 0xDE, 0xB3 } },
207
    { "White",                { 0xFF, 0xFF, 0xFF } },
208
    { "WhiteSmoke",           { 0xF5, 0xF5, 0xF5 } },
209
    { "Yellow",               { 0xFF, 0xFF, 0x00 } },
210
    { "YellowGreen",          { 0x9A, 0xCD, 0x32 } },
211
};
212

    
213
static int color_table_compare(const void *lhs, const void *rhs)
214
{
215
    return strcasecmp(lhs, ((const ColorEntry *)rhs)->name);
216
}
217

    
218
int av_parse_color(uint8_t *rgba_color, const char *color_string, void *log_ctx)
219
{
220
    if (!strcasecmp(color_string, "random") || !strcasecmp(color_string, "bikeshed")) {
221
        int rgba = ff_random_get_seed();
222
        rgba_color[0] = rgba >> 24;
223
        rgba_color[1] = rgba >> 16;
224
        rgba_color[2] = rgba >> 8;
225
        rgba_color[3] = rgba;
226
    } else
227
    if (!strncmp(color_string, "0x", 2)) {
228
        char *tail;
229
        int len = strlen(color_string);
230
        unsigned int rgba = strtoul(color_string, &tail, 16);
231

    
232
        if (*tail || (len != 8 && len != 10)) {
233
            av_log(log_ctx, AV_LOG_ERROR, "Invalid 0xRRGGBB[AA] color string: '%s'\n", color_string);
234
            return -1;
235
        }
236
        if (len == 10) {
237
            rgba_color[3] = rgba;
238
            rgba >>= 8;
239
        }
240
        rgba_color[0] = rgba >> 16;
241
        rgba_color[1] = rgba >> 8;
242
        rgba_color[2] = rgba;
243
    } else {
244
        const ColorEntry *entry = bsearch(color_string,
245
                                          color_table,
246
                                          FF_ARRAY_ELEMS(color_table),
247
                                          sizeof(ColorEntry),
248
                                          color_table_compare);
249
        if (!entry) {
250
            av_log(log_ctx, AV_LOG_ERROR, "Cannot find color '%s'\n", color_string);
251
            return -1;
252
        }
253
        memcpy(rgba_color, entry->rgba_color, 4);
254
    }
255

    
256
    return 0;
257
}
258

    
259
/**
260
 * Stores the value in the field in ctx that is named like key.
261
 * ctx must be an AVClass context, storing is done using AVOptions.
262
 *
263
 * @param buf the string to parse, buf will be updated to point at the
264
 * separator just after the parsed key/value pair
265
 * @param key_val_sep a 0-terminated list of characters used to
266
 * separate key from value
267
 * @param pairs_sep a 0-terminated list of characters used to separate
268
 * two pairs from each other
269
 * @return 0 if the key/value pair has been successfully parsed and
270
 * set, or a negative value corresponding to an AVERROR code in case
271
 * of error:
272
 * AVERROR(EINVAL) if the key/value pair cannot be parsed,
273
 * the error code issued by av_set_string3() if the key/value pair
274
 * cannot be set
275
 */
276
static int parse_key_value_pair(void *ctx, const char **buf,
277
                                const char *key_val_sep, const char *pairs_sep)
278
{
279
    char *key = av_get_token(buf, key_val_sep);
280
    char *val;
281
    int ret;
282

    
283
    if (*key && strspn(*buf, key_val_sep)) {
284
        (*buf)++;
285
        val = av_get_token(buf, pairs_sep);
286
    } else {
287
        av_log(ctx, AV_LOG_ERROR, "Missing key or no key/value separator found after key '%s'\n", key);
288
        av_free(key);
289
        return AVERROR(EINVAL);
290
    }
291

    
292
    av_log(ctx, AV_LOG_DEBUG, "Setting value '%s' for key '%s'\n", val, key);
293

    
294
    ret = av_set_string3(ctx, key, val, 1, NULL);
295

    
296
    av_free(key);
297
    av_free(val);
298
    return ret;
299
}
300

    
301
int av_set_options_string(void *ctx, const char *opts,
302
                          const char *key_val_sep, const char *pairs_sep)
303
{
304
    int ret, count = 0;
305

    
306
    while (*opts) {
307
        if ((ret = parse_key_value_pair(ctx, &opts, key_val_sep, pairs_sep)) < 0)
308
            return ret;
309
        count++;
310

    
311
        if (*opts)
312
            opts++;
313
    }
314

    
315
    return count;
316
}
317

    
318
#ifdef TEST
319

    
320
#undef printf
321

    
322
typedef struct TestContext
323
{
324
    const AVClass *class;
325
    int num;
326
    int toggle;
327
    char *string;
328
    int flags;
329
    AVRational rational;
330
} TestContext;
331

    
332
#define OFFSET(x) offsetof(TestContext, x)
333

    
334
#define TEST_FLAG_COOL 01
335
#define TEST_FLAG_LAME 02
336
#define TEST_FLAG_MU   04
337

    
338
static const AVOption test_options[]= {
339
{"num",      "set num",        OFFSET(num),      FF_OPT_TYPE_INT,      0,              0,        100                 },
340
{"toggle",   "set toggle",     OFFSET(toggle),   FF_OPT_TYPE_INT,      0,              0,        1                   },
341
{"rational", "set rational",   OFFSET(rational), FF_OPT_TYPE_RATIONAL, 0,              0,        10                  },
342
{"string",   "set string",     OFFSET(string),   FF_OPT_TYPE_STRING,   0,              CHAR_MIN, CHAR_MAX            },
343
{"flags",    "set flags",      OFFSET(flags),    FF_OPT_TYPE_FLAGS,    0,              0,        INT_MAX, 0, "flags" },
344
{"cool",     "set cool flag ", 0,                FF_OPT_TYPE_CONST,    TEST_FLAG_COOL, INT_MIN,  INT_MAX, 0, "flags" },
345
{"lame",     "set lame flag ", 0,                FF_OPT_TYPE_CONST,    TEST_FLAG_LAME, INT_MIN,  INT_MAX, 0, "flags" },
346
{"mu",       "set mu flag ",   0,                FF_OPT_TYPE_CONST,    TEST_FLAG_MU,   INT_MIN,  INT_MAX, 0, "flags" },
347
{NULL},
348
};
349

    
350
static const char *test_get_name(void *ctx)
351
{
352
    return "test";
353
}
354

    
355
static const AVClass test_class = {
356
    "TestContext",
357
    test_get_name,
358
    test_options
359
};
360

    
361
int main(void)
362
{
363
    int i;
364

    
365
    const char *strings[] = {
366
        "''",
367
        "",
368
        ":",
369
        "\\",
370
        "'",
371
        "    ''    :",
372
        "    ''  ''  :",
373
        "foo   '' :",
374
        "'foo'",
375
        "foo     ",
376
        "foo\\",
377
        "foo':  blah:blah",
378
        "foo\\:  blah:blah",
379
        "foo\'",
380
        "'foo :  '  :blahblah",
381
        "\\ :blah",
382
        "     foo",
383
        "      foo       ",
384
        "      foo     \\ ",
385
        "foo ':blah",
386
        " foo   bar    :   blahblah",
387
        "\\f\\o\\o",
388
        "'foo : \\ \\  '   : blahblah",
389
        "'\\fo\\o:': blahblah",
390
        "\\'fo\\o\\:':  foo  '  :blahblah"
391
    };
392

    
393
    for (i=0; i < FF_ARRAY_ELEMS(strings); i++) {
394
        const char *p= strings[i];
395
        printf("|%s|", p);
396
        printf(" -> |%s|", av_get_token(&p, ":"));
397
        printf(" + |%s|\n", p);
398
    }
399

    
400
    printf("\nTesting av_parse_color()\n");
401
    {
402
        uint8_t rgba[4];
403
        const char *color_names[] = {
404
            "bikeshed",
405
            "RaNdOm",
406
            "foo",
407
            "red",
408
            "Red ",
409
            "RED",
410
            "Violet",
411
            "Yellow",
412
            "Red",
413
            "0x000000",
414
            "0x0000000",
415
            "0xff000000",
416
            "0x3e34ff",
417
            "0x3e34ffaa",
418
            "0xffXXee",
419
            "0xfoobar",
420
            "0xffffeeeeeeee",
421
        };
422

    
423
        av_log_set_level(AV_LOG_DEBUG);
424

    
425
        for (int i = 0;  i < FF_ARRAY_ELEMS(color_names); i++) {
426
            if (av_parse_color(rgba, color_names[i], NULL) >= 0)
427
                printf("%s -> R(%d) G(%d) B(%d) A(%d)\n", color_names[i], rgba[0], rgba[1], rgba[2], rgba[3]);
428
        }
429
    }
430

    
431
    printf("\nTesting av_set_options_string()\n");
432
    {
433
        TestContext test_ctx;
434
        const char *options[] = {
435
            "",
436
            ":",
437
            "=",
438
            "foo=:",
439
            ":=foo",
440
            "=foo",
441
            "foo=",
442
            "foo",
443
            "foo=val",
444
            "foo==val",
445
            "toggle=:",
446
            "string=:",
447
            "toggle=1 : foo",
448
            "toggle=100",
449
            "toggle==1",
450
            "flags=+mu-lame : num=42: toggle=0",
451
            "num=42 : string=blahblah",
452
            "rational=0 : rational=1/2 : rational=1/-1",
453
            "rational=-1/0",
454
        };
455

    
456
        test_ctx.class = &test_class;
457
        av_opt_set_defaults2(&test_ctx, 0, 0);
458
        test_ctx.string = av_strdup("default");
459

    
460
        av_log_set_level(AV_LOG_DEBUG);
461

    
462
        for (i=0; i < FF_ARRAY_ELEMS(options); i++) {
463
            av_log(&test_ctx, AV_LOG_DEBUG, "Setting options string '%s'\n", options[i]);
464
            if (av_set_options_string(&test_ctx, options[i], "=", ":") < 0)
465
                av_log(&test_ctx, AV_LOG_ERROR, "Error setting options string: '%s'\n", options[i]);
466
            printf("\n");
467
        }
468
    }
469

    
470
    return 0;
471
}
472

    
473
#endif