yading@10
|
1 /*
|
yading@10
|
2 * ASCII/ANSI art decoder
|
yading@10
|
3 * Copyright (c) 2010 Peter Ross <pross@xvid.org>
|
yading@10
|
4 *
|
yading@10
|
5 * This file is part of FFmpeg.
|
yading@10
|
6 *
|
yading@10
|
7 * FFmpeg is free software; you can redistribute it and/or
|
yading@10
|
8 * modify it under the terms of the GNU Lesser General Public
|
yading@10
|
9 * License as published by the Free Software Foundation; either
|
yading@10
|
10 * version 2.1 of the License, or (at your option) any later version.
|
yading@10
|
11 *
|
yading@10
|
12 * FFmpeg is distributed in the hope that it will be useful,
|
yading@10
|
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
yading@10
|
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
yading@10
|
15 * Lesser General Public License for more details.
|
yading@10
|
16 *
|
yading@10
|
17 * You should have received a copy of the GNU Lesser General Public
|
yading@10
|
18 * License along with FFmpeg; if not, write to the Free Software
|
yading@10
|
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
yading@10
|
20 */
|
yading@10
|
21
|
yading@10
|
22 /**
|
yading@10
|
23 * @file
|
yading@10
|
24 * ASCII/ANSI art decoder
|
yading@10
|
25 */
|
yading@10
|
26
|
yading@10
|
27 #include "libavutil/common.h"
|
yading@10
|
28 #include "libavutil/frame.h"
|
yading@10
|
29 #include "libavutil/lfg.h"
|
yading@10
|
30 #include "libavutil/xga_font_data.h"
|
yading@10
|
31 #include "avcodec.h"
|
yading@10
|
32 #include "cga_data.h"
|
yading@10
|
33 #include "internal.h"
|
yading@10
|
34
|
yading@10
|
35 #define ATTR_BOLD 0x01 /**< Bold/Bright-foreground (mode 1) */
|
yading@10
|
36 #define ATTR_FAINT 0x02 /**< Faint (mode 2) */
|
yading@10
|
37 #define ATTR_UNDERLINE 0x08 /**< Underline (mode 4) */
|
yading@10
|
38 #define ATTR_BLINK 0x10 /**< Blink/Bright-background (mode 5) */
|
yading@10
|
39 #define ATTR_REVERSE 0x40 /**< Reverse (mode 7) */
|
yading@10
|
40 #define ATTR_CONCEALED 0x80 /**< Concealed (mode 8) */
|
yading@10
|
41
|
yading@10
|
42 #define DEFAULT_FG_COLOR 7 /**< CGA color index */
|
yading@10
|
43 #define DEFAULT_BG_COLOR 0
|
yading@10
|
44 #define DEFAULT_SCREEN_MODE 3 /**< 80x25 */
|
yading@10
|
45
|
yading@10
|
46 #define FONT_WIDTH 8 /**< Font width */
|
yading@10
|
47
|
yading@10
|
48 /** map ansi color index to cga palette index */
|
yading@10
|
49 static const uint8_t ansi_to_cga[16] = {
|
yading@10
|
50 0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15
|
yading@10
|
51 };
|
yading@10
|
52
|
yading@10
|
53 typedef struct {
|
yading@10
|
54 AVFrame *frame;
|
yading@10
|
55 int x; /**< x cursor position (pixels) */
|
yading@10
|
56 int y; /**< y cursor position (pixels) */
|
yading@10
|
57 int sx; /**< saved x cursor position (pixels) */
|
yading@10
|
58 int sy; /**< saved y cursor position (pixels) */
|
yading@10
|
59 const uint8_t* font; /**< font */
|
yading@10
|
60 int font_height; /**< font height */
|
yading@10
|
61 int attributes; /**< attribute flags */
|
yading@10
|
62 int fg; /**< foreground color */
|
yading@10
|
63 int bg; /**< background color */
|
yading@10
|
64 int first_frame;
|
yading@10
|
65
|
yading@10
|
66 /* ansi parser state machine */
|
yading@10
|
67 enum {
|
yading@10
|
68 STATE_NORMAL = 0,
|
yading@10
|
69 STATE_ESCAPE,
|
yading@10
|
70 STATE_CODE,
|
yading@10
|
71 STATE_MUSIC_PREAMBLE
|
yading@10
|
72 } state;
|
yading@10
|
73 #define MAX_NB_ARGS 4
|
yading@10
|
74 int args[MAX_NB_ARGS];
|
yading@10
|
75 int nb_args; /**< number of arguments (may exceed MAX_NB_ARGS) */
|
yading@10
|
76 } AnsiContext;
|
yading@10
|
77
|
yading@10
|
78 static av_cold int decode_init(AVCodecContext *avctx)
|
yading@10
|
79 {
|
yading@10
|
80 AnsiContext *s = avctx->priv_data;
|
yading@10
|
81 avctx->pix_fmt = AV_PIX_FMT_PAL8;
|
yading@10
|
82
|
yading@10
|
83 s->frame = av_frame_alloc();
|
yading@10
|
84 if (!s->frame)
|
yading@10
|
85 return AVERROR(ENOMEM);
|
yading@10
|
86
|
yading@10
|
87 /* defaults */
|
yading@10
|
88 s->font = avpriv_vga16_font;
|
yading@10
|
89 s->font_height = 16;
|
yading@10
|
90 s->fg = DEFAULT_FG_COLOR;
|
yading@10
|
91 s->bg = DEFAULT_BG_COLOR;
|
yading@10
|
92
|
yading@10
|
93 if (!avctx->width || !avctx->height)
|
yading@10
|
94 avcodec_set_dimensions(avctx, 80<<3, 25<<4);
|
yading@10
|
95
|
yading@10
|
96 return 0;
|
yading@10
|
97 }
|
yading@10
|
98
|
yading@10
|
99 static void set_palette(uint32_t *pal)
|
yading@10
|
100 {
|
yading@10
|
101 int r, g, b;
|
yading@10
|
102 memcpy(pal, ff_cga_palette, 16 * 4);
|
yading@10
|
103 pal += 16;
|
yading@10
|
104 #define COLOR(x) ((x) * 40 + 55)
|
yading@10
|
105 for (r = 0; r < 6; r++)
|
yading@10
|
106 for (g = 0; g < 6; g++)
|
yading@10
|
107 for (b = 0; b < 6; b++)
|
yading@10
|
108 *pal++ = 0xFF000000 | (COLOR(r) << 16) | (COLOR(g) << 8) | COLOR(b);
|
yading@10
|
109 #define GRAY(x) ((x) * 10 + 8)
|
yading@10
|
110 for (g = 0; g < 24; g++)
|
yading@10
|
111 *pal++ = 0xFF000000 | (GRAY(g) << 16) | (GRAY(g) << 8) | GRAY(g);
|
yading@10
|
112 }
|
yading@10
|
113
|
yading@10
|
114 static void hscroll(AVCodecContext *avctx)
|
yading@10
|
115 {
|
yading@10
|
116 AnsiContext *s = avctx->priv_data;
|
yading@10
|
117 int i;
|
yading@10
|
118
|
yading@10
|
119 if (s->y < avctx->height - s->font_height) {
|
yading@10
|
120 s->y += s->font_height;
|
yading@10
|
121 return;
|
yading@10
|
122 }
|
yading@10
|
123
|
yading@10
|
124 i = 0;
|
yading@10
|
125 for (; i < avctx->height - s->font_height; i++)
|
yading@10
|
126 memcpy(s->frame->data[0] + i * s->frame->linesize[0],
|
yading@10
|
127 s->frame->data[0] + (i + s->font_height) * s->frame->linesize[0],
|
yading@10
|
128 avctx->width);
|
yading@10
|
129 for (; i < avctx->height; i++)
|
yading@10
|
130 memset(s->frame->data[0] + i * s->frame->linesize[0],
|
yading@10
|
131 DEFAULT_BG_COLOR, avctx->width);
|
yading@10
|
132 }
|
yading@10
|
133
|
yading@10
|
134 static void erase_line(AVCodecContext * avctx, int xoffset, int xlength)
|
yading@10
|
135 {
|
yading@10
|
136 AnsiContext *s = avctx->priv_data;
|
yading@10
|
137 int i;
|
yading@10
|
138 for (i = 0; i < s->font_height; i++)
|
yading@10
|
139 memset(s->frame->data[0] + (s->y + i)*s->frame->linesize[0] + xoffset,
|
yading@10
|
140 DEFAULT_BG_COLOR, xlength);
|
yading@10
|
141 }
|
yading@10
|
142
|
yading@10
|
143 static void erase_screen(AVCodecContext *avctx)
|
yading@10
|
144 {
|
yading@10
|
145 AnsiContext *s = avctx->priv_data;
|
yading@10
|
146 int i;
|
yading@10
|
147 for (i = 0; i < avctx->height; i++)
|
yading@10
|
148 memset(s->frame->data[0] + i * s->frame->linesize[0], DEFAULT_BG_COLOR, avctx->width);
|
yading@10
|
149 s->x = s->y = 0;
|
yading@10
|
150 }
|
yading@10
|
151
|
yading@10
|
152 /**
|
yading@10
|
153 * Draw character to screen
|
yading@10
|
154 */
|
yading@10
|
155 static void draw_char(AVCodecContext *avctx, int c)
|
yading@10
|
156 {
|
yading@10
|
157 AnsiContext *s = avctx->priv_data;
|
yading@10
|
158 int fg = s->fg;
|
yading@10
|
159 int bg = s->bg;
|
yading@10
|
160
|
yading@10
|
161 if ((s->attributes & ATTR_BOLD))
|
yading@10
|
162 fg += 8;
|
yading@10
|
163 if ((s->attributes & ATTR_BLINK))
|
yading@10
|
164 bg += 8;
|
yading@10
|
165 if ((s->attributes & ATTR_REVERSE))
|
yading@10
|
166 FFSWAP(int, fg, bg);
|
yading@10
|
167 if ((s->attributes & ATTR_CONCEALED))
|
yading@10
|
168 fg = bg;
|
yading@10
|
169 ff_draw_pc_font(s->frame->data[0] + s->y * s->frame->linesize[0] + s->x,
|
yading@10
|
170 s->frame->linesize[0], s->font, s->font_height, c, fg, bg);
|
yading@10
|
171 s->x += FONT_WIDTH;
|
yading@10
|
172 if (s->x >= avctx->width) {
|
yading@10
|
173 s->x = 0;
|
yading@10
|
174 hscroll(avctx);
|
yading@10
|
175 }
|
yading@10
|
176 }
|
yading@10
|
177
|
yading@10
|
178 /**
|
yading@10
|
179 * Execute ANSI escape code
|
yading@10
|
180 * @return 0 on success, negative on error
|
yading@10
|
181 */
|
yading@10
|
182 static int execute_code(AVCodecContext * avctx, int c)
|
yading@10
|
183 {
|
yading@10
|
184 AnsiContext *s = avctx->priv_data;
|
yading@10
|
185 int ret, i, width, height;
|
yading@10
|
186 switch(c) {
|
yading@10
|
187 case 'A': //Cursor Up
|
yading@10
|
188 s->y = FFMAX(s->y - (s->nb_args > 0 ? s->args[0]*s->font_height : s->font_height), 0);
|
yading@10
|
189 break;
|
yading@10
|
190 case 'B': //Cursor Down
|
yading@10
|
191 s->y = FFMIN(s->y + (s->nb_args > 0 ? s->args[0]*s->font_height : s->font_height), avctx->height - s->font_height);
|
yading@10
|
192 break;
|
yading@10
|
193 case 'C': //Cursor Right
|
yading@10
|
194 s->x = FFMIN(s->x + (s->nb_args > 0 ? s->args[0]*FONT_WIDTH : FONT_WIDTH), avctx->width - FONT_WIDTH);
|
yading@10
|
195 break;
|
yading@10
|
196 case 'D': //Cursor Left
|
yading@10
|
197 s->x = FFMAX(s->x - (s->nb_args > 0 ? s->args[0]*FONT_WIDTH : FONT_WIDTH), 0);
|
yading@10
|
198 break;
|
yading@10
|
199 case 'H': //Cursor Position
|
yading@10
|
200 case 'f': //Horizontal and Vertical Position
|
yading@10
|
201 s->y = s->nb_args > 0 ? av_clip((s->args[0] - 1)*s->font_height, 0, avctx->height - s->font_height) : 0;
|
yading@10
|
202 s->x = s->nb_args > 1 ? av_clip((s->args[1] - 1)*FONT_WIDTH, 0, avctx->width - FONT_WIDTH) : 0;
|
yading@10
|
203 break;
|
yading@10
|
204 case 'h': //set creen mode
|
yading@10
|
205 case 'l': //reset screen mode
|
yading@10
|
206 if (s->nb_args < 2)
|
yading@10
|
207 s->args[0] = DEFAULT_SCREEN_MODE;
|
yading@10
|
208 width = avctx->width;
|
yading@10
|
209 height = avctx->height;
|
yading@10
|
210 switch(s->args[0]) {
|
yading@10
|
211 case 0: case 1: case 4: case 5: case 13: case 19: //320x200 (25 rows)
|
yading@10
|
212 s->font = avpriv_cga_font;
|
yading@10
|
213 s->font_height = 8;
|
yading@10
|
214 width = 40<<3;
|
yading@10
|
215 height = 25<<3;
|
yading@10
|
216 break;
|
yading@10
|
217 case 2: case 3: //640x400 (25 rows)
|
yading@10
|
218 s->font = avpriv_vga16_font;
|
yading@10
|
219 s->font_height = 16;
|
yading@10
|
220 width = 80<<3;
|
yading@10
|
221 height = 25<<4;
|
yading@10
|
222 break;
|
yading@10
|
223 case 6: case 14: //640x200 (25 rows)
|
yading@10
|
224 s->font = avpriv_cga_font;
|
yading@10
|
225 s->font_height = 8;
|
yading@10
|
226 width = 80<<3;
|
yading@10
|
227 height = 25<<3;
|
yading@10
|
228 break;
|
yading@10
|
229 case 7: //set line wrapping
|
yading@10
|
230 break;
|
yading@10
|
231 case 15: case 16: //640x350 (43 rows)
|
yading@10
|
232 s->font = avpriv_cga_font;
|
yading@10
|
233 s->font_height = 8;
|
yading@10
|
234 width = 80<<3;
|
yading@10
|
235 height = 43<<3;
|
yading@10
|
236 break;
|
yading@10
|
237 case 17: case 18: //640x480 (60 rows)
|
yading@10
|
238 s->font = avpriv_cga_font;
|
yading@10
|
239 s->font_height = 8;
|
yading@10
|
240 width = 80<<3;
|
yading@10
|
241 height = 60<<4;
|
yading@10
|
242 break;
|
yading@10
|
243 default:
|
yading@10
|
244 avpriv_request_sample(avctx, "Unsupported screen mode");
|
yading@10
|
245 }
|
yading@10
|
246 if (width != avctx->width || height != avctx->height) {
|
yading@10
|
247 av_frame_unref(s->frame);
|
yading@10
|
248 avcodec_set_dimensions(avctx, width, height);
|
yading@10
|
249 if ((ret = ff_get_buffer(avctx, s->frame,
|
yading@10
|
250 AV_GET_BUFFER_FLAG_REF)) < 0)
|
yading@10
|
251 return ret;
|
yading@10
|
252 s->frame->pict_type = AV_PICTURE_TYPE_I;
|
yading@10
|
253 s->frame->palette_has_changed = 1;
|
yading@10
|
254 set_palette((uint32_t *)s->frame->data[1]);
|
yading@10
|
255 erase_screen(avctx);
|
yading@10
|
256 } else if (c == 'l') {
|
yading@10
|
257 erase_screen(avctx);
|
yading@10
|
258 }
|
yading@10
|
259 break;
|
yading@10
|
260 case 'J': //Erase in Page
|
yading@10
|
261 switch (s->args[0]) {
|
yading@10
|
262 case 0:
|
yading@10
|
263 erase_line(avctx, s->x, avctx->width - s->x);
|
yading@10
|
264 if (s->y < avctx->height - s->font_height)
|
yading@10
|
265 memset(s->frame->data[0] + (s->y + s->font_height)*s->frame->linesize[0],
|
yading@10
|
266 DEFAULT_BG_COLOR, (avctx->height - s->y - s->font_height)*s->frame->linesize[0]);
|
yading@10
|
267 break;
|
yading@10
|
268 case 1:
|
yading@10
|
269 erase_line(avctx, 0, s->x);
|
yading@10
|
270 if (s->y > 0)
|
yading@10
|
271 memset(s->frame->data[0], DEFAULT_BG_COLOR, s->y * s->frame->linesize[0]);
|
yading@10
|
272 break;
|
yading@10
|
273 case 2:
|
yading@10
|
274 erase_screen(avctx);
|
yading@10
|
275 }
|
yading@10
|
276 break;
|
yading@10
|
277 case 'K': //Erase in Line
|
yading@10
|
278 switch(s->args[0]) {
|
yading@10
|
279 case 0:
|
yading@10
|
280 erase_line(avctx, s->x, avctx->width - s->x);
|
yading@10
|
281 break;
|
yading@10
|
282 case 1:
|
yading@10
|
283 erase_line(avctx, 0, s->x);
|
yading@10
|
284 break;
|
yading@10
|
285 case 2:
|
yading@10
|
286 erase_line(avctx, 0, avctx->width);
|
yading@10
|
287 }
|
yading@10
|
288 break;
|
yading@10
|
289 case 'm': //Select Graphics Rendition
|
yading@10
|
290 if (s->nb_args == 0) {
|
yading@10
|
291 s->nb_args = 1;
|
yading@10
|
292 s->args[0] = 0;
|
yading@10
|
293 }
|
yading@10
|
294 for (i = 0; i < FFMIN(s->nb_args, MAX_NB_ARGS); i++) {
|
yading@10
|
295 int m = s->args[i];
|
yading@10
|
296 if (m == 0) {
|
yading@10
|
297 s->attributes = 0;
|
yading@10
|
298 s->fg = DEFAULT_FG_COLOR;
|
yading@10
|
299 s->bg = DEFAULT_BG_COLOR;
|
yading@10
|
300 } else if (m == 1 || m == 2 || m == 4 || m == 5 || m == 7 || m == 8) {
|
yading@10
|
301 s->attributes |= 1 << (m - 1);
|
yading@10
|
302 } else if (m >= 30 && m <= 37) {
|
yading@10
|
303 s->fg = ansi_to_cga[m - 30];
|
yading@10
|
304 } else if (m == 38 && i + 2 < FFMIN(s->nb_args, MAX_NB_ARGS) && s->args[i + 1] == 5 && s->args[i + 2] < 256) {
|
yading@10
|
305 int index = s->args[i + 2];
|
yading@10
|
306 s->fg = index < 16 ? ansi_to_cga[index] : index;
|
yading@10
|
307 i += 2;
|
yading@10
|
308 } else if (m == 39) {
|
yading@10
|
309 s->fg = ansi_to_cga[DEFAULT_FG_COLOR];
|
yading@10
|
310 } else if (m >= 40 && m <= 47) {
|
yading@10
|
311 s->bg = ansi_to_cga[m - 40];
|
yading@10
|
312 } else if (m == 48 && i + 2 < FFMIN(s->nb_args, MAX_NB_ARGS) && s->args[i + 1] == 5 && s->args[i + 2] < 256) {
|
yading@10
|
313 int index = s->args[i + 2];
|
yading@10
|
314 s->bg = index < 16 ? ansi_to_cga[index] : index;
|
yading@10
|
315 i += 2;
|
yading@10
|
316 } else if (m == 49) {
|
yading@10
|
317 s->fg = ansi_to_cga[DEFAULT_BG_COLOR];
|
yading@10
|
318 } else {
|
yading@10
|
319 avpriv_request_sample(avctx, "Unsupported rendition parameter");
|
yading@10
|
320 }
|
yading@10
|
321 }
|
yading@10
|
322 break;
|
yading@10
|
323 case 'n': //Device Status Report
|
yading@10
|
324 case 'R': //report current line and column
|
yading@10
|
325 /* ignore */
|
yading@10
|
326 break;
|
yading@10
|
327 case 's': //Save Cursor Position
|
yading@10
|
328 s->sx = s->x;
|
yading@10
|
329 s->sy = s->y;
|
yading@10
|
330 break;
|
yading@10
|
331 case 'u': //Restore Cursor Position
|
yading@10
|
332 s->x = av_clip(s->sx, 0, avctx->width - FONT_WIDTH);
|
yading@10
|
333 s->y = av_clip(s->sy, 0, avctx->height - s->font_height);
|
yading@10
|
334 break;
|
yading@10
|
335 default:
|
yading@10
|
336 avpriv_request_sample(avctx, "Unknown escape code");
|
yading@10
|
337 break;
|
yading@10
|
338 }
|
yading@10
|
339 return 0;
|
yading@10
|
340 }
|
yading@10
|
341
|
yading@10
|
342 static int decode_frame(AVCodecContext *avctx,
|
yading@10
|
343 void *data, int *got_frame,
|
yading@10
|
344 AVPacket *avpkt)
|
yading@10
|
345 {
|
yading@10
|
346 AnsiContext *s = avctx->priv_data;
|
yading@10
|
347 uint8_t *buf = avpkt->data;
|
yading@10
|
348 int buf_size = avpkt->size;
|
yading@10
|
349 const uint8_t *buf_end = buf+buf_size;
|
yading@10
|
350 int ret, i, count;
|
yading@10
|
351
|
yading@10
|
352 if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
|
yading@10
|
353 return ret;
|
yading@10
|
354 if (!avctx->frame_number) {
|
yading@10
|
355 for (i=0; i<avctx->height; i++)
|
yading@10
|
356 memset(s->frame->data[0]+ i*s->frame->linesize[0], 0, avctx->width);
|
yading@10
|
357 memset(s->frame->data[1], 0, AVPALETTE_SIZE);
|
yading@10
|
358 }
|
yading@10
|
359
|
yading@10
|
360 s->frame->pict_type = AV_PICTURE_TYPE_I;
|
yading@10
|
361 s->frame->palette_has_changed = 1;
|
yading@10
|
362 set_palette((uint32_t *)s->frame->data[1]);
|
yading@10
|
363 if (!s->first_frame) {
|
yading@10
|
364 erase_screen(avctx);
|
yading@10
|
365 s->first_frame = 1;
|
yading@10
|
366 }
|
yading@10
|
367
|
yading@10
|
368 while(buf < buf_end) {
|
yading@10
|
369 switch(s->state) {
|
yading@10
|
370 case STATE_NORMAL:
|
yading@10
|
371 switch (buf[0]) {
|
yading@10
|
372 case 0x00: //NUL
|
yading@10
|
373 case 0x07: //BEL
|
yading@10
|
374 case 0x1A: //SUB
|
yading@10
|
375 /* ignore */
|
yading@10
|
376 break;
|
yading@10
|
377 case 0x08: //BS
|
yading@10
|
378 s->x = FFMAX(s->x - 1, 0);
|
yading@10
|
379 break;
|
yading@10
|
380 case 0x09: //HT
|
yading@10
|
381 i = s->x / FONT_WIDTH;
|
yading@10
|
382 count = ((i + 8) & ~7) - i;
|
yading@10
|
383 for (i = 0; i < count; i++)
|
yading@10
|
384 draw_char(avctx, ' ');
|
yading@10
|
385 break;
|
yading@10
|
386 case 0x0A: //LF
|
yading@10
|
387 hscroll(avctx);
|
yading@10
|
388 case 0x0D: //CR
|
yading@10
|
389 s->x = 0;
|
yading@10
|
390 break;
|
yading@10
|
391 case 0x0C: //FF
|
yading@10
|
392 erase_screen(avctx);
|
yading@10
|
393 break;
|
yading@10
|
394 case 0x1B: //ESC
|
yading@10
|
395 s->state = STATE_ESCAPE;
|
yading@10
|
396 break;
|
yading@10
|
397 default:
|
yading@10
|
398 draw_char(avctx, buf[0]);
|
yading@10
|
399 }
|
yading@10
|
400 break;
|
yading@10
|
401 case STATE_ESCAPE:
|
yading@10
|
402 if (buf[0] == '[') {
|
yading@10
|
403 s->state = STATE_CODE;
|
yading@10
|
404 s->nb_args = 0;
|
yading@10
|
405 s->args[0] = -1;
|
yading@10
|
406 } else {
|
yading@10
|
407 s->state = STATE_NORMAL;
|
yading@10
|
408 draw_char(avctx, 0x1B);
|
yading@10
|
409 continue;
|
yading@10
|
410 }
|
yading@10
|
411 break;
|
yading@10
|
412 case STATE_CODE:
|
yading@10
|
413 switch(buf[0]) {
|
yading@10
|
414 case '0': case '1': case '2': case '3': case '4':
|
yading@10
|
415 case '5': case '6': case '7': case '8': case '9':
|
yading@10
|
416 if (s->nb_args < MAX_NB_ARGS)
|
yading@10
|
417 s->args[s->nb_args] = FFMAX(s->args[s->nb_args], 0) * 10 + buf[0] - '0';
|
yading@10
|
418 break;
|
yading@10
|
419 case ';':
|
yading@10
|
420 s->nb_args++;
|
yading@10
|
421 if (s->nb_args < MAX_NB_ARGS)
|
yading@10
|
422 s->args[s->nb_args] = 0;
|
yading@10
|
423 break;
|
yading@10
|
424 case 'M':
|
yading@10
|
425 s->state = STATE_MUSIC_PREAMBLE;
|
yading@10
|
426 break;
|
yading@10
|
427 case '=': case '?':
|
yading@10
|
428 /* ignore */
|
yading@10
|
429 break;
|
yading@10
|
430 default:
|
yading@10
|
431 if (s->nb_args > MAX_NB_ARGS)
|
yading@10
|
432 av_log(avctx, AV_LOG_WARNING, "args overflow (%i)\n", s->nb_args);
|
yading@10
|
433 if (s->nb_args < MAX_NB_ARGS && s->args[s->nb_args] >= 0)
|
yading@10
|
434 s->nb_args++;
|
yading@10
|
435 if ((ret = execute_code(avctx, buf[0])) < 0)
|
yading@10
|
436 return ret;
|
yading@10
|
437 s->state = STATE_NORMAL;
|
yading@10
|
438 }
|
yading@10
|
439 break;
|
yading@10
|
440 case STATE_MUSIC_PREAMBLE:
|
yading@10
|
441 if (buf[0] == 0x0E || buf[0] == 0x1B)
|
yading@10
|
442 s->state = STATE_NORMAL;
|
yading@10
|
443 /* ignore music data */
|
yading@10
|
444 break;
|
yading@10
|
445 }
|
yading@10
|
446 buf++;
|
yading@10
|
447 }
|
yading@10
|
448
|
yading@10
|
449 *got_frame = 1;
|
yading@10
|
450 if ((ret = av_frame_ref(data, s->frame)) < 0)
|
yading@10
|
451 return ret;
|
yading@10
|
452 return buf_size;
|
yading@10
|
453 }
|
yading@10
|
454
|
yading@10
|
455 static av_cold int decode_close(AVCodecContext *avctx)
|
yading@10
|
456 {
|
yading@10
|
457 AnsiContext *s = avctx->priv_data;
|
yading@10
|
458
|
yading@10
|
459 av_frame_free(&s->frame);
|
yading@10
|
460 return 0;
|
yading@10
|
461 }
|
yading@10
|
462
|
yading@10
|
463 AVCodec ff_ansi_decoder = {
|
yading@10
|
464 .name = "ansi",
|
yading@10
|
465 .type = AVMEDIA_TYPE_VIDEO,
|
yading@10
|
466 .id = AV_CODEC_ID_ANSI,
|
yading@10
|
467 .priv_data_size = sizeof(AnsiContext),
|
yading@10
|
468 .init = decode_init,
|
yading@10
|
469 .close = decode_close,
|
yading@10
|
470 .decode = decode_frame,
|
yading@10
|
471 .capabilities = CODEC_CAP_DR1,
|
yading@10
|
472 .long_name = NULL_IF_CONFIG_SMALL("ASCII/ANSI art"),
|
yading@10
|
473 };
|