Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 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 
25
 
26
#include "avstring.h"
27
#include "avutil.h"
28
#include "common.h"
29
#include "eval.h"
30
#include "log.h"
31
#include "random_seed.h"
32
#include "parseutils.h"
33
 
34
#ifdef TEST
35
 
36
#define av_get_random_seed av_get_random_seed_deterministic
37
static uint32_t av_get_random_seed_deterministic(void);
38
 
39
#define time(t) 1331972053
40
 
41
#endif
42
 
43
int av_parse_ratio(AVRational *q, const char *str, int max,
44
                   int log_offset, void *log_ctx)
45
{
46
    char c;
47
    int ret;
48
 
49
    if (sscanf(str, "%d:%d%c", &q->num, &q->den, &c) != 2) {
50
        double d;
51
        ret = av_expr_parse_and_eval(&d, str, NULL, NULL,
52
                                     NULL, NULL, NULL, NULL,
53
                                     NULL, log_offset, log_ctx);
54
        if (ret < 0)
55
            return ret;
56
        *q = av_d2q(d, max);
57
    } else {
58
        av_reduce(&q->num, &q->den, q->num, q->den, max);
59
    }
60
 
61
    return 0;
62
}
63
 
64
typedef struct {
65
    const char *abbr;
66
    int width, height;
67
} VideoSizeAbbr;
68
 
69
typedef struct {
70
    const char *abbr;
71
    AVRational rate;
72
} VideoRateAbbr;
73
 
74
static const VideoSizeAbbr video_size_abbrs[] = {
75
    { "ntsc",      720, 480 },
76
    { "pal",       720, 576 },
77
    { "qntsc",     352, 240 }, /* VCD compliant NTSC */
78
    { "qpal",      352, 288 }, /* VCD compliant PAL */
79
    { "sntsc",     640, 480 }, /* square pixel NTSC */
80
    { "spal",      768, 576 }, /* square pixel PAL */
81
    { "film",      352, 240 },
82
    { "ntsc-film", 352, 240 },
83
    { "sqcif",     128,  96 },
84
    { "qcif",      176, 144 },
85
    { "cif",       352, 288 },
86
    { "4cif",      704, 576 },
87
    { "16cif",    1408,1152 },
88
    { "qqvga",     160, 120 },
89
    { "qvga",      320, 240 },
90
    { "vga",       640, 480 },
91
    { "svga",      800, 600 },
92
    { "xga",      1024, 768 },
93
    { "uxga",     1600,1200 },
94
    { "qxga",     2048,1536 },
95
    { "sxga",     1280,1024 },
96
    { "qsxga",    2560,2048 },
97
    { "hsxga",    5120,4096 },
98
    { "wvga",      852, 480 },
99
    { "wxga",     1366, 768 },
100
    { "wsxga",    1600,1024 },
101
    { "wuxga",    1920,1200 },
102
    { "woxga",    2560,1600 },
103
    { "wqsxga",   3200,2048 },
104
    { "wquxga",   3840,2400 },
105
    { "whsxga",   6400,4096 },
106
    { "whuxga",   7680,4800 },
107
    { "cga",       320, 200 },
108
    { "ega",       640, 350 },
109
    { "hd480",     852, 480 },
110
    { "hd720",    1280, 720 },
111
    { "hd1080",   1920,1080 },
112
    { "2k",       2048,1080 }, /* Digital Cinema System Specification */
113
    { "2kflat",   1998,1080 },
114
    { "2kscope",  2048, 858 },
115
    { "4k",       4096,2160 }, /* Digital Cinema System Specification */
116
    { "4kflat",   3996,2160 },
117
    { "4kscope",  4096,1716 },
118
    { "nhd",       640,360  },
119
    { "hqvga",     240,160  },
120
    { "wqvga",     400,240  },
121
    { "fwqvga",    432,240  },
122
    { "hvga",      480,320  },
123
    { "qhd",       960,540  },
124
};
125
 
126
static const VideoRateAbbr video_rate_abbrs[]= {
127
    { "ntsc",      { 30000, 1001 } },
128
    { "pal",       {    25,    1 } },
129
    { "qntsc",     { 30000, 1001 } }, /* VCD compliant NTSC */
130
    { "qpal",      {    25,    1 } }, /* VCD compliant PAL */
131
    { "sntsc",     { 30000, 1001 } }, /* square pixel NTSC */
132
    { "spal",      {    25,    1 } }, /* square pixel PAL */
133
    { "film",      {    24,    1 } },
134
    { "ntsc-film", { 24000, 1001 } },
135
};
136
 
