00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "libavutil/intreadwrite.h"
00023 #include "libavutil/imgutils.h"
00024 #include "avcodec.h"
00025
00026 #define RT_OLD 0
00027 #define RT_STANDARD 1
00028 #define RT_BYTE_ENCODED 2
00029 #define RT_FORMAT_RGB 3
00030 #define RT_FORMAT_TIFF 4
00031 #define RT_FORMAT_IFF 5
00032
00033 typedef struct SUNRASTContext {
00034 AVFrame picture;
00035 } SUNRASTContext;
00036
00037 static av_cold int sunrast_init(AVCodecContext *avctx) {
00038 SUNRASTContext *s = avctx->priv_data;
00039
00040 avcodec_get_frame_defaults(&s->picture);
00041 avctx->coded_frame= &s->picture;
00042
00043 return 0;
00044 }
00045
00046 static int sunrast_decode_frame(AVCodecContext *avctx, void *data,
00047 int *data_size, AVPacket *avpkt) {
00048 const uint8_t *buf = avpkt->data;
00049 const uint8_t *buf_end = avpkt->data + avpkt->size;
00050 SUNRASTContext * const s = avctx->priv_data;
00051 AVFrame *picture = data;
00052 AVFrame * const p = &s->picture;
00053 unsigned int w, h, depth, type, maptype, maplength, stride, x, y, len, alen;
00054 uint8_t *ptr, *ptr2 = NULL;
00055 const uint8_t *bufstart = buf;
00056
00057 if (avpkt->size < 32)
00058 return AVERROR_INVALIDDATA;
00059
00060 if (AV_RB32(buf) != 0x59a66a95) {
00061 av_log(avctx, AV_LOG_ERROR, "this is not sunras encoded data\n");
00062 return -1;
00063 }
00064
00065 w = AV_RB32(buf+4);
00066 h = AV_RB32(buf+8);
00067 depth = AV_RB32(buf+12);
00068 type = AV_RB32(buf+20);
00069 maptype = AV_RB32(buf+24);
00070 maplength = AV_RB32(buf+28);
00071 buf += 32;
00072
00073 if (type > RT_FORMAT_IFF) {
00074 av_log(avctx, AV_LOG_ERROR, "invalid (compression) type\n");
00075 return -1;
00076 }
00077 if (av_image_check_size(w, h, 0, avctx)) {
00078 av_log(avctx, AV_LOG_ERROR, "invalid image size\n");
00079 return -1;
00080 }
00081 if (maptype & ~1) {
00082 av_log(avctx, AV_LOG_ERROR, "invalid colormap type\n");
00083 return -1;
00084 }
00085
00086 if (type == RT_FORMAT_TIFF || type == RT_FORMAT_IFF) {
00087 av_log(avctx, AV_LOG_ERROR, "unsupported (compression) type\n");
00088 return -1;
00089 }
00090
00091 switch (depth) {
00092 case 1:
00093 avctx->pix_fmt = maplength ? PIX_FMT_PAL8 : PIX_FMT_MONOWHITE;
00094 break;
00095 case 4:
00096 avctx->pix_fmt = maplength ? PIX_FMT_PAL8 : PIX_FMT_NONE;
00097 break;
00098 case 8:
00099 avctx->pix_fmt = maplength ? PIX_FMT_PAL8 : PIX_FMT_GRAY8;
00100 break;
00101 case 24:
00102 avctx->pix_fmt = (type == RT_FORMAT_RGB) ? PIX_FMT_RGB24 : PIX_FMT_BGR24;
00103 break;
00104 case 32:
00105 avctx->pix_fmt = (type == RT_FORMAT_RGB) ? PIX_FMT_RGB0 : PIX_FMT_BGR0;
00106 break;
00107 default:
00108 av_log(avctx, AV_LOG_ERROR, "invalid depth\n");
00109 return -1;
00110 }
00111
00112 if (p->data[0])
00113 avctx->release_buffer(avctx, p);
00114
00115 if (w != avctx->width || h != avctx->height)
00116 avcodec_set_dimensions(avctx, w, h);
00117 if (avctx->get_buffer(avctx, p) < 0) {
00118 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00119 return -1;
00120 }
00121
00122 p->pict_type = AV_PICTURE_TYPE_I;
00123
00124 if (buf_end - buf < maplength)
00125 return AVERROR_INVALIDDATA;
00126
00127 if (depth > 8 && maplength) {
00128 av_log(avctx, AV_LOG_WARNING, "useless colormap found or file is corrupted, trying to recover\n");
00129
00130 } else if (maplength) {
00131 unsigned int len = maplength / 3;
00132
00133 if (!maplength) {
00134 av_log(avctx, AV_LOG_ERROR, "colormap expected\n");
00135 return -1;
00136 }
00137 if (maplength % 3 || maplength > 768) {
00138 av_log(avctx, AV_LOG_WARNING, "invalid colormap length\n");
00139 return -1;
00140 }
00141
00142 ptr = p->data[1];
00143 for (x=0; x<len; x++, ptr+=4)
00144 *(uint32_t *)ptr = (0xFF<<24) + (buf[x]<<16) + (buf[len+x]<<8) + buf[len+len+x];
00145 }
00146
00147 buf += maplength;
00148
00149 if (maplength && depth < 8) {
00150 ptr = ptr2 = av_malloc((w + 15) * h);
00151 if (!ptr)
00152 return AVERROR(ENOMEM);
00153 stride = (w + 15 >> 3) * depth;
00154 } else {
00155 ptr = p->data[0];
00156 stride = p->linesize[0];
00157 }
00158
00159
00160 len = (depth * w + 7) >> 3;
00161 alen = len + (len&1);
00162
00163 if (type == RT_BYTE_ENCODED) {
00164 int value, run;
00165 uint8_t *end = ptr + h*stride;
00166
00167 x = 0;
00168 while (ptr != end && buf < buf_end) {
00169 run = 1;
00170 if (buf_end - buf < 1)
00171 return AVERROR_INVALIDDATA;
00172
00173 if ((value = *buf++) == 0x80) {
00174 run = *buf++ + 1;
00175 if (run != 1)
00176 value = *buf++;
00177 }
00178 while (run--) {
00179 if (x < len)
00180 ptr[x] = value;
00181 if (++x >= alen) {
00182 x = 0;
00183 ptr += stride;
00184 if (ptr == end)
00185 break;
00186 }
00187 }
00188 }
00189 } else {
00190 for (y=0; y<h; y++) {
00191 if (buf_end - buf < len)
00192 break;
00193 memcpy(ptr, buf, len);
00194 ptr += stride;
00195 buf += alen;
00196 }
00197 }
00198 if (avctx->pix_fmt == PIX_FMT_PAL8 && depth < 8) {
00199 uint8_t *ptr_free = ptr2;
00200 ptr = p->data[0];
00201 for (y=0; y<h; y++) {
00202 for (x = 0; x < (w + 7 >> 3) * depth; x++) {
00203 if (depth == 1) {
00204 ptr[8*x] = ptr2[x] >> 7;
00205 ptr[8*x+1] = ptr2[x] >> 6 & 1;
00206 ptr[8*x+2] = ptr2[x] >> 5 & 1;
00207 ptr[8*x+3] = ptr2[x] >> 4 & 1;
00208 ptr[8*x+4] = ptr2[x] >> 3 & 1;
00209 ptr[8*x+5] = ptr2[x] >> 2 & 1;
00210 ptr[8*x+6] = ptr2[x] >> 1 & 1;
00211 ptr[8*x+7] = ptr2[x] & 1;
00212 } else {
00213 ptr[2*x] = ptr2[x] >> 4;
00214 ptr[2*x+1] = ptr2[x] & 0xF;
00215 }
00216 }
00217 ptr += p->linesize[0];
00218 ptr2 += (w + 15 >> 3) * depth;
00219 }
00220 av_freep(&ptr_free);
00221 }
00222
00223 *picture = s->picture;
00224 *data_size = sizeof(AVFrame);
00225
00226 return buf - bufstart;
00227 }
00228
00229 static av_cold int sunrast_end(AVCodecContext *avctx) {
00230 SUNRASTContext *s = avctx->priv_data;
00231
00232 if(s->picture.data[0])
00233 avctx->release_buffer(avctx, &s->picture);
00234
00235 return 0;
00236 }
00237
00238 AVCodec ff_sunrast_decoder = {
00239 .name = "sunrast",
00240 .type = AVMEDIA_TYPE_VIDEO,
00241 .id = CODEC_ID_SUNRAST,
00242 .priv_data_size = sizeof(SUNRASTContext),
00243 .init = sunrast_init,
00244 .close = sunrast_end,
00245 .decode = sunrast_decode_frame,
00246 .capabilities = CODEC_CAP_DR1,
00247 .long_name = NULL_IF_CONFIG_SMALL("Sun Rasterfile image"),
00248 };