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;
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_OLD || 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 = PIX_FMT_MONOWHITE;
00094 break;
00095 case 8:
00096 avctx->pix_fmt = PIX_FMT_PAL8;
00097 break;
00098 case 24:
00099 avctx->pix_fmt = (type == RT_FORMAT_RGB) ? PIX_FMT_RGB24 : PIX_FMT_BGR24;
00100 break;
00101 default:
00102 av_log(avctx, AV_LOG_ERROR, "invalid depth\n");
00103 return -1;
00104 }
00105
00106 if (p->data[0])
00107 avctx->release_buffer(avctx, p);
00108
00109 if (w != avctx->width || h != avctx->height)
00110 avcodec_set_dimensions(avctx, w, h);
00111 if (avctx->get_buffer(avctx, p) < 0) {
00112 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00113 return -1;
00114 }
00115
00116 p->pict_type = AV_PICTURE_TYPE_I;
00117
00118 if (buf_end - buf < maplength)
00119 return AVERROR_INVALIDDATA;
00120
00121 if (depth != 8 && maplength) {
00122 av_log(avctx, AV_LOG_WARNING, "useless colormap found or file is corrupted, trying to recover\n");
00123
00124 } else if (depth == 8) {
00125 unsigned int len = maplength / 3;
00126
00127 if (!maplength) {
00128 av_log(avctx, AV_LOG_ERROR, "colormap expected\n");
00129 return -1;
00130 }
00131 if (maplength % 3 || maplength > 768) {
00132 av_log(avctx, AV_LOG_WARNING, "invalid colormap length\n");
00133 return -1;
00134 }
00135
00136 ptr = p->data[1];
00137 for (x=0; x<len; x++, ptr+=4)
00138 *(uint32_t *)ptr = (0xFF<<24) + (buf[x]<<16) + (buf[len+x]<<8) + buf[len+len+x];
00139 }
00140
00141 buf += maplength;
00142
00143 ptr = p->data[0];
00144 stride = p->linesize[0];
00145
00146
00147 len = (depth * w + 7) >> 3;
00148 alen = len + (len&1);
00149
00150 if (type == RT_BYTE_ENCODED) {
00151 int value, run;
00152 uint8_t *end = ptr + h*stride;
00153
00154 x = 0;
00155 while (ptr != end && buf < buf_end) {
00156 run = 1;
00157 if (buf_end - buf < 1)
00158 return AVERROR_INVALIDDATA;
00159
00160 if ((value = *buf++) == 0x80) {
00161 run = *buf++ + 1;
00162 if (run != 1)
00163 value = *buf++;
00164 }
00165 while (run--) {
00166 if (x < len)
00167 ptr[x] = value;
00168 if (++x >= alen) {
00169 x = 0;
00170 ptr += stride;
00171 if (ptr == end)
00172 break;
00173 }
00174 }
00175 }
00176 } else {
00177 for (y=0; y<h; y++) {
00178 if (buf_end - buf < len)
00179 break;
00180 memcpy(ptr, buf, len);
00181 ptr += stride;
00182 buf += alen;
00183 }
00184 }
00185
00186 *picture = s->picture;
00187 *data_size = sizeof(AVFrame);
00188
00189 return buf - bufstart;
00190 }
00191
00192 static av_cold int sunrast_end(AVCodecContext *avctx) {
00193 SUNRASTContext *s = avctx->priv_data;
00194
00195 if(s->picture.data[0])
00196 avctx->release_buffer(avctx, &s->picture);
00197
00198 return 0;
00199 }
00200
00201 AVCodec ff_sunrast_decoder = {
00202 .name = "sunrast",
00203 .type = AVMEDIA_TYPE_VIDEO,
00204 .id = CODEC_ID_SUNRAST,
00205 .priv_data_size = sizeof(SUNRASTContext),
00206 .init = sunrast_init,
00207 .close = sunrast_end,
00208 .decode = sunrast_decode_frame,
00209 .capabilities = CODEC_CAP_DR1,
00210 .long_name = NULL_IF_CONFIG_SMALL("Sun Rasterfile image"),
00211 };