137
int av_parse_video_size(int *width_ptr, int *height_ptr, const char *str)
138
{
139
    int i;
140
    int n = FF_ARRAY_ELEMS(video_size_abbrs);
141
    const char *p;
142
    int width = 0, height = 0;
143
 
144
    for (i = 0; i < n; i++) {
145
        if (!strcmp(video_size_abbrs[i].abbr, str)) {
146
            width  = video_size_abbrs[i].width;
147
            height = video_size_abbrs[i].height;
148
            break;
149
        }
150
    }
151
    if (i == n) {
152
        width = strtol(str, (void*)&p, 10);
153
        if (*p)
154
            p++;
155
        height = strtol(p, (void*)&p, 10);
156
 
157
        /* trailing extraneous data detected, like in 123x345foobar */
158
        if (*p)
159
            return AVERROR(EINVAL);
160
    }
161
    if (width <= 0 || height <= 0)
162
        return AVERROR(EINVAL);
163
    *width_ptr  = width;
164
    *height_ptr = height;
165
    return 0;
166
}
167
 
168
int av_parse_video_rate(AVRational *rate, const char *arg)
169
{
170
    int i, ret;
171
    int n = FF_ARRAY_ELEMS(video_rate_abbrs);
172
 
173
    /* First, we check our abbreviation table */
174
    for (i = 0; i < n; ++i)
175
        if (!strcmp(video_rate_abbrs[i].abbr, arg)) {
176
            *rate = video_rate_abbrs[i].rate;
177
            return 0;
178
        }
179
 
180
    /* Then, we try to parse it as fraction */
181
    if ((ret = av_parse_ratio_quiet(rate, arg, 1001000)) < 0)
182
        return ret;
183
    if (rate->num <= 0 || rate->den <= 0)
184
        return AVERROR(EINVAL);
185
    return 0;
186
}
187
 
188
typedef struct {
189
    const char *name;            ///< a string representing the name of the color
190
    uint8_t     rgb_color[3];    ///< RGB values for the color
191
} ColorEntry;
192
 
