summaryrefslogtreecommitdiff
path: root/libavcodec/ansi.c
diff options
context:
space:
mode:
Diffstat (limited to 'libavcodec/ansi.c')
-rw-r--r--libavcodec/ansi.c85
1 files changed, 58 insertions, 27 deletions
diff --git a/libavcodec/ansi.c b/libavcodec/ansi.c
index c851d88891..68132dfb1c 100644
--- a/libavcodec/ansi.c
+++ b/libavcodec/ansi.c
@@ -2,20 +2,20 @@
* ASCII/ANSI art decoder
* Copyright (c) 2010 Peter Ross <pross@xvid.org>
*
- * This file is part of Libav.
+ * This file is part of FFmpeg.
*
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
@@ -27,6 +27,7 @@
#include "libavutil/common.h"
#include "libavutil/frame.h"
#include "libavutil/lfg.h"
+#include "libavutil/xga_font_data.h"
#include "avcodec.h"
#include "cga_data.h"
#include "internal.h"
@@ -60,6 +61,7 @@ typedef struct {
int attributes; /**< attribute flags */
int fg; /**< foreground color */
int bg; /**< background color */
+ int first_frame;
/* ansi parser state machine */
enum {
@@ -83,7 +85,7 @@ static av_cold int decode_init(AVCodecContext *avctx)
return AVERROR(ENOMEM);
/* defaults */
- s->font = ff_vga16_font;
+ s->font = avpriv_vga16_font;
s->font_height = 16;
s->fg = DEFAULT_FG_COLOR;
s->bg = DEFAULT_BG_COLOR;
@@ -94,12 +96,27 @@ static av_cold int decode_init(AVCodecContext *avctx)
return 0;
}
+static void set_palette(uint32_t *pal)
+{
+ int r, g, b;
+ memcpy(pal, ff_cga_palette, 16 * 4);
+ pal += 16;
+#define COLOR(x) ((x) * 40 + 55)
+ for (r = 0; r < 6; r++)
+ for (g = 0; g < 6; g++)
+ for (b = 0; b < 6; b++)
+ *pal++ = 0xFF000000 | (COLOR(r) << 16) | (COLOR(g) << 8) | COLOR(b);
+#define GRAY(x) ((x) * 10 + 8)
+ for (g = 0; g < 24; g++)
+ *pal++ = 0xFF000000 | (GRAY(g) << 16) | (GRAY(g) << 8) | GRAY(g);
+}
+
static void hscroll(AVCodecContext *avctx)
{
AnsiContext *s = avctx->priv_data;
int i;
- if (s->y < avctx->height - s->font_height) {
+ if (s->y <= avctx->height - 2*s->font_height) {
s->y += s->font_height;
return;
}
@@ -152,7 +169,7 @@ static void draw_char(AVCodecContext *avctx, int c)
ff_draw_pc_font(s->frame->data[0] + s->y * s->frame->linesize[0] + s->x,
s->frame->linesize[0], s->font, s->font_height, c, fg, bg);
s->x += FONT_WIDTH;
- if (s->x >= avctx->width) {
+ if (s->x > avctx->width - FONT_WIDTH) {
s->x = 0;
hscroll(avctx);
}
@@ -188,21 +205,23 @@ static int execute_code(AVCodecContext * avctx, int c)
case 'l': //reset screen mode
if (s->nb_args < 2)
s->args[0] = DEFAULT_SCREEN_MODE;
+ width = avctx->width;
+ height = avctx->height;
switch(s->args[0]) {
case 0: case 1: case 4: case 5: case 13: case 19: //320x200 (25 rows)
- s->font = ff_cga_font;
+ s->font = avpriv_cga_font;
s->font_height = 8;
width = 40<<3;
height = 25<<3;
break;
case 2: case 3: //640x400 (25 rows)
- s->font = ff_vga16_font;
+ s->font = avpriv_vga16_font;
s->font_height = 16;
width = 80<<3;
height = 25<<4;
break;
case 6: case 14: //640x200 (25 rows)
- s->font = ff_cga_font;
+ s->font = avpriv_cga_font;
s->font_height = 8;
width = 80<<3;
height = 25<<3;
@@ -210,13 +229,13 @@ static int execute_code(AVCodecContext * avctx, int c)
case 7: //set line wrapping
break;
case 15: case 16: //640x350 (43 rows)
- s->font = ff_cga_font;
+ s->font = avpriv_cga_font;
s->font_height = 8;
width = 80<<3;
height = 43<<3;
break;
case 17: case 18: //640x480 (60 rows)
- s->font = ff_cga_font;
+ s->font = avpriv_cga_font;
s->font_height = 8;
width = 80<<3;
height = 60<<4;
@@ -224,17 +243,17 @@ static int execute_code(AVCodecContext * avctx, int c)
default:
avpriv_request_sample(avctx, "Unsupported screen mode");
}
+ s->x = av_clip(s->x, 0, width - FONT_WIDTH);
+ s->y = av_clip(s->y, 0, height - s->font_height);
if (width != avctx->width || height != avctx->height) {
av_frame_unref(s->frame);
avcodec_set_dimensions(avctx, width, height);
- ret = ff_get_buffer(avctx, s->frame, AV_GET_BUFFER_FLAG_REF);
- if (ret < 0) {
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_get_buffer(avctx, s->frame,
+ AV_GET_BUFFER_FLAG_REF)) < 0)
return ret;
- }
s->frame->pict_type = AV_PICTURE_TYPE_I;
s->frame->palette_has_changed = 1;
- memcpy(s->frame->data[1], ff_cga_palette, 16 * 4);
+ set_palette((uint32_t *)s->frame->data[1]);
erase_screen(avctx);
} else if (c == 'l') {
erase_screen(avctx);
@@ -282,12 +301,20 @@ static int execute_code(AVCodecContext * avctx, int c)
s->bg = DEFAULT_BG_COLOR;
} else if (m == 1 || m == 2 || m == 4 || m == 5 || m == 7 || m == 8) {
s->attributes |= 1 << (m - 1);
- } else if (m >= 30 && m <= 38) {
+ } else if (m >= 30 && m <= 37) {
s->fg = ansi_to_cga[m - 30];
+ } else if (m == 38 && i + 2 < FFMIN(s->nb_args, MAX_NB_ARGS) && s->args[i + 1] == 5 && s->args[i + 2] < 256) {
+ int index = s->args[i + 2];
+ s->fg = index < 16 ? ansi_to_cga[index] : index;
+ i += 2;
} else if (m == 39) {
s->fg = ansi_to_cga[DEFAULT_FG_COLOR];
} else if (m >= 40 && m <= 47) {
s->bg = ansi_to_cga[m - 40];
+ } else if (m == 48 && i + 2 < FFMIN(s->nb_args, MAX_NB_ARGS) && s->args[i + 1] == 5 && s->args[i + 2] < 256) {
+ int index = s->args[i + 2];
+ s->bg = index < 16 ? ansi_to_cga[index] : index;
+ i += 2;
} else if (m == 49) {
s->fg = ansi_to_cga[DEFAULT_BG_COLOR];
} else {
@@ -311,6 +338,8 @@ static int execute_code(AVCodecContext * avctx, int c)
avpriv_request_sample(avctx, "Unknown escape code");
break;
}
+ s->x = av_clip(s->x, 0, avctx->width - FONT_WIDTH);
+ s->y = av_clip(s->y, 0, avctx->height - s->font_height);
return 0;
}
@@ -324,19 +353,21 @@ static int decode_frame(AVCodecContext *avctx,
const uint8_t *buf_end = buf+buf_size;
int ret, i, count;
- ret = ff_reget_buffer(avctx, s->frame);
- if (ret < 0){
- av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+ if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
return ret;
- }
if (!avctx->frame_number) {
- memset(s->frame->data[0], 0, avctx->height * FFABS(s->frame->linesize[0]));
+ for (i=0; i<avctx->height; i++)
+ memset(s->frame->data[0]+ i*s->frame->linesize[0], 0, avctx->width);
memset(s->frame->data[1], 0, AVPALETTE_SIZE);
}
s->frame->pict_type = AV_PICTURE_TYPE_I;
s->frame->palette_has_changed = 1;
- memcpy(s->frame->data[1], ff_cga_palette, 16 * 4);
+ set_palette((uint32_t *)s->frame->data[1]);
+ if (!s->first_frame) {
+ erase_screen(avctx);
+ s->first_frame = 1;
+ }
while(buf < buf_end) {
switch(s->state) {
@@ -375,7 +406,7 @@ static int decode_frame(AVCodecContext *avctx,
if (buf[0] == '[') {
s->state = STATE_CODE;
s->nb_args = 0;
- s->args[0] = 0;
+ s->args[0] = -1;
} else {
s->state = STATE_NORMAL;
draw_char(avctx, 0x1B);
@@ -387,7 +418,7 @@ static int decode_frame(AVCodecContext *avctx,
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if (s->nb_args < MAX_NB_ARGS)
- s->args[s->nb_args] = s->args[s->nb_args] * 10 + buf[0] - '0';
+ s->args[s->nb_args] = FFMAX(s->args[s->nb_args], 0) * 10 + buf[0] - '0';
break;
case ';':
s->nb_args++;
@@ -403,7 +434,7 @@ static int decode_frame(AVCodecContext *avctx,
default:
if (s->nb_args > MAX_NB_ARGS)
av_log(avctx, AV_LOG_WARNING, "args overflow (%i)\n", s->nb_args);
- if (s->nb_args < MAX_NB_ARGS && s->args[s->nb_args])
+ if (s->nb_args < MAX_NB_ARGS && s->args[s->nb_args] >= 0)
s->nb_args++;
if ((ret = execute_code(avctx, buf[0])) < 0)
return ret;