Statistics
| Branch: | Revision:

ffmpeg / libavutil / parseutils.c @ f6c7375a

History | View | Annotate | Download (22.1 KB)

1
/*
2
 * This file is part of FFmpeg.
3
 *
4
 * FFmpeg is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
6
 * License as published by the Free Software Foundation; either
7
 * version 2.1 of the License, or (at your option) any later version.
8
 *
9
 * FFmpeg 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 GNU
12
 * Lesser General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
15
 * License along with FFmpeg; if not, write to the Free Software
16
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
 */
18

    
19
/**
20
 * @file
21
 * misc parsing utilities
22
 */
23

    
24
#include <strings.h>
25
#include <sys/time.h>
26
#include <time.h>
27
#include "parseutils.h"
28
#include "libavutil/avutil.h"
29
#include "libavutil/eval.h"
30
#include "libavutil/avstring.h"
31
#include "libavutil/random_seed.h"
32

    
33
typedef struct {
34
    const char *abbr;
35
    int width, height;
36
} VideoSizeAbbr;
37

    
38
typedef struct {
39
    const char *abbr;
40
    AVRational rate;
41
} VideoRateAbbr;
42

    
43
static const VideoSizeAbbr video_size_abbrs[] = {
44
    { "ntsc",      720, 480 },
45
    { "pal",       720, 576 },
46
    { "qntsc",     352, 240 }, /* VCD compliant NTSC */
47
    { "qpal",      352, 288 }, /* VCD compliant PAL */
48
    { "sntsc",     640, 480 }, /* square pixel NTSC */
49
    { "spal",      768, 576 }, /* square pixel PAL */
50
    { "film",      352, 240 },
51
    { "ntsc-film", 352, 240 },
52
    { "sqcif",     128,  96 },
53
    { "qcif",      176, 144 },
54
    { "cif",       352, 288 },
55
    { "4cif",      704, 576 },
56
    { "16cif",    1408,1152 },
57
    { "qqvga",     160, 120 },
58
    { "qvga",      320, 240 },
59
    { "vga",       640, 480 },
60
    { "svga",      800, 600 },
61
    { "xga",      1024, 768 },
62
    { "uxga",     1600,1200 },
63
    { "qxga",     2048,1536 },
64
    { "sxga",     1280,1024 },
65
    { "qsxga",    2560,2048 },
66
    { "hsxga",    5120,4096 },
67
    { "wvga",      852, 480 },
68
    { "wxga",     1366, 768 },
69
    { "wsxga",    1600,1024 },
70
    { "wuxga",    1920,1200 },
71
    { "woxga",    2560,1600 },
72
    { "wqsxga",   3200,2048 },
73
    { "wquxga",   3840,2400 },
74
    { "whsxga",   6400,4096 },
75
    { "whuxga",   7680,4800 },
76
    { "cga",       320, 200 },
77
    { "ega",       640, 350 },
78
    { "hd480",     852, 480 },
79
    { "hd720",    1280, 720 },
80
    { "hd1080",   1920,1080 },
81
};
82

    
83
static const VideoRateAbbr video_rate_abbrs[]= {
84
    { "ntsc",      { 30000, 1001 } },
85
    { "pal",       {    25,    1 } },
86
    { "qntsc",     { 30000, 1001 } }, /* VCD compliant NTSC */
87
    { "qpal",      {    25,    1 } }, /* VCD compliant PAL */
88
    { "sntsc",     { 30000, 1001 } }, /* square pixel NTSC */
89
    { "spal",      {    25,    1 } }, /* square pixel PAL */
90
    { "film",      {    24,    1 } },
91
    { "ntsc-film", { 24000, 1001 } },
92
};
93

    
94
int av_parse_video_size(int *width_ptr, int *height_ptr, const char *str)
95
{
96
    int i;
97
    int n = FF_ARRAY_ELEMS(video_size_abbrs);
98
    char *p;
99
    int width = 0, height = 0;
100

    
101
    for (i = 0; i < n; i++) {
102
        if (!strcmp(video_size_abbrs[i].abbr, str)) {
103
            width  = video_size_abbrs[i].width;
104
            height = video_size_abbrs[i].height;
105
            break;
106
        }
107
    }
108
    if (i == n) {
109
        p = str;
110
        width = strtol(p, &p, 10);
111
        if (*p)
112
            p++;
113
        height = strtol(p, &p, 10);
114
    }
115
    if (width <= 0 || height <= 0)
116
        return AVERROR(EINVAL);
117
    *width_ptr  = width;
118
    *height_ptr = height;
119
    return 0;
120
}
121

    
122
int av_parse_video_rate(AVRational *rate, const char *arg)
123
{
124
    int i, ret;
125
    int n = FF_ARRAY_ELEMS(video_rate_abbrs);
126
    double res;
127

    
128
    /* First, we check our abbreviation table */
129
    for (i = 0; i < n; ++i)
130
        if (!strcmp(video_rate_abbrs[i].abbr, arg)) {
131
            *rate = video_rate_abbrs[i].rate;
132
            return 0;
133
        }
134

    
135
    /* Then, we try to parse it as fraction */
136
    if ((ret = av_expr_parse_and_eval(&res, arg, NULL, NULL, NULL, NULL, NULL, NULL,
137
                                      NULL, 0, NULL)) < 0)
138
        return ret;
139
    *rate = av_d2q(res, 1001000);
140
    if (rate->num <= 0 || rate->den <= 0)
141
        return AVERROR(EINVAL);
142
    return 0;
143
}
144

    
145
typedef struct {
146
    const char *name;            ///< a string representing the name of the color
147
    uint8_t     rgb_color[3];    ///< RGB values for the color
148
} ColorEntry;
149

    
150
static ColorEntry color_table[] = {
151
    { "AliceBlue",            { 0xF0, 0xF8, 0xFF } },
152
    { "AntiqueWhite",         { 0xFA, 0xEB, 0xD7 } },
153
    { "Aqua",                 { 0x00, 0xFF, 0xFF } },
154
    { "Aquamarine",           { 0x7F, 0xFF, 0xD4 } },
155
    { "Azure",                { 0xF0, 0xFF, 0xFF } },
156
    { "Beige",                { 0xF5, 0xF5, 0xDC } },
157
    { "Bisque",               { 0xFF, 0xE4, 0xC4 } },
158
    { "Black",                { 0x00, 0x00, 0x00 } },
159
    { "BlanchedAlmond",       { 0xFF, 0xEB, 0xCD } },
160
    { "Blue",                 { 0x00, 0x00, 0xFF } },
161
    { "BlueViolet",           { 0x8A, 0x2B, 0xE2 } },
162
    { "Brown",                { 0xA5, 0x2A, 0x2A } },
163
    { "BurlyWood",            { 0xDE, 0xB8, 0x87 } },
164
    { "CadetBlue",            { 0x5F, 0x9E, 0xA0 } },
165
    { "Chartreuse",           { 0x7F, 0xFF, 0x00 } },
166
    { "Chocolate",            { 0xD2, 0x69, 0x1E } },
167
    { "Coral",                { 0xFF, 0x7F, 0x50 } },
168
    { "CornflowerBlue",       { 0x64, 0x95, 0xED } },
169
    { "Cornsilk",             { 0xFF, 0xF8, 0xDC } },
170
    { "Crimson",              { 0xDC, 0x14, 0x3C } },
171
    { "Cyan",                 { 0x00, 0xFF, 0xFF } },
172
    { "DarkBlue",             { 0x00, 0x00, 0x8B } },
173
    { "DarkCyan",             { 0x00, 0x8B, 0x8B } },
174
    { "DarkGoldenRod",        { 0xB8, 0x86, 0x0B } },
175
    { "DarkGray",             { 0xA9, 0xA9, 0xA9 } },
176
    { "DarkGreen",            { 0x00, 0x64, 0x00 } },
177
    { "DarkKhaki",            { 0xBD, 0xB7, 0x6B } },
178
    { "DarkMagenta",          { 0x8B, 0x00, 0x8B } },
179
    { "DarkOliveGreen",       { 0x55, 0x6B, 0x2F } },
180
    { "Darkorange",           { 0xFF, 0x8C, 0x00 } },
181
    { "DarkOrchid",           { 0x99, 0x32, 0xCC } },
182
    { "DarkRed",              { 0x8B, 0x00, 0x00 } },
183
    { "DarkSalmon",           { 0xE9, 0x96, 0x7A } },
184
    { "DarkSeaGreen",         { 0x8F, 0xBC, 0x8F } },
185
    { "DarkSlateBlue",        { 0x48, 0x3D, 0x8B } },
186
    { "DarkSlateGray",        { 0x2F, 0x4F, 0x4F } },
187
    { "DarkTurquoise",        { 0x00, 0xCE, 0xD1 } },
188
    { "DarkViolet",           { 0x94, 0x00, 0xD3 } },
189
    { "DeepPink",             { 0xFF, 0x14, 0x93 } },
190
    { "DeepSkyBlue",          { 0x00, 0xBF, 0xFF } },
191
    { "DimGray",              { 0x69, 0x69, 0x69 } },
192
    { "DodgerBlue",           { 0x1E, 0x90, 0xFF } },
193
    { "FireBrick",            { 0xB2, 0x22, 0x22 } },
194
    { "FloralWhite",          { 0xFF, 0xFA, 0xF0 } },
195
    { "ForestGreen",          { 0x22, 0x8B, 0x22 } },
196
    { "Fuchsia",              { 0xFF, 0x00, 0xFF } },
197
    { "Gainsboro",            { 0xDC, 0xDC, 0xDC } },
198
    { "GhostWhite",           { 0xF8, 0xF8, 0xFF } },
199
    { "Gold",                 { 0xFF, 0xD7, 0x00 } },
200
    { "GoldenRod",            { 0xDA, 0xA5, 0x20 } },
201
    { "Gray",                 { 0x80, 0x80, 0x80 } },
202
    { "Green",                { 0x00, 0x80, 0x00 } },
203
    { "GreenYellow",          { 0xAD, 0xFF, 0x2F } },
204
    { "HoneyDew",             { 0xF0, 0xFF, 0xF0 } },
205
    { "HotPink",              { 0xFF, 0x69, 0xB4 } },
206
    { "IndianRed",            { 0xCD, 0x5C, 0x5C } },
207
    { "Indigo",               { 0x4B, 0x00, 0x82 } },
208
    { "Ivory",                { 0xFF, 0xFF, 0xF0 } },
209
    { "Khaki",                { 0xF0, 0xE6, 0x8C } },
210
    { "Lavender",             { 0xE6, 0xE6, 0xFA } },
211
    { "LavenderBlush",        { 0xFF, 0xF0, 0xF5 } },
212
    { "LawnGreen",            { 0x7C, 0xFC, 0x00 } },
213
    { "LemonChiffon",         { 0xFF, 0xFA, 0xCD } },
214
    { "LightBlue",            { 0xAD, 0xD8, 0xE6 } },
215
    { "LightCoral",           { 0xF0, 0x80, 0x80 } },
216
    { "LightCyan",            { 0xE0, 0xFF, 0xFF } },
217
    { "LightGoldenRodYellow", { 0xFA, 0xFA, 0xD2 } },
218
    { "LightGrey",            { 0xD3, 0xD3, 0xD3 } },
219
    { "LightGreen",           { 0x90, 0xEE, 0x90 } },
220
    { "LightPink",            { 0xFF, 0xB6, 0xC1 } },
221
    { "LightSalmon",          { 0xFF, 0xA0, 0x7A } },
222
    { "LightSeaGreen",        { 0x20, 0xB2, 0xAA } },
223
    { "LightSkyBlue",         { 0x87, 0xCE, 0xFA } },
224
    { "LightSlateGray",       { 0x77, 0x88, 0x99 } },
225
    { "LightSteelBlue",       { 0xB0, 0xC4, 0xDE } },
226
    { "LightYellow",          { 0xFF, 0xFF, 0xE0 } },
227
    { "Lime",                 { 0x00, 0xFF, 0x00 } },
228
    { "LimeGreen",            { 0x32, 0xCD, 0x32 } },
229
    { "Linen",                { 0xFA, 0xF0, 0xE6 } },
230
    { "Magenta",              { 0xFF, 0x00, 0xFF } },
231
    { "Maroon",               { 0x80, 0x00, 0x00 } },
232
    { "MediumAquaMarine",     { 0x66, 0xCD, 0xAA } },
233
    { "MediumBlue",           { 0x00, 0x00, 0xCD } },
234
    { "MediumOrchid",         { 0xBA, 0x55, 0xD3 } },
235
    { "MediumPurple",         { 0x93, 0x70, 0xD8 } },
236
    { "MediumSeaGreen",       { 0x3C, 0xB3, 0x71 } },
237
    { "MediumSlateBlue",      { 0x7B, 0x68, 0xEE } },
238
    { "MediumSpringGreen",    { 0x00, 0xFA, 0x9A } },
239
    { "MediumTurquoise",      { 0x48, 0xD1, 0xCC } },
240
    { "MediumVioletRed",      { 0xC7, 0x15, 0x85 } },
241
    { "MidnightBlue",         { 0x19, 0x19, 0x70 } },
242
    { "MintCream",            { 0xF5, 0xFF, 0xFA } },
243
    { "MistyRose",            { 0xFF, 0xE4, 0xE1 } },
244
    { "Moccasin",             { 0xFF, 0xE4, 0xB5 } },
245
    { "NavajoWhite",          { 0xFF, 0xDE, 0xAD } },
246
    { "Navy",                 { 0x00, 0x00, 0x80 } },
247
    { "OldLace",              { 0xFD, 0xF5, 0xE6 } },
248
    { "Olive",                { 0x80, 0x80, 0x00 } },
249
    { "OliveDrab",            { 0x6B, 0x8E, 0x23 } },
250
    { "Orange",               { 0xFF, 0xA5, 0x00 } },
251
    { "OrangeRed",            { 0xFF, 0x45, 0x00 } },
252
    { "Orchid",               { 0xDA, 0x70, 0xD6 } },
253
    { "PaleGoldenRod",        { 0xEE, 0xE8, 0xAA } },
254
    { "PaleGreen",            { 0x98, 0xFB, 0x98 } },
255
    { "PaleTurquoise",        { 0xAF, 0xEE, 0xEE } },
256
    { "PaleVioletRed",        { 0xD8, 0x70, 0x93 } },
257
    { "PapayaWhip",           { 0xFF, 0xEF, 0xD5 } },
258
    { "PeachPuff",            { 0xFF, 0xDA, 0xB9 } },
259
    { "Peru",                 { 0xCD, 0x85, 0x3F } },
260
    { "Pink",                 { 0xFF, 0xC0, 0xCB } },
261
    { "Plum",                 { 0xDD, 0xA0, 0xDD } },
262
    { "PowderBlue",           { 0xB0, 0xE0, 0xE6 } },
263
    { "Purple",               { 0x80, 0x00, 0x80 } },
264
    { "Red",                  { 0xFF, 0x00, 0x00 } },
265
    { "RosyBrown",            { 0xBC, 0x8F, 0x8F } },
266
    { "RoyalBlue",            { 0x41, 0x69, 0xE1 } },
267
    { "SaddleBrown",          { 0x8B, 0x45, 0x13 } },
268
    { "Salmon",               { 0xFA, 0x80, 0x72 } },
269
    { "SandyBrown",           { 0xF4, 0xA4, 0x60 } },
270
    { "SeaGreen",             { 0x2E, 0x8B, 0x57 } },
271
    { "SeaShell",             { 0xFF, 0xF5, 0xEE } },
272
    { "Sienna",               { 0xA0, 0x52, 0x2D } },
273
    { "Silver",               { 0xC0, 0xC0, 0xC0 } },
274
    { "SkyBlue",              { 0x87, 0xCE, 0xEB } },
275
    { "SlateBlue",            { 0x6A, 0x5A, 0xCD } },
276
    { "SlateGray",            { 0x70, 0x80, 0x90 } },
277
    { "Snow",                 { 0xFF, 0xFA, 0xFA } },
278
    { "SpringGreen",          { 0x00, 0xFF, 0x7F } },
279
    { "SteelBlue",            { 0x46, 0x82, 0xB4 } },
280
    { "Tan",                  { 0xD2, 0xB4, 0x8C } },
281
    { "Teal",                 { 0x00, 0x80, 0x80 } },
282
    { "Thistle",              { 0xD8, 0xBF, 0xD8 } },
283
    { "Tomato",               { 0xFF, 0x63, 0x47 } },
284
    { "Turquoise",            { 0x40, 0xE0, 0xD0 } },
285
    { "Violet",               { 0xEE, 0x82, 0xEE } },
286
    { "Wheat",                { 0xF5, 0xDE, 0xB3 } },
287
    { "White",                { 0xFF, 0xFF, 0xFF } },
288
    { "WhiteSmoke",           { 0xF5, 0xF5, 0xF5 } },
289
    { "Yellow",               { 0xFF, 0xFF, 0x00 } },
290
    { "YellowGreen",          { 0x9A, 0xCD, 0x32 } },
291
};
292

    
293
static int color_table_compare(const void *lhs, const void *rhs)
294
{
295
    return strcasecmp(lhs, ((const ColorEntry *)rhs)->name);
296
}
297

    
298
#define ALPHA_SEP '@'
299

    
300
int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen,
301
                   void *log_ctx)