193
static const ColorEntry color_table[] = {
194
    { "AliceBlue",            { 0xF0, 0xF8, 0xFF } },
195
    { "AntiqueWhite",         { 0xFA, 0xEB, 0xD7 } },
196
    { "Aqua",                 { 0x00, 0xFF, 0xFF } },
197
    { "Aquamarine",           { 0x7F, 0xFF, 0xD4 } },
198
    { "Azure",                { 0xF0, 0xFF, 0xFF } },
199
    { "Beige",                { 0xF5, 0xF5, 0xDC } },
200
    { "Bisque",               { 0xFF, 0xE4, 0xC4 } },
201
    { "Black",                { 0x00, 0x00, 0x00 } },
202
    { "BlanchedAlmond",       { 0xFF, 0xEB, 0xCD } },
203
    { "Blue",                 { 0x00, 0x00, 0xFF } },
204
    { "BlueViolet",           { 0x8A, 0x2B, 0xE2 } },
205
    { "Brown",                { 0xA5, 0x2A, 0x2A } },
206
    { "BurlyWood",            { 0xDE, 0xB8, 0x87 } },
207
    { "CadetBlue",            { 0x5F, 0x9E, 0xA0 } },
208
    { "Chartreuse",           { 0x7F, 0xFF, 0x00 } },
209
    { "Chocolate",            { 0xD2, 0x69, 0x1E } },
210
    { "Coral",                { 0xFF, 0x7F, 0x50 } },
211
    { "CornflowerBlue",       { 0x64, 0x95, 0xED } },
212
    { "Cornsilk",             { 0xFF, 0xF8, 0xDC } },
213
    { "Crimson",              { 0xDC, 0x14, 0x3C } },
214
    { "Cyan",                 { 0x00, 0xFF, 0xFF } },
215
    { "DarkBlue",             { 0x00, 0x00, 0x8B } },
216
    { "DarkCyan",             { 0x00, 0x8B, 0x8B } },
217
    { "DarkGoldenRod",        { 0xB8, 0x86, 0x0B } },
218
    { "DarkGray",             { 0xA9, 0xA9, 0xA9 } },
219
    { "DarkGreen",            { 0x00, 0x64, 0x00 } },
220
    { "DarkKhaki",            { 0xBD, 0xB7, 0x6B } },
221
    { "DarkMagenta",          { 0x8B, 0x00, 0x8B } },
222
    { "DarkOliveGreen",       { 0x55, 0x6B, 0x2F } },
223
    { "Darkorange",           { 0xFF, 0x8C, 0x00 } },
224
    { "DarkOrchid",           { 0x99, 0x32, 0xCC } },
225
    { "DarkRed",              { 0x8B, 0x00, 0x00 } },
226
    { "DarkSalmon",           { 0xE9, 0x96, 0x7A } },
227
    { "DarkSeaGreen",         { 0x8F, 0xBC, 0x8F } },
228
    { "DarkSlateBlue",        { 0x48, 0x3D, 0x8B } },
229
    { "DarkSlateGray",        { 0x2F, 0x4F, 0x4F } },
230
    { "DarkTurquoise",        { 0x00, 0xCE, 0xD1 } },
231
    { "DarkViolet",           { 0x94, 0x00, 0xD3 } },
232
    { "DeepPink",             { 0xFF, 0x14, 0x93 } },
233
    { "DeepSkyBlue",          { 0x00, 0xBF, 0xFF } },
234
    { "DimGray",              { 0x69, 0x69, 0x69 } },
235
    { "DodgerBlue",           { 0x1E, 0x90, 0xFF } },
236
    { "FireBrick",            { 0xB2, 0x22, 0x22 } },
237
    { "FloralWhite",          { 0xFF, 0xFA, 0xF0 } },
238
    { "ForestGreen",          { 0x22, 0x8B, 0x22 } },
239
    { "Fuchsia",              { 0xFF, 0x00, 0xFF } },
240
    { "Gainsboro",            { 0xDC, 0xDC, 0xDC } },
241
    { "GhostWhite",           { 0xF8, 0xF8, 0xFF } },
242
    { "Gold",                 { 0xFF, 0xD7, 0x00 } },
243
    { "GoldenRod",            { 0xDA, 0xA5, 0x20 } },
244
    { "Gray",                 { 0x80, 0x80, 0x80 } },
245
    { "Green",                { 0x00, 0x80, 0x00 } },
246
    { "GreenYellow",          { 0xAD, 0xFF, 0x2F } },
247
    { "HoneyDew",             { 0xF0, 0xFF, 0xF0 } },
248
    { "HotPink",              { 0xFF, 0x69, 0xB4 } },
249
    { "IndianRed",            { 0xCD, 0x5C, 0x5C } },
250
    { "Indigo",               { 0x4B, 0x00, 0x82 } },
251
    { "Ivory",                { 0xFF, 0xFF, 0xF0 } },
252
    { "Khaki",                { 0xF0, 0xE6, 0x8C } },
253
    { "Lavender",             { 0xE6, 0xE6, 0xFA } },
254
    { "LavenderBlush",        { 0xFF, 0xF0, 0xF5 } },
255
    { "LawnGreen",            { 0x7C, 0xFC, 0x00 } },
256
    { "LemonChiffon",         { 0xFF, 0xFA, 0xCD } },
257
    { "LightBlue",            { 0xAD, 0xD8, 0xE6 } },
258
    { "LightCoral",           { 0xF0, 0x80, 0x80 } },
259
    { "LightCyan",            { 0xE0, 0xFF, 0xFF } },
260
    { "LightGoldenRodYellow", { 0xFA, 0xFA, 0xD2 } },
261
    { "LightGreen",           { 0x90, 0xEE, 0x90 } },
262
    { "LightGrey",            { 0xD3, 0xD3, 0xD3 } },
263
    { "LightPink",            { 0xFF, 0xB6, 0xC1 } },
264
    { "LightSalmon",          { 0xFF, 0xA0, 0x7A } },
265
    { "LightSeaGreen",        { 0x20, 0xB2, 0xAA } },
266
    { "LightSkyBlue",         { 0x87, 0xCE, 0xFA } },
267
    { "LightSlateGray",       { 0x77, 0x88, 0x99 } },
268
    { "LightSteelBlue",       { 0xB0, 0xC4, 0xDE } },
269
    { "LightYellow",          { 0xFF, 0xFF, 0xE0 } },
270
    { "Lime",                 { 0x00, 0xFF, 0x00 } },
271
    { "LimeGreen",            { 0x32, 0xCD, 0x32 } },
272
    { "Linen",                { 0xFA, 0xF0, 0xE6 } },
273
    { "Magenta",              { 0xFF, 0x00, 0xFF } },
274
    { "Maroon",               { 0x80, 0x00, 0x00 } },
275
    { "MediumAquaMarine",     { 0x66, 0xCD, 0xAA } },
276
    { "MediumBlue",           { 0x00, 0x00, 0xCD } },
277
    { "MediumOrchid",         { 0xBA, 0x55, 0xD3 } },
278
    { "MediumPurple",         { 0x93, 0x70, 0xD8 } },
279
    { "MediumSeaGreen",       { 0x3C, 0xB3, 0x71 } },
280
    { "MediumSlateBlue",      { 0x7B, 0x68, 0xEE } },
281
    { "MediumSpringGreen",    { 0x00, 0xFA, 0x9A } },
282
    { "MediumTurquoise",      { 0x48, 0xD1, 0xCC } },
283
    { "MediumVioletRed",      { 0xC7, 0x15, 0x85 } },
284
    { "MidnightBlue",         { 0x19, 0x19, 0x70 } },
285
    { "MintCream",            { 0xF5, 0xFF, 0xFA } },
286
    { "MistyRose",            { 0xFF, 0xE4, 0xE1 } },
287
    { "Moccasin",             { 0xFF, 0xE4, 0xB5 } },
288
    { "NavajoWhite",          { 0xFF, 0xDE, 0xAD } },
289
    { "Navy",                 { 0x00, 0x00, 0x80 } },
290
    { "OldLace",              { 0xFD, 0xF5, 0xE6 } },
291
    { "Olive",                { 0x80, 0x80, 0x00 } },
292
    { "OliveDrab",            { 0x6B, 0x8E, 0x23 } },
293
    { "Orange",               { 0xFF, 0xA5, 0x00 } },
294
    { "OrangeRed",            { 0xFF, 0x45, 0x00 } },
295
    { "Orchid",               { 0xDA, 0x70, 0xD6 } },
296
    { "PaleGoldenRod",        { 0xEE, 0xE8, 0xAA } },
297
    { "PaleGreen",            { 0x98, 0xFB, 0x98 } },
298
    { "PaleTurquoise",        { 0xAF, 0xEE, 0xEE } },
299
    { "PaleVioletRed",        { 0xD8, 0x70, 0x93 } },
300
    { "PapayaWhip",           { 0xFF, 0xEF, 0xD5 } },
301
    { "PeachPuff",            { 0xFF, 0xDA, 0xB9 } },
302
    { "Peru",                 { 0xCD, 0x85, 0x3F } },
303
    { "Pink",                 { 0xFF, 0xC0, 0xCB } },
304
    { "Plum",                 { 0xDD, 0xA0, 0xDD } },
305
    { "PowderBlue",           { 0xB0, 0xE0, 0xE6 } },
306
    { "Purple",               { 0x80, 0x00, 0x80 } },
307
    { "Red",                  { 0xFF, 0x00, 0x00 } },
308
    { "RosyBrown",            { 0xBC, 0x8F, 0x8F } },
309
    { "RoyalBlue",            { 0x41, 0x69, 0xE1 } },
310
    { "SaddleBrown",          { 0x8B, 0x45, 0x13 } },
311
    { "Salmon",               { 0xFA, 0x80, 0x72 } },
312
    { "SandyBrown",           { 0xF4, 0xA4, 0x60 } },
313
    { "SeaGreen",             { 0x2E, 0x8B, 0x57 } },
314
    { "SeaShell",             { 0xFF, 0xF5, 0xEE } },
315
    { "Sienna",               { 0xA0, 0x52, 0x2D } },
316
    { "Silver",               { 0xC0, 0xC0, 0xC0 } },
317
    { "SkyBlue",              { 0x87, 0xCE, 0xEB } },
318
    { "SlateBlue",            { 0x6A, 0x5A, 0xCD } },
319
    { "SlateGray",            { 0x70, 0x80, 0x90 } },
320
    { "Snow",                 { 0xFF, 0xFA, 0xFA } },
321
    { "SpringGreen",          { 0x00, 0xFF, 0x7F } },
322
    { "SteelBlue",            { 0x46, 0x82, 0xB4 } },
323
    { "Tan",                  { 0xD2, 0xB4, 0x8C } },
324
    { "Teal",                 { 0x00, 0x80, 0x80 } },
325
    { "Thistle",              { 0xD8, 0xBF, 0xD8 } },
326
    { "Tomato",               { 0xFF, 0x63, 0x47 } },
327
    { "Turquoise",            { 0x40, 0xE0, 0xD0 } },
328
    { "Violet",               { 0xEE, 0x82, 0xEE } },
329
    { "Wheat",                { 0xF5, 0xDE, 0xB3 } },
330
    { "White",                { 0xFF, 0xFF, 0xFF } },
331
    { "WhiteSmoke",           { 0xF5, 0xF5, 0xF5 } },
332
    { "Yellow",               { 0xFF, 0xFF, 0x00 } },
333
    { "YellowGreen",          { 0x9A, 0xCD, 0x32 } },
334
};
335
 
