Libav 0.7.1
|
00001 /* 00002 * Pictor/PC Paint decoder 00003 * Copyright (c) 2010 Peter Ross <pross@xvid.org> 00004 * 00005 * This file is part of Libav. 00006 * 00007 * Libav is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * Libav is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with Libav; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 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 } PicContext; 00037 00038 static void picmemset_8bpp(PicContext *s, int value, int run, int *x, int *y) 00039 { 00040 while (run > 0) { 00041 uint8_t *d = s->frame.data[0] + *y * s->frame.linesize[0]; 00042 if (*x + run >= s->width) { 00043 int n = s->width - *x; 00044 memset(d + *x, value, n); 00045 run -= n; 00046 *x = 0; 00047 *y -= 1; 00048 if (*y < 0) 00049 break; 00050 } else { 00051 memset(d + *x, value, run); 00052 *x += run; 00053 break; 00054 } 00055 } 00056 } 00057 00058 static void picmemset(PicContext *s, int value, int run, int *x, int *y, int *plane, int bits_per_plane) 00059 { 00060 uint8_t *d; 00061 int shift = *plane * bits_per_plane; 00062 int mask = ((1 << bits_per_plane) - 1) << shift; 00063 value <<= shift; 00064 00065 while (run > 0) { 00066 int j; 00067 for (j = 8-bits_per_plane; j >= 0; j -= bits_per_plane) { 00068 d = s->frame.data[0] + *y * s->frame.linesize[0]; 00069 d[*x] |= (value >> j) & mask; 00070 *x += 1; 00071 if (*x == s->width) { 00072 *y -= 1; 00073 *x = 0; 00074 if (*y < 0) { 00075 *y = s->height - 1; 00076 *plane += 1; 00077 value <<= bits_per_plane; 00078 mask <<= bits_per_plane; 00079 if (*plane >= s->nb_planes) 00080 break; 00081 } 00082 } 00083 } 00084 run--; 00085 } 00086 } 00087 00088 static const uint8_t cga_mode45_index[6][4] = { 00089 [0] = { 0, 3, 5, 7 }, // mode4, palette#1, low intensity 00090 [1] = { 0, 2, 4, 6 }, // mode4, palette#2, low intensity 00091 [2] = { 0, 3, 4, 7 }, // mode5, low intensity 00092 [3] = { 0, 11, 13, 15 }, // mode4, palette#1, high intensity 00093 [4] = { 0, 10, 12, 14 }, // mode4, palette#2, high intensity 00094 [5] = { 0, 11, 12, 15 }, // mode5, high intensity 00095 }; 00096 00097 static int decode_frame(AVCodecContext *avctx, 00098 void *data, int *data_size, 00099 AVPacket *avpkt) 00100 { 00101 PicContext *s = avctx->priv_data; 00102 int buf_size = avpkt->size; 00103 const uint8_t *buf = avpkt->data; 00104 const uint8_t *buf_end = avpkt->data + buf_size; 00105 uint32_t *palette; 00106 int bits_per_plane, bpp, etype, esize, npal; 00107 int i, x, y, plane; 00108 00109 if (buf_size < 11) 00110 return AVERROR_INVALIDDATA; 00111 00112 if (bytestream_get_le16(&buf) != 0x1234) 00113 return AVERROR_INVALIDDATA; 00114 s->width = bytestream_get_le16(&buf); 00115 s->height = bytestream_get_le16(&buf); 00116 buf += 4; 00117 bits_per_plane = *buf & 0xF; 00118 s->nb_planes = (*buf++ >> 4) + 1; 00119 bpp = s->nb_planes ? bits_per_plane*s->nb_planes : bits_per_plane; 00120 if (bits_per_plane > 8 || bpp < 1 || bpp > 32) { 00121 av_log_ask_for_sample(s, "unsupported bit depth\n"); 00122 return AVERROR_INVALIDDATA; 00123 } 00124 00125 if (*buf == 0xFF) { 00126 buf += 2; 00127 etype = bytestream_get_le16(&buf); 00128 esize = bytestream_get_le16(&buf); 00129 if (buf_end - buf < esize) 00130 return AVERROR_INVALIDDATA; 00131 } else { 00132 etype = -1; 00133 esize = 0; 00134 } 00135 00136 avctx->pix_fmt = PIX_FMT_PAL8; 00137 00138 if (s->width != avctx->width && s->height != avctx->height) { 00139 if (av_image_check_size(s->width, s->height, 0, avctx) < 0) 00140 return -1; 00141 avcodec_set_dimensions(avctx, s->width, s->height); 00142 if (s->frame.data[0]) 00143 avctx->release_buffer(avctx, &s->frame); 00144 } 00145 00146 if (avctx->get_buffer(avctx, &s->frame) < 0){ 00147 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); 00148 return -1; 00149 } 00150 memset(s->frame.data[0], 0, s->height * s->frame.linesize[0]); 00151 s->frame.pict_type = AV_PICTURE_TYPE_I; 00152 s->frame.palette_has_changed = 1; 00153 00154 palette = (uint32_t*)s->frame.data[1]; 00155 if (etype == 1 && esize > 1 && *buf < 6) { 00156 int idx = *buf; 00157 npal = 4; 00158 for (i = 0; i < npal; i++) 00159 palette[i] = ff_cga_palette[ cga_mode45_index[idx][i] ]; 00160 } else if (etype == 2) { 00161 npal = FFMIN(esize, 16); 00162 for (i = 0; i < npal; i++) 00163 palette[i] = ff_cga_palette[ FFMIN(buf[i], 16)]; 00164 } else if (etype == 3) { 00165 npal = FFMIN(esize, 16); 00166 for (i = 0; i < npal; i++) 00167 palette[i] = ff_ega_palette[ FFMIN(buf[i], 63)]; 00168 } else if (etype == 4 || etype == 5) { 00169 npal = FFMIN(esize / 3, 256); 00170 for (i = 0; i < npal; i++) 00171 palette[i] = AV_RB24(buf + i*3) << 2; 00172 } else { 00173 if (bpp == 1) { 00174 npal = 2; 00175 palette[0] = 0x000000; 00176 palette[1] = 0xFFFFFF; 00177 } else if (bpp == 2) { 00178 npal = 4; 00179 for (i = 0; i < npal; i++) 00180 palette[i] = ff_cga_palette[ cga_mode45_index[0][i] ]; 00181 } else { 00182 npal = 16; 00183 memcpy(palette, ff_cga_palette, npal * 4); 00184 } 00185 } 00186 // fill remaining palette entries 00187 memset(palette + npal, 0, AVPALETTE_SIZE - npal * 4); 00188 buf += esize; 00189 00190 00191 x = 0; 00192 y = s->height - 1; 00193 plane = 0; 00194 if (bytestream_get_le16(&buf)) { 00195 while (buf_end - buf >= 6) { 00196 const uint8_t *buf_pend = buf + FFMIN(AV_RL16(buf), buf_end - buf); 00197 //ignore uncompressed block size reported at buf[2] 00198 int marker = buf[4]; 00199 buf += 5; 00200 00201 while (plane < s->nb_planes && buf_pend - buf >= 1) { 00202 int run = 1; 00203 int val = *buf++; 00204 if (val == marker) { 00205 run = *buf++; 00206 if (run == 0) 00207 run = bytestream_get_le16(&buf); 00208 val = *buf++; 00209 } 00210 if (buf > buf_end) 00211 break; 00212 00213 if (bits_per_plane == 8) { 00214 picmemset_8bpp(s, val, run, &x, &y); 00215 if (y < 0) 00216 break; 00217 } else { 00218 picmemset(s, val, run, &x, &y, &plane, bits_per_plane); 00219 } 00220 } 00221 } 00222 } else { 00223 av_log_ask_for_sample(s, "uncompressed image\n"); 00224 return buf_size; 00225 } 00226 00227 *data_size = sizeof(AVFrame); 00228 *(AVFrame*)data = s->frame; 00229 return buf_size; 00230 } 00231 00232 static av_cold int decode_end(AVCodecContext *avctx) 00233 { 00234 PicContext *s = avctx->priv_data; 00235 if (s->frame.data[0]) 00236 avctx->release_buffer(avctx, &s->frame); 00237 return 0; 00238 } 00239 00240 AVCodec ff_pictor_decoder = { 00241 "pictor", 00242 AVMEDIA_TYPE_VIDEO, 00243 CODEC_ID_PICTOR, 00244 sizeof(PicContext), 00245 NULL, 00246 NULL, 00247 decode_end, 00248 decode_frame, 00249 CODEC_CAP_DR1, 00250 .long_name = NULL_IF_CONFIG_SMALL("Pictor/PC Paint"), 00251 };