]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/interplayvideo.c
Check *data_size in decode_frame()
[ffmpeg] / libavcodec / interplayvideo.c
index a8a7c0f562041bfaf852230098e050ec8aba284e..16ac977ec069349667e2f50ac02503e3df9ff7ed 100644 (file)
@@ -2,20 +2,21 @@
  * Interplay MVE Video Decoder
  * Copyright (C) 2003 the ffmpeg project
  *
- * This library is free software; you can redistribute it and/or
+ * This file is part of FFmpeg.
+ *
+ * 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 of the License, or (at your option) any later version.
+ * version 2.1 of the License, or (at your option) any later version.
  *
- * This library 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 this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
 /**
@@ -38,8 +39,8 @@
 #include <string.h>
 #include <unistd.h>
 
-#include "common.h"
 #include "avcodec.h"
+#include "bytestream.h"
 #include "dsputil.h"
 
 #define PALETTE_COUNT 256
@@ -47,7 +48,7 @@
 /* debugging support */
 #define DEBUG_INTERPLAY 0
 #if DEBUG_INTERPLAY
-#define debug_interplay printf
+#define debug_interplay(x,...) av_log(NULL, AV_LOG_DEBUG, x, __VA_ARGS__)
 #else
 static inline void debug_interplay(const char *format, ...) { }
 #endif