302
{
303
    char *tail, color_string2[128];
304
    const ColorEntry *entry;
305
    int len, hex_offset = 0;
306

    
307
    if (color_string[0] == '#') {
308
        hex_offset = 1;
309
    } else if (!strncmp(color_string, "0x", 2))
310
        hex_offset = 2;
311

    
312
    if (slen < 0)
313
        slen = strlen(color_string);
314
    av_strlcpy(color_string2, color_string + hex_offset,
315
               FFMIN(slen-hex_offset+1, sizeof(color_string2)));
316
    if ((tail = strchr(color_string2, ALPHA_SEP)))
317
        *tail++ = 0;
318
    len = strlen(color_string2);
319
    rgba_color[3] = 255;
320

    
321
    if (!strcasecmp(color_string2, "random") || !strcasecmp(color_string2, "bikeshed")) {
322
        int rgba = av_get_random_seed();
323
        rgba_color[0] = rgba >> 24;
324
        rgba_color[1] = rgba >> 16;
325
        rgba_color[2] = rgba >> 8;
326
        rgba_color[3] = rgba;
327
    } else if (hex_offset ||
328
               strspn(color_string2, "0123456789ABCDEFabcdef") == len) {
329
        char *tail;
330
        unsigned int rgba = strtoul(color_string2, &tail, 16);
331

    
332
        if (*tail || (len != 6 && len != 8)) {
333
            av_log(log_ctx, AV_LOG_ERROR, "Invalid 0xRRGGBB[AA] color string: '%s'\n", color_string2);
334
            return AVERROR(EINVAL);
335
        }
336
        if (len == 8) {
337
            rgba_color[3] = rgba;
338
            rgba >>= 8;
339
        }
340
        rgba_color[0] = rgba >> 16;
341
        rgba_color[1] = rgba >> 8;
342
        rgba_color[2] = rgba;
343
    } else {
344
        entry = bsearch(color_string2,
345
                        color_table,
346
                        FF_ARRAY_ELEMS(color_table),
347
                        sizeof(ColorEntry),
348
                        color_table_compare);
349
        if (!entry) {
350
            av_log(log_ctx, AV_LOG_ERROR, "Cannot find color '%s'\n", color_string2);
351
            return AVERROR(EINVAL);
352
        }
353
        memcpy(rgba_color, entry->rgb_color, 3);
354
    }
355

    
356
    if (tail) {
357
        unsigned long int alpha;
358
        const char *alpha_string = tail;
359
        if (!strncmp(alpha_string, "0x", 2)) {
360
            alpha = strtoul(alpha_string, &tail, 16);
361
        } else {
362
            alpha = 255 * strtod(alpha_string, &tail);
363
        }
364

    
365
        if (tail == alpha_string || *tail || alpha > 255) {
366
            av_log(log_ctx, AV_LOG_ERROR, "Invalid alpha value specifier '%s' in '%s'\n",
367
                   alpha_string, color_string);
368
            return AVERROR(EINVAL);
369
        }
370
        rgba_color[3] = alpha;
371
    }
372

    
373
    return 0;
374
}
375

    
376
/* get a positive number between n_min and n_max, for a maximum length
377
   of len_max. Return -1 if error. */