336
static int color_table_compare(const void *lhs, const void *rhs)
337
{
338
    return av_strcasecmp(lhs, ((const ColorEntry *)rhs)->name);
339
}
340
 
341
#define ALPHA_SEP '@'
342
 
343
int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen,
344
                   void *log_ctx)
345
{
346
    char *tail, color_string2[128];
347
    const ColorEntry *entry;
348
    int len, hex_offset = 0;
349
 
350
    if (color_string[0] == '#') {
351
        hex_offset = 1;
352
    } else if (!strncmp(color_string, "0x", 2))
353
        hex_offset = 2;
354
 
355
    if (slen < 0)
356
        slen = strlen(color_string);
357
    av_strlcpy(color_string2, color_string + hex_offset,
358
               FFMIN(slen-hex_offset+1, sizeof(color_string2)));
359
    if ((tail = strchr(color_string2, ALPHA_SEP)))
360
        *tail++ = 0;
361
    len = strlen(color_string2);
362
    rgba_color[3] = 255;
363
 
364
    if (!av_strcasecmp(color_string2, "random") || !av_strcasecmp(color_string2, "bikeshed")) {
365
        int rgba = av_get_random_seed();
366
        rgba_color[0] = rgba >> 24;
367
        rgba_color[1] = rgba >> 16;
368
        rgba_color[2] = rgba >> 8;
369
        rgba_color[3] = rgba;
370
    } else if (hex_offset ||
371
               strspn(color_string2, "0123456789ABCDEFabcdef") == len) {
372
        char *tail;
373
        unsigned int rgba = strtoul(color_string2, &tail, 16);
374
 
375
        if (*tail || (len != 6 && len != 8)) {
376
            av_log(log_ctx, AV_LOG_ERROR, "Invalid 0xRRGGBB[AA] color string: '%s'\n", color_string2);
377
            return AVERROR(EINVAL);
378
        }
379
        if (len == 8) {
380
            rgba_color[3] = rgba;
381
            rgba >>= 8;
382
        }
383
        rgba_color[0] = rgba >> 16;
384
        rgba_color[1] = rgba >> 8;
385
        rgba_color[2] = rgba;
386
    } else {
387
        entry = bsearch(color_string2,
388
                        color_table,
389
                        FF_ARRAY_ELEMS(color_table),
390
                        sizeof(ColorEntry),
391
                        color_table_compare);
392
        if (!entry) {
393
            av_log(log_ctx, AV_LOG_ERROR, "Cannot find color '%s'\n", color_string2);
394
            return AVERROR(EINVAL);
395
        }
396
        memcpy(rgba_color, entry->rgb_color, 3);
397
    }
398
 
399
    if (tail) {
400
        double alpha;
401
        const char *alpha_string = tail;
402
        if (!strncmp(alpha_string, "0x", 2)) {
403
            alpha = strtoul(alpha_string, &tail, 16);
404
        } else {
405
            double norm_alpha = strtod(alpha_string, &tail);
406
            if (norm_alpha < 0.0 || norm_alpha > 1.0)
407
                alpha = 256;
408
            else
409
                alpha = 255 * norm_alpha;
410
        }
411
 
412
        if (tail == alpha_string || *tail || alpha > 255 || alpha < 0) {
413
            av_log(log_ctx, AV_LOG_ERROR, "Invalid alpha value specifier '%s' in '%s'\n",
414
                   alpha_string, color_string);
415
            return AVERROR(EINVAL);
416
        }
417
        rgba_color[3] = alpha;
418
    }
419
 
420
    return 0;
421
}
422
 
