Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

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