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 */ |