423
const char *av_get_known_color_name(int color_idx, const uint8_t **rgbp)
424
{
425
    const ColorEntry *color;
426
 
427
    if ((unsigned)color_idx >= FF_ARRAY_ELEMS(color_table))
428
        return NULL;
429
 
430
    color = &color_table[color_idx];
431
    if (rgbp)
432
        *rgbp = color->rgb_color;
433
 
434
    return color->name;
435
}
436
 
437
/* get a positive number between n_min and n_max, for a maximum length
438
   of len_max. Return -1 if error. */
439
static int date_get_num(const char **pp,
440
                        int n_min, int n_max, int len_max)
441
{
442
    int i, val, c;
443
    const char *p;
444
 
445
    p = *pp;
446
    val = 0;
447
    for(i = 0; i < len_max; i++) {
448
        c = *p;
449
        if (!av_isdigit(c))
450
            break;
451
        val = (val * 10) + c - '0';
452
        p++;
453
    }
454
    /* no number read ? */
455
    if (p == *pp)
456
        return -1;
457
    if (val < n_min || val > n_max)
458
        return -1;
459
    *pp = p;
460
    return val;
461
}
462
 
463
char *av_small_strptime(const char *p, const char *fmt, struct tm *dt)
464
{
465
    int c, val;
466
 
467
    for(;;) {
468
        /* consume time string until a non whitespace char is found */
469
        while (av_isspace(*fmt)) {
470
            while (av_isspace(*p))
471
                p++;
472
            fmt++;
473
        }
474
        c = *fmt++;
475
        if (c == '\0') {
476
            return (char *)p;
477
        } else if (c == '%') {
478
            c = *fmt++;
479
            switch(c) {
480
            case 'H':
481
            case 'J':
482
                val = date_get_num(&p, 0, c == 'H' ? 23 : INT_MAX, 2);
483
                if (val == -1)
484
                    return NULL;
485
                dt->tm_hour = val;
486
                break;
487
            case 'M':
488
                val = date_get_num(&p, 0, 59, 2);
489
                if (val == -1)
490
                    return NULL;
491
                dt->tm_min = val;
492
                break;
493
            case 'S':
494
                val = date_get_num(&p, 0, 59, 2);
495
                if (val == -1)
496
                    return NULL;
497
                dt->tm_sec = val;
498
                break;
499
            case 'Y':
500
                val = date_get_num(&p, 0, 9999, 4);
501
                if (val == -1)
502
                    return NULL;
503
                dt->tm_year = val - 1900;
504
                break;
505
            case 'm':
506
                val = date_get_num(&p, 1, 12, 2);
507
                if (val == -1)
508
                    return NULL;
509
                dt->tm_mon = val - 1;
510
                break;
511
            case 'd':
512
                val = date_get_num(&p, 1, 31, 2);
513
                if (val == -1)
514
                    return NULL;
515
                dt->tm_mday = val;
516
                break;
517
            case '%':
518
                goto match;
519
            default:
520
                return NULL;
521
            }
522
        } else {
523
        match:
524
            if (c != *p)
525
                return NULL;
526
            p++;
527
        }
528
    }
529
}
530
 
