From 2a2bbcb05fde486eef76d070f26eecddd4de0ace Mon Sep 17 00:00:00 2001
From: Mike Melanson <mike@multimedia.cx>
Date: Thu, 30 Oct 2003 05:40:58 +0000
Subject: [PATCH] revised palette API, courtesy of Roberto Togni (rtogni at
 freemail.it)

Originally committed as revision 2451 to svn://svn.ffmpeg.org/ffmpeg/trunk
---
 libavcodec/avcodec.h        | 26 +++++++++++----
 libavcodec/idcinvideo.c     | 27 ++++------------
 libavcodec/interplayvideo.c | 37 ++++++---------------
 libavcodec/utils.c          |  1 +
 libavcodec/vqavideo.c       |  7 ++--
 libavcodec/xan.c            | 64 +++++++++++++++++++++----------------
 libavformat/idcin.c         | 24 ++++++++------
 libavformat/ipmovie.c       | 11 ++++---
 libavformat/wc3movie.c      | 16 +++++++---
 9 files changed, 107 insertions(+), 106 deletions(-)

diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index ad3eb546a10..90b20f425d4 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -453,7 +453,13 @@ typedef struct AVPanScan{
      * - decoding: set by lavc\
      */\
     AVPanScan *pan_scan;\
-    
+    \
+    /**\
+     * tell user application that palette has changed from previous frame.\
+     * - encoding: ??? (no palette-enabled encoder yet)\
+     * - decoding: set by lavc (default 0)\
+     */\
+    int palette_has_changed;\
 
 #define FF_QSCALE_TYPE_MPEG1	0
 #define FF_QSCALE_TYPE_MPEG2	1
@@ -1345,6 +1351,13 @@ typedef struct AVCodecContext {
      * - decoding: unused
      */
     int lmax;
+
+    /**
+     * Palette control structure
+     * - encoding: ??? (no palette-enabled encoder yet)
+     * - decoding: set by user.
+     */
+    struct AVPaletteControl *palctrl;
     
 } AVCodecContext;
 
@@ -1426,17 +1439,18 @@ typedef struct AVPicture {
  * This structure defines a method for communicating palette changes
  * between and demuxer and a decoder.
  */
+#define AVPALETTE_SIZE 256
 typedef struct AVPaletteControl {
 
     /* demuxer sets this to 1 to indicate the palette has changed;
      * decoder resets to 0 */
     int palette_changed;
 
-    /* 256 3-byte RGB palette entries; the components should be
-     * formatted in the buffer as "RGBRGB..." and should be scaled to
-     * 8 bits if they originally represented 6-bit VGA palette
-     * components */
-    unsigned char palette[256 * 3];
+    /* 4-byte ARGB palette entries, stored in native byte order; note that
+     * the individual palette components should be on a 8-bit scale; if
+     * the palette data comes from a IBM VGA native format, the component
+     * data is probably 6 bits in size and needs to be scaled */
+    unsigned int palette[AVPALETTE_SIZE];
 
 } AVPaletteControl;
 
diff --git a/libavcodec/idcinvideo.c b/libavcodec/idcinvideo.c
index d516e39fbf7..b3a658296a0 100644
--- a/libavcodec/idcinvideo.c
+++ b/libavcodec/idcinvideo.c
@@ -72,8 +72,6 @@ typedef struct IdcinContext {
     unsigned char *buf;
     int size;
 
-    unsigned char palette[PALETTE_COUNT * 4];
-
     hnode_t huff_nodes[256][HUF_TOKENS*2];
     int num_huff_nodes[256];
 
@@ -218,27 +216,11 @@ static int idcin_decode_frame(AVCodecContext *avctx,
                               uint8_t *buf, int buf_size)
 {
     IdcinContext *s = (IdcinContext *)avctx->priv_data;
-    AVPaletteControl *palette_control = 
-        (AVPaletteControl *)avctx->extradata;
-    int i;
-    unsigned int *palette32;
-    int palette_index = 0;
-    unsigned char r, g, b;
+    AVPaletteControl *palette_control = avctx->palctrl;
 
     s->buf = buf;
     s->size = buf_size;
 
-    if (palette_control->palette_changed) {
-        palette32 = (unsigned int *)s->palette;
-        for (i = 0; i < PALETTE_COUNT; i++) {
-            r = palette_control->palette[palette_index++] * 1;
-            g = palette_control->palette[palette_index++] * 1;
-            b = palette_control->palette[palette_index++] * 1;
-            palette32[i] = (r << 16) | (g << 8) | (b);
-        }
-        palette_control->palette_changed = 0;
-    }
-
     if (s->frame.data[0])
         avctx->release_buffer(avctx, &s->frame);
 
@@ -250,7 +232,12 @@ static int idcin_decode_frame(AVCodecContext *avctx,
     idcin_decode_vlcs(s);
 
     /* make the palette available on the way out */
-    memcpy(s->frame.data[1], s->palette, PALETTE_COUNT * 4);
+    memcpy(s->frame.data[1], palette_control->palette, PALETTE_COUNT * 4);
+    /* If palette changed inform application*/
+    if (palette_control->palette_changed) {
+        palette_control->palette_changed = 0;
+        s->frame.palette_has_changed = 1;
+    }
 
     *data_size = sizeof(AVFrame);
     *(AVFrame*)data = s->frame;
diff --git a/libavcodec/interplayvideo.c b/libavcodec/interplayvideo.c
index a8a7c0f5620..72e03774755 100644
--- a/libavcodec/interplayvideo.c
+++ b/libavcodec/interplayvideo.c
@@ -65,8 +65,6 @@ typedef struct IpvideoContext {
     unsigned char *buf;
     int size;
 
-    unsigned char palette[PALETTE_COUNT * 4];
-
     unsigned char *stream_ptr;
     unsigned char *stream_end;
     unsigned char *pixel_ptr;
@@ -83,21 +81,6 @@ typedef struct IpvideoContext {
     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; \
@@ -828,7 +811,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 */
@@ -874,9 +857,8 @@ static int ipvideo_decode_init(AVCodecContext *avctx)
 
     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) {
+        printf (" Interplay video: palette expected.\n");
         return -1;
     }
 
@@ -916,13 +898,7 @@ static int ipvideo_decode_frame(AVCodecContext *avctx,
                                 uint8_t *buf, int buf_size)
 {
     IpvideoContext *s = avctx->priv_data;
-    AVPaletteControl *palette_control = (AVPaletteControl *)avctx->extradata;
-
-    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;
-    }
+    AVPaletteControl *palette_control = avctx->palctrl;
 
     s->decoding_map = buf;
     s->buf = buf + s->decoding_map_size;
@@ -936,6 +912,11 @@ static int ipvideo_decode_frame(AVCodecContext *avctx,
 
     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;
 
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index 79552f4b61f..ace54ef1177 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -318,6 +318,7 @@ void avcodec_get_context_defaults(AVCodecContext *s){
     
     s->intra_quant_bias= FF_DEFAULT_QUANT_BIAS;
     s->inter_quant_bias= FF_DEFAULT_QUANT_BIAS;
+    s->palctrl = NULL;
 }
 
 /**
diff --git a/libavcodec/vqavideo.c b/libavcodec/vqavideo.c
index 174116dbc31..8f4ac173f3c 100644
--- a/libavcodec/vqavideo.c
+++ b/libavcodec/vqavideo.c
@@ -120,7 +120,7 @@ typedef struct VqaContext {
     unsigned char *buf;
     int size;
 
-    unsigned char palette[PALETTE_COUNT * 4];
+    unsigned int palette[PALETTE_COUNT];
 
     int width;   /* width of a frame */
     int height;   /* height of a frame */
@@ -311,7 +311,6 @@ static void vqa_decode_chunk(VqaContext *s)
     unsigned int index = 0;
     int i;
     unsigned char r, g, b;
-    unsigned int *palette32;
     int index_shift;
 
     int cbf0_chunk = -1;
@@ -407,13 +406,12 @@ static void vqa_decode_chunk(VqaContext *s)
             return;
         }
         cpl0_chunk += CHUNK_PREAMBLE_SIZE;
-        palette32 = (unsigned int *)s->palette;
         for (i = 0; i < chunk_size / 3; i++) {
             /* scale by 4 to transform 6-bit palette -> 8-bit */
             r = s->buf[cpl0_chunk++] * 4;
             g = s->buf[cpl0_chunk++] * 4;
             b = s->buf[cpl0_chunk++] * 4;
-            palette32[i] = (r << 16) | (g << 8) | (b);
+            s->palette[i] = (r << 16) | (g << 8) | (b);
         }
     }
 
@@ -583,6 +581,7 @@ static int vqa_decode_frame(AVCodecContext *avctx,
 
     /* make the palette available on the way out */
     memcpy(s->frame.data[1], s->palette, PALETTE_COUNT * 4);
+    s->frame.palette_has_changed = 1;
 
     *data_size = sizeof(AVFrame);
     *(AVFrame*)data = s->frame;
diff --git a/libavcodec/xan.c b/libavcodec/xan.c
index 8359782e69b..49e207677f0 100644
--- a/libavcodec/xan.c
+++ b/libavcodec/xan.c
@@ -115,9 +115,8 @@ static int xan_decode_init(AVCodecContext *avctx)
     s->avctx = avctx;
 
     if ((avctx->codec->id == CODEC_ID_XAN_WC3) && 
-        (s->avctx->extradata_size != sizeof(AVPaletteControl))) {
-        printf (" WC3 Xan video: expected extradata_size of %d\n",
-            sizeof(AVPaletteControl));
+        (s->avctx->palctrl == NULL)) {
+        printf (" WC3 Xan video: palette expected.\n");
         return -1;
     }
 
@@ -253,12 +252,13 @@ static void xan_unpack(unsigned char *dest, unsigned char *src)
 }
 
 static void inline xan_wc3_build_palette(XanContext *s, 
-    unsigned char *palette_data)
+    unsigned int *palette_data)
 {
     int i;
     unsigned char r, g, b;
     unsigned short *palette16;
     unsigned int *palette32;
+    unsigned int pal_elem;
 
     /* transform the palette passed through the palette control structure
      * into the necessary internal format depending on colorspace */
@@ -268,9 +268,10 @@ static void inline xan_wc3_build_palette(XanContext *s,
     case PIX_FMT_RGB555:
         palette16 = (unsigned short *)s->palette;
         for (i = 0; i < PALETTE_COUNT; i++) {
-            r = *palette_data++;
-            g = *palette_data++;
-            b = *palette_data++;
+            pal_elem = palette_data[i];
+            r = (pal_elem >> 16) & 0xff;
+            g = (pal_elem >> 8) & 0xff;
+            b = pal_elem & 0xff;
             palette16[i] = 
                 ((r >> 3) << 10) |
                 ((g >> 3) <<  5) |
@@ -281,9 +282,10 @@ static void inline xan_wc3_build_palette(XanContext *s,
     case PIX_FMT_RGB565:
         palette16 = (unsigned short *)s->palette;
         for (i = 0; i < PALETTE_COUNT; i++) {
-            r = *palette_data++;
-            g = *palette_data++;
-            b = *palette_data++;
+            pal_elem = palette_data[i];
+            r = (pal_elem >> 16) & 0xff;
+            g = (pal_elem >> 8) & 0xff;
+            b = pal_elem & 0xff;
             palette16[i] = 
                 ((r >> 3) << 11) |
                 ((g >> 2) <<  5) |
@@ -293,17 +295,22 @@ static void inline xan_wc3_build_palette(XanContext *s,
 
     case PIX_FMT_RGB24:
         for (i = 0; i < PALETTE_COUNT; i++) {
-            s->palette[i * 4 + 0] = *palette_data++;
-            s->palette[i * 4 + 1] = *palette_data++;
-            s->palette[i * 4 + 2] = *palette_data++;
+            pal_elem = palette_data[i];
+            r = (pal_elem >> 16) & 0xff;
+            g = (pal_elem >> 8) & 0xff;
+            b = pal_elem & 0xff;
+            s->palette[i * 4 + 0] = r;
+            s->palette[i * 4 + 1] = g;
+            s->palette[i * 4 + 2] = b;
         }
         break;
 
     case PIX_FMT_BGR24:
         for (i = 0; i < PALETTE_COUNT; i++) {
-            r = *palette_data++;
-            g = *palette_data++;
-            b = *palette_data++;
+            pal_elem = palette_data[i];
+            r = (pal_elem >> 16) & 0xff;
+            g = (pal_elem >> 8) & 0xff;
+            b = pal_elem & 0xff;
             s->palette[i * 4 + 0] = b;
             s->palette[i * 4 + 1] = g;
             s->palette[i * 4 + 2] = r;
@@ -313,19 +320,15 @@ static void inline xan_wc3_build_palette(XanContext *s,
     case PIX_FMT_PAL8:
     case PIX_FMT_RGBA32:
         palette32 = (unsigned int *)s->palette;
-        for (i = 0; i < PALETTE_COUNT; i++) {
-            r = *palette_data++;
-            g = *palette_data++;
-            b = *palette_data++;
-            palette32[i] = (r << 16) | (g << 8) | (b);
-        }
+        memcpy (palette32, palette_data, PALETTE_COUNT * sizeof(unsigned int));
         break;
 
     case PIX_FMT_YUV444P:
         for (i = 0; i < PALETTE_COUNT; i++) {
-            r = *palette_data++;
-            g = *palette_data++;
-            b = *palette_data++;
+            pal_elem = palette_data[i];
+            r = (pal_elem >> 16) & 0xff;
+            g = (pal_elem >> 8) & 0xff;
+            b = pal_elem & 0xff;
             s->palette[i * 4 + 0] = COMPUTE_Y(r, g, b);
             s->palette[i * 4 + 1] = COMPUTE_U(r, g, b);
             s->palette[i * 4 + 2] = COMPUTE_V(r, g, b);
@@ -730,8 +733,11 @@ static void xan_wc3_decode_frame(XanContext *s) {
     }
 
     /* for PAL8, make the palette available on the way out */
-    if (s->avctx->pix_fmt == PIX_FMT_PAL8)
+    if (s->avctx->pix_fmt == PIX_FMT_PAL8) {
         memcpy(s->current_frame.data[1], s->palette, PALETTE_COUNT * 4);
+        s->current_frame.palette_has_changed = 1;
+        s->avctx->palctrl->palette_changed = 0;
+    }
 }
 
 static void xan_wc4_decode_frame(XanContext *s) {
@@ -742,13 +748,15 @@ static int xan_decode_frame(AVCodecContext *avctx,
                             uint8_t *buf, int buf_size)
 {
     XanContext *s = avctx->priv_data;
-    AVPaletteControl *palette_control = (AVPaletteControl *)avctx->extradata;
+    AVPaletteControl *palette_control = avctx->palctrl;
     int keyframe = 0;
 
     if (palette_control->palette_changed) {
         /* load the new palette and reset the palette control */
         xan_wc3_build_palette(s, palette_control->palette);
-        palette_control->palette_changed = 0;
+        /* If pal8 we clear flag when we copy palette */
+        if (s->avctx->pix_fmt != PIX_FMT_PAL8)
+            palette_control->palette_changed = 0;
         keyframe = 1;
     }
 
diff --git a/libavformat/idcin.c b/libavformat/idcin.c
index 6125c64afcb..9d13aa56346 100644
--- a/libavformat/idcin.c
+++ b/libavformat/idcin.c
@@ -90,8 +90,7 @@ typedef struct IdcinDemuxContext {
 
     int64_t pts;
 
-    /* keep reference to extradata but never free it */
-    void *extradata;
+    AVPaletteControl palctrl;
 } IdcinDemuxContext;
 
 static int idcin_probe(AVProbeData *p)
@@ -175,7 +174,7 @@ static int idcin_read_header(AVFormatContext *s,
         HUFFMAN_TABLE_SIZE)
         return -EIO;
     /* save a reference in order to transport the palette */
-    idcin->extradata = st->codec.extradata;
+    st->codec.palctrl = &idcin->palctrl;
 
     /* if sample rate is 0, assume no audio */
     if (sample_rate) {
@@ -227,9 +226,10 @@ static int idcin_read_packet(AVFormatContext *s,
     unsigned int chunk_size;
     IdcinDemuxContext *idcin = (IdcinDemuxContext *)s->priv_data;
     ByteIOContext *pb = &s->pb;
-    AVPaletteControl *palette_control = (AVPaletteControl *)idcin->extradata;
     int i;
     int palette_scale;
+    unsigned char r, g, b;
+    unsigned char palette_buffer[768];
 
     if (url_feof(&s->pb))
         return -EIO;
@@ -240,20 +240,23 @@ static int idcin_read_packet(AVFormatContext *s,
             return -EIO;
         } else if (command == 1) {
             /* trigger a palette change */
-            palette_control->palette_changed = 1;
-            if (get_buffer(pb, palette_control->palette, 768) != 768)
+            idcin->palctrl.palette_changed = 1;
+            if (get_buffer(pb, palette_buffer, 768) != 768)
                 return -EIO;
             /* scale the palette as necessary */
             palette_scale = 2;
             for (i = 0; i < 768; i++)
-                if (palette_control->palette[i] > 63) {
+                if (palette_buffer[i] > 63) {
                     palette_scale = 0;
                     break;
                 }
 
-            if (palette_scale)
-                for (i = 0; i < 768; i++)
-                    palette_control->palette[i] <<= palette_scale;
+            for (i = 0; i < 256; i++) {
+                r = palette_buffer[i * 3    ] << palette_scale;
+                g = palette_buffer[i * 3 + 1] << palette_scale;
+                b = palette_buffer[i * 3 + 2] << palette_scale;
+                idcin->palctrl.palette[i] = (r << 16) | (g << 8) | (b);
+            }
         }
 
         chunk_size = get_le32(pb);
@@ -293,6 +296,7 @@ static int idcin_read_packet(AVFormatContext *s,
 
 static int idcin_read_close(AVFormatContext *s)
 {
+
     return 0;
 }
 
diff --git a/libavformat/ipmovie.c b/libavformat/ipmovie.c
index e8ba0b70432..caaa3dd63b4 100644
--- a/libavformat/ipmovie.c
+++ b/libavformat/ipmovie.c
@@ -232,6 +232,7 @@ static int process_ipmovie_chunk(IPMVEContext *s, ByteIOContext *pb,
     int i, j;
     int first_color, last_color;
     int audio_flags;
+    unsigned char r, g, b;
 
     /* see if there are any pending packets */
     chunk_type = load_ipmovie_packet(s, pb, pkt);
@@ -463,9 +464,10 @@ static int process_ipmovie_chunk(IPMVEContext *s, ByteIOContext *pb,
             for (i = first_color; i <= last_color; i++) {
                 /* the palette is stored as a 6-bit VGA palette, thus each
                  * component is shifted up to a 8-bit range */
-                s->palette_control.palette[i * 3 + 0] = scratch[j++] * 4;
-                s->palette_control.palette[i * 3 + 1] = scratch[j++] * 4;
-                s->palette_control.palette[i * 3 + 2] = scratch[j++] * 4;
+                r = scratch[j++] * 4;
+                g = scratch[j++] * 4;
+                b = scratch[j++] * 4;
+                s->palette_control.palette[i] = (r << 16) | (g << 8) | (b);
             }
             /* indicate a palette change */
             s->palette_control.palette_changed = 1;
@@ -573,8 +575,7 @@ static int ipmovie_read_header(AVFormatContext *s,
     st->codec.height = ipmovie->video_height;
 
     /* palette considerations */
-    st->codec.extradata_size = sizeof(AVPaletteControl);
-    st->codec.extradata = &ipmovie->palette_control;
+    st->codec.palctrl = &ipmovie->palette_control;
 
     if (ipmovie->audio_type) {
         st = av_new_stream(s, 0);
diff --git a/libavformat/wc3movie.c b/libavformat/wc3movie.c
index 16e4412681d..cedb9042313 100644
--- a/libavformat/wc3movie.c
+++ b/libavformat/wc3movie.c
@@ -258,8 +258,7 @@ static int wc3_read_header(AVFormatContext *s,
     st->codec.height = wc3->height;
 
     /* palette considerations */
-    st->codec.extradata_size = sizeof(AVPaletteControl);
-    st->codec.extradata = &wc3->palette_control;
+    st->codec.palctrl = &wc3->palette_control;
 
     st = av_new_stream(s, 0);
     if (!st)
@@ -294,6 +293,9 @@ static int wc3_read_packet(AVFormatContext *s,
     unsigned char preamble[WC3_PREAMBLE_SIZE];
     unsigned char text[1024];
     unsigned int palette_number;
+    int i;
+    unsigned char r, g, b;
+    int base_palette_index;
 
     while (!packet_read) {
 
@@ -319,9 +321,13 @@ static int wc3_read_packet(AVFormatContext *s,
             palette_number = LE_32(&preamble[0]);
             if (palette_number >= wc3->palette_count)
                 return AVERROR_INVALIDDATA;
-            memcpy(wc3->palette_control.palette, 
-                &wc3->palettes[palette_number * PALETTE_COUNT * 3],
-                PALETTE_COUNT * 3);
+            base_palette_index = palette_number * PALETTE_COUNT * 3;
+            for (i = 0; i < PALETTE_COUNT; i++) {
+                r = wc3->palettes[base_palette_index + i * 3 + 0];
+                g = wc3->palettes[base_palette_index + i * 3 + 1];
+                b = wc3->palettes[base_palette_index + i * 3 + 2];
+                wc3->palette_control.palette[i] = (r << 16) | (g << 8) | (b);
+            }
             wc3->palette_control.palette_changed = 1;
             break;
 
-- 
GitLab