avcodec/aacdec_fixed: use 64bit to avoid overflow in rounding in apply_dependent_coup...
[ffmpeg.git] / libavcodec / ansi.c
index e705da6..f1fafab 100644 (file)
@@ -25,6 +25,7 @@
  */
 
 #include "libavutil/common.h"
+#include "libavutil/frame.h"
 #include "libavutil/lfg.h"
 #include "libavutil/xga_font_data.h"
 #include "avcodec.h"
@@ -49,8 +50,8 @@ static const uint8_t ansi_to_cga[16] = {
     0,  4,  2,  6,  1,  5,  3, 7, 8, 12, 10, 14,  9, 13, 11, 15
 };
 
-typedef struct {
-    AVFrame frame;
+typedef struct AnsiContext {
+    AVFrame *frame;
     int x;                /**< x cursor position (pixels) */
     int y;                /**< y cursor position (pixels) */
     int sx;               /**< saved x cursor position (pixels) */
@@ -85,9 +86,18 @@ static av_cold int decode_init(AVCodecContext *avctx)
     s->fg          = DEFAULT_FG_COLOR;
     s->bg          = DEFAULT_BG_COLOR;
 
-    avcodec_get_frame_defaults(&s->frame);
-    if (!avctx->width || !avctx->height)
-        avcodec_set_dimensions(avctx, 80<<3, 25<<4);
+    if (!avctx->width || !avctx->height) {
+        int ret = ff_set_dimensions(avctx, 80 << 3, 25 << 4);
+        if (ret < 0)
+            return ret;
+    } else if (avctx->width % FONT_WIDTH || avctx->height % s->font_height) {
+        av_log(avctx, AV_LOG_ERROR, "Invalid dimensions %d %d\n", avctx->width, avctx->height);
+        return AVERROR(EINVAL);
+    }
+
+    s->frame = av_frame_alloc();
+    if (!s->frame)
+        return AVERROR(ENOMEM);
 
     return 0;
 }
@@ -112,18 +122,18 @@ 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;
     }
 
     i = 0;
     for (; i < avctx->height - s->font_height; i++)
-        memcpy(s->frame.data[0] + i * s->frame.linesize[0],
-               s->frame.data[0] + (i + s->font_height) * s->frame.linesize[0],
+        memcpy(s->frame->data[0] + i * s->frame->linesize[0],
+               s->frame->data[0] + (i + s->font_height) * s->frame->linesize[0],
                avctx->width);
     for (; i < avctx->height; i++)
-        memset(s->frame.data[0] + i * s->frame.linesize[0],
+        memset(s->frame->data[0] + i * s->frame->linesize[0],
             DEFAULT_BG_COLOR, avctx->width);
 }
 
@@ -132,7 +142,7 @@ static void erase_line(AVCodecContext * avctx, int xoffset, int xlength)
     AnsiContext *s = avctx->priv_data;
     int i;
     for (i = 0; i < s->font_height; i++)
-        memset(s->frame.data[0] + (s->y + i)*s->frame.linesize[0] + xoffset,
+        memset(s->frame->data[0] + (s->y + i)*s->frame->linesize[0] + xoffset,
             DEFAULT_BG_COLOR, xlength);
 }
 
@@ -141,7 +151,7 @@ static void erase_screen(AVCodecContext *avctx)
     AnsiContext *s = avctx->priv_data;
     int i;
     for (i = 0; i < avctx->height; i++)
-        memset(s->frame.data[0] + i * s->frame.linesize[0], DEFAULT_BG_COLOR, avctx->width);
+        memset(s->frame->data[0] + i * s->frame->linesize[0], DEFAULT_BG_COLOR, avctx->width);
     s->x = s->y = 0;
 }
 
@@ -162,10 +172,10 @@ static void draw_char(AVCodecContext *avctx, int c)
         FFSWAP(int, fg, bg);
     if ((s->attributes & ATTR_CONCEALED))
         fg = bg;
-    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);
+    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);
     }