531
time_t av_timegm(struct tm *tm)
532
{
533
    time_t t;
534
 
535
    int y = tm->tm_year + 1900, m = tm->tm_mon + 1, d = tm->tm_mday;
536
 
537
    if (m < 3) {
538
        m += 12;
539
        y--;
540
    }
541
 
542
    t = 86400LL *
543
        (d + (153 * m - 457) / 5 + 365 * y + y / 4 - y / 100 + y / 400 - 719469);
544
 
545
    t += 3600 * tm->tm_hour + 60 * tm->tm_min + tm->tm_sec;
546
 
547
    return t;
548
}
549
 
550
int av_parse_time(int64_t *timeval, const char *timestr, int duration)
551
{
552
    const char *p, *q;
553
    int64_t t;
554
    time_t now;
555
    struct tm dt = { 0 };
556
    int today = 0, negative = 0, microseconds = 0;
557
    int i;
558
    static const char * const date_fmt[] = {
559
        "%Y-%m-%d",
560
        "%Y%m%d",
561
    };
562
    static const char * const time_fmt[] = {
563
        "%H:%M:%S",
564
        "%H%M%S",
565
    };
566
 
567
    p = timestr;
568
    q = NULL;
569
    *timeval = INT64_MIN;
570
    if (!duration) {
571
        now = time(0);
572
 
573
        if (!av_strcasecmp(timestr, "now")) {
574
            *timeval = (int64_t) now * 1000000;
575
            return 0;
576
        }
577
 
578
        /* parse the year-month-day part */
579
        for (i = 0; i < FF_ARRAY_ELEMS(date_fmt); i++) {
580
            q = av_small_strptime(p, date_fmt[i], &dt);
581
            if (q)
582
                break;
583
        }
584
 
585
        /* if the year-month-day part is missing, then take the
586
         * current year-month-day time */
587
        if (!q) {
588
            today = 1;
589
            q = p;
590
        }
591
        p = q;
592
 
593
        if (*p == 'T' || *p == 't' || *p == ' ')
594
            p++;
595
 
596
        /* parse the hour-minute-second part */
597
        for (i = 0; i < FF_ARRAY_ELEMS(time_fmt); i++) {
598
            q = av_small_strptime(p, time_fmt[i], &dt);
599
            if (q)
600
                break;
601
        }
602
    } else {
603
        /* parse timestr as a duration */
604
        if (p[0] == '-') {
605
            negative = 1;
606
            ++p;
607
        }
608
        /* parse timestr as HH:MM:SS */
609
        q = av_small_strptime(p, "%J:%M:%S", &dt);
610
        if (!q) {
611
            /* parse timestr as MM:SS */
612
            q = av_small_strptime(p, "%M:%S", &dt);
613
            dt.tm_hour = 0;
614
        }
615
        if (!q) {
616
            /* parse timestr as S+ */
617
            dt.tm_sec = strtol(p, (void *)&q, 10);
618
            if (q == p) /* the parsing didn't succeed */
619
                return AVERROR(EINVAL);
620
            dt.tm_min = 0;
621
            dt.tm_hour = 0;
622
        }
623
    }
624
 
625
    /* Now we have all the fields that we can get */
626
    if (!q)
627
        return AVERROR(EINVAL);
628
 
629
    /* parse the .m... part */
630
    if (*q == '.') {
631
        int n;
632
        q++;
633
        for (n = 100000; n >= 1; n /= 10, q++) {
634
            if (!av_isdigit(*q))
635
                break;
636
            microseconds += n * (*q - '0');
637
        }
638
        while (av_isdigit(*q))
639
            q++;
640
    }
641
 
642
    if (duration) {
643
        t = dt.tm_hour * 3600 + dt.tm_min * 60 + dt.tm_sec;
644
    } else {
645
        int is_utc = *q == 'Z' || *q == 'z';
646
        q += is_utc;
647
        if (today) { /* fill in today's date */
648
            struct tm dt2 = is_utc ? *gmtime(&now) : *localtime(&now);
649
            dt2.tm_hour = dt.tm_hour;
650
            dt2.tm_min  = dt.tm_min;
651
            dt2.tm_sec  = dt.tm_sec;
652
            dt = dt2;
653
        }
654
        t = is_utc ? av_timegm(&dt) : mktime(&dt);
655
    }
656
 
657
    /* Check that we are at the end of the string */
658
    if (*q)
659
        return AVERROR(EINVAL);
660
 
661
    t *= 1000000;
662
    t += microseconds;
663
    *timeval = negative ? -t : t;
664
    return 0;
665
}
666
 
