00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00027 #include "libavutil/imgutils.h"
00028 #include "avcodec.h"
00029 #include "bytestream.h"
00030 #include "cga_data.h"
00031
00032 typedef struct PicContext {
00033 AVFrame frame;
00034 int width, height;
00035 int nb_planes;
00036 GetByteContext g;
00037 } PicContext;
00038
00039 static void picmemset_8bpp(PicContext *s, int value, int run, int *x, int *y)
00040 {
00041 while (run > 0) {
00042 uint8_t *d = s->frame.data[0] + *y * s->frame.linesize[0];
00043 if (*x + run >= s->width) {
00044 int n = s->width - *x;
00045 memset(d + *x, value, n);
00046 run -= n;
00047 *x = 0;
00048 *y -= 1;
00049 if (*y < 0)
00050 break;
00051 } else {
00052 memset(d + *x, value, run);
00053 *x += run;
00054 break;
00055 }
00056 }
00057 }
00058
00059 static void picmemset(PicContext *s, int value, int run,
00060 int *x, int *y, int *plane, int bits_per_plane)
00061 {
00062 uint8_t *d;
00063 int shift = *plane * bits_per_plane;
00064 int mask = ((1 << bits_per_plane) - 1) << shift;
00065 value <<= shift;
00066
00067 while (run > 0) {
00068 int j;
00069 for (j = 8-bits_per_plane; j >= 0; j -= bits_per_plane) {
00070 d = s->frame.data[0] + *y * s->frame.linesize[0];
00071 d[*x] |= (value >> j) & mask;
00072 *x += 1;
00073 if (*x == s->width) {
00074 *y -= 1;
00075 *x = 0;
00076 if (*y < 0) {
00077 *y = s->height - 1;
00078 *plane += 1;
00079 value <<= bits_per_plane;
00080 mask <<= bits_per_plane;
00081 if (*plane >= s->nb_planes)
00082 break;
00083 }
00084 }
00085 }
00086 run--;
00087 }
00088 }
00089
00090 static const uint8_t cga_mode45_index[6][4] = {
00091 [0] = { 0, 3, 5, 7 },
00092 [1] = { 0, 2, 4, 6 },
00093 [2] = { 0, 3, 4, 7 },
00094 [3] = { 0, 11, 13, 15 },
00095 [4] = { 0, 10, 12, 14 },
00096 [5] = { 0, 11, 12, 15 },
00097 };
00098
00099 static av_cold int decode_init(AVCodecContext *avctx)
00100 {
00101 PicContext *s = avctx->priv_data;
00102
00103 avcodec_get_frame_defaults(&s->frame);
00104 return 0;
00105 }
00106
00107 static int decode_frame(AVCodecContext *avctx,
00108 void *data, int *data_size,
00109 AVPacket *avpkt)
00110 {
00111 PicContext *s = avctx->priv_data;
00112 uint32_t *palette;
00113 int bits_per_plane, bpp, etype, esize, npal, pos_after_pal;
00114 int i, x, y, plane, tmp;
00115
00116 bytestream2_init(&s->g, avpkt->data, avpkt->size);
00117
00118 if (bytestream2_get_bytes_left(&s->g) < 11)
00119 return AVERROR_INVALIDDATA;
00120
00121 if (bytestream2_get_le16u(&s->g) != 0x1234)
00122 return AVERROR_INVALIDDATA;
00123
00124 s->width = bytestream2_get_le16u(&s->g);
00125 s->height = bytestream2_get_le16u(&s->g);
00126 bytestream2_skip(&s->g, 4);
00127 tmp = bytestream2_get_byteu(&s->g);
00128 bits_per_plane = tmp & 0xF;
00129 s->nb_planes = (tmp >> 4) + 1;
00130 bpp = bits_per_plane * s->nb_planes;
00131 if (bits_per_plane > 8 || bpp < 1 || bpp > 32) {
00132 av_log_ask_for_sample(avctx, "unsupported bit depth\n");
00133 return AVERROR_INVALIDDATA;
00134 }
00135
00136 if (bytestream2_peek_byte(&s->g) == 0xFF || bpp == 8) {
00137 bytestream2_skip(&s->g, 2);
00138 etype = bytestream2_get_le16(&s->g);
00139 esize = bytestream2_get_le16(&s->g);
00140 if (bytestream2_get_bytes_left(&s->g) < esize)
00141 return AVERROR_INVALIDDATA;
00142 } else {
00143 etype = -1;
00144 esize = 0;
00145 }
00146
00147 avctx->pix_fmt = PIX_FMT_PAL8;
00148
00149 if (s->width != avctx->width && s->height != avctx->height) {
00150 if (av_image_check_size(s->width, s->height, 0, avctx) < 0)
00151 return -1;
00152 avcodec_set_dimensions(avctx, s->width, s->height);
00153 if (s->frame.data[0])
00154 avctx->release_buffer(avctx, &s->frame);
00155 }
00156
00157 if (avctx->get_buffer(avctx, &s->frame) < 0){
00158 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00159 return -1;
00160 }
00161 memset(s->frame.data[0], 0, s->height * s->frame.linesize[0]);
00162 s->frame.pict_type = AV_PICTURE_TYPE_I;
00163 s->frame.palette_has_changed = 1;
00164
00165 pos_after_pal = bytestream2_tell(&s->g) + esize;
00166 palette = (uint32_t*)s->frame.data[1];
00167 if (etype == 1 && esize > 1 && bytestream2_peek_byte(&s->g) < 6) {
00168 int idx = bytestream2_get_byte(&s->g);
00169 npal = 4;
00170 for (i = 0; i < npal; i++)
00171 palette[i] = ff_cga_palette[ cga_mode45_index[idx][i] ];
00172 } else if (etype == 2) {
00173 npal = FFMIN(esize, 16);
00174 for (i = 0; i < npal; i++) {
00175 int pal_idx = bytestream2_get_byte(&s->g);
00176 palette[i] = ff_cga_palette[FFMIN(pal_idx, 16)];
00177 }
00178 } else if (etype == 3) {
00179 npal = FFMIN(esize, 16);
00180 for (i = 0; i < npal; i++) {
00181 int pal_idx = bytestream2_get_byte(&s->g);
00182 palette[i] = ff_ega_palette[FFMIN(pal_idx, 63)];
00183 }
00184 } else if (etype == 4 || etype == 5) {
00185 npal = FFMIN(esize / 3, 256);
00186 for (i = 0; i < npal; i++) {
00187 palette[i] = bytestream2_get_be24(&s->g) << 2;
00188 palette[i] |= 0xFFU << 24 | palette[i] >> 6 & 0x30303;
00189 }
00190 } else {
00191 if (bpp == 1) {
00192 npal = 2;
00193 palette[0] = 0xFF000000;
00194 palette[1] = 0xFFFFFFFF;
00195 } else if (bpp == 2) {
00196 npal = 4;
00197 for (i = 0; i < npal; i++)
00198 palette[i] = ff_cga_palette[ cga_mode45_index[0][i] ];
00199 } else {
00200 npal = 16;
00201 memcpy(palette, ff_cga_palette, npal * 4);
00202 }
00203 }
00204
00205 memset(palette + npal, 0, AVPALETTE_SIZE - npal * 4);
00206
00207 bytestream2_seek(&s->g, pos_after_pal, SEEK_SET);
00208
00209 y = s->height - 1;
00210 if (bytestream2_get_le16(&s->g)) {
00211 x = 0;
00212 plane = 0;
00213 while (y >= 0 && bytestream2_get_bytes_left(&s->g) >= 6) {
00214 int stop_size, marker, t1, t2;
00215
00216 t1 = bytestream2_get_bytes_left(&s->g);
00217 t2 = bytestream2_get_le16(&s->g);
00218 stop_size = t1 - FFMIN(t1, t2);
00219
00220 bytestream2_skip(&s->g, 2);
00221 marker = bytestream2_get_byte(&s->g);
00222
00223 while (plane < s->nb_planes && y >= 0 &&
00224 bytestream2_get_bytes_left(&s->g) > stop_size) {
00225 int run = 1;
00226 int val = bytestream2_get_byte(&s->g);
00227 if (val == marker) {
00228 run = bytestream2_get_byte(&s->g);
00229 if (run == 0)
00230 run = bytestream2_get_le16(&s->g);
00231 val = bytestream2_get_byte(&s->g);
00232 }
00233 if (!bytestream2_get_bytes_left(&s->g))
00234 break;
00235
00236 if (bits_per_plane == 8) {
00237 picmemset_8bpp(s, val, run, &x, &y);
00238 } else {
00239 picmemset(s, val, run, &x, &y, &plane, bits_per_plane);
00240 }
00241 }
00242 }
00243 } else {
00244 while (y >= 0 && bytestream2_get_bytes_left(&s->g) > 0) {
00245 memcpy(s->frame.data[0] + y * s->frame.linesize[0], s->g.buffer, FFMIN(avctx->width, bytestream2_get_bytes_left(&s->g)));
00246 bytestream2_skip(&s->g, avctx->width);
00247 y--;
00248 }
00249 }
00250
00251 *data_size = sizeof(AVFrame);
00252 *(AVFrame*)data = s->frame;
00253 return avpkt->size;
00254 }
00255
00256 static av_cold int decode_end(AVCodecContext *avctx)
00257 {
00258 PicContext *s = avctx->priv_data;
00259 if (s->frame.data[0])
00260 avctx->release_buffer(avctx, &s->frame);
00261 return 0;
00262 }
00263
00264 AVCodec ff_pictor_decoder = {
00265 .name = "pictor",
00266 .type = AVMEDIA_TYPE_VIDEO,
00267 .id = CODEC_ID_PICTOR,
00268 .priv_data_size = sizeof(PicContext),
00269 .init = decode_init,
00270 .close = decode_end,
00271 .decode = decode_frame,
00272 .capabilities = CODEC_CAP_DR1,
00273 .long_name = NULL_IF_CONFIG_SMALL("Pictor/PC Paint"),
00274 };