378
static int date_get_num(const char **pp,
379
                        int n_min, int n_max, int len_max)
380
{
381
    int i, val, c;
382
    const char *p;
383

    
384
    p = *pp;
385
    val = 0;
386
    for(i = 0; i < len_max; i++) {
387
        c = *p;
388
        if (!isdigit(c))
389
            break;
390
        val = (val * 10) + c - '0';
391
        p++;
392
    }
393
    /* no number read ? */
394
    if (p == *pp)
395
        return -1;
396
    if (val < n_min || val > n_max)
397
        return -1;
398
    *pp = p;
399
    return val;
400
}
401

    
402
/* small strptime for ffmpeg */
403
static
404
const char *small_strptime(const char *p, const char *fmt,
405
                           struct tm *dt)
406
{
407
    int c, val;
408

    
409
    for(;;) {
410
        c = *fmt++;
411
        if (c == '\0') {
412
            return p;
413
        } else if (c == '%') {
414
            c = *fmt++;
415
            switch(c) {
416
            case 'H':
417
                val = date_get_num(&p, 0, 23, 2);
418
                if (val == -1)
419
                    return NULL;
420
                dt->tm_hour = val;
421
                break;
422
            case 'M':
423
                val = date_get_num(&p, 0, 59, 2);
424
                if (val == -1)
425
                    return NULL;
426
                dt->tm_min = val;
427
                break;
428
            case 'S':
429
                val = date_get_num(&p, 0, 59, 2);
430
                if (val == -1)
431
                    return NULL;
432
                dt->tm_sec = val;
433
                break;
434
            case 'Y':
435
                val = date_get_num(&p, 0, 9999, 4);
436
                if (val == -1)
437
                    return NULL;
438
                dt->tm_year = val - 1900;
439
                break;
440
            case 'm':
441
                val = date_get_num(&p, 1, 12, 2);
442
                if (val == -1)
443
                    return NULL;
444
                dt->tm_mon = val - 1;
445
                break;
446
            case 'd':
447
                val = date_get_num(&p, 1, 31, 2);
448
                if (val == -1)
449
                    return NULL;
450
                dt->tm_mday = val;
451
                break;
452
            case '%':
453
                goto match;
454
            default:
455
                return NULL;
456
            }
457
        } else {
458
        match:
459
            if (c != *p)
460
                return NULL;
461
            p++;
462
        }
463
    }
464
    return p;
465
}
466

    
467
static time_t mktimegm(struct tm *tm)
468
{
469
    time_t t;
470

    
471
    int y = tm->tm_year + 1900, m = tm->tm_mon + 1, d = tm->tm_mday;
472

    
473
    if (m < 3) {
474
        m += 12;
475
        y--;
476
    }
477

    
478
    t = 86400 *
479
        (d + (153 * m - 457) / 5 + 365 * y + y / 4 - y / 100 + y / 400 - 719469);
480

    
481
    t += 3600 * tm->tm_hour + 60 * tm->tm_min + tm->tm_sec;
482

    
483
    return t;
484
}
485

    
486
int av_parse_time(int64_t *timeval, const char *datestr, int duration)
487
{
488
    const char *p;
489
    int64_t t;
490
    struct tm dt;
491
    int i;
492
    static const char * const date_fmt[] = {
493
        "%Y-%m-%d",
494
        "%Y%m%d",
495
    };
496
    static const char * const time_fmt[] = {
497
        "%H:%M:%S",
498
        "%H%M%S",
499
    };
500
    const char *q;
501
    int is_utc, len;
502
    char lastch;
503
    int negative = 0;
504

    
505
#undef time
506
    time_t now = time(0);
507

    
508
    len = strlen(datestr);
509
    if (len > 0)
510
        lastch = datestr[len - 1];
511
    else
512
        lastch = '\0';
513
    is_utc = (lastch == 'z' || lastch == 'Z');
514

    
515
    memset(&dt, 0, sizeof(dt));
516

    
517
    p = datestr;
518
    q = NULL;
519
    if (!duration) {
520
        if (!strncasecmp(datestr, "now", len)) {
521
            *timeval = (int64_t) now * 1000000;
522
            return 0;
523
        }
524

    
525
        /* parse the year-month-day part */
526
        for (i = 0; i < FF_ARRAY_ELEMS(date_fmt); i++) {
527
            q = small_strptime(p, date_fmt[i], &dt);
528
            if (q) {
529
                break;
530
            }
531
        }
532

    
533
        /* if the year-month-day part is missing, then take the
534
         * current year-month-day time */
535
        if (!q) {
536
            if (is_utc) {
537
                dt = *gmtime(&now);
538
            } else {
539
                dt = *localtime(&now);
540
            }
541
            dt.tm_hour = dt.tm_min = dt.tm_sec = 0;
542
        } else {
543
            p = q;
544
        }
545

    
546
        if (*p == 'T' || *p == 't' || *p == ' ')
547
            p++;
548

    
549
        /* parse the hour-minute-second part */
550
        for (i = 0; i < FF_ARRAY_ELEMS(time_fmt); i++) {
551
            q = small_strptime(p, time_fmt[i], &dt);
552
            if (q) {
553
                break;
554
            }
555
        }
556
    } else {
557
        /* parse datestr as a duration */
558
        if (p[0] == '-') {
559
            negative = 1;
560
            ++p;
561
        }
562
        /* parse datestr as HH:MM:SS */
563
        q = small_strptime(p, time_fmt[0], &dt);
564
        if (!q) {
565
            /* parse datestr as S+ */
566
            dt.tm_sec = strtol(p, (char **)&q, 10);
567
            if (q == p) {
568
                /* the parsing didn't succeed */
569
                *timeval = INT64_MIN;
570
                return AVERROR(EINVAL);
571
            }
572
            dt.tm_min = 0;
573
            dt.tm_hour = 0;
574
        }
575
    }
576

    
577
    /* Now we have all the fields that we can get */
578
    if (!q) {
579
        *timeval = INT64_MIN;
580
        return AVERROR(EINVAL);
581
    }
582

    
583
    if (duration) {
584
        t = dt.tm_hour * 3600 + dt.tm_min * 60 + dt.tm_sec;
585
    } else {
586
        dt.tm_isdst = -1;       /* unknown */
587
        if (is_utc) {
588
            t = mktimegm(&dt);
589
        } else {
590
            t = mktime(&dt);
591
        }
592
    }
593

    
594
    t *= 1000000;
595

    
596
    /* parse the .m... part */
597
    if (*q == '.') {
598
        int val, n;
599
        q++;
600
        for (val = 0, n = 100000; n >= 1; n /= 10, q++) {
601
            if (!isdigit(*q))
602
                break;
603
            val += n * (*q - '0');
604
        }
605
        t += val;
606
    }
607
    *timeval = negative ? -t : t;
608
    return 0;
609
}
610

    
611
#ifdef TEST
612

    
613
#undef printf
614

    
615
int main(void)
616
{
617
    printf("Testing av_parse_video_rate()\n");
618
    {
619
        int i;
620
        const char *rates[] = {
621
            "-inf",
622
            "inf",
623
            "nan",
624
            "123/0",
625
            "-123 / 0",
626
            "",
627
            "/",
628
            " 123  /  321",
629
            "foo/foo",
630
            "foo/1",
631
            "1/foo",
632
            "0/0",
633
            "/0",
634
            "1/",
635
            "1",
636
            "0",
637
            "-123/123",
638
            "-foo",
639
            "123.23",
640
            ".23",
641
            "-.23",
642
            "-0.234",
643
            "-0.0000001",
644
            "  21332.2324   ",
645
            " -21332.2324   ",
646
        };
647

    
648
        for (i = 0; i < FF_ARRAY_ELEMS(rates); i++) {
649
            int ret;
650
            AVRational q = (AVRational){0, 0};
651
            ret = av_parse_video_rate(&q, rates[i]),
652
            printf("'%s' -> %d/%d ret:%d\n",
653
                   rates[i], q.num, q.den, ret);
654
        }
655
    }
656

    
657
    printf("\nTesting av_parse_color()\n");
658
    {
659
        int i;
660
        uint8_t rgba[4];
661
        const char *color_names[] = {
662
            "bikeshed",
663
            "RaNdOm",
664
            "foo",
665
            "red",
666
            "Red ",
667
            "RED",
668
            "Violet",
669
            "Yellow",
670
            "Red",
671
            "0x000000",
672
            "0x0000000",
673
            "0xff000000",
674
            "0x3e34ff",
675
            "0x3e34ffaa",
676
            "0xffXXee",
677
            "0xfoobar",
678
            "0xffffeeeeeeee",
679
            "#ff0000",
680
            "#ffXX00",
681
            "ff0000",
682
            "ffXX00",
683
            "red@foo",
684
            "random@10",
685
            "0xff0000@1.0",
686
            "red@",
687
            "red@0xfff",
688
            "red@0xf",
689
            "red@2",
690
            "red@0.1",
691
            "red@-1",
692
            "red@0.5",
693
            "red@1.0",
694
            "red@256",
695
            "red@10foo",
696
            "red@-1.0",
697
            "red@-0.0",
698
        };
699

    
700
        av_log_set_level(AV_LOG_DEBUG);
701

    
702
        for (i = 0;  i < FF_ARRAY_ELEMS(color_names); i++) {
703
            if (av_parse_color(rgba, color_names[i], -1, NULL) >= 0)
704
                printf("%s -> R(%d) G(%d) B(%d) A(%d)\n", color_names[i], rgba[0], rgba[1], rgba[2], rgba[3]);
705
        }
706
    }
707

    
708
    return 0;
709
}
710

    
711
#endif /* TEST */