b8923eda46800ed19e0d43ad06499189790b6fa4
[ffmpeg.git] / libavfilter / parseutils.c
1 /*
2  * copyright (c) 2009 Stefano Sabatini
3  * This file is part of FFmpeg.
4  *
5  * FFmpeg is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * FFmpeg is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with FFmpeg; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19
20 /**
21  * @file
22  * parsing utils
23  */
24
25 #include <strings.h>
26 #include "libavutil/avutil.h"
27 #include "libavutil/avstring.h"
28 #include "libavutil/random_seed.h"
29 #include "parseutils.h"
30
31 typedef struct {
32     const char *name;            ///< a string representing the name of the color
33     uint8_t     rgb_color[3];    ///< RGB values for the color
34 } ColorEntry;
35
36 static ColorEntry color_table[] = {
37     { "AliceBlue",            { 0xF0, 0xF8, 0xFF } },
38     { "AntiqueWhite",         { 0xFA, 0xEB, 0xD7 } },
39     { "Aqua",                 { 0x00, 0xFF, 0xFF } },
40     { "Aquamarine",           { 0x7F, 0xFF, 0xD4 } },
41     { "Azure",                { 0xF0, 0xFF, 0xFF } },
42     { "Beige",                { 0xF5, 0xF5, 0xDC } },
43     { "Bisque",               { 0xFF, 0xE4, 0xC4 } },
44     { "Black",                { 0x00, 0x00, 0x00 } },
45     { "BlanchedAlmond",       { 0xFF, 0xEB, 0xCD } },
46     { "Blue",                 { 0x00, 0x00, 0xFF } },
47     { "BlueViolet",           { 0x8A, 0x2B, 0xE2 } },
48     { "Brown",                { 0xA5, 0x2A, 0x2A } },
49     { "BurlyWood",            { 0xDE, 0xB8, 0x87 } },
50     { "CadetBlue",            { 0x5F, 0x9E, 0xA0 } },
51     { "Chartreuse",           { 0x7F, 0xFF, 0x00 } },
52     { "Chocolate",            { 0xD2, 0x69, 0x1E } },
53     { "Coral",                { 0xFF, 0x7F, 0x50 } },
54     { "CornflowerBlue",       { 0x64, 0x95, 0xED } },
55     { "Cornsilk",             { 0xFF, 0xF8, 0xDC } },
56     { "Crimson",              { 0xDC, 0x14, 0x3C } },
57     { "Cyan",                 { 0x00, 0xFF, 0xFF } },
58     { "DarkBlue",             { 0x00, 0x00, 0x8B } },
59     { "DarkCyan",             { 0x00, 0x8B, 0x8B } },
60     { "DarkGoldenRod",        { 0xB8, 0x86, 0x0B } },
61     { "DarkGray",             { 0xA9, 0xA9, 0xA9 } },
62     { "DarkGreen",            { 0x00, 0x64, 0x00 } },
63     { "DarkKhaki",            { 0xBD, 0xB7, 0x6B } },
64     { "DarkMagenta",          { 0x8B, 0x00, 0x8B } },
65     { "DarkOliveGreen",       { 0x55, 0x6B, 0x2F } },
66     { "Darkorange",           { 0xFF, 0x8C, 0x00 } },
67     { "DarkOrchid",           { 0x99, 0x32, 0xCC } },
68     { "DarkRed",              { 0x8B, 0x00, 0x00 } },
69     { "DarkSalmon",           { 0xE9, 0x96, 0x7A } },
70     { "DarkSeaGreen",         { 0x8F, 0xBC, 0x8F } },
71     { "DarkSlateBlue",        { 0x48, 0x3D, 0x8B } },
72     { "DarkSlateGray",        { 0x2F, 0x4F, 0x4F } },
73     { "DarkTurquoise",        { 0x00, 0xCE, 0xD1 } },
74     { "DarkViolet",           { 0x94, 0x00, 0xD3 } },
75     { "DeepPink",             { 0xFF, 0x14, 0x93 } },
76     { "DeepSkyBlue",          { 0x00, 0xBF, 0xFF } },
77     { "DimGray",              { 0x69, 0x69, 0x69 } },
78     { "DodgerBlue",           { 0x1E, 0x90, 0xFF } },
79     { "FireBrick",            { 0xB2, 0x22, 0x22 } },
80     { "FloralWhite",          { 0xFF, 0xFA, 0xF0 } },
81     { "ForestGreen",          { 0x22, 0x8B, 0x22 } },
82     { "Fuchsia",              { 0xFF, 0x00, 0xFF } },
83     { "Gainsboro",            { 0xDC, 0xDC, 0xDC } },
84     { "GhostWhite",           { 0xF8, 0xF8, 0xFF } },
85     { "Gold",                 { 0xFF, 0xD7, 0x00 } },
86     { "GoldenRod",            { 0xDA, 0xA5, 0x20 } },
87     { "Gray",                 { 0x80, 0x80, 0x80 } },
88     { "Green",                { 0x00, 0x80, 0x00 } },
89     { "GreenYellow",          { 0xAD, 0xFF, 0x2F } },
90     { "HoneyDew",             { 0xF0, 0xFF, 0xF0 } },
91     { "HotPink",              { 0xFF, 0x69, 0xB4 } },
92     { "IndianRed",            { 0xCD, 0x5C, 0x5C } },
93     { "Indigo",               { 0x4B, 0x00, 0x82 } },
94     { "Ivory",                { 0xFF, 0xFF, 0xF0 } },
95     { "Khaki",                { 0xF0, 0xE6, 0x8C } },
96     { "Lavender",             { 0xE6, 0xE6, 0xFA } },
97     { "LavenderBlush",        { 0xFF, 0xF0, 0xF5 } },
98     { "LawnGreen",            { 0x7C, 0xFC, 0x00 } },
99     { "LemonChiffon",         { 0xFF, 0xFA, 0xCD } },
100     { "LightBlue",            { 0xAD, 0xD8, 0xE6 } },
101     { "LightCoral",           { 0xF0, 0x80, 0x80 } },
102     { "LightCyan",            { 0xE0, 0xFF, 0xFF } },
103     { "LightGoldenRodYellow", { 0xFA, 0xFA, 0xD2 } },
104     { "LightGrey",            { 0xD3, 0xD3, 0xD3 } },
105     { "LightGreen",           { 0x90, 0xEE, 0x90 } },
106     { "LightPink",            { 0xFF, 0xB6, 0xC1 } },
107     { "LightSalmon",          { 0xFF, 0xA0, 0x7A } },
108     { "LightSeaGreen",        { 0x20, 0xB2, 0xAA } },
109     { "LightSkyBlue",         { 0x87, 0xCE, 0xFA } },
110     { "LightSlateGray",       { 0x77, 0x88, 0x99 } },
111     { "LightSteelBlue",       { 0xB0, 0xC4, 0xDE } },
112     { "LightYellow",          { 0xFF, 0xFF, 0xE0 } },
113     { "Lime",                 { 0x00, 0xFF, 0x00 } },
114     { "LimeGreen",            { 0x32, 0xCD, 0x32 } },
115     { "Linen",                { 0xFA, 0xF0, 0xE6 } },
116     { "Magenta",              { 0xFF, 0x00, 0xFF } },
117     { "Maroon",               { 0x80, 0x00, 0x00 } },
118     { "MediumAquaMarine",     { 0x66, 0xCD, 0xAA } },
119     { "MediumBlue",           { 0x00, 0x00, 0xCD } },
120     { "MediumOrchid",         { 0xBA, 0x55, 0xD3 } },
121     { "MediumPurple",         { 0x93, 0x70, 0xD8 } },
122     { "MediumSeaGreen",       { 0x3C, 0xB3, 0x71 } },
123     { "MediumSlateBlue",      { 0x7B, 0x68, 0xEE } },
124     { "MediumSpringGreen",    { 0x00, 0xFA, 0x9A } },
125     { "MediumTurquoise",      { 0x48, 0xD1, 0xCC } },
126     { "MediumVioletRed",      { 0xC7, 0x15, 0x85 } },
127     { "MidnightBlue",         { 0x19, 0x19, 0x70 } },
128     { "MintCream",            { 0xF5, 0xFF, 0xFA } },
129     { "MistyRose",            { 0xFF, 0xE4, 0xE1 } },
130     { "Moccasin",             { 0xFF, 0xE4, 0xB5 } },
131     { "NavajoWhite",          { 0xFF, 0xDE, 0xAD } },
132     { "Navy",                 { 0x00, 0x00, 0x80 } },
133     { "OldLace",              { 0xFD, 0xF5, 0xE6 } },
134     { "Olive",                { 0x80, 0x80, 0x00 } },
135     { "OliveDrab",            { 0x6B, 0x8E, 0x23 } },
136     { "Orange",               { 0xFF, 0xA5, 0x00 } },
137     { "OrangeRed",            { 0xFF, 0x45, 0x00 } },
138     { "Orchid",               { 0xDA, 0x70, 0xD6 } },
139     { "PaleGoldenRod",        { 0xEE, 0xE8, 0xAA } },
140     { "PaleGreen",            { 0x98, 0xFB, 0x98 } },
141     { "PaleTurquoise",        { 0xAF, 0xEE, 0xEE } },
142     { "PaleVioletRed",        { 0xD8, 0x70, 0x93 } },
143     { "PapayaWhip",           { 0xFF, 0xEF, 0xD5 } },
144     { "PeachPuff",            { 0xFF, 0xDA, 0xB9 } },
145     { "Peru",                 { 0xCD, 0x85, 0x3F } },
146     { "Pink",                 { 0xFF, 0xC0, 0xCB } },
147     { "Plum",                 { 0xDD, 0xA0, 0xDD } },
148     { "PowderBlue",           { 0xB0, 0xE0, 0xE6 } },
149     { "Purple",               { 0x80, 0x00, 0x80 } },
150     { "Red",                  { 0xFF, 0x00, 0x00 } },
151     { "RosyBrown",            { 0xBC, 0x8F, 0x8F } },
152     { "RoyalBlue",            { 0x41, 0x69, 0xE1 } },
153     { "SaddleBrown",          { 0x8B, 0x45, 0x13 } },
154     { "Salmon",               { 0xFA, 0x80, 0x72 } },
155     { "SandyBrown",           { 0xF4, 0xA4, 0x60 } },
156     { "SeaGreen",             { 0x2E, 0x8B, 0x57 } },
157     { "SeaShell",             { 0xFF, 0xF5, 0xEE } },
158     { "Sienna",               { 0xA0, 0x52, 0x2D } },
159     { "Silver",               { 0xC0, 0xC0, 0xC0 } },
160     { "SkyBlue",              { 0x87, 0xCE, 0xEB } },
161     { "SlateBlue",            { 0x6A, 0x5A, 0xCD } },
162     { "SlateGray",            { 0x70, 0x80, 0x90 } },
163     { "Snow",                 { 0xFF, 0xFA, 0xFA } },
164     { "SpringGreen",          { 0x00, 0xFF, 0x7F } },
165     { "SteelBlue",            { 0x46, 0x82, 0xB4 } },
166     { "Tan",                  { 0xD2, 0xB4, 0x8C } },
167     { "Teal",                 { 0x00, 0x80, 0x80 } },
168     { "Thistle",              { 0xD8, 0xBF, 0xD8 } },
169     { "Tomato",               { 0xFF, 0x63, 0x47 } },
170     { "Turquoise",            { 0x40, 0xE0, 0xD0 } },
171     { "Violet",               { 0xEE, 0x82, 0xEE } },
172     { "Wheat",                { 0xF5, 0xDE, 0xB3 } },
173     { "White",                { 0xFF, 0xFF, 0xFF } },
174     { "WhiteSmoke",           { 0xF5, 0xF5, 0xF5 } },
175     { "Yellow",               { 0xFF, 0xFF, 0x00 } },
176     { "YellowGreen",          { 0x9A, 0xCD, 0x32 } },
177 };
178
179 static int color_table_compare(const void *lhs, const void *rhs)
180 {
181     return strcasecmp(lhs, ((const ColorEntry *)rhs)->name);
182 }
183
184 #define ALPHA_SEP '@'
185
186 int av_parse_color(uint8_t *rgba_color, const char *color_string, void *log_ctx)
187 {
188     char *tail, color_string2[128];
189     const ColorEntry *entry;
190     av_strlcpy(color_string2, color_string, sizeof(color_string2));
191     if ((tail = strchr(color_string2, ALPHA_SEP)))
192         *tail++ = 0;
193     rgba_color[3] = 255;
194
195     if (!strcasecmp(color_string2, "random") || !strcasecmp(color_string2, "bikeshed")) {
196         int rgba = av_get_random_seed();
197         rgba_color[0] = rgba >> 24;
198         rgba_color[1] = rgba >> 16;
199         rgba_color[2] = rgba >> 8;
200         rgba_color[3] = rgba;
201     } else if (!strncmp(color_string2, "0x", 2)) {
202         char *tail;
203         int len = strlen(color_string2);
204         unsigned int rgba = strtoul(color_string2, &tail, 16);
205
206         if (*tail || (len != 8 && len != 10)) {
207             av_log(log_ctx, AV_LOG_ERROR, "Invalid 0xRRGGBB[AA] color string: '%s'\n", color_string2);
208             return AVERROR(EINVAL);
209         }
210         if (len == 10) {
211             rgba_color[3] = rgba;
212             rgba >>= 8;
213         }
214         rgba_color[0] = rgba >> 16;
215         rgba_color[1] = rgba >> 8;
216         rgba_color[2] = rgba;
217     } else {
218         entry = bsearch(color_string2,
219                         color_table,
220                         FF_ARRAY_ELEMS(color_table),
221                         sizeof(ColorEntry),
222                         color_table_compare);
223         if (!entry) {
224             av_log(log_ctx, AV_LOG_ERROR, "Cannot find color '%s'\n", color_string2);
225             return AVERROR(EINVAL);
226         }
227         memcpy(rgba_color, entry->rgb_color, 3);
228     }
229
230     if (tail) {
231         unsigned long int alpha;
232         const char *alpha_string = tail;
233         if (!strncmp(alpha_string, "0x", 2)) {
234             alpha = strtoul(alpha_string, &tail, 16);
235         } else {
236             alpha = strtoul(alpha_string, &tail, 10);
237             if (*tail) {
238                 double d = strtod(alpha_string, &tail);
239                 alpha = d * 255;
240             }
241         }
242
243         if (tail == alpha_string || *tail || alpha > 255) {
244             av_log(log_ctx, AV_LOG_ERROR, "Invalid alpha value specifier '%s' in '%s'\n",
245                    alpha_string, color_string);
246             return AVERROR(EINVAL);
247         }
248         rgba_color[3] = alpha;
249     }
250
251     return 0;
252 }
253
254 #ifdef TEST
255
256 #undef printf
257
258 int main(void)
259 {
260     int i;
261
262     printf("\nTesting av_parse_color()\n");
263     {
264         uint8_t rgba[4];
265         const char *color_names[] = {
266             "bikeshed",
267             "RaNdOm",
268             "foo",
269             "red",
270             "Red ",
271             "RED",
272             "Violet",
273             "Yellow",
274             "Red",
275             "0x000000",
276             "0x0000000",
277             "0xff000000",
278             "0x3e34ff",
279             "0x3e34ffaa",
280             "0xffXXee",
281             "0xfoobar",
282             "0xffffeeeeeeee",
283             "red@foo",
284             "random@10",
285             "0xff0000@1.0",
286             "red@",
287             "red@0xfff",
288             "red@0xf",
289             "red@2",
290             "red@0.1",
291             "red@-1",
292             "red@0.5",
293             "red@1.0",
294             "red@256",
295             "red@10foo",
296             "red@-1.0",
297             "red@-0.0",
298         };
299
300         av_log_set_level(AV_LOG_DEBUG);
301
302         for (int i = 0;  i < FF_ARRAY_ELEMS(color_names); i++) {
303             if (av_parse_color(rgba, color_names[i], NULL) >= 0)
304                 printf("%s -> R(%d) G(%d) B(%d) A(%d)\n", color_names[i], rgba[0], rgba[1], rgba[2], rgba[3]);
305         }
306     }
307
308     return 0;
309 }
310
311 #endif