libavutil/parseutils.c
Go to the documentation of this file.
00001 /*
00002  * This file is part of FFmpeg.
00003  *
00004  * FFmpeg is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Lesser General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2.1 of the License, or (at your option) any later version.
00008  *
00009  * FFmpeg is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Lesser General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Lesser General Public
00015  * License along with FFmpeg; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00017  */
00018 
00024 #include <sys/time.h>
00025 #include <time.h>
00026 
00027 #include "avstring.h"
00028 #include "avutil.h"
00029 #include "eval.h"
00030 #include "log.h"
00031 #include "random_seed.h"
00032 #include "parseutils.h"
00033 
00034 typedef struct {
00035     const char *abbr;
00036     int width, height;
00037 } VideoSizeAbbr;
00038 
00039 typedef struct {
00040     const char *abbr;
00041     AVRational rate;
00042 } VideoRateAbbr;
00043 
00044 static const VideoSizeAbbr video_size_abbrs[] = {
00045     { "ntsc",      720, 480 },
00046     { "pal",       720, 576 },
00047     { "qntsc",     352, 240 }, /* VCD compliant NTSC */
00048     { "qpal",      352, 288 }, /* VCD compliant PAL */
00049     { "sntsc",     640, 480 }, /* square pixel NTSC */
00050     { "spal",      768, 576 }, /* square pixel PAL */
00051     { "film",      352, 240 },
00052     { "ntsc-film", 352, 240 },
00053     { "sqcif",     128,  96 },
00054     { "qcif",      176, 144 },
00055     { "cif",       352, 288 },
00056     { "4cif",      704, 576 },
00057     { "16cif",    1408,1152 },
00058     { "qqvga",     160, 120 },
00059     { "qvga",      320, 240 },
00060     { "vga",       640, 480 },
00061     { "svga",      800, 600 },
00062     { "xga",      1024, 768 },
00063     { "uxga",     1600,1200 },
00064     { "qxga",     2048,1536 },
00065     { "sxga",     1280,1024 },
00066     { "qsxga",    2560,2048 },
00067     { "hsxga",    5120,4096 },
00068     { "wvga",      852, 480 },
00069     { "wxga",     1366, 768 },
00070     { "wsxga",    1600,1024 },
00071     { "wuxga",    1920,1200 },
00072     { "woxga",    2560,1600 },
00073     { "wqsxga",   3200,2048 },
00074     { "wquxga",   3840,2400 },
00075     { "whsxga",   6400,4096 },
00076     { "whuxga",   7680,4800 },
00077     { "cga",       320, 200 },
00078     { "ega",       640, 350 },
00079     { "hd480",     852, 480 },
00080     { "hd720",    1280, 720 },
00081     { "hd1080",   1920,1080 },
00082 };
00083 
00084 static const VideoRateAbbr video_rate_abbrs[]= {
00085     { "ntsc",      { 30000, 1001 } },
00086     { "pal",       {    25,    1 } },
00087     { "qntsc",     { 30000, 1001 } }, /* VCD compliant NTSC */
00088     { "qpal",      {    25,    1 } }, /* VCD compliant PAL */
00089     { "sntsc",     { 30000, 1001 } }, /* square pixel NTSC */
00090     { "spal",      {    25,    1 } }, /* square pixel PAL */
00091     { "film",      {    24,    1 } },
00092     { "ntsc-film", { 24000, 1001 } },
00093 };
00094 
00095 int av_parse_video_size(int *width_ptr, int *height_ptr, const char *str)
00096 {
00097     int i;
00098     int n = FF_ARRAY_ELEMS(video_size_abbrs);
00099     const char *p;
00100     int width = 0, height = 0;
00101 
00102     for (i = 0; i < n; i++) {
00103         if (!strcmp(video_size_abbrs[i].abbr, str)) {
00104             width  = video_size_abbrs[i].width;
00105             height = video_size_abbrs[i].height;
00106             break;
00107         }
00108     }
00109     if (i == n) {
00110         p = str;
00111         width = strtol(p, (void*)&p, 10);
00112         if (*p)
00113             p++;
00114         height = strtol(p, (void*)&p, 10);
00115     }
00116     if (width <= 0 || height <= 0)
00117         return AVERROR(EINVAL);
00118     *width_ptr  = width;
00119     *height_ptr = height;
00120     return 0;
00121 }
00122 
00123 int av_parse_video_rate(AVRational *rate, const char *arg)
00124 {
00125     int i, ret;
00126     int n = FF_ARRAY_ELEMS(video_rate_abbrs);
00127     double res;
00128 
00129     /* First, we check our abbreviation table */
00130     for (i = 0; i < n; ++i)
00131         if (!strcmp(video_rate_abbrs[i].abbr, arg)) {
00132             *rate = video_rate_abbrs[i].rate;
00133             return 0;
00134         }
00135 
00136     /* Then, we try to parse it as fraction */
00137     if ((ret = av_expr_parse_and_eval(&res, arg, NULL, NULL, NULL, NULL, NULL, NULL,
00138                                       NULL, 0, NULL)) < 0)
00139         return ret;
00140     *rate = av_d2q(res, 1001000);
00141     if (rate->num <= 0 || rate->den <= 0)
00142         return AVERROR(EINVAL);
00143     return 0;
00144 }
00145 
00146 typedef struct {
00147     const char *name;            
00148     uint8_t     rgb_color[3];    
00149 } ColorEntry;
00150 
00151 static const ColorEntry color_table[] = {
00152     { "AliceBlue",            { 0xF0, 0xF8, 0xFF } },
00153     { "AntiqueWhite",         { 0xFA, 0xEB, 0xD7 } },
00154     { "Aqua",                 { 0x00, 0xFF, 0xFF } },
00155     { "Aquamarine",           { 0x7F, 0xFF, 0xD4 } },
00156     { "Azure",                { 0xF0, 0xFF, 0xFF } },
00157     { "Beige",                { 0xF5, 0xF5, 0xDC } },
00158     { "Bisque",               { 0xFF, 0xE4, 0xC4 } },
00159     { "Black",                { 0x00, 0x00, 0x00 } },
00160     { "BlanchedAlmond",       { 0xFF, 0xEB, 0xCD } },
00161     { "Blue",                 { 0x00, 0x00, 0xFF } },
00162     { "BlueViolet",           { 0x8A, 0x2B, 0xE2 } },
00163     { "Brown",                { 0xA5, 0x2A, 0x2A } },
00164     { "BurlyWood",            { 0xDE, 0xB8, 0x87 } },
00165     { "CadetBlue",            { 0x5F, 0x9E, 0xA0 } },
00166     { "Chartreuse",           { 0x7F, 0xFF, 0x00 } },
00167     { "Chocolate",            { 0xD2, 0x69, 0x1E } },
00168     { "Coral",                { 0xFF, 0x7F, 0x50 } },
00169     { "CornflowerBlue",       { 0x64, 0x95, 0xED } },
00170     { "Cornsilk",             { 0xFF, 0xF8, 0xDC } },
00171     { "Crimson",              { 0xDC, 0x14, 0x3C } },
00172     { "Cyan",                 { 0x00, 0xFF, 0xFF } },
00173     { "DarkBlue",             { 0x00, 0x00, 0x8B } },
00174     { "DarkCyan",             { 0x00, 0x8B, 0x8B } },
00175     { "DarkGoldenRod",        { 0xB8, 0x86, 0x0B } },
00176     { "DarkGray",             { 0xA9, 0xA9, 0xA9 } },
00177     { "DarkGreen",            { 0x00, 0x64, 0x00 } },
00178     { "DarkKhaki",            { 0xBD, 0xB7, 0x6B } },
00179     { "DarkMagenta",          { 0x8B, 0x00, 0x8B } },
00180     { "DarkOliveGreen",       { 0x55, 0x6B, 0x2F } },
00181     { "Darkorange",           { 0xFF, 0x8C, 0x00 } },
00182     { "DarkOrchid",           { 0x99, 0x32, 0xCC } },
00183     { "DarkRed",              { 0x8B, 0x00, 0x00 } },
00184     { "DarkSalmon",           { 0xE9, 0x96, 0x7A } },
00185     { "DarkSeaGreen",         { 0x8F, 0xBC, 0x8F } },
00186     { "DarkSlateBlue",        { 0x48, 0x3D, 0x8B } },
00187     { "DarkSlateGray",        { 0x2F, 0x4F, 0x4F } },
00188     { "DarkTurquoise",        { 0x00, 0xCE, 0xD1 } },
00189     { "DarkViolet",           { 0x94, 0x00, 0xD3 } },
00190     { "DeepPink",             { 0xFF, 0x14, 0x93 } },
00191     { "DeepSkyBlue",          { 0x00, 0xBF, 0xFF } },
00192     { "DimGray",              { 0x69, 0x69, 0x69 } },
00193     { "DodgerBlue",           { 0x1E, 0x90, 0xFF } },
00194     { "FireBrick",            { 0xB2, 0x22, 0x22 } },
00195     { "FloralWhite",          { 0xFF, 0xFA, 0xF0 } },
00196     { "ForestGreen",          { 0x22, 0x8B, 0x22 } },
00197     { "Fuchsia",              { 0xFF, 0x00, 0xFF } },
00198     { "Gainsboro",            { 0xDC, 0xDC, 0xDC } },
00199     { "GhostWhite",           { 0xF8, 0xF8, 0xFF } },
00200     { "Gold",                 { 0xFF, 0xD7, 0x00 } },
00201     { "GoldenRod",            { 0xDA, 0xA5, 0x20 } },
00202     { "Gray",                 { 0x80, 0x80, 0x80 } },
00203     { "Green",                { 0x00, 0x80, 0x00 } },
00204     { "GreenYellow",          { 0xAD, 0xFF, 0x2F } },
00205     { "HoneyDew",             { 0xF0, 0xFF, 0xF0 } },
00206     { "HotPink",              { 0xFF, 0x69, 0xB4 } },
00207     { "IndianRed",            { 0xCD, 0x5C, 0x5C } },
00208     { "Indigo",               { 0x4B, 0x00, 0x82 } },
00209     { "Ivory",                { 0xFF, 0xFF, 0xF0 } },
00210     { "Khaki",                { 0xF0, 0xE6, 0x8C } },
00211     { "Lavender",             { 0xE6, 0xE6, 0xFA } },
00212     { "LavenderBlush",        { 0xFF, 0xF0, 0xF5 } },
00213     { "LawnGreen",            { 0x7C, 0xFC, 0x00 } },
00214     { "LemonChiffon",         { 0xFF, 0xFA, 0xCD } },
00215     { "LightBlue",            { 0xAD, 0xD8, 0xE6 } },
00216     { "LightCoral",           { 0xF0, 0x80, 0x80 } },
00217     { "LightCyan",            { 0xE0, 0xFF, 0xFF } },
00218     { "LightGoldenRodYellow", { 0xFA, 0xFA, 0xD2 } },
00219     { "LightGrey",            { 0xD3, 0xD3, 0xD3 } },
00220     { "LightGreen",           { 0x90, 0xEE, 0x90 } },
00221     { "LightPink",            { 0xFF, 0xB6, 0xC1 } },
00222     { "LightSalmon",          { 0xFF, 0xA0, 0x7A } },
00223     { "LightSeaGreen",        { 0x20, 0xB2, 0xAA } },
00224     { "LightSkyBlue",         { 0x87, 0xCE, 0xFA } },
00225     { "LightSlateGray",       { 0x77, 0x88, 0x99 } },
00226     { "LightSteelBlue",       { 0xB0, 0xC4, 0xDE } },
00227     { "LightYellow",          { 0xFF, 0xFF, 0xE0 } },
00228     { "Lime",                 { 0x00, 0xFF, 0x00 } },
00229     { "LimeGreen",            { 0x32, 0xCD, 0x32 } },
00230     { "Linen",                { 0xFA, 0xF0, 0xE6 } },
00231     { "Magenta",              { 0xFF, 0x00, 0xFF } },
00232     { "Maroon",               { 0x80, 0x00, 0x00 } },
00233     { "MediumAquaMarine",     { 0x66, 0xCD, 0xAA } },
00234     { "MediumBlue",           { 0x00, 0x00, 0xCD } },
00235     { "MediumOrchid",         { 0xBA, 0x55, 0xD3 } },
00236     { "MediumPurple",         { 0x93, 0x70, 0xD8 } },
00237     { "MediumSeaGreen",       { 0x3C, 0xB3, 0x71 } },
00238     { "MediumSlateBlue",      { 0x7B, 0x68, 0xEE } },
00239     { "MediumSpringGreen",    { 0x00, 0xFA, 0x9A } },
00240     { "MediumTurquoise",      { 0x48, 0xD1, 0xCC } },
00241     { "MediumVioletRed",      { 0xC7, 0x15, 0x85 } },
00242     { "MidnightBlue",         { 0x19, 0x19, 0x70 } },
00243     { "MintCream",            { 0xF5, 0xFF, 0xFA } },
00244     { "MistyRose",            { 0xFF, 0xE4, 0xE1 } },
00245     { "Moccasin",             { 0xFF, 0xE4, 0xB5 } },
00246     { "NavajoWhite",          { 0xFF, 0xDE, 0xAD } },
00247     { "Navy",                 { 0x00, 0x00, 0x80 } },
00248     { "OldLace",              { 0xFD, 0xF5, 0xE6 } },
00249     { "Olive",                { 0x80, 0x80, 0x00 } },
00250     { "OliveDrab",            { 0x6B, 0x8E, 0x23 } },
00251     { "Orange",               { 0xFF, 0xA5, 0x00 } },
00252     { "OrangeRed",            { 0xFF, 0x45, 0x00 } },
00253     { "Orchid",               { 0xDA, 0x70, 0xD6 } },
00254     { "PaleGoldenRod",        { 0xEE, 0xE8, 0xAA } },
00255     { "PaleGreen",            { 0x98, 0xFB, 0x98 } },
00256     { "PaleTurquoise",        { 0xAF, 0xEE, 0xEE } },
00257     { "PaleVioletRed",        { 0xD8, 0x70, 0x93 } },
00258     { "PapayaWhip",           { 0xFF, 0xEF, 0xD5 } },
00259     { "PeachPuff",            { 0xFF, 0xDA, 0xB9 } },
00260     { "Peru",                 { 0xCD, 0x85, 0x3F } },
00261     { "Pink",                 { 0xFF, 0xC0, 0xCB } },
00262     { "Plum",                 { 0xDD, 0xA0, 0xDD } },
00263     { "PowderBlue",           { 0xB0, 0xE0, 0xE6 } },
00264     { "Purple",               { 0x80, 0x00, 0x80 } },
00265     { "Red",                  { 0xFF, 0x00, 0x00 } },
00266     { "RosyBrown",            { 0xBC, 0x8F, 0x8F } },
00267     { "RoyalBlue",            { 0x41, 0x69, 0xE1 } },
00268     { "SaddleBrown",          { 0x8B, 0x45, 0x13 } },
00269     { "Salmon",               { 0xFA, 0x80, 0x72 } },
00270     { "SandyBrown",           { 0xF4, 0xA4, 0x60 } },
00271     { "SeaGreen",             { 0x2E, 0x8B, 0x57 } },
00272     { "SeaShell",             { 0xFF, 0xF5, 0xEE } },
00273     { "Sienna",               { 0xA0, 0x52, 0x2D } },
00274     { "Silver",               { 0xC0, 0xC0, 0xC0 } },
00275     { "SkyBlue",              { 0x87, 0xCE, 0xEB } },
00276     { "SlateBlue",            { 0x6A, 0x5A, 0xCD } },
00277     { "SlateGray",            { 0x70, 0x80, 0x90 } },
00278     { "Snow",                 { 0xFF, 0xFA, 0xFA } },
00279     { "SpringGreen",          { 0x00, 0xFF, 0x7F } },
00280     { "SteelBlue",            { 0x46, 0x82, 0xB4 } },
00281     { "Tan",                  { 0xD2, 0xB4, 0x8C } },
00282     { "Teal",                 { 0x00, 0x80, 0x80 } },
00283     { "Thistle",              { 0xD8, 0xBF, 0xD8 } },
00284     { "Tomato",               { 0xFF, 0x63, 0x47 } },
00285     { "Turquoise",            { 0x40, 0xE0, 0xD0 } },
00286     { "Violet",               { 0xEE, 0x82, 0xEE } },
00287     { "Wheat",                { 0xF5, 0xDE, 0xB3 } },
00288     { "White",                { 0xFF, 0xFF, 0xFF } },
00289     { "WhiteSmoke",           { 0xF5, 0xF5, 0xF5 } },
00290     { "Yellow",               { 0xFF, 0xFF, 0x00 } },
00291     { "YellowGreen",          { 0x9A, 0xCD, 0x32 } },
00292 };
00293 
00294 static int color_table_compare(const void *lhs, const void *rhs)
00295 {
00296     return av_strcasecmp(lhs, ((const ColorEntry *)rhs)->name);
00297 }
00298 
00299 #define ALPHA_SEP '@'
00300 
00301 int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen,
00302                    void *log_ctx)
00303 {
00304     char *tail, color_string2[128];
00305     const ColorEntry *entry;
00306     int len, hex_offset = 0;
00307 
00308     if (color_string[0] == '#') {
00309         hex_offset = 1;
00310     } else if (!strncmp(color_string, "0x", 2))
00311         hex_offset = 2;
00312 
00313     if (slen < 0)
00314         slen = strlen(color_string);
00315     av_strlcpy(color_string2, color_string + hex_offset,
00316                FFMIN(slen-hex_offset+1, sizeof(color_string2)));
00317     if ((tail = strchr(color_string2, ALPHA_SEP)))
00318         *tail++ = 0;
00319     len = strlen(color_string2);
00320     rgba_color[3] = 255;
00321 
00322     if (!av_strcasecmp(color_string2, "random") || !av_strcasecmp(color_string2, "bikeshed")) {
00323         int rgba = av_get_random_seed();
00324         rgba_color[0] = rgba >> 24;
00325         rgba_color[1] = rgba >> 16;
00326         rgba_color[2] = rgba >> 8;
00327         rgba_color[3] = rgba;
00328     } else if (hex_offset ||
00329                strspn(color_string2, "0123456789ABCDEFabcdef") == len) {
00330         char *tail;
00331         unsigned int rgba = strtoul(color_string2, &tail, 16);
00332 
00333         if (*tail || (len != 6 && len != 8)) {
00334             av_log(log_ctx, AV_LOG_ERROR, "Invalid 0xRRGGBB[AA] color string: '%s'\n", color_string2);
00335             return AVERROR(EINVAL);
00336         }
00337         if (len == 8) {
00338             rgba_color[3] = rgba;
00339             rgba >>= 8;
00340         }
00341         rgba_color[0] = rgba >> 16;
00342         rgba_color[1] = rgba >> 8;
00343         rgba_color[2] = rgba;
00344     } else {
00345         entry = bsearch(color_string2,
00346                         color_table,
00347                         FF_ARRAY_ELEMS(color_table),
00348                         sizeof(ColorEntry),
00349                         color_table_compare);
00350         if (!entry) {
00351             av_log(log_ctx, AV_LOG_ERROR, "Cannot find color '%s'\n", color_string2);
00352             return AVERROR(EINVAL);
00353         }
00354         memcpy(rgba_color, entry->rgb_color, 3);
00355     }
00356 
00357     if (tail) {
00358         unsigned long int alpha;
00359         const char *alpha_string = tail;
00360         if (!strncmp(alpha_string, "0x", 2)) {
00361             alpha = strtoul(alpha_string, &tail, 16);
00362         } else {
00363             alpha = 255 * strtod(alpha_string, &tail);
00364         }
00365 
00366         if (tail == alpha_string || *tail || alpha > 255) {
00367             av_log(log_ctx, AV_LOG_ERROR, "Invalid alpha value specifier '%s' in '%s'\n",
00368                    alpha_string, color_string);
00369             return AVERROR(EINVAL);
00370         }
00371         rgba_color[3] = alpha;
00372     }
00373 
00374     return 0;
00375 }
00376 
00377 /* get a positive number between n_min and n_max, for a maximum length
00378    of len_max. Return -1 if error. */
00379 static int date_get_num(const char **pp,
00380                         int n_min, int n_max, int len_max)
00381 {
00382     int i, val, c;
00383     const char *p;
00384 
00385     p = *pp;
00386     val = 0;
00387     for(i = 0; i < len_max; i++) {
00388         c = *p;
00389         if (!isdigit(c))
00390             break;
00391         val = (val * 10) + c - '0';
00392         p++;
00393     }
00394     /* no number read ? */
00395     if (p == *pp)
00396         return -1;
00397     if (val < n_min || val > n_max)
00398         return -1;
00399     *pp = p;
00400     return val;
00401 }
00402 
00413 static const char *small_strptime(const char *p, const char *fmt, struct tm *dt)
00414 {
00415     int c, val;
00416 
00417     for(;;) {
00418         c = *fmt++;
00419         if (c == '\0') {
00420             return p;
00421         } else if (c == '%') {
00422             c = *fmt++;
00423             switch(c) {
00424             case 'H':
00425                 val = date_get_num(&p, 0, 23, 2);
00426                 if (val == -1)
00427                     return NULL;
00428                 dt->tm_hour = val;
00429                 break;
00430             case 'M':
00431                 val = date_get_num(&p, 0, 59, 2);
00432                 if (val == -1)
00433                     return NULL;
00434                 dt->tm_min = val;
00435                 break;
00436             case 'S':
00437                 val = date_get_num(&p, 0, 59, 2);
00438                 if (val == -1)
00439                     return NULL;
00440                 dt->tm_sec = val;
00441                 break;
00442             case 'Y':
00443                 val = date_get_num(&p, 0, 9999, 4);
00444                 if (val == -1)
00445                     return NULL;
00446                 dt->tm_year = val - 1900;
00447                 break;
00448             case 'm':
00449                 val = date_get_num(&p, 1, 12, 2);
00450                 if (val == -1)
00451                     return NULL;
00452                 dt->tm_mon = val - 1;
00453                 break;
00454             case 'd':
00455                 val = date_get_num(&p, 1, 31, 2);
00456                 if (val == -1)
00457                     return NULL;
00458                 dt->tm_mday = val;
00459                 break;
00460             case '%':
00461                 goto match;
00462             default:
00463                 return NULL;
00464             }
00465         } else {
00466         match:
00467             if (c != *p)
00468                 return NULL;
00469             p++;
00470         }
00471     }
00472 }
00473 
00474 time_t av_timegm(struct tm *tm)
00475 {
00476     time_t t;
00477 
00478     int y = tm->tm_year + 1900, m = tm->tm_mon + 1, d = tm->tm_mday;
00479 
00480     if (m < 3) {
00481         m += 12;
00482         y--;
00483     }
00484 
00485     t = 86400 *
00486         (d + (153 * m - 457) / 5 + 365 * y + y / 4 - y / 100 + y / 400 - 719469);
00487 
00488     t += 3600 * tm->tm_hour + 60 * tm->tm_min + tm->tm_sec;
00489 
00490     return t;
00491 }
00492 
00493 int av_parse_time(int64_t *timeval, const char *timestr, int duration)
00494 {
00495     const char *p;
00496     int64_t t;
00497     struct tm dt;
00498     int i;
00499     static const char * const date_fmt[] = {
00500         "%Y-%m-%d",
00501         "%Y%m%d",
00502     };
00503     static const char * const time_fmt[] = {
00504         "%H:%M:%S",
00505         "%H%M%S",
00506     };
00507     const char *q;
00508     int is_utc, len;
00509     char lastch;
00510     int negative = 0;
00511 
00512 #undef time
00513     time_t now = time(0);
00514 
00515     len = strlen(timestr);
00516     if (len > 0)
00517         lastch = timestr[len - 1];
00518     else
00519         lastch = '\0';
00520     is_utc = (lastch == 'z' || lastch == 'Z');
00521 
00522     memset(&dt, 0, sizeof(dt));
00523 
00524     p = timestr;
00525     q = NULL;
00526     if (!duration) {
00527         if (!av_strncasecmp(timestr, "now", len)) {
00528             *timeval = (int64_t) now * 1000000;
00529             return 0;
00530         }
00531 
00532         /* parse the year-month-day part */
00533         for (i = 0; i < FF_ARRAY_ELEMS(date_fmt); i++) {
00534             q = small_strptime(p, date_fmt[i], &dt);
00535             if (q) {
00536                 break;
00537             }
00538         }
00539 
00540         /* if the year-month-day part is missing, then take the
00541          * current year-month-day time */
00542         if (!q) {
00543             if (is_utc) {
00544                 dt = *gmtime(&now);
00545             } else {
00546                 dt = *localtime(&now);
00547             }
00548             dt.tm_hour = dt.tm_min = dt.tm_sec = 0;
00549         } else {
00550             p = q;
00551         }
00552 
00553         if (*p == 'T' || *p == 't' || *p == ' ')
00554             p++;
00555 
00556         /* parse the hour-minute-second part */
00557         for (i = 0; i < FF_ARRAY_ELEMS(time_fmt); i++) {
00558             q = small_strptime(p, time_fmt[i], &dt);
00559             if (q) {
00560                 break;
00561             }
00562         }
00563     } else {
00564         /* parse timestr as a duration */
00565         if (p[0] == '-') {
00566             negative = 1;
00567             ++p;
00568         }
00569         /* parse timestr as HH:MM:SS */
00570         q = small_strptime(p, time_fmt[0], &dt);
00571         if (!q) {
00572             /* parse timestr as S+ */
00573             dt.tm_sec = strtol(p, (void *)&q, 10);
00574             if (q == p) {
00575                 /* the parsing didn't succeed */
00576                 *timeval = INT64_MIN;
00577                 return AVERROR(EINVAL);
00578             }
00579             dt.tm_min = 0;
00580             dt.tm_hour = 0;
00581         }
00582     }
00583 
00584     /* Now we have all the fields that we can get */
00585     if (!q) {
00586         *timeval = INT64_MIN;
00587         return AVERROR(EINVAL);
00588     }
00589 
00590     if (duration) {
00591         t = dt.tm_hour * 3600 + dt.tm_min * 60 + dt.tm_sec;
00592     } else {
00593         dt.tm_isdst = -1;       /* unknown */
00594         if (is_utc) {
00595             t = av_timegm(&dt);
00596         } else {
00597             t = mktime(&dt);
00598         }
00599     }
00600 
00601     t *= 1000000;
00602 
00603     /* parse the .m... part */
00604     if (*q == '.') {
00605         int val, n;
00606         q++;
00607         for (val = 0, n = 100000; n >= 1; n /= 10, q++) {
00608             if (!isdigit(*q))
00609                 break;
00610             val += n * (*q - '0');
00611         }
00612         t += val;
00613     }
00614     *timeval = negative ? -t : t;
00615     return 0;
00616 }
00617 
00618 int av_find_info_tag(char *arg, int arg_size, const char *tag1, const char *info)
00619 {
00620     const char *p;
00621     char tag[128], *q;
00622 
00623     p = info;
00624     if (*p == '?')
00625         p++;
00626     for(;;) {
00627         q = tag;
00628         while (*p != '\0' && *p != '=' && *p != '&') {
00629             if ((q - tag) < sizeof(tag) - 1)
00630                 *q++ = *p;
00631             p++;
00632         }
00633         *q = '\0';
00634         q = arg;
00635         if (*p == '=') {
00636             p++;
00637             while (*p != '&' && *p != '\0') {
00638                 if ((q - arg) < arg_size - 1) {
00639                     if (*p == '+')
00640                         *q++ = ' ';
00641                     else
00642                         *q++ = *p;
00643                 }
00644                 p++;
00645             }
00646         }
00647         *q = '\0';
00648         if (!strcmp(tag, tag1))
00649             return 1;
00650         if (*p != '&')
00651             break;
00652         p++;
00653     }
00654     return 0;
00655 }
00656 
00657 #ifdef TEST
00658 
00659 #undef printf
00660 
00661 int main(void)
00662 {
00663     printf("Testing av_parse_video_rate()\n");
00664     {
00665         int i;
00666         const char *rates[] = {
00667             "-inf",
00668             "inf",
00669             "nan",
00670             "123/0",
00671             "-123 / 0",
00672             "",
00673             "/",
00674             " 123  /  321",
00675             "foo/foo",
00676             "foo/1",
00677             "1/foo",
00678             "0/0",
00679             "/0",
00680             "1/",
00681             "1",
00682             "0",
00683             "-123/123",
00684             "-foo",
00685             "123.23",
00686             ".23",
00687             "-.23",
00688             "-0.234",
00689             "-0.0000001",
00690             "  21332.2324   ",
00691             " -21332.2324   ",
00692         };
00693 
00694         for (i = 0; i < FF_ARRAY_ELEMS(rates); i++) {
00695             int ret;
00696             AVRational q = (AVRational){0, 0};
00697             ret = av_parse_video_rate(&q, rates[i]),
00698             printf("'%s' -> %d/%d ret:%d\n",
00699                    rates[i], q.num, q.den, ret);
00700         }
00701     }
00702 
00703     printf("\nTesting av_parse_color()\n");
00704     {
00705         int i;
00706         uint8_t rgba[4];
00707         const char *color_names[] = {
00708             "bikeshed",
00709             "RaNdOm",
00710             "foo",
00711             "red",
00712             "Red ",
00713             "RED",
00714             "Violet",
00715             "Yellow",
00716             "Red",
00717             "0x000000",
00718             "0x0000000",
00719             "0xff000000",
00720             "0x3e34ff",
00721             "0x3e34ffaa",
00722             "0xffXXee",
00723             "0xfoobar",
00724             "0xffffeeeeeeee",
00725             "#ff0000",
00726             "#ffXX00",
00727             "ff0000",
00728             "ffXX00",
00729             "red@foo",
00730             "random@10",
00731             "0xff0000@1.0",
00732             "red@",
00733             "red@0xfff",
00734             "red@0xf",
00735             "red@2",
00736             "red@0.1",
00737             "red@-1",
00738             "red@0.5",
00739             "red@1.0",
00740             "red@256",
00741             "red@10foo",
00742             "red@-1.0",
00743             "red@-0.0",
00744         };
00745 
00746         av_log_set_level(AV_LOG_DEBUG);
00747 
00748         for (i = 0;  i < FF_ARRAY_ELEMS(color_names); i++) {
00749             if (av_parse_color(rgba, color_names[i], -1, NULL) >= 0)
00750                 printf("%s -> R(%d) G(%d) B(%d) A(%d)\n", color_names[i], rgba[0], rgba[1], rgba[2], rgba[3]);
00751         }
00752     }
00753 
00754     return 0;
00755 }
00756 
00757 #endif /* TEST */