667
int av_find_info_tag(char *arg, int arg_size, const char *tag1, const char *info)
668
{
669
    const char *p;
670
    char tag[128], *q;
671
 
672
    p = info;
673
    if (*p == '?')
674
        p++;
675
    for(;;) {
676
        q = tag;
677
        while (*p != '\0' && *p != '=' && *p != '&') {
678
            if ((q - tag) < sizeof(tag) - 1)
679
                *q++ = *p;
680
            p++;
681
        }
682
        *q = '\0';
683
        q = arg;
684
        if (*p == '=') {
685
            p++;
686
            while (*p != '&' && *p != '\0') {
687
                if ((q - arg) < arg_size - 1) {
688
                    if (*p == '+')
689
                        *q++ = ' ';
690
                    else
691
                        *q++ = *p;
692
                }
693
                p++;
694
            }
695
        }
696
        *q = '\0';
697
        if (!strcmp(tag, tag1))
698
            return 1;
699
        if (*p != '&')
700
            break;
701
        p++;
702
    }
703
    return 0;
704
}
705
 
706
#ifdef TEST
707
 
708
static uint32_t randomv = MKTAG('L','A','V','U');
709
 
710
static uint32_t av_get_random_seed_deterministic(void)
711
{
712
    return randomv = randomv * 1664525 + 1013904223;
713
}
714
 
