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
83 /* defaults */
88
91 if (ret < 0)
92 return ret;
96 }
97
101
102 return 0;
103 }
104
106 {
109 pal += 16;
110 #define COLOR(x) ((x) * 40 + 55)
111 for (r = 0; r < 6; r++)
112 for (g = 0; g < 6; g++)
113 for (b = 0; b < 6; b++)
115 #define GRAY(x) ((x) * 10 + 8)
116 for (g = 0; g < 24; g++)
117 *pal++ = 0xFF000000 | (
GRAY(g) << 16) | (
GRAY(g) << 8) |
GRAY(g);
118 }
119
121 {
123 int i;
124
127 return;
128 }
129
130 i = 0;
135 for (; i < avctx->
height; i++)
138 }
139
141 {
143 int i;
147 }
148
150 {
152 int i;
153 for (i = 0; i < avctx->
height; i++)
156 }
157
158 /**
159 * Draw character to screen
160 */
162 {
166
168 fg += 8;
170 bg += 8;
174 fg = bg;
181 }
182 }
183
184 /**
185 * Execute ANSI escape code
186 * @return 0 on success, negative on error
187 */
189 {
191 int ret, i;
194
195 switch(c) {
196 case 'A': //Cursor Up
198 break;
199 case 'B': //Cursor Down
201 break;
202 case 'C': //Cursor Right
204 break;
205 case 'D': //Cursor Left
207 break;
208 case 'H': //Cursor Position
209 case 'f': //Horizontal and Vertical Position
211 s->
x = s->
nb_args > 1 ? av_clip((s->
args[1] - 1)*FONT_WIDTH, 0, avctx->
width - FONT_WIDTH) : 0;
212 break;
213 case 'h': //set screen mode
214 case 'l': //reset screen mode
218 case 0: case 1: case 4: case 5: case 13: case 19: //320x200 (25 rows)
221 width = 40<<3;
222 height = 25<<3;
223 break;
224 case 2: case 3: //640x400 (25 rows)
227 width = 80<<3;
228 height = 25<<4;
229 break;
230 case 6: case 14: //640x200 (25 rows)
233 width = 80<<3;
234 height = 25<<3;
235 break;
236 case 7: //set line wrapping
237 break;
238 case 15: case 16: //640x350 (43 rows)
241 width = 80<<3;
242 height = 43<<3;
243 break;
244 case 17: case 18: //640x480 (60 rows)
247 width = 80<<3;
248 height = 60<<4;
249 break;
250 default:
252 }
253 s->
x = av_clip(s->
x, 0, width - FONT_WIDTH);
255 if (width != avctx->
width || height != avctx->
height) {
258 if (ret < 0)
259 return ret;
262 return ret;
267 } else if (c == 'l') {
269 }
270 break;
271 case 'J': //Erase in Page
272 switch (s->
args[0]) {
273 case 0:
278 break;
279 case 1:
283 break;
284 case 2:
286 }
287 break;
288 case 'K': //Erase in Line
290 case 0:
292 break;
293 case 1:
295 break;
296 case 2:
298 }
299 break;
300 case 'm': //Select Graphics Rendition
304 }
307 if (m == 0) {
311 } else if (m == 1 || m == 2 || m == 4 || m == 5 || m == 7 || m == 8) {
313 } else if (m >= 30 && m <= 37) {
318 i += 2;
319 } else if (m == 39) {
321 } else if (m >= 40 && m <= 47) {
326 i += 2;
327 } else if (m == 49) {
329 } else {
331 }
332 }
333 break;
334 case 'n': //Device Status Report
335 case 'R': //report current line and column
336 /* ignore */
337 break;
338 case 's': //Save Cursor Position
341 break;
342 case 'u': //Restore Cursor Position
343 s->
x = av_clip(s->
sx, 0, avctx->
width - FONT_WIDTH);
345 break;
346 default:
348 break;
349 }
352 return 0;
353 }
354
356 void *
data,
int *got_frame,
358 {
361 int buf_size = avpkt->
size;
362 const uint8_t *buf_end = buf+buf_size;
364
366 return ret;
368 for (i=0; i<avctx->
height; i++)
371 }
372
379 }
380
381 while(buf < buf_end) {
383 case STATE_NORMAL:
384 switch (buf[0]) {
385 case 0x00: //NUL
386 case 0x07: //BEL
387 case 0x1A: //SUB
388 /* ignore */
389 break;
390 case 0x08: //BS
392 break;
393 case 0x09: //HT
395 count = ((i + 8) & ~7) - i;
396 for (i = 0; i <
count; i++)
398 break;
399 case 0x0A: //LF
401 case 0x0D: //CR
403 break;
404 case 0x0C: //FF
406 break;
407 case 0x1B: //ESC
408 s->
state = STATE_ESCAPE;
409 break;
410 default:
412 }
413 break;
414 case STATE_ESCAPE:
415 if (buf[0] == '[') {
416 s->
state = STATE_CODE;
419 } else {
420 s->
state = STATE_NORMAL;
422 continue;
423 }
424 break;
425 case STATE_CODE:
426 switch(buf[0]) {
427 case '0': case '1': case '2': case '3': case '4':
428 case '5': case '6': case '7': case '8': case '9':
431 break;
432 case ';':
436 break;
437 case 'M':
438 s->
state = STATE_MUSIC_PREAMBLE;
439 break;
440 case '=': case '?':
441 /* ignore */
442 break;
443 default:
449 return ret;
450 s->
state = STATE_NORMAL;
451 }
452 break;
453 case STATE_MUSIC_PREAMBLE:
454 if (buf[0] == 0x0E || buf[0] == 0x1B)
455 s->
state = STATE_NORMAL;
456 /* ignore music data */
457 break;
458 }
459 buf++;
460 }
461
462 *got_frame = 1;
464 return ret;
465 return buf_size;
466 }
467
469 {
471
473 return 0;
474 }
475
487 };
static void draw_char(AVCodecContext *avctx, int c)
Draw character to screen.
#define FONT_WIDTH
Font width.
int x
x cursor position (pixels)
#define ATTR_REVERSE
Reverse (mode 7)
This structure describes decoded (raw) audio or video data.
ptrdiff_t const GLvoid * data
#define ATTR_CONCEALED
Concealed (mode 8)
#define AV_LOG_WARNING
Something somehow does not look correct.
int ff_set_dimensions(AVCodecContext *s, int width, int height)
Check that the provided frame dimensions are valid and set them on the codec context.
static av_cold int init(AVCodecContext *avctx)
int nb_args
number of arguments (may exceed MAX_NB_ARGS)
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
const uint8_t avpriv_vga16_font[4096]
#define DEFAULT_SCREEN_MODE
80x25
static void erase_screen(AVCodecContext *avctx)
static void decode(AVCodecContext *dec_ctx, AVPacket *pkt, AVFrame *frame, FILE *outfile)
int ff_reget_buffer(AVCodecContext *avctx, AVFrame *frame)
Identical in function to av_frame_make_writable(), except it uses ff_get_buffer() to allocate the buf...
static int execute_code(AVCodecContext *avctx, int c)
Execute ANSI escape code.
static void hscroll(AVCodecContext *avctx)
void void avpriv_request_sample(void *avc, const char *msg,...) av_printf_format(2
Log a generic warning message about a missing feature.
#define FF_CODEC_CAP_INIT_THREADSAFE
The codec does not modify any global variables in the init function, allowing to call the init functi...
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
8 bits with AV_PIX_FMT_RGB32 palette
int av_frame_ref(AVFrame *dst, const AVFrame *src)
Set up a new reference to the data described by the source frame.
static av_cold int decode_close(AVCodecContext *avctx)
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
int sy
saved y cursor position (pixels)
const uint8_t avpriv_cga_font[2048]
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
static void erase_line(AVCodecContext *avctx, int xoffset, int xlength)
const char * name
Name of the codec implementation.
reference-counted frame API
#define ATTR_BLINK
Blink/Bright-background (mode 5)
enum AVPictureType pict_type
Picture type of the frame.
int width
picture width / height.
static av_cold int decode_init(AVCodecContext *avctx)
#define ATTR_BOLD
Bold/Bright-foreground (mode 1)
void ff_draw_pc_font(uint8_t *dst, int linesize, const uint8_t *font, int font_height, int ch, int fg, int bg)
Draw CGA/EGA/VGA font to 8-bit pixel buffer.
Libavcodec external API header.
int font_height
font height
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
main external API structure.
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
int palette_has_changed
Tell user application that palette has changed from previous frame.
static const uint8_t ansi_to_cga[16]
map ansi color index to cga palette index
static void set_palette(uint32_t *pal)
const uint32_t ff_cga_palette[16]
void av_frame_unref(AVFrame *frame)
Unreference all the buffers referenced by frame and reset the frame fields.
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
int sx
saved x cursor position (pixels)
common internal api header.
common internal and external API header
int y
y cursor position (pixels)
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
enum AnsiContext::@35 state
int frame_number
Frame counter, set by libavcodec.
#define DEFAULT_FG_COLOR
CGA color index.
#define FFSWAP(type, a, b)
int attributes
attribute flags
This structure stores compressed data.
#define AV_GET_BUFFER_FLAG_REF
The decoder will keep a reference to the frame and may reuse it later.
#define AV_CODEC_CAP_DR1
Codec uses get_buffer() for allocating buffers and supports custom allocators.
CGA/EGA/VGA ROM font data.