1 /*
2 * ASCII/ANSI art decoder
3 * Copyright (c) 2010 Peter Ross <pross@xvid.org>
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 /**
23 * @file
24 * ASCII/ANSI art decoder
25 */
26
34
35 #define ATTR_BOLD 0x01 /**< Bold/Bright-foreground (mode 1) */
36 #define ATTR_FAINT 0x02 /**< Faint (mode 2) */
37 #define ATTR_UNDERLINE 0x08 /**< Underline (mode 4) */
38 #define ATTR_BLINK 0x10 /**< Blink/Bright-background (mode 5) */
39 #define ATTR_REVERSE 0x40 /**< Reverse (mode 7) */
40 #define ATTR_CONCEALED 0x80 /**< Concealed (mode 8) */
41
42 #define DEFAULT_FG_COLOR 7 /**< CGA color index */
43 #define DEFAULT_BG_COLOR 0
44 #define DEFAULT_SCREEN_MODE 3 /**< 80x25 */
45
46 #define FONT_WIDTH 8 /**< Font width */
47
48 /** map ansi color index to cga palette index */
50 0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15
51 };
52
55 int x;
/**< x cursor position (pixels) */
56 int y;
/**< y cursor position (pixels) */
57 int sx;
/**< saved x cursor position (pixels) */
58 int sy;
/**< saved y cursor position (pixels) */
62 int fg;
/**< foreground color */
63 int bg;
/**< background color */
65
66 /* ansi parser state machine */
67 enum {
75 int nb_args;
/**< number of arguments (may exceed MAX_NB_ARGS) */
77
79 {
82
86
87 /* defaults */
92
95
96 return 0;
97 }
98
100 {
103 pal += 16;
104 #define COLOR(x) ((x) * 40 + 55)
105 for (r = 0; r < 6; r++)
106 for (g = 0; g < 6; g++)
107 for (b = 0; b < 6; b++)
109 #define GRAY(x) ((x) * 10 + 8)
110 for (g = 0; g < 24; g++)
111 *pal++ = 0xFF000000 | (
GRAY(g) << 16) | (
GRAY(g) << 8) |
GRAY(g);
112 }
113
115 {
117 int i;
118
121 return;
122 }
123
124 i = 0;
129 for (; i < avctx->
height; i++)
132 }
133
135 {
137 int i;
141 }
142
144 {
146 int i;
147 for (i = 0; i < avctx->
height; i++)
150 }
151
152 /**
153 * Draw character to screen
154 */
156 {
160
162 fg += 8;
164 bg += 8;
168 fg = bg;
175 }
176 }
177
178 /**
179 * Execute ANSI escape code
180 * @return 0 on success, negative on error
181 */
183 {
186 switch(c) {
187 case 'A': //Cursor Up
189 break;
190 case 'B': //Cursor Down
192 break;
193 case 'C': //Cursor Right
195 break;
196 case 'D': //Cursor Left
198 break;
199 case 'H': //Cursor Position
200 case 'f': //Horizontal and Vertical Position
202 s->
x = s->
nb_args > 1 ? av_clip((s->
args[1] - 1)*FONT_WIDTH, 0, avctx->
width - FONT_WIDTH) : 0;
203 break;
204 case 'h': //set creen mode
205 case 'l': //reset screen mode
208 width = avctx->
width;
211 case 0: case 1: case 4: case 5: case 13: case 19: //320x200 (25 rows)
214 width = 40<<3;
215 height = 25<<3;
216 break;
217 case 2: case 3: //640x400 (25 rows)
220 width = 80<<3;
221 height = 25<<4;
222 break;
223 case 6: case 14: //640x200 (25 rows)
226 width = 80<<3;
227 height = 25<<3;
228 break;
229 case 7: //set line wrapping
230 break;
231 case 15: case 16: //640x350 (43 rows)
234 width = 80<<3;
235 height = 43<<3;
236 break;
237 case 17: case 18: //640x480 (60 rows)
240 width = 80<<3;
241 height = 60<<4;
242 break;
243 default:
245 }
246 s->
x = av_clip(s->
x, 0, width - FONT_WIDTH);
248 if (width != avctx->
width || height != avctx->
height) {
258 } else if (c == 'l') {
260 }
261 break;
262 case 'J': //Erase in Page
263 switch (s->
args[0]) {
264 case 0:
269 break;
270 case 1:
274 break;
275 case 2:
277 }
278 break;
279 case 'K': //Erase in Line
281 case 0:
283 break;
284 case 1:
286 break;
287 case 2:
289 }
290 break;
291 case 'm': //Select Graphics Rendition
295 }
298 if (m == 0) {
302 } else if (m == 1 || m == 2 || m == 4 || m == 5 || m == 7 || m == 8) {
304 } else if (m >= 30 && m <= 37) {
309 i += 2;
310 } else if (m == 39) {
312 } else if (m >= 40 && m <= 47) {
317 i += 2;
318 } else if (m == 49) {
320 } else {
322 }
323 }
324 break;
325 case 'n': //Device Status Report
326 case 'R': //report current line and column
327 /* ignore */
328 break;
329 case 's': //Save Cursor Position
332 break;
333 case 'u': //Restore Cursor Position
334 s->
x = av_clip(s->
sx, 0, avctx->
width - FONT_WIDTH);
336 break;
337 default:
339 break;
340 }
343 return 0;
344 }
345
347 void *
data,
int *got_frame,
349 {
352 int buf_size = avpkt->
size;
353 const uint8_t *buf_end = buf+buf_size;
355
359 for (i=0; i<avctx->
height; i++)
362 }
363
370 }
371
372 while(buf < buf_end) {
374 case STATE_NORMAL:
375 switch (buf[0]) {
376 case 0x00: //NUL
377 case 0x07: //BEL
378 case 0x1A: //SUB
379 /* ignore */
380 break;
381 case 0x08: //BS
383 break;
384 case 0x09: //HT
386 count = ((i + 8) & ~7) - i;
387 for (i = 0; i <
count; i++)
389 break;
390 case 0x0A: //LF
392 case 0x0D: //CR
394 break;
395 case 0x0C: //FF
397 break;
398 case 0x1B: //ESC
399 s->
state = STATE_ESCAPE;
400 break;
401 default:
403 }
404 break;
405 case STATE_ESCAPE:
406 if (buf[0] == '[') {
407 s->
state = STATE_CODE;
410 } else {
411 s->
state = STATE_NORMAL;
413 continue;
414 }
415 break;
416 case STATE_CODE:
417 switch(buf[0]) {
418 case '0': case '1': case '2': case '3': case '4':
419 case '5': case '6': case '7': case '8': case '9':
422 break;
423 case ';':
427 break;
428 case 'M':
429 s->
state = STATE_MUSIC_PREAMBLE;
430 break;
431 case '=': case '?':
432 /* ignore */
433 break;
434 default:
441 s->
state = STATE_NORMAL;
442 }
443 break;
444 case STATE_MUSIC_PREAMBLE:
445 if (buf[0] == 0x0E || buf[0] == 0x1B)
446 s->
state = STATE_NORMAL;
447 /* ignore music data */
448 break;
449 }
450 buf++;
451 }
452
453 *got_frame = 1;
456 return buf_size;
457 }
458
460 {
462
464 return 0;
465 }
466
477 };