@@ -59,16 +60,14 @@ typedef struct IpvideoContext {
     AVFrame second_last_frame;
     AVFrame last_frame;
     AVFrame current_frame;
-    unsigned char *decoding_map;
+    const unsigned char *decoding_map;
     int decoding_map_size;
 
-    unsigned char *buf;
+    const unsigned char *buf;
     int size;
 
-    unsigned char palette[PALETTE_COUNT * 4];
-
-    unsigned char *stream_ptr;
-    unsigned char *stream_end;
+    const unsigned char *stream_ptr;
+    const unsigned char *stream_end;
     unsigned char *pixel_ptr;
     int line_inc;
     int stride;
@@ -78,35 +77,20 @@ typedef struct IpvideoContext {
 
 #define CHECK_STREAM_PTR(n) \
   if ((s->stream_ptr + n) > s->stream_end) { \
-    printf ("Interplay video warning: stream_ptr out of bounds (%p >= %p)\n", \
+    av_log(s->avctx, AV_LOG_ERROR, "Interplay video warning: stream_ptr out of bounds (%p >= %p)\n", \
       s->stream_ptr + n, s->stream_end); \
     return -1; \
   }
 
-static void ipvideo_new_palette(IpvideoContext *s, unsigned char *palette) {
-
-    int i;
-    unsigned char r, g, b;
-    unsigned int *palette32;
-
-    palette32 = (unsigned int *)s->palette;
-    for (i = 0; i < PALETTE_COUNT; i++) {
-        r = *palette++;
-        g = *palette++;
-        b = *palette++;
-        palette32[i] = (r << 16) | (g << 8) | (b);
-    }
-}
-
 #define COPY_FROM_CURRENT() \
     motion_offset = current_offset; \
     motion_offset += y * s->stride; \
     motion_offset += x; \
     if (motion_offset < 0) { \
-        printf (" Interplay video: motion offset < 0 (%d)\n", motion_offset); \
+        av_log(s->avctx, AV_LOG_ERROR, " Interplay video: motion offset < 0 (%d)\n", motion_offset); \
         return -1; \
     } else if (motion_offset > s->upper_motion_limit_offset) { \
-        printf (" Interplay video: motion offset above limit (%d >= %d)\n", \
+        av_log(s->avctx, AV_LOG_ERROR, " Interplay video: motion offset above limit (%d >= %d)\n", \
             motion_offset, s->upper_motion_limit_offset); \
         return -1; \
     } \
@@ -118,10 +102,10 @@ static void ipvideo_new_palette(IpvideoContext *s, unsigned char *palette) {
     motion_offset += y * s->stride; \
     motion_offset += x; \
     if (motion_offset < 0) { \
-        printf (" Interplay video: motion offset < 0 (%d)\n", motion_offset); \
+        av_log(s->avctx, AV_LOG_ERROR, " Interplay video: motion offset < 0 (%d)\n", motion_offset); \
         return -1; \
     } else if (motion_offset > s->upper_motion_limit_offset) { \
-        printf (" Interplay video: motion offset above limit (%d >= %d)\n", \
+        av_log(s->avctx, AV_LOG_ERROR, " Interplay video: motion offset above limit (%d >= %d)\n", \
             motion_offset, s->upper_motion_limit_offset); \
         return -1; \
     } \
@@ -133,10 +117,10 @@ static void ipvideo_new_palette(IpvideoContext *s, unsigned char *palette) {
     motion_offset += y * s->stride; \
     motion_offset += x; \
     if (motion_offset < 0) { \
-        printf (" Interplay video: motion offset < 0 (%d)\n", motion_offset); \
+        av_log(s->avctx, AV_LOG_ERROR, " Interplay video: motion offset < 0 (%d)\n", motion_offset); \
         return -1; \
     } else if (motion_offset > s->upper_motion_limit_offset) { \
-        printf (" Interplay video: motion offset above limit (%d >= %d)\n", \
+        av_log(s->avctx, AV_LOG_ERROR, " Interplay video: motion offset above limit (%d >= %d)\n", \
             motion_offset, s->upper_motion_limit_offset); \
         return -1; \
     } \
@@ -271,7 +255,7 @@ static int ipvideo_decode_block_opcode_0x5(IpvideoContext *s)
 static int ipvideo_decode_block_opcode_0x6(IpvideoContext *s)
 {
     /* mystery opcode? skip multiple blocks? */
-    printf ("  Interplay video: Help! Mystery opcode 0x6 seen\n");
+    av_log(s->avctx, AV_LOG_ERROR, "  Interplay video: Help! Mystery opcode 0x6 seen\n");
 
     /* report success */
     return 0;
@@ -313,10 +297,8 @@ static int ipvideo_decode_block_opcode_0x7(IpvideoContext *s)
 
         /* need 2 more bytes from the stream */
         CHECK_STREAM_PTR(2);
-        B[0] = *s->stream_ptr++;
-        B[1] = *s->stream_ptr++;
 
-        flags = (B[1] << 8) | B[0];
+        flags = bytestream_get_le16(&s->stream_ptr);
         bitmask = 0x0001;
         for (y = 0; y < 8; y += 2) {
             for (x = 0; x < 8; x += 2, bitmask <<= 1) {
@@ -494,7 +476,6 @@ static int ipvideo_decode_block_opcode_0x9(IpvideoContext *s)
 {
     int x, y;
     unsigned char P[4];
-    unsigned char B[4];
     unsigned int flags = 0;
     int shifter = 0;
     unsigned char pix;
@@ -512,8 +493,7 @@ static int ipvideo_decode_block_opcode_0x9(IpvideoContext *s)
 
         for (y = 0; y < 8; y++) {
             /* get the next set of 8 2-bit flags */
-            flags = (s->stream_ptr[1] << 8) | s->stream_ptr[0];
-            s->stream_ptr += 2;
+            flags = bytestream_get_le16(&s->stream_ptr);
             for (x = 0, shifter = 0; x < 8; x++, shifter += 2) {
                 *s->pixel_ptr++ = P[(flags >> shifter) & 0x03];
             }
@@ -525,11 +505,7 @@ static int ipvideo_decode_block_opcode_0x9(IpvideoContext *s)
         /* 1 of 4 colors for each 2x2 block, need 4 more bytes */
         CHECK_STREAM_PTR(4);
 
-        B[0] = *s->stream_ptr++;
-        B[1] = *s->stream_ptr++;
-        B[2] = *s->stream_ptr++;
-        B[3] = *s->stream_ptr++;
-        flags = (B[3] << 24) | (B[2] << 16) | (B[1] << 8) | B[0];
+        flags = bytestream_get_le32(&s->stream_ptr);
         shifter = 0;
 
         for (y = 0; y < 8; y += 2) {
@@ -551,11 +527,7 @@ static int ipvideo_decode_block_opcode_0x9(IpvideoContext *s)
         for (y = 0; y < 8; y++) {
             /* time to reload flags? */
             if ((y == 0) || (y == 4)) {
-                B[0] = *s->stream_ptr++;
-                B[1] = *s->stream_ptr++;
-                B[2] = *s->stream_ptr++;
-                B[3] = *s->stream_ptr++;
-                flags = (B[3] << 24) | (B[2] << 16) | (B[1] << 8) | B[0];
+                flags = bytestream_get_le32(&s->stream_ptr);
                 shifter = 0;
             }
             for (x = 0; x < 8; x += 2, shifter += 2) {
@@ -574,11 +546,7 @@ static int ipvideo_decode_block_opcode_0x9(IpvideoContext *s)
         for (y = 0; y < 8; y += 2) {
             /* time to reload flags? */
             if ((y == 0) || (y == 4)) {
-                B[0] = *s->stream_ptr++;
-                B[1] = *s->stream_ptr++;
-                B[2] = *s->stream_ptr++;
-                B[3] = *s->stream_ptr++;
-                flags = (B[3] << 24) | (B[2] << 16) | (B[1] << 8) | B[0];
+                flags = bytestream_get_le32(&s->stream_ptr);
                 shifter = 0;
             }
             for (x = 0; x < 8; x++, shifter += 2) {
@@ -828,7 +796,7 @@ static void ipvideo_decode_opcodes(IpvideoContext *s)
         code_counts[x] = 0;
 
     /* this is PAL8, so make the palette available */
-    memcpy(s->current_frame.data[1], s->palette, PALETTE_COUNT * 4);
+    memcpy(s->current_frame.data[1], s->avctx->palctrl->palette, PALETTE_COUNT * 4);
 
     s->stride = s->current_frame.linesize[0];
     s->stream_ptr = s->buf + 14;  /* data starts 14 bytes in */
@@ -836,7 +804,6 @@ static void ipvideo_decode_opcodes(IpvideoContext *s)
     s->line_inc = s->stride - 8;
     s->upper_motion_limit_offset = (s->avctx->height - 8) * s->stride
         + s->avctx->width - 8;
-    s->dsp = s->dsp;
 
     for (y = 0; y < (s->stride * s->avctx->height); y += s->stride * 8) {
         for (x = y; x < y + s->avctx->width; x += 8) {
@@ -855,7 +822,7 @@ static void ipvideo_decode_opcodes(IpvideoContext *s)
             s->pixel_ptr = s->current_frame.data[0] + x;
             ret = ipvideo_decode_block[opcode](s);
             if (ret != 0) {
-                printf(" Interplay video: decode problem on frame %d, @ block (%d, %d)\n",
+                av_log(s->avctx, AV_LOG_ERROR, " Interplay video: decode problem on frame %d, @ block (%d, %d)\n",
                     frame, x - y, y / s->stride);
                 return;
             }
@@ -863,25 +830,23 @@ static void ipvideo_decode_opcodes(IpvideoContext *s)
     }
     if ((s->stream_ptr != s->stream_end) &&
         (s->stream_ptr + 1 != s->stream_end)) {
-        printf (" Interplay video: decode finished with %d bytes left over\n",
+        av_log(s->avctx, AV_LOG_ERROR, " Interplay video: decode finished with %td bytes left over\n",
             s->stream_end - s->stream_ptr);
     }
 }
 
-static int ipvideo_decode_init(AVCodecContext *avctx)
+static av_cold int ipvideo_decode_init(AVCodecContext *avctx)
 {
     IpvideoContext *s = avctx->priv_data;
 
     s->avctx = avctx;
 
-    if (s->avctx->extradata_size != sizeof(AVPaletteControl)) {
-        printf (" Interplay video: expected extradata_size of %d\n",
-               (int)sizeof(AVPaletteControl));
+    if (s->avctx->palctrl == NULL) {
+        av_log(avctx, AV_LOG_ERROR, " Interplay video: palette expected.\n");
         return -1;
     }
 
     avctx->pix_fmt = PIX_FMT_PAL8;
-    avctx->has_b_frames = 0;
     dsputil_init(&s->dsp, avctx);
 
     /* decoding map contains 4 bits of information per 8x8 block */
@@ -913,16 +878,15 @@ static int ipvideo_decode_init(AVCodecContext *avctx)
 
 static int ipvideo_decode_frame(AVCodecContext *avctx,
                                 void *data, int *data_size,
-                                uint8_t *buf, int buf_size)
+                                const uint8_t *buf, int buf_size)
 {
     IpvideoContext *s = avctx->priv_data;
-    AVPaletteControl *palette_control = (AVPaletteControl *)avctx->extradata;
+    AVPaletteControl *palette_control = avctx->palctrl;
 
-    if (palette_control->palette_changed) {
-        /* load the new palette and reset the palette control */
-        ipvideo_new_palette(s, palette_control->palette);
-        palette_control->palette_changed = 0;
-    }
+    /* compressed buffer needs to be large enough to at least hold an entire
+     * decoding map */
+    if (buf_size < s->decoding_map_size)
+        return buf_size;
 
     s->decoding_map = buf;
     s->buf = buf + s->decoding_map_size;
@@ -930,12 +894,17 @@ static int ipvideo_decode_frame(AVCodecContext *avctx,
 
     s->current_frame.reference = 3;
     if (avctx->get_buffer(avctx, &s->current_frame)) {
-        printf ("  Interplay Video: get_buffer() failed\n");
+        av_log(avctx, AV_LOG_ERROR, "  Interplay Video: get_buffer() failed\n");
         return -1;
     }
 
     ipvideo_decode_opcodes(s);
 
+    if (palette_control->palette_changed) {
+        palette_control->palette_changed = 0;
+        s->current_frame.palette_has_changed = 1;
+    }
+
     *data_size = sizeof(AVFrame);
     *(AVFrame*)data = s->current_frame;
 
@@ -950,7 +919,7 @@ static int ipvideo_decode_frame(AVCodecContext *avctx,
     return buf_size;
 }
 
-static int ipvideo_decode_end(AVCodecContext *avctx)
+static av_cold int ipvideo_decode_end(AVCodecContext *avctx)
 {
     IpvideoContext *s = avctx->priv_data;
 
@@ -973,4 +942,5 @@ AVCodec interplay_video_decoder = {
     ipvideo_decode_end,
     ipvideo_decode_frame,
     CODEC_CAP_DR1,
+    .long_name = NULL_IF_CONFIG_SMALL("Interplay MVE Video"),
 };