1/* 2 * Sun Rasterfile (.sun/.ras/im{1,8,24}/.sunras) image decoder 3 * Copyright (c) 2007, 2008 Ivo van Poorten 4 * 5 * This file is part of Libav. 6 * 7 * Libav is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * Libav is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with Libav; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22#include "libavutil/intreadwrite.h" 23#include "libavutil/imgutils.h" 24#include "avcodec.h" 25 26#define RT_OLD 0 27#define RT_STANDARD 1 28#define RT_BYTE_ENCODED 2 29#define RT_FORMAT_RGB 3 30#define RT_FORMAT_TIFF 4 31#define RT_FORMAT_IFF 5 32 33typedef struct SUNRASTContext { 34 AVFrame picture; 35} SUNRASTContext; 36 37static av_cold int sunrast_init(AVCodecContext *avctx) { 38 SUNRASTContext *s = avctx->priv_data; 39 40 avcodec_get_frame_defaults(&s->picture); 41 avctx->coded_frame= &s->picture; 42 43 return 0; 44} 45 46static int sunrast_decode_frame(AVCodecContext *avctx, void *data, 47 int *data_size, AVPacket *avpkt) { 48 const uint8_t *buf = avpkt->data; 49 const uint8_t *buf_end = avpkt->data + avpkt->size; 50 SUNRASTContext * const s = avctx->priv_data; 51 AVFrame *picture = data; 52 AVFrame * const p = &s->picture; 53 unsigned int w, h, depth, type, maptype, maplength, stride, x, y, len, alen; 54 uint8_t *ptr; 55 const uint8_t *bufstart = buf; 56 57 if (avpkt->size < 32) 58 return AVERROR_INVALIDDATA; 59 60 if (AV_RB32(buf) != 0x59a66a95) { 61 av_log(avctx, AV_LOG_ERROR, "this is not sunras encoded data\n"); 62 return -1; 63 } 64 65 w = AV_RB32(buf+4); 66 h = AV_RB32(buf+8); 67 depth = AV_RB32(buf+12); 68 type = AV_RB32(buf+20); 69 maptype = AV_RB32(buf+24); 70 maplength = AV_RB32(buf+28); 71 buf += 32; 72 73 if (type == RT_FORMAT_TIFF || type == RT_FORMAT_IFF) { 74 av_log(avctx, AV_LOG_ERROR, "unsupported (compression) type\n"); 75 return -1; 76 } 77 if (type < RT_OLD || type > RT_FORMAT_IFF) { 78 av_log(avctx, AV_LOG_ERROR, "invalid (compression) type\n"); 79 return -1; 80 } 81 if (av_image_check_size(w, h, 0, avctx)) { 82 av_log(avctx, AV_LOG_ERROR, "invalid image size\n"); 83 return -1; 84 } 85 if (maptype & ~1) { 86 av_log(avctx, AV_LOG_ERROR, "invalid colormap type\n"); 87 return -1; 88 } 89 90 91 switch (depth) { 92 case 1: 93 avctx->pix_fmt = PIX_FMT_MONOWHITE; 94 break; 95 case 8: 96 avctx->pix_fmt = PIX_FMT_PAL8; 97 break; 98 case 24: 99 avctx->pix_fmt = (type == RT_FORMAT_RGB) ? PIX_FMT_RGB24 : PIX_FMT_BGR24; 100 break; 101 default: 102 av_log(avctx, AV_LOG_ERROR, "invalid depth\n"); 103 return -1; 104 } 105 106 if (p->data[0]) 107 avctx->release_buffer(avctx, p); 108 109 if (w != avctx->width || h != avctx->height) 110 avcodec_set_dimensions(avctx, w, h); 111 if (avctx->get_buffer(avctx, p) < 0) { 112 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); 113 return -1; 114 } 115 116 p->pict_type = AV_PICTURE_TYPE_I; 117 118 if (buf_end - buf < maplength) 119 return AVERROR_INVALIDDATA; 120 121 if (depth != 8 && maplength) { 122 av_log(avctx, AV_LOG_WARNING, "useless colormap found or file is corrupted, trying to recover\n"); 123 124 } else if (depth == 8) { 125 unsigned int len = maplength / 3; 126 127 if (!maplength) { 128 av_log(avctx, AV_LOG_ERROR, "colormap expected\n"); 129 return -1; 130 } 131 if (maplength % 3 || maplength > 768) { 132 av_log(avctx, AV_LOG_WARNING, "invalid colormap length\n"); 133 return -1; 134 } 135 136 ptr = p->data[1]; 137 for (x=0; x<len; x++, ptr+=4) 138 *(uint32_t *)ptr = (buf[x]<<16) + (buf[len+x]<<8) + buf[len+len+x]; 139 } 140 141 buf += maplength; 142 143 ptr = p->data[0]; 144 stride = p->linesize[0]; 145 146 /* scanlines are aligned on 16 bit boundaries */ 147 len = (depth * w + 7) >> 3; 148 alen = len + (len&1); 149 150 if (type == RT_BYTE_ENCODED) { 151 int value, run; 152 uint8_t *end = ptr + h*stride; 153 154 x = 0; 155 while (ptr != end && buf < buf_end) { 156 run = 1; 157 if (buf_end - buf < 1) 158 return AVERROR_INVALIDDATA; 159 160 if ((value = *buf++) == 0x80) { 161 run = *buf++ + 1; 162 if (run != 1) 163 value = *buf++; 164 } 165 while (run--) { 166 if (x < len) 167 ptr[x] = value; 168 if (++x >= alen) { 169 x = 0; 170 ptr += stride; 171 if (ptr == end) 172 break; 173 } 174 } 175 } 176 } else { 177 for (y=0; y<h; y++) { 178 if (buf_end - buf < len) 179 break; 180 memcpy(ptr, buf, len); 181 ptr += stride; 182 buf += alen; 183 } 184 } 185 186 *picture = s->picture; 187 *data_size = sizeof(AVFrame); 188 189 return buf - bufstart; 190} 191 192static av_cold int sunrast_end(AVCodecContext *avctx) { 193 SUNRASTContext *s = avctx->priv_data; 194 195 if(s->picture.data[0]) 196 avctx->release_buffer(avctx, &s->picture); 197 198 return 0; 199} 200 201AVCodec ff_sunrast_decoder = { 202 .name = "sunrast", 203 .type = AVMEDIA_TYPE_VIDEO, 204 .id = CODEC_ID_SUNRAST, 205 .priv_data_size = sizeof(SUNRASTContext), 206 .init = sunrast_init, 207 .close = sunrast_end, 208 .decode = sunrast_decode_frame, 209 .capabilities = CODEC_CAP_DR1, 210 .long_name = NULL_IF_CONFIG_SMALL("Sun Rasterfile image"), 211}; 212