Libav 0.7.1
libavutil/parseutils.c
Go to the documentation of this file.
00001 /*
00002  * This file is part of Libav.
00003  *
00004  * Libav 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  * Libav 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 Libav; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00017  */
00018 
00024 #include <strings.h>
00025 #include <sys/time.h>
00026 #include <time.h>
00027 
00028 #include "avstring.h"
00029 #include "avutil.h"
00030 #include "eval.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     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, &p, 10);
00112         if (*p)
00113             p++;
00114         height = strtol(p, &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 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 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 (!strcasecmp(color_string2, "random") || !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 
00403 /* small strptime for ffmpeg */
00404 static
00405 const char *small_strptime(const char *p, const char *fmt,
00406                            struct tm *dt)
00407 {
00408     int c, val;
00409 
00410     for(;;) {
00411         c = *fmt++;
00412         if (c == '\0') {
00413             return p;
00414         } else if (c == '%') {
00415             c = *fmt++;
00416             switch(c) {
00417             case 'H':
00418                 val = date_get_num(&p, 0, 23, 2);
00419                 if (val == -1)
00420                     return NULL;
00421                 dt->tm_hour = val;
00422                 break;
00423             case 'M':
00424                 val = date_get_num(&p, 0, 59, 2);
00425                 if (val == -1)
00426                     return NULL;
00427                 dt->tm_min = val;
00428                 break;
00429             case 'S':
00430                 val = date_get_num(&p, 0, 59, 2);
00431                 if (val == -1)
00432                     return NULL;
00433                 dt->tm_sec = val;
00434                 break;
00435             case 'Y':
00436                 val = date_get_num(&p, 0, 9999, 4);
00437                 if (val == -1)
00438                     return NULL;
00439                 dt->tm_year = val - 1900;
00440                 break;
00441             case 'm':
00442                 val = date_get_num(&p, 1, 12, 2);
00443                 if (val == -1)
00444                     return NULL;
00445                 dt->tm_mon = val - 1;
00446                 break;
00447             case 'd':
00448                 val = date_get_num(&p, 1, 31, 2);
00449                 if (val == -1)
00450                     return NULL;
00451                 dt->tm_mday = val;
00452                 break;
00453             case '%':
00454                 goto match;
00455             default:
00456                 return NULL;
00457             }
00458         } else {
00459         match:
00460             if (c != *p)
00461                 return NULL;
00462             p++;
00463         }
00464     }
00465     return p;
00466 }
00467 
00468 static time_t mktimegm(struct tm *tm)
00469 {
00470     time_t t;
00471 
00472     int y = tm->tm_year + 1900, m = tm->tm_mon + 1, d = tm->tm_mday;
00473 
00474     if (m < 3) {
00475         m += 12;
00476         y--;
00477     }
00478 
00479     t = 86400 *
00480         (d + (153 * m - 457) / 5 + 365 * y + y / 4 - y / 100 + y / 400 - 719469);
00481 
00482     t += 3600 * tm->tm_hour + 60 * tm->tm_min + tm->tm_sec;
00483 
00484     return t;
00485 }
00486 
00487 int av_parse_time(int64_t *timeval, const char *datestr, int duration)
00488 {
00489     const char *p;
00490     int64_t t;
00491     struct tm dt;
00492     int i;
00493     static const char * const date_fmt[] = {
00494         "%Y-%m-%d",
00495         "%Y%m%d",
00496     };
00497     static const char * const time_fmt[] = {
00498         "%H:%M:%S",
00499         "%H%M%S",
00500     };
00501     const char *q;
00502     int is_utc, len;
00503     char lastch;
00504     int negative = 0;
00505 
00506 #undef time
00507     time_t now = time(0);
00508 
00509     len = strlen(datestr);
00510     if (len > 0)
00511         lastch = datestr[len - 1];
00512     else
00513         lastch = '\0';
00514     is_utc = (lastch == 'z' || lastch == 'Z');
00515 
00516     memset(&dt, 0, sizeof(dt));
00517 
00518     p = datestr;
00519     q = NULL;
00520     if (!duration) {
00521         if (!strncasecmp(datestr, "now", len)) {
00522             *timeval = (int64_t) now * 1000000;
00523             return 0;
00524         }
00525 
00526         /* parse the year-month-day part */
00527         for (i = 0; i < FF_ARRAY_ELEMS(date_fmt); i++) {
00528             q = small_strptime(p, date_fmt[i], &dt);
00529             if (q) {
00530                 break;
00531             }
00532         }
00533 
00534         /* if the year-month-day part is missing, then take the
00535          * current year-month-day time */
00536         if (!q) {
00537             if (is_utc) {
00538                 dt = *gmtime(&now);
00539             } else {
00540                 dt = *localtime(&now);
00541             }
00542             dt.tm_hour = dt.tm_min = dt.tm_sec = 0;
00543         } else {
00544             p = q;
00545         }
00546 
00547         if (*p == 'T' || *p == 't' || *p == ' ')
00548             p++;
00549 
00550         /* parse the hour-minute-second part */
00551         for (i = 0; i < FF_ARRAY_ELEMS(time_fmt); i++) {
00552             q = small_strptime(p, time_fmt[i], &dt);
00553             if (q) {
00554                 break;
00555             }
00556         }
00557     } else {
00558         /* parse datestr as a duration */
00559         if (p[0] == '-') {
00560             negative = 1;
00561             ++p;
00562         }
00563         /* parse datestr as HH:MM:SS */
00564         q = small_strptime(p, time_fmt[0], &dt);
00565         if (!q) {
00566             /* parse datestr as S+ */
00567             dt.tm_sec = strtol(p, (char **)&q, 10);
00568             if (q == p) {
00569                 /* the parsing didn't succeed */
00570                 *timeval = INT64_MIN;
00571                 return AVERROR(EINVAL);
00572             }
00573             dt.tm_min = 0;
00574             dt.tm_hour = 0;
00575         }
00576     }
00577 
00578     /* Now we have all the fields that we can get */
00579     if (!q) {
00580         *timeval = INT64_MIN;
00581         return AVERROR(EINVAL);
00582     }
00583 
00584     if (duration) {
00585         t = dt.tm_hour * 3600 + dt.tm_min * 60 + dt.tm_sec;
00586     } else {
00587         dt.tm_isdst = -1;       /* unknown */
00588         if (is_utc) {
00589             t = mktimegm(&dt);
00590         } else {
00591             t = mktime(&dt);
00592         }
00593     }
00594 
00595     t *= 1000000;
00596 
00597     /* parse the .m... part */
00598     if (*q == '.') {
00599         int val, n;
00600         q++;
00601         for (val = 0, n = 100000; n >= 1; n /= 10, q++) {
00602             if (!isdigit(*q))
00603                 break;
00604             val += n * (*q - '0');
00605         }
00606         t += val;
00607     }
00608     *timeval = negative ? -t : t;
00609     return 0;
00610 }
00611 
00612 int av_find_info_tag(char *arg, int arg_size, const char *tag1, const char *info)
00613 {
00614     const char *p;
00615     char tag[128], *q;
00616 
00617     p = info;
00618     if (*p == '?')
00619         p++;
00620     for(;;) {
00621         q = tag;
00622         while (*p != '\0' && *p != '=' && *p != '&') {
00623             if ((q - tag) < sizeof(tag) - 1)
00624                 *q++ = *p;
00625             p++;
00626         }
00627         *q = '\0';
00628         q = arg;
00629         if (*p == '=') {
00630             p++;
00631             while (*p != '&' && *p != '\0') {
00632                 if ((q - arg) < arg_size - 1) {
00633                     if (*p == '+')
00634                         *q++ = ' ';
00635                     else
00636                         *q++ = *p;
00637                 }
00638                 p++;
00639             }
00640         }
00641         *q = '\0';
00642         if (!strcmp(tag, tag1))
00643             return 1;
00644         if (*p != '&')
00645             break;
00646         p++;
00647     }
00648     return 0;
00649 }
00650 
00651 #ifdef TEST
00652 
00653 #undef printf
00654 
00655 int main(void)
00656 {
00657     printf("Testing av_parse_video_rate()\n");
00658     {
00659         int i;
00660         const char *rates[] = {
00661             "-inf",
00662             "inf",
00663             "nan",
00664             "123/0",
00665             "-123 / 0",
00666             "",
00667             "/",
00668             " 123  /  321",
00669             "foo/foo",
00670             "foo/1",
00671             "1/foo",
00672             "0/0",
00673             "/0",
00674             "1/",
00675             "1",
00676             "0",
00677             "-123/123",
00678             "-foo",
00679             "123.23",
00680             ".23",
00681             "-.23",
00682             "-0.234",
00683             "-0.0000001",
00684             "  21332.2324   ",
00685             " -21332.2324   ",
00686         };
00687 
00688         for (i = 0; i < FF_ARRAY_ELEMS(rates); i++) {
00689             int ret;
00690             AVRational q = (AVRational){0, 0};
00691             ret = av_parse_video_rate(&q, rates[i]),
00692             printf("'%s' -> %d/%d ret:%d\n",
00693                    rates[i], q.num, q.den, ret);
00694         }
00695     }
00696 
00697     printf("\nTesting av_parse_color()\n");
00698     {
00699         int i;
00700         uint8_t rgba[4];
00701         const char *color_names[] = {
00702             "bikeshed",
00703             "RaNdOm",
00704             "foo",
00705             "red",
00706             "Red ",
00707             "RED",
00708             "Violet",
00709             "Yellow",
00710             "Red",
00711             "0x000000",
00712             "0x0000000",
00713             "0xff000000",
00714             "0x3e34ff",
00715             "0x3e34ffaa",
00716             "0xffXXee",
00717             "0xfoobar",
00718             "0xffffeeeeeeee",
00719             "#ff0000",
00720             "#ffXX00",
00721             "ff0000",
00722             "ffXX00",
00723             "red@foo",
00724             "random@10",
00725             "0xff0000@1.0",
00726             "red@",
00727             "red@0xfff",
00728             "red@0xf",
00729             "red@2",
00730             "red@0.1",
00731             "red@-1",
00732             "red@0.5",
00733             "red@1.0",
00734             "red@256",
00735             "red@10foo",
00736             "red@-1.0",
00737             "red@-0.0",
00738         };
00739 
00740         av_log_set_level(AV_LOG_DEBUG);
00741 
00742         for (i = 0;  i < FF_ARRAY_ELEMS(color_names); i++) {
00743             if (av_parse_color(rgba, color_names[i], -1, NULL) >= 0)
00744                 printf("%s -> R(%d) G(%d) B(%d) A(%d)\n", color_names[i], rgba[0], rgba[1], rgba[2], rgba[3]);
00745         }
00746     }
00747 
00748     return 0;
00749 }
00750 
00751 #endif /* TEST */