Statistics
| Branch: | Revision:

ffmpeg / libavutil / parseutils.c @ 08675bb3

History | View | Annotate | Download (23 KB)

1 126b638e Stefano Sabatini
/*
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 7ffe76e5 Reinhard Tartler
 * misc parsing utilities
22 126b638e Stefano Sabatini
 */
23
24 0985e1a3 Aurelien Jacobs
#include <strings.h>
25 40c3fe2c Stefano Sabatini
#include <sys/time.h>
26
#include <time.h>
27 126b638e Stefano Sabatini
#include "parseutils.h"
28
#include "libavutil/avutil.h"
29 bc12b3b1 Stefano Sabatini
#include "libavutil/eval.h"
30 0985e1a3 Aurelien Jacobs
#include "libavutil/avstring.h"
31
#include "libavutil/random_seed.h"
32 126b638e Stefano Sabatini
33
typedef struct {
34
    const char *abbr;
35
    int width, height;
36 dc4a50a0 Stefano Sabatini
} VideoSizeAbbr;
37 126b638e Stefano Sabatini
38
typedef struct {
39
    const char *abbr;
40 c90c80ac Stefano Sabatini
    AVRational rate;
41 dc4a50a0 Stefano Sabatini
} VideoRateAbbr;
42 126b638e Stefano Sabatini
43 dc4a50a0 Stefano Sabatini
static const VideoSizeAbbr video_size_abbrs[] = {
44 126b638e Stefano Sabatini
    { "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 dc4a50a0 Stefano Sabatini
static const VideoRateAbbr video_rate_abbrs[]= {
84 c90c80ac Stefano Sabatini
    { "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 126b638e Stefano Sabatini
};
93
94
int av_parse_video_size(int *width_ptr, int *height_ptr, const char *str)
95
{
96
    int i;
97 dc4a50a0 Stefano Sabatini
    int n = FF_ARRAY_ELEMS(video_size_abbrs);
98 126b638e Stefano Sabatini
    char *p;
99 dc4a50a0 Stefano Sabatini
    int width = 0, height = 0;
100 126b638e Stefano Sabatini
101
    for (i = 0; i < n; i++) {
102 dc4a50a0 Stefano Sabatini
        if (!strcmp(video_size_abbrs[i].abbr, str)) {
103
            width  = video_size_abbrs[i].width;
104
            height = video_size_abbrs[i].height;
105 126b638e Stefano Sabatini
            break;
106
        }
107
    }
108
    if (i == n) {
109
        p = str;
110 dc4a50a0 Stefano Sabatini
        width = strtol(p, &p, 10);
111 126b638e Stefano Sabatini
        if (*p)
112
            p++;
113 dc4a50a0 Stefano Sabatini
        height = strtol(p, &p, 10);
114 126b638e Stefano Sabatini
    }
115 dc4a50a0 Stefano Sabatini
    if (width <= 0 || height <= 0)
116 afead106 Stefano Sabatini
        return AVERROR(EINVAL);
117 dc4a50a0 Stefano Sabatini
    *width_ptr  = width;
118
    *height_ptr = height;
119 126b638e Stefano Sabatini
    return 0;
120
}
121
122 dc4a50a0 Stefano Sabatini
int av_parse_video_rate(AVRational *rate, const char *arg)
123 126b638e Stefano Sabatini
{
124 bc12b3b1 Stefano Sabatini
    int i, ret;
125 dc4a50a0 Stefano Sabatini
    int n = FF_ARRAY_ELEMS(video_rate_abbrs);
126 bc12b3b1 Stefano Sabatini
    double res;
127 126b638e Stefano Sabatini
128
    /* First, we check our abbreviation table */
129
    for (i = 0; i < n; ++i)
130 6705dd5f Stefano Sabatini
        if (!strcmp(video_rate_abbrs[i].abbr, arg)) {
131
            *rate = video_rate_abbrs[i].rate;
132
            return 0;
133
        }
134 126b638e Stefano Sabatini
135
    /* Then, we try to parse it as fraction */
136 d2af7205 Stefano Sabatini
    if ((ret = av_expr_parse_and_eval(&res, arg, NULL, NULL, NULL, NULL, NULL, NULL,
137 bc12b3b1 Stefano Sabatini
                                      NULL, 0, NULL)) < 0)
138
        return ret;
139
    *rate = av_d2q(res, 1001000);
140 dc4a50a0 Stefano Sabatini
    if (rate->num <= 0 || rate->den <= 0)
141 afead106 Stefano Sabatini
        return AVERROR(EINVAL);
142 126b638e Stefano Sabatini
    return 0;
143
}
144 00e962a2 Stefano Sabatini
145 0985e1a3 Aurelien Jacobs
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 40c3fe2c Stefano Sabatini
/* 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 1b98107c Anton Khirnov
int av_find_info_tag(char *arg, int arg_size, const char *tag1, const char *info)
612
{
613
    const char *p;
614
    char tag[128], *q;
615
616
    p = info;
617
    if (*p == '?')
618
        p++;
619
    for(;;) {
620
        q = tag;
621
        while (*p != '\0' && *p != '=' && *p != '&') {
622
            if ((q - tag) < sizeof(tag) - 1)
623
                *q++ = *p;
624
            p++;
625
        }
626
        *q = '\0';
627
        q = arg;
628
        if (*p == '=') {
629
            p++;
630
            while (*p != '&' && *p != '\0') {
631
                if ((q - arg) < arg_size - 1) {
632
                    if (*p == '+')
633
                        *q++ = ' ';
634
                    else
635
                        *q++ = *p;
636
                }
637
                p++;
638
            }
639
        }
640
        *q = '\0';
641
        if (!strcmp(tag, tag1))
642
            return 1;
643
        if (*p != '&')
644
            break;
645
        p++;
646
    }
647
    return 0;
648
}
649
650 00e962a2 Stefano Sabatini
#ifdef TEST
651
652
#undef printf
653
654
int main(void)
655
{
656
    printf("Testing av_parse_video_rate()\n");
657
    {
658
        int i;
659
        const char *rates[] = {
660
            "-inf",
661
            "inf",
662
            "nan",
663
            "123/0",
664
            "-123 / 0",
665
            "",
666
            "/",
667
            " 123  /  321",
668
            "foo/foo",
669
            "foo/1",
670
            "1/foo",
671
            "0/0",
672
            "/0",
673
            "1/",
674
            "1",
675
            "0",
676
            "-123/123",
677
            "-foo",
678
            "123.23",
679
            ".23",
680
            "-.23",
681
            "-0.234",
682
            "-0.0000001",
683
            "  21332.2324   ",
684
            " -21332.2324   ",
685
        };
686
687
        for (i = 0; i < FF_ARRAY_ELEMS(rates); i++) {
688
            int ret;
689
            AVRational q = (AVRational){0, 0};
690
            ret = av_parse_video_rate(&q, rates[i]),
691
            printf("'%s' -> %d/%d ret:%d\n",
692
                   rates[i], q.num, q.den, ret);
693
        }
694
    }
695
696 0985e1a3 Aurelien Jacobs
    printf("\nTesting av_parse_color()\n");
697
    {
698
        int i;
699
        uint8_t rgba[4];
700
        const char *color_names[] = {
701
            "bikeshed",
702
            "RaNdOm",
703
            "foo",
704
            "red",
705
            "Red ",
706
            "RED",
707
            "Violet",
708
            "Yellow",
709
            "Red",
710
            "0x000000",
711
            "0x0000000",
712
            "0xff000000",
713
            "0x3e34ff",
714
            "0x3e34ffaa",
715
            "0xffXXee",
716
            "0xfoobar",
717
            "0xffffeeeeeeee",
718
            "#ff0000",
719
            "#ffXX00",
720
            "ff0000",
721
            "ffXX00",
722
            "red@foo",
723
            "random@10",
724
            "0xff0000@1.0",
725
            "red@",
726
            "red@0xfff",
727
            "red@0xf",
728
            "red@2",
729
            "red@0.1",
730
            "red@-1",
731
            "red@0.5",
732
            "red@1.0",
733
            "red@256",
734
            "red@10foo",
735
            "red@-1.0",
736
            "red@-0.0",
737
        };
738
739
        av_log_set_level(AV_LOG_DEBUG);
740
741
        for (i = 0;  i < FF_ARRAY_ELEMS(color_names); i++) {
742
            if (av_parse_color(rgba, color_names[i], -1, NULL) >= 0)
743
                printf("%s -> R(%d) G(%d) B(%d) A(%d)\n", color_names[i], rgba[0], rgba[1], rgba[2], rgba[3]);
744
        }
745
    }
746
747 00e962a2 Stefano Sabatini
    return 0;
748
}
749
750
#endif /* TEST */