Increase Pictor/PC Paint palette dynamics.
[ffmpeg.git] / libavcodec / pictordec.c
1 /*
2  * Pictor/PC Paint decoder
3  * Copyright (c) 2010 Peter Ross <pross@xvid.org>
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21
22 /**
23  * @file
24  * Pictor/PC Paint decoder
25  */
26
27 #include "libavutil/imgutils.h"
28 #include "avcodec.h"
29 #include "bytestream.h"
30 #include "cga_data.h"
31
32 typedef struct PicContext {
33     AVFrame frame;
34     int width, height;
35     int nb_planes;
36 } PicContext;
37
38 static void picmemset_8bpp(PicContext *s, int value, int run, int *x, int *y)
39 {
40     while (run > 0) {
41         uint8_t *d = s->frame.data[0] + *y * s->frame.linesize[0];
42         if (*x + run >= s->width) {
43             int n = s->width - *x;
44             memset(d + *x, value, n);
45             run -= n;
46             *x = 0;
47             *y -= 1;
48             if (*y < 0)
49                 break;
50         } else {
51             memset(d + *x, value, run);
52             *x += run;
53             break;
54         }
55     }
56 }
57
58 static void picmemset(PicContext *s, int value, int run, int *x, int *y, int *plane, int bits_per_plane)
59 {
60     uint8_t *d;
61     int shift = *plane * bits_per_plane;
62     int mask  = ((1 << bits_per_plane) - 1) << shift;
63     value   <<= shift;
64
65     while (run > 0) {
66         int j;
67         for (j = 8-bits_per_plane; j >= 0; j -= bits_per_plane) {
68             d = s->frame.data[0] + *y * s->frame.linesize[0];
69             d[*x] |= (value >> j) & mask;
70             *x += 1;
71             if (*x == s->width) {
72                 *y -= 1;
73                 *x = 0;
74                 if (*y < 0) {
75                    *y = s->height - 1;
76                    *plane += 1;
77                    value <<= bits_per_plane;
78                    mask  <<= bits_per_plane;
79                    if (*plane >= s->nb_planes)
80                        break;
81                 }
82             }
83         }
84         run--;
85     }
86 }
87
88 static const uint8_t cga_mode45_index[6][4] = {
89     [0] = { 0, 3,  5,   7 }, // mode4, palette#1, low intensity
90     [1] = { 0, 2,  4,   6 }, // mode4, palette#2, low intensity
91     [2] = { 0, 3,  4,   7 }, // mode5, low intensity
92     [3] = { 0, 11, 13, 15 }, // mode4, palette#1, high intensity
93     [4] = { 0, 10, 12, 14 }, // mode4, palette#2, high intensity
94     [5] = { 0, 11, 12, 15 }, // mode5, high intensity
95 };
96
97 static av_cold int decode_init(AVCodecContext *avctx)
98 {
99     PicContext *s = avctx->priv_data;
100
101     avcodec_get_frame_defaults(&s->frame);
102     return 0;
103 }
104
105 static int decode_frame(AVCodecContext *avctx,
106                         void *data, int *data_size,
107                         AVPacket *avpkt)
108 {
109     PicContext *s = avctx->priv_data;
110     int buf_size = avpkt->size;
111     const uint8_t *buf = avpkt->data;
112     const uint8_t *buf_end = avpkt->data + buf_size;
113     uint32_t *palette;
114     int bits_per_plane, bpp, etype, esize, npal;
115     int i, x, y, plane;
116
117     if (buf_size < 11)
118         return AVERROR_INVALIDDATA;
119
120     if (bytestream_get_le16(&buf) != 0x1234)
121         return AVERROR_INVALIDDATA;
122     s->width  = bytestream_get_le16(&buf);
123     s->height = bytestream_get_le16(&buf);
124     buf += 4;
125     bits_per_plane    = *buf & 0xF;
126     s->nb_planes      = (*buf++ >> 4) + 1;
127     bpp               = s->nb_planes ? bits_per_plane*s->nb_planes : bits_per_plane;
128     if (bits_per_plane > 8 || bpp < 1 || bpp > 32) {
129         av_log_ask_for_sample(s, "unsupported bit depth\n");
130         return AVERROR_INVALIDDATA;
131     }
132
133     if (*buf == 0xFF) {
134         buf += 2;
135         etype  = bytestream_get_le16(&buf);
136         esize  = bytestream_get_le16(&buf);
137         if (buf_end - buf < esize)
138             return AVERROR_INVALIDDATA;
139     } else {
140         etype = -1;
141         esize = 0;
142     }
143
144     avctx->pix_fmt = PIX_FMT_PAL8;
145
146     if (s->width != avctx->width && s->height != avctx->height) {
147         if (av_image_check_size(s->width, s->height, 0, avctx) < 0)
148             return -1;
149         avcodec_set_dimensions(avctx, s->width, s->height);
150         if (s->frame.data[0])
151             avctx->release_buffer(avctx, &s->frame);
152     }
153
154     if (avctx->get_buffer(avctx, &s->frame) < 0){
155         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
156         return -1;
157     }
158     memset(s->frame.data[0], 0, s->height * s->frame.linesize[0]);
159     s->frame.pict_type           = AV_PICTURE_TYPE_I;
160     s->frame.palette_has_changed = 1;
161
162     palette = (uint32_t*)s->frame.data[1];
163     if (etype == 1 && esize > 1 && *buf < 6) {
164         int idx = *buf;
165         npal = 4;
166         for (i = 0; i < npal; i++)
167             palette[i] = ff_cga_palette[ cga_mode45_index[idx][i] ];
168     } else if (etype == 2) {
169         npal = FFMIN(esize, 16);
170         for (i = 0; i < npal; i++)
171             palette[i] = ff_cga_palette[ FFMIN(buf[i], 16)];
172     } else if (etype == 3) {
173         npal = FFMIN(esize, 16);
174         for (i = 0; i < npal; i++)
175             palette[i] = ff_ega_palette[ FFMIN(buf[i], 63)];
176     } else if (etype == 4 || etype == 5) {
177         npal = FFMIN(esize / 3, 256);
178         for (i = 0; i < npal; i++) {
179             palette[i] = AV_RB24(buf + i*3) << 2;
180             palette[i] |= 0xFF << 24 | palette[i] >> 6 & 0x30303;
181         }
182     } else {
183         if (bpp == 1) {
184             npal = 2;
185             palette[0] = 0xFF000000;
186             palette[1] = 0xFFFFFFFF;
187         } else if (bpp == 2) {
188             npal = 4;
189             for (i = 0; i < npal; i++)
190                 palette[i] = ff_cga_palette[ cga_mode45_index[0][i] ];
191         } else {
192             npal = 16;
193             memcpy(palette, ff_cga_palette, npal * 4);
194         }
195     }
196     // fill remaining palette entries
197     memset(palette + npal, 0, AVPALETTE_SIZE - npal * 4);
198     buf += esize;
199
200
201     x = 0;
202     y = s->height - 1;
203     plane = 0;
204     if (bytestream_get_le16(&buf)) {
205         while (buf_end - buf >= 6) {
206             const uint8_t *buf_pend = buf + FFMIN(AV_RL16(buf), buf_end - buf);
207             //ignore uncompressed block size reported at buf[2]
208             int marker = buf[4];
209             buf += 5;
210
211             while (plane < s->nb_planes && buf_pend - buf >= 1) {
212                 int run = 1;
213                 int val = *buf++;
214                 if (val == marker) {
215                     run = *buf++;
216                     if (run == 0)
217                         run = bytestream_get_le16(&buf);
218                     val = *buf++;
219                 }
220                 if (buf > buf_end)
221                     break;
222
223                 if (bits_per_plane == 8) {
224                     picmemset_8bpp(s, val, run, &x, &y);
225                     if (y < 0)
226                         break;
227                 } else {
228                     picmemset(s, val, run, &x, &y, &plane, bits_per_plane);
229                 }
230             }
231         }
232     } else {
233         av_log_ask_for_sample(s, "uncompressed image\n");
234         return buf_size;
235     }
236
237     *data_size = sizeof(AVFrame);
238     *(AVFrame*)data = s->frame;
239     return buf_size;
240 }
241
242 static av_cold int decode_end(AVCodecContext *avctx)
243 {
244     PicContext *s = avctx->priv_data;
245     if (s->frame.data[0])
246         avctx->release_buffer(avctx, &s->frame);
247     return 0;
248 }
249
250 AVCodec ff_pictor_decoder = {
251     .name           = "pictor",
252     .type           = AVMEDIA_TYPE_VIDEO,
253     .id             = CODEC_ID_PICTOR,
254     .priv_data_size = sizeof(PicContext),
255     decode_init,
256     .close          = decode_end,
257     .decode         = decode_frame,
258     .capabilities   = CODEC_CAP_DR1,
259     .long_name = NULL_IF_CONFIG_SMALL("Pictor/PC Paint"),
260 };