ansi.c
Go to the documentation of this file.
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 
27 #include "libavutil/common.h"
28 #include "libavutil/frame.h"
29 #include "libavutil/lfg.h"
31 #include "avcodec.h"
32 #include "cga_data.h"
33 #include "internal.h"
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 */
49 static const uint8_t ansi_to_cga[16] = {
50  0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15
51 };
52 
53 typedef struct {
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) */
59  const uint8_t* font; /**< font */
60  int font_height; /**< font height */
61  int attributes; /**< attribute flags */
62  int fg; /**< foreground color */
63  int bg; /**< background color */
65 
66  /* ansi parser state machine */
67  enum {
68  STATE_NORMAL = 0,
71  STATE_MUSIC_PREAMBLE
72  } state;
73 #define MAX_NB_ARGS 4
75  int nb_args; /**< number of arguments (may exceed MAX_NB_ARGS) */
76 } AnsiContext;
77 
79 {
80  AnsiContext *s = avctx->priv_data;
81  avctx->pix_fmt = AV_PIX_FMT_PAL8;
82 
83  s->frame = av_frame_alloc();
84  if (!s->frame)
85  return AVERROR(ENOMEM);
86 
87  /* defaults */
89  s->font_height = 16;
90  s->fg = DEFAULT_FG_COLOR;
91  s->bg = DEFAULT_BG_COLOR;
92 
93  if (!avctx->width || !avctx->height)
94  avcodec_set_dimensions(avctx, 80<<3, 25<<4);
95 
96  return 0;
97 }
98 
99 static void set_palette(uint32_t *pal)
100 {
101  int r, g, b;
102  memcpy(pal, ff_cga_palette, 16 * 4);
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++)
108  *pal++ = 0xFF000000 | (COLOR(r) << 16) | (COLOR(g) << 8) | COLOR(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 
114 static void hscroll(AVCodecContext *avctx)
115 {
116  AnsiContext *s = avctx->priv_data;
117  int i;
118 
119  if (s->y < avctx->height - s->font_height) {
120  s->y += s->font_height;
121  return;
122  }
123 
124  i = 0;
125  for (; i < avctx->height - s->font_height; i++)
126  memcpy(s->frame->data[0] + i * s->frame->linesize[0],
127  s->frame->data[0] + (i + s->font_height) * s->frame->linesize[0],
128  avctx->width);
129  for (; i < avctx->height; i++)
130  memset(s->frame->data[0] + i * s->frame->linesize[0],
131  DEFAULT_BG_COLOR, avctx->width);
132 }
133 
134 static void erase_line(AVCodecContext * avctx, int xoffset, int xlength)
135 {
136  AnsiContext *s = avctx->priv_data;
137  int i;
138  for (i = 0; i < s->font_height; i++)
139  memset(s->frame->data[0] + (s->y + i)*s->frame->linesize[0] + xoffset,
140  DEFAULT_BG_COLOR, xlength);
141 }
142 
143 static void erase_screen(AVCodecContext *avctx)
144 {
145  AnsiContext *s = avctx->priv_data;
146  int i;
147  for (i = 0; i < avctx->height; i++)
148  memset(s->frame->data[0] + i * s->frame->linesize[0], DEFAULT_BG_COLOR, avctx->width);
149  s->x = s->y = 0;
150 }
151 
152 /**
153  * Draw character to screen
154  */
155 static void draw_char(AVCodecContext *avctx, int c)
156 {
157  AnsiContext *s = avctx->priv_data;
158  int fg = s->fg;
159  int bg = s->bg;
160 
161  if ((s->attributes & ATTR_BOLD))
162  fg += 8;
163  if ((s->attributes & ATTR_BLINK))
164  bg += 8;
165  if ((s->attributes & ATTR_REVERSE))
166  FFSWAP(int, fg, bg);
167  if ((s->attributes & ATTR_CONCEALED))
168  fg = bg;
169  ff_draw_pc_font(s->frame->data[0] + s->y * s->frame->linesize[0] + s->x,
170  s->frame->linesize[0], s->font, s->font_height, c, fg, bg);
171  s->x += FONT_WIDTH;
172  if (s->x >= avctx->width) {
173  s->x = 0;
174  hscroll(avctx);
175  }
176 }
177 
178 /**
179  * Execute ANSI escape code
180  * @return 0 on success, negative on error
181  */
182 static int execute_code(AVCodecContext * avctx, int c)
183 {
184  AnsiContext *s = avctx->priv_data;
185  int ret, i, width, height;
186  switch(c) {
187  case 'A': //Cursor Up
188  s->y = FFMAX(s->y - (s->nb_args > 0 ? s->args[0]*s->font_height : s->font_height), 0);
189  break;
190  case 'B': //Cursor Down
191  s->y = FFMIN(s->y + (s->nb_args > 0 ? s->args[0]*s->font_height : s->font_height), avctx->height - s->font_height);
192  break;
193  case 'C': //Cursor Right
194  s->x = FFMIN(s->x + (s->nb_args > 0 ? s->args[0]*FONT_WIDTH : FONT_WIDTH), avctx->width - FONT_WIDTH);
195  break;
196  case 'D': //Cursor Left
197  s->x = FFMAX(s->x - (s->nb_args > 0 ? s->args[0]*FONT_WIDTH : FONT_WIDTH), 0);
198  break;
199  case 'H': //Cursor Position
200  case 'f': //Horizontal and Vertical Position
201  s->y = s->nb_args > 0 ? av_clip((s->args[0] - 1)*s->font_height, 0, avctx->height - s->font_height) : 0;
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
206  if (s->nb_args < 2)
207  s->args[0] = DEFAULT_SCREEN_MODE;
208  width = avctx->width;
209  height = avctx->height;
210  switch(s->args[0]) {
211  case 0: case 1: case 4: case 5: case 13: case 19: //320x200 (25 rows)
212  s->font = avpriv_cga_font;
213  s->font_height = 8;
214  width = 40<<3;
215  height = 25<<3;
216  break;
217  case 2: case 3: //640x400 (25 rows)
218  s->font = avpriv_vga16_font;
219  s->font_height = 16;
220  width = 80<<3;
221  height = 25<<4;
222  break;
223  case 6: case 14: //640x200 (25 rows)
224  s->font = avpriv_cga_font;
225  s->font_height = 8;
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)
232  s->font = avpriv_cga_font;
233  s->font_height = 8;
234  width = 80<<3;
235  height = 43<<3;
236  break;
237  case 17: case 18: //640x480 (60 rows)
238  s->font = avpriv_cga_font;
239  s->font_height = 8;
240  width = 80<<3;
241  height = 60<<4;
242  break;
243  default:
244  avpriv_request_sample(avctx, "Unsupported screen mode");
245  }
246  if (width != avctx->width || height != avctx->height) {
247  av_frame_unref(s->frame);
248  avcodec_set_dimensions(avctx, width, height);
249  if ((ret = ff_get_buffer(avctx, s->frame,
251  return ret;
253  s->frame->palette_has_changed = 1;
254  set_palette((uint32_t *)s->frame->data[1]);
255  erase_screen(avctx);
256  } else if (c == 'l') {
257  erase_screen(avctx);
258  }
259  break;
260  case 'J': //Erase in Page
261  switch (s->args[0]) {
262  case 0:
263  erase_line(avctx, s->x, avctx->width - s->x);
264  if (s->y < avctx->height - s->font_height)
265  memset(s->frame->data[0] + (s->y + s->font_height)*s->frame->linesize[0],
266  DEFAULT_BG_COLOR, (avctx->height - s->y - s->font_height)*s->frame->linesize[0]);
267  break;
268  case 1:
269  erase_line(avctx, 0, s->x);
270  if (s->y > 0)
271  memset(s->frame->data[0], DEFAULT_BG_COLOR, s->y * s->frame->linesize[0]);
272  break;
273  case 2:
274  erase_screen(avctx);
275  }
276  break;
277  case 'K': //Erase in Line
278  switch(s->args[0]) {
279  case 0:
280  erase_line(avctx, s->x, avctx->width - s->x);
281  break;
282  case 1:
283  erase_line(avctx, 0, s->x);
284  break;
285  case 2:
286  erase_line(avctx, 0, avctx->width);
287  }
288  break;
289  case 'm': //Select Graphics Rendition
290  if (s->nb_args == 0) {
291  s->nb_args = 1;
292  s->args[0] = 0;
293  }
294  for (i = 0; i < FFMIN(s->nb_args, MAX_NB_ARGS); i++) {
295  int m = s->args[i];
296  if (m == 0) {
297  s->attributes = 0;
298  s->fg = DEFAULT_FG_COLOR;
299  s->bg = DEFAULT_BG_COLOR;
300  } else if (m == 1 || m == 2 || m == 4 || m == 5 || m == 7 || m == 8) {
301  s->attributes |= 1 << (m - 1);
302  } else if (m >= 30 && m <= 37) {
303  s->fg = ansi_to_cga[m - 30];
304  } else if (m == 38 && i + 2 < FFMIN(s->nb_args, MAX_NB_ARGS) && s->args[i + 1] == 5 && s->args[i + 2] < 256) {
305  int index = s->args[i + 2];
306  s->fg = index < 16 ? ansi_to_cga[index] : index;
307  i += 2;
308  } else if (m == 39) {
310  } else if (m >= 40 && m <= 47) {
311  s->bg = ansi_to_cga[m - 40];
312  } else if (m == 48 && i + 2 < FFMIN(s->nb_args, MAX_NB_ARGS) && s->args[i + 1] == 5 && s->args[i + 2] < 256) {
313  int index = s->args[i + 2];
314  s->bg = index < 16 ? ansi_to_cga[index] : index;
315  i += 2;
316  } else if (m == 49) {
318  } else {
319  avpriv_request_sample(avctx, "Unsupported rendition parameter");
320  }
321  }
322  break;
323  case 'n': //Device Status Report
324  case 'R': //report current line and column
325  /* ignore */
326  break;
327  case 's': //Save Cursor Position
328  s->sx = s->x;
329  s->sy = s->y;
330  break;
331  case 'u': //Restore Cursor Position
332  s->x = av_clip(s->sx, 0, avctx->width - FONT_WIDTH);
333  s->y = av_clip(s->sy, 0, avctx->height - s->font_height);
334  break;
335  default:
336  avpriv_request_sample(avctx, "Unknown escape code");
337  break;
338  }
339  return 0;
340 }
341 
342 static int decode_frame(AVCodecContext *avctx,
343  void *data, int *got_frame,
344  AVPacket *avpkt)
345 {
346  AnsiContext *s = avctx->priv_data;
347  uint8_t *buf = avpkt->data;
348  int buf_size = avpkt->size;
349  const uint8_t *buf_end = buf+buf_size;
350  int ret, i, count;
351 
352  if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
353  return ret;
354  if (!avctx->frame_number) {
355  for (i=0; i<avctx->height; i++)
356  memset(s->frame->data[0]+ i*s->frame->linesize[0], 0, avctx->width);
357  memset(s->frame->data[1], 0, AVPALETTE_SIZE);
358  }
359 
361  s->frame->palette_has_changed = 1;
362  set_palette((uint32_t *)s->frame->data[1]);
363  if (!s->first_frame) {
364  erase_screen(avctx);
365  s->first_frame = 1;
366  }
367 
368  while(buf < buf_end) {
369  switch(s->state) {
370  case STATE_NORMAL:
371  switch (buf[0]) {
372  case 0x00: //NUL
373  case 0x07: //BEL
374  case 0x1A: //SUB
375  /* ignore */
376  break;
377  case 0x08: //BS
378  s->x = FFMAX(s->x - 1, 0);
379  break;
380  case 0x09: //HT
381  i = s->x / FONT_WIDTH;
382  count = ((i + 8) & ~7) - i;
383  for (i = 0; i < count; i++)
384  draw_char(avctx, ' ');
385  break;
386  case 0x0A: //LF
387  hscroll(avctx);
388  case 0x0D: //CR
389  s->x = 0;
390  break;
391  case 0x0C: //FF
392  erase_screen(avctx);
393  break;
394  case 0x1B: //ESC
395  s->state = STATE_ESCAPE;
396  break;
397  default:
398  draw_char(avctx, buf[0]);
399  }
400  break;
401  case STATE_ESCAPE:
402  if (buf[0] == '[') {
403  s->state = STATE_CODE;
404  s->nb_args = 0;
405  s->args[0] = -1;
406  } else {
407  s->state = STATE_NORMAL;
408  draw_char(avctx, 0x1B);
409  continue;
410  }
411  break;
412  case STATE_CODE:
413  switch(buf[0]) {
414  case '0': case '1': case '2': case '3': case '4':
415  case '5': case '6': case '7': case '8': case '9':
416  if (s->nb_args < MAX_NB_ARGS)
417  s->args[s->nb_args] = FFMAX(s->args[s->nb_args], 0) * 10 + buf[0] - '0';
418  break;
419  case ';':
420  s->nb_args++;
421  if (s->nb_args < MAX_NB_ARGS)
422  s->args[s->nb_args] = 0;
423  break;
424  case 'M':
425  s->state = STATE_MUSIC_PREAMBLE;
426  break;
427  case '=': case '?':
428  /* ignore */
429  break;
430  default:
431  if (s->nb_args > MAX_NB_ARGS)
432  av_log(avctx, AV_LOG_WARNING, "args overflow (%i)\n", s->nb_args);
433  if (s->nb_args < MAX_NB_ARGS && s->args[s->nb_args] >= 0)
434  s->nb_args++;
435  if ((ret = execute_code(avctx, buf[0])) < 0)
436  return ret;
437  s->state = STATE_NORMAL;
438  }
439  break;
440  case STATE_MUSIC_PREAMBLE:
441  if (buf[0] == 0x0E || buf[0] == 0x1B)
442  s->state = STATE_NORMAL;
443  /* ignore music data */
444  break;
445  }
446  buf++;
447  }
448 
449  *got_frame = 1;
450  if ((ret = av_frame_ref(data, s->frame)) < 0)
451  return ret;
452  return buf_size;
453 }
454 
456 {
457  AnsiContext *s = avctx->priv_data;
458 
459  av_frame_free(&s->frame);
460  return 0;
461 }
462 
464  .name = "ansi",
465  .type = AVMEDIA_TYPE_VIDEO,
466  .id = AV_CODEC_ID_ANSI,
467  .priv_data_size = sizeof(AnsiContext),
468  .init = decode_init,
469  .close = decode_close,
470  .decode = decode_frame,
471  .capabilities = CODEC_CAP_DR1,
472  .long_name = NULL_IF_CONFIG_SMALL("ASCII/ANSI art"),
473 };
static void draw_char(AVCodecContext *avctx, int c)
Draw character to screen.
Definition: ansi.c:155
#define FONT_WIDTH
Font width.
Definition: ansi.c:46
const char * s
Definition: avisynth_c.h:668
int x
x cursor position (pixels)
Definition: ansi.c:55
#define ATTR_REVERSE
Reverse (mode 7)
Definition: ansi.c:39
This structure describes decoded (raw) audio or video data.
Definition: frame.h:76
int bg
background color
Definition: ansi.c:63
#define ATTR_CONCEALED
Concealed (mode 8)
Definition: ansi.c:40
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:35
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:154
int nb_args
number of arguments (may exceed MAX_NB_ARGS)
Definition: ansi.c:75
void avcodec_set_dimensions(AVCodecContext *s, int width, int height)
enum AVPixelFormat pix_fmt
Pixel format, see AV_PIX_FMT_xxx.
const uint8_t avpriv_vga16_font[4096]
#define DEFAULT_SCREEN_MODE
80x25
Definition: ansi.c:44
static void erase_screen(AVCodecContext *avctx)
Definition: ansi.c:143
static int execute_code(AVCodecContext *avctx, int c)
Execute ANSI escape code.
Definition: ansi.c:182
static void hscroll(AVCodecContext *avctx)
Definition: ansi.c:114
void void avpriv_request_sample(void *avc, const char *msg,...) av_printf_format(2
Log a generic warning message about a missing feature.
uint8_t
#define av_cold
Definition: attributes.h:78
8 bit with PIX_FMT_RGB32 palette
Definition: pixfmt.h:79
window constants for m
#define AVPALETTE_SIZE
Definition: pixfmt.h:33
#define b
Definition: input.c:42
enum AnsiContext::@34 state
#define CODEC_CAP_DR1
Codec uses get_buffer() for allocating buffers and supports custom allocators.
uint8_t * data
CGA/EGA/VGA ROM data.
#define DEFAULT_BG_COLOR
Definition: ansi.c:43
static av_cold int decode_close(AVCodecContext *avctx)
Definition: ansi.c:455
const uint8_t * font
font
Definition: ansi.c:59
int sy
saved y cursor position (pixels)
Definition: ansi.c:58
const uint8_t avpriv_cga_font[2048]
Definition: xga_font_data.c:29
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Spectrum Plot time data
const char * r
Definition: vf_curves.c:94
static void erase_line(AVCodecContext *avctx, int xoffset, int xlength)
Definition: ansi.c:134
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:246
const char * name
Name of the codec implementation.
#define FFMAX(a, b)
Definition: common.h:56
external API header
#define ATTR_BLINK
Blink/Bright-background (mode 5)
Definition: ansi.c:38
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...
FFT buffer for g
Definition: stft_peak.m:17
enum AVPictureType pict_type
Picture type of the frame.
Definition: frame.h:144
#define FFMIN(a, b)
Definition: common.h:58
ret
Definition: avfilter.c:821
int width
picture width / height.
static av_cold int decode_init(AVCodecContext *avctx)
Definition: ansi.c:78
#define ATTR_BOLD
Bold/Bright-foreground (mode 1)
Definition: ansi.c:35
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.
Definition: cga_data.c:46
static int width
Definition: tests/utils.c:158
int font_height
font height
Definition: ansi.c:60
int args[MAX_NB_ARGS]
Definition: ansi.c:74
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:101
main external API structure.
static void close(AVCodecParserContext *s)
Definition: h264_parser.c:375
int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags)
Get a buffer for a frame.
void * buf
Definition: avisynth_c.h:594
BYTE int const BYTE int int int height
Definition: avisynth_c.h:713
int index
Definition: gxfenc.c:89
synthesis window for stochastic i
int palette_has_changed
Tell user application that palette has changed from previous frame.
Definition: frame.h:280
int fg
foreground color
Definition: ansi.c:62
static const uint8_t ansi_to_cga[16]
map ansi color index to cga palette index
Definition: ansi.c:49
void av_frame_unref(AVFrame *frame)
Unreference all the buffers referenced by frame and reset the frame fields.
Definition: frame.c:330
#define GRAY(x)
static void set_palette(uint32_t *pal)
Definition: ansi.c:99
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Buffer references ownership and permissions
const uint32_t ff_cga_palette[16]
Definition: cga_data.c:30
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:95
static uint32_t state
Definition: trasher.c:27
int av_frame_ref(AVFrame *dst, AVFrame *src)
Setup a new reference to the data described by an given frame.
Definition: frame.c:228
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:87
int sx
saved x cursor position (pixels)
Definition: ansi.c:57
common internal api header.
common internal and external API header
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:108
static double c[64]
AVFrame * frame
Definition: ansi.c:54
int y
y cursor position (pixels)
Definition: ansi.c:56
static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
Definition: ansi.c:342
int first_frame
Definition: ansi.c:64
int frame_number
Frame counter, set by libavcodec.
void INT64 INT64 count
Definition: avisynth_c.h:594
#define MAX_NB_ARGS
Definition: ansi.c:73
#define DEFAULT_FG_COLOR
CGA color index.
Definition: ansi.c:42
static int decode(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt)
Definition: crystalhd.c:868
#define FFSWAP(type, a, b)
Definition: common.h:61
int attributes
attribute flags
Definition: ansi.c:61
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.
xlength
Definition: lab2_4.m:5
CGA/EGA/VGA ROM font data.
AVCodec ff_ansi_decoder
Definition: ansi.c:463
#define COLOR(x)