]> git.sesse.net Git - ffmpeg/blob - libavfilter/parseutils.c
ebb00614ee405c81fce95d6fd1d6d51193159003
[ffmpeg] / 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     int len, hex_offset = 0;
191
192     if (color_string[0] == '#') {
193         hex_offset = 1;
194     } else if (!strncmp(color_string, "0x", 2))
195         hex_offset = 2;
196
197     av_strlcpy(color_string2, color_string + hex_offset, sizeof(color_string2));
198     if ((tail = strchr(color_string2, ALPHA_SEP)))
199         *tail++ = 0;
200     len = strlen(color_string2);
201     rgba_color[3] = 255;
202
203     if (!strcasecmp(color_string2, "random") || !strcasecmp(color_string2, "bikeshed")) {
204         int rgba = av_get_random_seed();
205         rgba_color[0] = rgba >> 24;
206         rgba_color[1] = rgba >> 16;
207         rgba_color[2] = rgba >> 8;
208         rgba_color[3] = rgba;
209     } else if (hex_offset ||
210                strspn(color_string2, "0123456789ABCDEFabcdef") == len) {
211         char *tail;
212         unsigned int rgba = strtoul(color_string2, &tail, 16);
213
214         if (*tail || (len != 6 && len != 8)) {
215             av_log(log_ctx, AV_LOG_ERROR, "Invalid 0xRRGGBB[AA] color string: '%s'\n", color_string2);
216             return AVERROR(EINVAL);
217         }
218         if (len == 8) {
219             rgba_color[3] = rgba;
220             rgba >>= 8;
221         }
222         rgba_color[0] = rgba >> 16;
223         rgba_color[1] = rgba >> 8;
224         rgba_color[2] = rgba;
225     } else {
226         entry = bsearch(color_string2,
227                         color_table,
228                         FF_ARRAY_ELEMS(color_table),
229                         sizeof(ColorEntry),
230                         color_table_compare);
231         if (!entry) {
232             av_log(log_ctx, AV_LOG_ERROR, "Cannot find color '%s'\n", color_string2);
233             return AVERROR(EINVAL);
234         }
235         memcpy(rgba_color, entry->rgb_color, 3);
236     }
237
238     if (tail) {
239         unsigned long int alpha;
240         const char *alpha_string = tail;
241         if (!strncmp(alpha_string, "0x", 2)) {
242             alpha = strtoul(alpha_string, &tail, 16);
243         } else {
244             alpha = 255 * strtod(alpha_string, &tail);
245         }
246
247         if (tail == alpha_string || *tail || alpha > 255) {
248             av_log(log_ctx, AV_LOG_ERROR, "Invalid alpha value specifier '%s' in '%s'\n",
249                    alpha_string, color_string);
250             return AVERROR(EINVAL);
251         }
252         rgba_color[3] = alpha;
253     }
254
255     return 0;
256 }
257
258 #ifdef TEST
259
260 #undef printf
261
262 int main(void)
263 {
264     int i;
265
266     printf("\nTesting av_parse_color()\n");
267     {
268         uint8_t rgba[4];
269         const char *color_names[] = {
270             "bikeshed",
271             "RaNdOm",
272             "foo",
273             "red",
274             "Red ",
275             "RED",
276             "Violet",
277             "Yellow",
278             "Red",
279             "0x000000",
280             "0x0000000",
281             "0xff000000",
282             "0x3e34ff",
283             "0x3e34ffaa",
284             "0xffXXee",
285             "0xfoobar",
286             "0xffffeeeeeeee",
287             "#ff0000",
288             "#ffXX00",
289             "ff0000",
290             "ffXX00",
291             "red@foo",
292             "random@10",
293             "0xff0000@1.0",
294             "red@",
295             "red@0xfff",
296             "red@0xf",
297             "red@2",
298             "red@0.1",
299             "red@-1",
300             "red@0.5",
301             "red@1.0",
302             "red@256",
303             "red@10foo",
304             "red@-1.0",
305             "red@-0.0",
306         };
307
308         av_log_set_level(AV_LOG_DEBUG);
309
310         for (i = 0;  i < FF_ARRAY_ELEMS(color_names); i++) {
311             if (av_parse_color(rgba, color_names[i], NULL) >= 0)
312                 printf("%s -> R(%d) G(%d) B(%d) A(%d)\n", color_names[i], rgba[0], rgba[1], rgba[2], rgba[3]);
313         }
314     }
315
316     return 0;
317 }
318
319 #endif