Libav 0.7.1
|
00001 /* 00002 * PC Paintbrush PCX (.pcx) image decoder 00003 * Copyright (c) 2007, 2008 Ivo van Poorten 00004 * 00005 * This decoder does not support CGA palettes. I am unable to find samples 00006 * and Netpbm cannot generate them. 00007 * 00008 * This file is part of Libav. 00009 * 00010 * Libav is free software; you can redistribute it and/or 00011 * modify it under the terms of the GNU Lesser General Public 00012 * License as published by the Free Software Foundation; either 00013 * version 2.1 of the License, or (at your option) any later version. 00014 * 00015 * Libav is distributed in the hope that it will be useful, 00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00018 * Lesser General Public License for more details. 00019 * 00020 * You should have received a copy of the GNU Lesser General Public 00021 * License along with Libav; if not, write to the Free Software 00022 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00023 */ 00024 00025 #include "libavutil/imgutils.h" 00026 #include "avcodec.h" 00027 #include "bytestream.h" 00028 #include "get_bits.h" 00029 00030 typedef struct PCXContext { 00031 AVFrame picture; 00032 } PCXContext; 00033 00034 static av_cold int pcx_init(AVCodecContext *avctx) { 00035 PCXContext *s = avctx->priv_data; 00036 00037 avcodec_get_frame_defaults(&s->picture); 00038 avctx->coded_frame= &s->picture; 00039 00040 return 0; 00041 } 00042 00046 static const uint8_t *pcx_rle_decode(const uint8_t *src, uint8_t *dst, 00047 unsigned int bytes_per_scanline, int compressed) { 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 = *src++; 00055 if (value >= 0xc0) { 00056 run = value & 0x3f; 00057 value = *src++; 00058 } 00059 while (i<bytes_per_scanline && run--) 00060 dst[i++] = value; 00061 } 00062 } else { 00063 memcpy(dst, src, bytes_per_scanline); 00064 src += bytes_per_scanline; 00065 } 00066 00067 return src; 00068 } 00069 00070 static void pcx_palette(const uint8_t **src, uint32_t *dst, unsigned int pallen) { 00071 unsigned int i; 00072 00073 for (i=0; i<pallen; i++) 00074 *dst++ = bytestream_get_be24(src); 00075 if (pallen < 256) 00076 memset(dst, 0, (256 - pallen) * sizeof(*dst)); 00077 } 00078 00079 static int pcx_decode_frame(AVCodecContext *avctx, void *data, int *data_size, 00080 AVPacket *avpkt) { 00081 const uint8_t *buf = avpkt->data; 00082 int buf_size = avpkt->size; 00083 PCXContext * const s = avctx->priv_data; 00084 AVFrame *picture = data; 00085 AVFrame * const p = &s->picture; 00086 int compressed, xmin, ymin, xmax, ymax; 00087 unsigned int w, h, bits_per_pixel, bytes_per_line, nplanes, stride, y, x, 00088 bytes_per_scanline; 00089 uint8_t *ptr; 00090 uint8_t const *bufstart = buf; 00091 uint8_t *scanline; 00092 int ret = -1; 00093 00094 if (buf[0] != 0x0a || buf[1] > 5) { 00095 av_log(avctx, AV_LOG_ERROR, "this is not PCX encoded data\n"); 00096 return -1; 00097 } 00098 00099 compressed = buf[2]; 00100 xmin = AV_RL16(buf+ 4); 00101 ymin = AV_RL16(buf+ 6); 00102 xmax = AV_RL16(buf+ 8); 00103 ymax = AV_RL16(buf+10); 00104 00105 if (xmax < xmin || ymax < ymin) { 00106 av_log(avctx, AV_LOG_ERROR, "invalid image dimensions\n"); 00107 return -1; 00108 } 00109 00110 w = xmax - xmin + 1; 00111 h = ymax - ymin + 1; 00112 00113 bits_per_pixel = buf[3]; 00114 bytes_per_line = AV_RL16(buf+66); 00115 nplanes = buf[65]; 00116 bytes_per_scanline = nplanes * bytes_per_line; 00117 00118 if (bytes_per_scanline < w * bits_per_pixel * nplanes / 8) { 00119 av_log(avctx, AV_LOG_ERROR, "PCX data is corrupted\n"); 00120 return -1; 00121 } 00122 00123 switch ((nplanes<<8) + bits_per_pixel) { 00124 case 0x0308: 00125 avctx->pix_fmt = PIX_FMT_RGB24; 00126 break; 00127 case 0x0108: 00128 case 0x0104: 00129 case 0x0102: 00130 case 0x0101: 00131 case 0x0401: 00132 case 0x0301: 00133 case 0x0201: 00134 avctx->pix_fmt = PIX_FMT_PAL8; 00135 break; 00136 default: 00137 av_log(avctx, AV_LOG_ERROR, "invalid PCX file\n"); 00138 return -1; 00139 } 00140 00141 buf += 128; 00142 00143 if (p->data[0]) 00144 avctx->release_buffer(avctx, p); 00145 00146 if (av_image_check_size(w, h, 0, avctx)) 00147 return -1; 00148 if (w != avctx->width || h != avctx->height) 00149 avcodec_set_dimensions(avctx, w, h); 00150 if (avctx->get_buffer(avctx, p) < 0) { 00151 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); 00152 return -1; 00153 } 00154 00155 p->pict_type = AV_PICTURE_TYPE_I; 00156 00157 ptr = p->data[0]; 00158 stride = p->linesize[0]; 00159 00160 scanline = av_malloc(bytes_per_scanline); 00161 if (!scanline) 00162 return AVERROR(ENOMEM); 00163 00164 if (nplanes == 3 && bits_per_pixel == 8) { 00165 for (y=0; y<h; y++) { 00166 buf = pcx_rle_decode(buf, scanline, bytes_per_scanline, compressed); 00167 00168 for (x=0; x<w; x++) { 00169 ptr[3*x ] = scanline[x ]; 00170 ptr[3*x+1] = scanline[x+ bytes_per_line ]; 00171 ptr[3*x+2] = scanline[x+(bytes_per_line<<1)]; 00172 } 00173 00174 ptr += stride; 00175 } 00176 00177 } else if (nplanes == 1 && bits_per_pixel == 8) { 00178 const uint8_t *palstart = bufstart + buf_size - 769; 00179 00180 for (y=0; y<h; y++, ptr+=stride) { 00181 buf = pcx_rle_decode(buf, scanline, bytes_per_scanline, compressed); 00182 memcpy(ptr, scanline, w); 00183 } 00184 00185 if (buf != palstart) { 00186 av_log(avctx, AV_LOG_WARNING, "image data possibly corrupted\n"); 00187 buf = palstart; 00188 } 00189 if (*buf++ != 12) { 00190 av_log(avctx, AV_LOG_ERROR, "expected palette after image data\n"); 00191 goto end; 00192 } 00193 00194 } else if (nplanes == 1) { /* all packed formats, max. 16 colors */ 00195 GetBitContext s; 00196 00197 for (y=0; y<h; y++) { 00198 init_get_bits(&s, scanline, bytes_per_scanline<<3); 00199 00200 buf = pcx_rle_decode(buf, scanline, bytes_per_scanline, compressed); 00201 00202 for (x=0; x<w; x++) 00203 ptr[x] = get_bits(&s, bits_per_pixel); 00204 ptr += stride; 00205 } 00206 00207 } else { /* planar, 4, 8 or 16 colors */ 00208 int i; 00209 00210 for (y=0; y<h; y++) { 00211 buf = pcx_rle_decode(buf, scanline, bytes_per_scanline, compressed); 00212 00213 for (x=0; x<w; x++) { 00214 int m = 0x80 >> (x&7), v = 0; 00215 for (i=nplanes - 1; i>=0; i--) { 00216 v <<= 1; 00217 v += !!(scanline[i*bytes_per_line + (x>>3)] & m); 00218 } 00219 ptr[x] = v; 00220 } 00221 ptr += stride; 00222 } 00223 } 00224 00225 if (nplanes == 1 && bits_per_pixel == 8) { 00226 pcx_palette(&buf, (uint32_t *) p->data[1], 256); 00227 } else if (bits_per_pixel < 8) { 00228 const uint8_t *palette = bufstart+16; 00229 pcx_palette(&palette, (uint32_t *) p->data[1], 16); 00230 } 00231 00232 *picture = s->picture; 00233 *data_size = sizeof(AVFrame); 00234 00235 ret = buf - bufstart; 00236 end: 00237 av_free(scanline); 00238 return ret; 00239 } 00240 00241 static av_cold int pcx_end(AVCodecContext *avctx) { 00242 PCXContext *s = avctx->priv_data; 00243 00244 if(s->picture.data[0]) 00245 avctx->release_buffer(avctx, &s->picture); 00246 00247 return 0; 00248 } 00249 00250 AVCodec ff_pcx_decoder = { 00251 "pcx", 00252 AVMEDIA_TYPE_VIDEO, 00253 CODEC_ID_PCX, 00254 sizeof(PCXContext), 00255 pcx_init, 00256 NULL, 00257 pcx_end, 00258 pcx_decode_frame, 00259 CODEC_CAP_DR1, 00260 NULL, 00261 .long_name = NULL_IF_CONFIG_SMALL("PC Paintbrush PCX image"), 00262 };