715
int main(void)
716
{
717
    printf("Testing av_parse_video_rate()\n");
718
    {
719
        int i;
720
        static const char *const rates[] = {
721
            "-inf",
722
            "inf",
723
            "nan",
724
            "123/0",
725
            "-123 / 0",
726
            "",
727
            "/",
728
            " 123  /  321",
729
            "foo/foo",
730
            "foo/1",
731
            "1/foo",
732
            "0/0",
733
            "/0",
734
            "1/",
735
            "1",
736
            "0",
737
            "-123/123",
738
            "-foo",
739
            "123.23",
740
            ".23",
741
            "-.23",
742
            "-0.234",
743
            "-0.0000001",
744
            "  21332.2324   ",
745
            " -21332.2324   ",
746
        };
747
 
748
        for (i = 0; i < FF_ARRAY_ELEMS(rates); i++) {
749
            int ret;
750
            AVRational q = { 0, 0 };
751
            ret = av_parse_video_rate(&q, rates[i]);
752
            printf("'%s' -> %d/%d %s\n",
753
                   rates[i], q.num, q.den, ret ? "ERROR" : "OK");
754
        }
755
    }
756
 
757
    printf("\nTesting av_parse_color()\n");
758
    {
759
        int i;
760
        uint8_t rgba[4];
761
        static const char *const color_names[] = {
762
            "bikeshed",
763
            "RaNdOm",
764
            "foo",
765
            "red",
766
            "Red ",
767
            "RED",
768
            "Violet",
769
            "Yellow",
770
            "Red",
771
            "0x000000",
772
            "0x0000000",
773
            "0xff000000",
774
            "0x3e34ff",
775
            "0x3e34ffaa",
776
            "0xffXXee",
777
            "0xfoobar",
778
            "0xffffeeeeeeee",
779
            "#ff0000",
780
            "#ffXX00",
781
            "ff0000",
782
            "ffXX00",
783
            "red@foo",
784
            "random@10",
785
            "0xff0000@1.0",
786
            "red@",
787
            "red@0xfff",
788
            "red@0xf",
789
            "red@2",
790
            "red@0.1",
791
            "red@-1",
792
            "red@0.5",
793
            "red@1.0",
794
            "red@256",
795
            "red@10foo",
796
            "red@-1.0",
797
            "red@-0.0",
798
        };
799
 
800
        av_log_set_level(AV_LOG_DEBUG);
801
 
802
        for (i = 0;  i < FF_ARRAY_ELEMS(color_names); i++) {
803
            if (av_parse_color(rgba, color_names[i], -1, NULL) >= 0)
804
                printf("%s -> R(%d) G(%d) B(%d) A(%d)\n",
805
                       color_names[i], rgba[0], rgba[1], rgba[2], rgba[3]);
806
            else
807
                printf("%s -> error\n", color_names[i]);
808
        }
809
    }
810
 
811
    printf("\nTesting av_small_strptime()\n");
812
    {
813
        int i;
814
        struct tm tm = { 0 };
815
        struct fmt_timespec_entry {
816
            const char *fmt, *timespec;
817
        } fmt_timespec_entries[] = {
818
            { "%Y-%m-%d",                    "2012-12-21" },
819
            { "%Y - %m - %d",                "2012-12-21" },
820
            { "%Y-%m-%d %H:%M:%S",           "2012-12-21 20:12:21" },
821
            { "  %Y - %m - %d %H : %M : %S", "   2012 - 12 -  21   20 : 12 : 21" },
822
        };
823
 
824
        av_log_set_level(AV_LOG_DEBUG);
825
        for (i = 0;  i < FF_ARRAY_ELEMS(fmt_timespec_entries); i++) {
826
            char *p;
827
            struct fmt_timespec_entry *e = &fmt_timespec_entries[i];
828
            printf("fmt:'%s' spec:'%s' -> ", e->fmt, e->timespec);
829
            p = av_small_strptime(e->timespec, e->fmt, &tm);
830
            if (p) {
831
                printf("%04d-%02d-%2d %02d:%02d:%02d\n",
832
                       1900+tm.tm_year, tm.tm_mon+1, tm.tm_mday,
833
                       tm.tm_hour, tm.tm_min, tm.tm_sec);
834
            } else {
835
                printf("error\n");
836
            }
837
        }
838
    }
839
 
840
    printf("\nTesting av_parse_time()\n");
841
    {
842
        int i;
843
        int64_t tv;
844
        time_t tvi;
845
        struct tm *tm;
846
        static char tzstr[] = "TZ=CET-1";
847
        static const char * const time_string[] = {
848
            "now",
849
            "12:35:46",
850
            "2000-12-20 0:02:47.5z",
851
            "2000-12-20T010247.6",
852
        };
853
        static const char * const duration_string[] = {
854
            "2:34:56.79",
855
            "-1:23:45.67",
856
            "42.1729",
857
            "-1729.42",
858
            "12:34",
859
        };
860
 
861
        av_log_set_level(AV_LOG_DEBUG);
862
        putenv(tzstr);
863
        printf("(now is 2012-03-17 09:14:13 +0100, local time is UTC+1)\n");
864
        for (i = 0;  i < FF_ARRAY_ELEMS(time_string); i++) {
865
            printf("%-24s -> ", time_string[i]);
866
            if (av_parse_time(&tv, time_string[i], 0)) {
867
                printf("error\n");
868
            } else {
869
                tvi = tv / 1000000;
870
                tm = gmtime(&tvi);
871
                printf("%14"PRIi64".%06d = %04d-%02d-%02dT%02d:%02d:%02dZ\n",
872
                       tv / 1000000, (int)(tv % 1000000),
873
                       tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
874
                       tm->tm_hour, tm->tm_min, tm->tm_sec);
875
            }
876
        }
877
        for (i = 0;  i < FF_ARRAY_ELEMS(duration_string); i++) {
878
            printf("%-24s -> ", duration_string[i]);
879
            if (av_parse_time(&tv, duration_string[i], 1)) {
880
                printf("error\n");
881
            } else {
882
                printf("%+21"PRIi64"\n", tv);
883
            }
884
        }
885
    }
886
 
887
    return 0;
888
}
889
 
890
#endif /* TEST */