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 FFmpeg. 6 * 7 * FFmpeg 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 * FFmpeg 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 FFmpeg; 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/common.h" 23#include "libavutil/intreadwrite.h" 24#include "libavutil/imgutils.h" 25#include "avcodec.h" 26#include "internal.h" 27#include "sunrast.h" 28 29static int sunrast_decode_frame(AVCodecContext *avctx, void *data, 30 int *got_frame, AVPacket *avpkt) 31{ 32 const uint8_t *buf = avpkt->data; 33 const uint8_t *buf_end = avpkt->data + avpkt->size; 34 AVFrame * const p = data; 35 unsigned int w, h, depth, type, maptype, maplength, stride, x, y, len, alen; 36 uint8_t *ptr, *ptr2 = NULL; 37 const uint8_t *bufstart = buf; 38 int ret; 39 40 if (avpkt->size < 32) 41 return AVERROR_INVALIDDATA; 42 43 if (AV_RB32(buf) != RAS_MAGIC) { 44 av_log(avctx, AV_LOG_ERROR, "this is not sunras encoded data\n"); 45 return AVERROR_INVALIDDATA; 46 } 47 48 w = AV_RB32(buf + 4); 49 h = AV_RB32(buf + 8); 50 depth = AV_RB32(buf + 12); 51 type = AV_RB32(buf + 20); 52 maptype = AV_RB32(buf + 24); 53 maplength = AV_RB32(buf + 28); 54 buf += 32; 55 56 if (type == RT_EXPERIMENTAL) { 57 avpriv_request_sample(avctx, "TIFF/IFF/EXPERIMENTAL (compression) type"); 58 return AVERROR_PATCHWELCOME; 59 } 60 if (type > RT_FORMAT_IFF) { 61 av_log(avctx, AV_LOG_ERROR, "invalid (compression) type\n"); 62 return AVERROR_INVALIDDATA; 63 } 64 if (maptype == RMT_RAW) { 65 avpriv_request_sample(avctx, "Unknown colormap type"); 66 return AVERROR_PATCHWELCOME; 67 } 68 if (maptype > RMT_RAW) { 69 av_log(avctx, AV_LOG_ERROR, "invalid colormap type\n"); 70 return AVERROR_INVALIDDATA; 71 } 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 78 switch (depth) { 79 case 1: 80 avctx->pix_fmt = maplength ? AV_PIX_FMT_PAL8 : AV_PIX_FMT_MONOWHITE; 81 break; 82 case 4: 83 avctx->pix_fmt = maplength ? AV_PIX_FMT_PAL8 : AV_PIX_FMT_NONE; 84 break; 85 case 8: 86 avctx->pix_fmt = maplength ? AV_PIX_FMT_PAL8 : AV_PIX_FMT_GRAY8; 87 break; 88 case 24: 89 avctx->pix_fmt = (type == RT_FORMAT_RGB) ? AV_PIX_FMT_RGB24 : AV_PIX_FMT_BGR24; 90 break; 91 case 32: 92 avctx->pix_fmt = (type == RT_FORMAT_RGB) ? AV_PIX_FMT_0RGB : AV_PIX_FMT_0BGR; 93 break; 94 default: 95 av_log(avctx, AV_LOG_ERROR, "invalid depth\n"); 96 return AVERROR_INVALIDDATA; 97 } 98 99 ret = ff_set_dimensions(avctx, w, h); 100 if (ret < 0) 101 return ret; 102 103 if ((ret = ff_get_buffer(avctx, p, 0)) < 0) 104 return ret; 105 106 p->pict_type = AV_PICTURE_TYPE_I; 107 108 if (buf_end - buf < maplength) 109 return AVERROR_INVALIDDATA; 110 111 if (depth > 8 && maplength) { 112 av_log(avctx, AV_LOG_WARNING, "useless colormap found or file is corrupted, trying to recover\n"); 113 114 } else if (maplength) { 115 unsigned int len = maplength / 3; 116 117 if (maplength % 3 || maplength > 768) { 118 av_log(avctx, AV_LOG_WARNING, "invalid colormap length\n"); 119 return AVERROR_INVALIDDATA; 120 } 121 122 ptr = p->data[1]; 123 for (x = 0; x < len; x++, ptr += 4) 124 *(uint32_t *)ptr = (0xFFU<<24) + (buf[x]<<16) + (buf[len+x]<<8) + buf[len+len+x]; 125 } 126 127 buf += maplength; 128 129 if (maplength && depth < 8) { 130 ptr = ptr2 = av_malloc((w + 15) * h); 131 if (!ptr) 132 return AVERROR(ENOMEM); 133 stride = (w + 15 >> 3) * depth; 134 } else { 135 ptr = p->data[0]; 136 stride = p->linesize[0]; 137 } 138 139 /* scanlines are aligned on 16 bit boundaries */ 140 len = (depth * w + 7) >> 3; 141 alen = len + (len & 1); 142 143 if (type == RT_BYTE_ENCODED) { 144 int value, run; 145 uint8_t *end = ptr + h * stride; 146 147 x = 0; 148 while (ptr != end && buf < buf_end) { 149 run = 1; 150 if (buf_end - buf < 1) 151 return AVERROR_INVALIDDATA; 152 153 if ((value = *buf++) == RLE_TRIGGER) { 154 run = *buf++ + 1; 155 if (run != 1) 156 value = *buf++; 157 } 158 while (run--) { 159 if (x < len) 160 ptr[x] = value; 161 if (++x >= alen) { 162 x = 0; 163 ptr += stride; 164 if (ptr == end) 165 break; 166 } 167 } 168 } 169 } else { 170 for (y = 0; y < h; y++) { 171 if (buf_end - buf < len) 172 break; 173 memcpy(ptr, buf, len); 174 ptr += stride; 175 buf += alen; 176 } 177 } 178 if (avctx->pix_fmt == AV_PIX_FMT_PAL8 && depth < 8) { 179 uint8_t *ptr_free = ptr2; 180 ptr = p->data[0]; 181 for (y=0; y<h; y++) { 182 for (x = 0; x < (w + 7 >> 3) * depth; x++) { 183 if (depth == 1) { 184 ptr[8*x] = ptr2[x] >> 7; 185 ptr[8*x+1] = ptr2[x] >> 6 & 1; 186 ptr[8*x+2] = ptr2[x] >> 5 & 1; 187 ptr[8*x+3] = ptr2[x] >> 4 & 1; 188 ptr[8*x+4] = ptr2[x] >> 3 & 1; 189 ptr[8*x+5] = ptr2[x] >> 2 & 1; 190 ptr[8*x+6] = ptr2[x] >> 1 & 1; 191 ptr[8*x+7] = ptr2[x] & 1; 192 } else { 193 ptr[2*x] = ptr2[x] >> 4; 194 ptr[2*x+1] = ptr2[x] & 0xF; 195 } 196 } 197 ptr += p->linesize[0]; 198 ptr2 += (w + 15 >> 3) * depth; 199 } 200 av_freep(&ptr_free); 201 } 202 203 *got_frame = 1; 204 205 return buf - bufstart; 206} 207 208AVCodec ff_sunrast_decoder = { 209 .name = "sunrast", 210 .long_name = NULL_IF_CONFIG_SMALL("Sun Rasterfile image"), 211 .type = AVMEDIA_TYPE_VIDEO, 212 .id = AV_CODEC_ID_SUNRAST, 213 .decode = sunrast_decode_frame, 214 .capabilities = CODEC_CAP_DR1, 215}; 216