00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "libavutil/imgutils.h"
00026 #include "avcodec.h"
00027 #include "bytestream.h"
00028 #include "get_bits.h"
00029 #include "internal.h"
00030
00031 typedef struct PCXContext {
00032 AVFrame picture;
00033 } PCXContext;
00034
00035 static av_cold int pcx_init(AVCodecContext *avctx)
00036 {
00037 PCXContext *s = avctx->priv_data;
00038
00039 avcodec_get_frame_defaults(&s->picture);
00040 avctx->coded_frame= &s->picture;
00041
00042 return 0;
00043 }
00044
00045 static void pcx_rle_decode(GetByteContext *gb, uint8_t *dst,
00046 unsigned int bytes_per_scanline, int compressed)
00047 {
00048 unsigned int i = 0;
00049 unsigned char run, value;
00050
00051 if (compressed) {
00052 while (i<bytes_per_scanline) {
00053 run = 1;
00054 value = bytestream2_get_byte(gb);
00055 if (value >= 0xc0) {
00056 run = value & 0x3f;
00057 value = bytestream2_get_byte(gb);
00058 }
00059 while (i<bytes_per_scanline && run--)
00060 dst[i++] = value;
00061 }
00062 } else {
00063 bytestream2_get_buffer(gb, dst, bytes_per_scanline);
00064 }
00065 }
00066
00067 static void pcx_palette(GetByteContext *gb, uint32_t *dst, int pallen)
00068 {
00069 int i;
00070
00071 pallen = FFMIN(pallen, bytestream2_get_bytes_left(gb) / 3);
00072 for (i=0; i<pallen; i++)
00073 *dst++ = 0xFF000000 | bytestream2_get_be24u(gb);
00074 if (pallen < 256)
00075 memset(dst, 0, (256 - pallen) * sizeof(*dst));
00076 }
00077
00078 static int pcx_decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
00079 AVPacket *avpkt)
00080 {
00081 PCXContext * const s = avctx->priv_data;
00082 AVFrame *picture = data;
00083 AVFrame * const p = &s->picture;
00084 GetByteContext gb;
00085 int compressed, xmin, ymin, xmax, ymax, ret;
00086 unsigned int w, h, bits_per_pixel, bytes_per_line, nplanes, stride, y, x,
00087 bytes_per_scanline;
00088 uint8_t *ptr, *scanline;
00089
00090 if (avpkt->size < 128)
00091 return AVERROR_INVALIDDATA;
00092
00093 bytestream2_init(&gb, avpkt->data, avpkt->size);
00094
00095 if (bytestream2_get_byteu(&gb) != 0x0a || bytestream2_get_byteu(&gb) > 5) {
00096 av_log(avctx, AV_LOG_ERROR, "this is not PCX encoded data\n");
00097 return AVERROR_INVALIDDATA;
00098 }
00099
00100 compressed = bytestream2_get_byteu(&gb);
00101 bits_per_pixel = bytestream2_get_byteu(&gb);
00102 xmin = bytestream2_get_le16u(&gb);
00103 ymin = bytestream2_get_le16u(&gb);
00104 xmax = bytestream2_get_le16u(&gb);
00105 ymax = bytestream2_get_le16u(&gb);
00106 avctx->sample_aspect_ratio.num = bytestream2_get_le16u(&gb);
00107 avctx->sample_aspect_ratio.den = bytestream2_get_le16u(&gb);
00108
00109 if (xmax < xmin || ymax < ymin) {
00110 av_log(avctx, AV_LOG_ERROR, "invalid image dimensions\n");
00111 return AVERROR_INVALIDDATA;
00112 }
00113
00114 w = xmax - xmin + 1;
00115 h = ymax - ymin + 1;
00116
00117 bytestream2_skipu(&gb, 49);
00118 nplanes = bytestream2_get_byteu(&gb);
00119 bytes_per_line = bytestream2_get_le16u(&gb);
00120 bytes_per_scanline = nplanes * bytes_per_line;
00121
00122 if (bytes_per_scanline < w * bits_per_pixel * nplanes / 8) {
00123 av_log(avctx, AV_LOG_ERROR, "PCX data is corrupted\n");
00124 return AVERROR_INVALIDDATA;
00125 }
00126
00127 switch ((nplanes<<8) + bits_per_pixel) {
00128 case 0x0308:
00129 avctx->pix_fmt = AV_PIX_FMT_RGB24;
00130 break;
00131 case 0x0108:
00132 case 0x0104:
00133 case 0x0102:
00134 case 0x0101:
00135 case 0x0401:
00136 case 0x0301:
00137 case 0x0201:
00138 avctx->pix_fmt = AV_PIX_FMT_PAL8;
00139 break;
00140 default:
00141 av_log(avctx, AV_LOG_ERROR, "invalid PCX file\n");
00142 return AVERROR_INVALIDDATA;
00143 }
00144
00145 bytestream2_skipu(&gb, 60);
00146
00147 if (p->data[0])
00148 avctx->release_buffer(avctx, p);
00149
00150 if (av_image_check_size(w, h, 0, avctx))
00151 return AVERROR_INVALIDDATA;
00152 if (w != avctx->width || h != avctx->height)
00153 avcodec_set_dimensions(avctx, w, h);
00154 if ((ret = ff_get_buffer(avctx, p)) < 0) {
00155 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00156 return ret;
00157 }
00158
00159 p->pict_type = AV_PICTURE_TYPE_I;
00160
00161 ptr = p->data[0];
00162 stride = p->linesize[0];
00163
00164 scanline = av_malloc(bytes_per_scanline);
00165 if (!scanline)
00166 return AVERROR(ENOMEM);
00167
00168 if (nplanes == 3 && bits_per_pixel == 8) {
00169 for (y=0; y<h; y++) {
00170 pcx_rle_decode(&gb, scanline, bytes_per_scanline, compressed);
00171
00172 for (x=0; x<w; x++) {
00173 ptr[3*x ] = scanline[x ];
00174 ptr[3*x+1] = scanline[x+ bytes_per_line ];
00175 ptr[3*x+2] = scanline[x+(bytes_per_line<<1)];
00176 }
00177
00178 ptr += stride;
00179 }
00180
00181 } else if (nplanes == 1 && bits_per_pixel == 8) {
00182 int palstart = avpkt->size - 769;
00183
00184 for (y=0; y<h; y++, ptr+=stride) {
00185 pcx_rle_decode(&gb, scanline, bytes_per_scanline, compressed);
00186 memcpy(ptr, scanline, w);
00187 }
00188
00189 if (bytestream2_tell(&gb) != palstart) {
00190 av_log(avctx, AV_LOG_WARNING, "image data possibly corrupted\n");
00191 bytestream2_seek(&gb, palstart, SEEK_SET);
00192 }
00193 if (bytestream2_get_byte(&gb) != 12) {
00194 av_log(avctx, AV_LOG_ERROR, "expected palette after image data\n");
00195 ret = AVERROR_INVALIDDATA;
00196 goto end;
00197 }
00198
00199 } else if (nplanes == 1) {
00200 GetBitContext s;
00201
00202 for (y=0; y<h; y++) {
00203 init_get_bits(&s, scanline, bytes_per_scanline<<3);
00204
00205 pcx_rle_decode(&gb, scanline, bytes_per_scanline, compressed);
00206
00207 for (x=0; x<w; x++)
00208 ptr[x] = get_bits(&s, bits_per_pixel);
00209 ptr += stride;
00210 }
00211
00212 } else {
00213 int i;
00214
00215 for (y=0; y<h; y++) {
00216 pcx_rle_decode(&gb, scanline, bytes_per_scanline, compressed);
00217
00218 for (x=0; x<w; x++) {
00219 int m = 0x80 >> (x&7), v = 0;
00220 for (i=nplanes - 1; i>=0; i--) {
00221 v <<= 1;
00222 v += !!(scanline[i*bytes_per_line + (x>>3)] & m);
00223 }
00224 ptr[x] = v;
00225 }
00226 ptr += stride;
00227 }
00228 }
00229
00230 ret = bytestream2_tell(&gb);
00231 if (nplanes == 1 && bits_per_pixel == 8) {
00232 pcx_palette(&gb, (uint32_t *) p->data[1], 256);
00233 ret += 256 * 3;
00234 } else if (bits_per_pixel * nplanes == 1) {
00235 AV_WN32A(p->data[1] , 0xFF000000);
00236 AV_WN32A(p->data[1]+4, 0xFFFFFFFF);
00237 } else if (bits_per_pixel < 8) {
00238 bytestream2_seek(&gb, 16, SEEK_SET);
00239 pcx_palette(&gb, (uint32_t *) p->data[1], 16);
00240 }
00241
00242 *picture = s->picture;
00243 *got_frame = 1;
00244
00245 end:
00246 av_free(scanline);
00247 return ret;
00248 }
00249
00250 static av_cold int pcx_end(AVCodecContext *avctx)
00251 {
00252 PCXContext *s = avctx->priv_data;
00253
00254 if(s->picture.data[0])
00255 avctx->release_buffer(avctx, &s->picture);
00256
00257 return 0;
00258 }
00259
00260 AVCodec ff_pcx_decoder = {
00261 .name = "pcx",
00262 .type = AVMEDIA_TYPE_VIDEO,
00263 .id = AV_CODEC_ID_PCX,
00264 .priv_data_size = sizeof(PCXContext),
00265 .init = pcx_init,
00266 .close = pcx_end,
00267 .decode = pcx_decode_frame,
00268 .capabilities = CODEC_CAP_DR1,
00269 .long_name = NULL_IF_CONFIG_SMALL("PC Paintbrush PCX image"),
00270 };