@@ -178,7 +188,10 @@ static void draw_char(AVCodecContext *avctx, int c)
 static int execute_code(AVCodecContext * avctx, int c)
 {
     AnsiContext *s = avctx->priv_data;
-    int ret, i, width, height;
+    int ret, i;
+    int width  = avctx->width;
+    int height = avctx->height;
+
     switch(c) {
     case 'A': //Cursor Up
         s->y = FFMAX(s->y - (s->nb_args > 0 ? s->args[0]*s->font_height : s->font_height), 0);
@@ -197,12 +210,10 @@ static int execute_code(AVCodecContext * avctx, int c)
         s->y = s->nb_args > 0 ? av_clip((s->args[0] - 1)*s->font_height, 0, avctx->height - s->font_height) : 0;
         s->x = s->nb_args > 1 ? av_clip((s->args[1] - 1)*FONT_WIDTH,     0, avctx->width  - FONT_WIDTH) : 0;
         break;
-    case 'h': //set creen mode
+    case 'h': //set screen mode
     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 = avpriv_cga_font;
@@ -237,20 +248,21 @@ static int execute_code(AVCodecContext * avctx, int c)
             height = 60<<4;
             break;
         default:
-            av_log_ask_for_sample(avctx, "unsupported screen mode\n");
+            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) {
-            if (s->frame.data[0])
-                avctx->release_buffer(avctx, &s->frame);
-            avcodec_set_dimensions(avctx, width, height);
-            ret = ff_get_buffer(avctx, &s->frame);
-            if (ret < 0) {
-                av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+            av_frame_unref(s->frame);
+            ret = ff_set_dimensions(avctx, width, height);
+            if (ret < 0)
                 return ret;
-            }
-            s->frame.pict_type           = AV_PICTURE_TYPE_I;
-            s->frame.palette_has_changed = 1;
-            set_palette((uint32_t *)s->frame.data[1]);
+            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;
+            set_palette((uint32_t *)s->frame->data[1]);
             erase_screen(avctx);
         } else if (c == 'l') {
             erase_screen(avctx);
@@ -261,13 +273,13 @@ static int execute_code(AVCodecContext * avctx, int c)
         case 0:
             erase_line(avctx, s->x, avctx->width - s->x);
             if (s->y < avctx->height - s->font_height)
-                memset(s->frame.data[0] + (s->y + s->font_height)*s->frame.linesize[0],
-                    DEFAULT_BG_COLOR, (avctx->height - s->y - s->font_height)*s->frame.linesize[0]);
+                memset(s->frame->data[0] + (s->y + s->font_height)*s->frame->linesize[0],
+                    DEFAULT_BG_COLOR, (avctx->height - s->y - s->font_height)*s->frame->linesize[0]);
             break;
         case 1:
             erase_line(avctx, 0, s->x);
             if (s->y > 0)
-                memset(s->frame.data[0], DEFAULT_BG_COLOR, s->y * s->frame.linesize[0]);
+                memset(s->frame->data[0], DEFAULT_BG_COLOR, s->y * s->frame->linesize[0]);
             break;
         case 2:
             erase_screen(avctx);
@@ -315,7 +327,7 @@ static int execute_code(AVCodecContext * avctx, int c)
             } else if (m == 49) {
                 s->fg = ansi_to_cga[DEFAULT_BG_COLOR];
             } else {
-                av_log_ask_for_sample(avctx, "unsupported rendition parameter\n");
+                avpriv_request_sample(avctx, "Unsupported rendition parameter");
             }
         }
         break;
@@ -332,9 +344,11 @@ static int execute_code(AVCodecContext * avctx, int c)
         s->y = av_clip(s->sy, 0, avctx->height - s->font_height);
         break;
     default:
-        av_log_ask_for_sample(avctx, "unsupported escape code\n");
+        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;
 }
 
@@ -348,20 +362,17 @@ static int decode_frame(AVCodecContext *avctx,
     const uint8_t *buf_end   = buf+buf_size;
     int ret, i, count;
 
-    ret = avctx->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) {
         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);
+            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;
-    set_palette((uint32_t *)s->frame.data[1]);
+    s->frame->pict_type           = AV_PICTURE_TYPE_I;
+    s->frame->palette_has_changed = 1;
+    set_palette((uint32_t *)s->frame->data[1]);
     if (!s->first_frame) {
         erase_screen(avctx);
         s->first_frame = 1;
@@ -415,7 +426,7 @@ static int decode_frame(AVCodecContext *avctx,
             switch(buf[0]) {
             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)
+                if (s->nb_args < MAX_NB_ARGS && s->args[s->nb_args] < 6553)
                     s->args[s->nb_args] = FFMAX(s->args[s->nb_args], 0) * 10 + buf[0] - '0';
                 break;
             case ';':
@@ -434,8 +445,8 @@ static int decode_frame(AVCodecContext *avctx,
                     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] >= 0)
                     s->nb_args++;
-                if (execute_code(avctx, buf[0]) < 0)
-                    return -1;
+                if ((ret = execute_code(avctx, buf[0])) < 0)
+                    return ret;
                 s->state = STATE_NORMAL;
             }
             break;
@@ -449,26 +460,28 @@ static int decode_frame(AVCodecContext *avctx,
     }
 
     *got_frame = 1;
-    *(AVFrame*)data = s->frame;
+    if ((ret = av_frame_ref(data, s->frame)) < 0)
+        return ret;
     return buf_size;
 }
 
 static av_cold int decode_close(AVCodecContext *avctx)
 {
     AnsiContext *s = avctx->priv_data;
-    if (s->frame.data[0])
-        avctx->release_buffer(avctx, &s->frame);
+
+    av_frame_free(&s->frame);
     return 0;
 }
 
 AVCodec ff_ansi_decoder = {
     .name           = "ansi",
+    .long_name      = NULL_IF_CONFIG_SMALL("ASCII/ANSI art"),
     .type           = AVMEDIA_TYPE_VIDEO,
     .id             = AV_CODEC_ID_ANSI,
     .priv_data_size = sizeof(AnsiContext),
     .init           = decode_init,
     .close          = decode_close,
     .decode         = decode_frame,
-    .capabilities   = CODEC_CAP_DR1,
-    .long_name      = NULL_IF_CONFIG_SMALL("ASCII/ANSI art"),
+    .capabilities   = AV_CODEC_CAP_DR1,
+    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE,
 };