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