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