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