yading@10: /* yading@10: * Sun Rasterfile (.sun/.ras/im{1,8,24}/.sunras) image decoder yading@10: * Copyright (c) 2007, 2008 Ivo van Poorten yading@10: * yading@10: * This file is part of FFmpeg. yading@10: * yading@10: * FFmpeg is free software; you can redistribute it and/or yading@10: * modify it under the terms of the GNU Lesser General Public yading@10: * License as published by the Free Software Foundation; either yading@10: * version 2.1 of the License, or (at your option) any later version. yading@10: * yading@10: * FFmpeg is distributed in the hope that it will be useful, yading@10: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@10: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@10: * Lesser General Public License for more details. yading@10: * yading@10: * You should have received a copy of the GNU Lesser General Public yading@10: * License along with FFmpeg; if not, write to the Free Software yading@10: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA yading@10: */ yading@10: yading@10: #include "libavutil/common.h" yading@10: #include "libavutil/intreadwrite.h" yading@10: #include "libavutil/imgutils.h" yading@10: #include "avcodec.h" yading@10: #include "internal.h" yading@10: #include "sunrast.h" yading@10: yading@10: static int sunrast_decode_frame(AVCodecContext *avctx, void *data, yading@10: int *got_frame, AVPacket *avpkt) yading@10: { yading@10: const uint8_t *buf = avpkt->data; yading@10: const uint8_t *buf_end = avpkt->data + avpkt->size; yading@10: AVFrame * const p = data; yading@10: unsigned int w, h, depth, type, maptype, maplength, stride, x, y, len, alen; yading@10: uint8_t *ptr, *ptr2 = NULL; yading@10: const uint8_t *bufstart = buf; yading@10: int ret; yading@10: yading@10: if (avpkt->size < 32) yading@10: return AVERROR_INVALIDDATA; yading@10: yading@10: if (AV_RB32(buf) != RAS_MAGIC) { yading@10: av_log(avctx, AV_LOG_ERROR, "this is not sunras encoded data\n"); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: yading@10: w = AV_RB32(buf + 4); yading@10: h = AV_RB32(buf + 8); yading@10: depth = AV_RB32(buf + 12); yading@10: type = AV_RB32(buf + 20); yading@10: maptype = AV_RB32(buf + 24); yading@10: maplength = AV_RB32(buf + 28); yading@10: buf += 32; yading@10: yading@10: if (type == RT_EXPERIMENTAL) { yading@10: avpriv_request_sample(avctx, "TIFF/IFF/EXPERIMENTAL (compression) type"); yading@10: return AVERROR_PATCHWELCOME; yading@10: } yading@10: if (type > RT_FORMAT_IFF) { yading@10: av_log(avctx, AV_LOG_ERROR, "invalid (compression) type\n"); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: if (av_image_check_size(w, h, 0, avctx)) { yading@10: av_log(avctx, AV_LOG_ERROR, "invalid image size\n"); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: if (maptype == RMT_RAW) { yading@10: avpriv_request_sample(avctx, "Unknown colormap type"); yading@10: return AVERROR_PATCHWELCOME; yading@10: } yading@10: if (maptype > RMT_RAW) { yading@10: av_log(avctx, AV_LOG_ERROR, "invalid colormap type\n"); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: yading@10: if (type == RT_FORMAT_TIFF || type == RT_FORMAT_IFF) { yading@10: av_log(avctx, AV_LOG_ERROR, "unsupported (compression) type\n"); yading@10: return -1; yading@10: } yading@10: yading@10: switch (depth) { yading@10: case 1: yading@10: avctx->pix_fmt = maplength ? AV_PIX_FMT_PAL8 : AV_PIX_FMT_MONOWHITE; yading@10: break; yading@10: case 4: yading@10: avctx->pix_fmt = maplength ? AV_PIX_FMT_PAL8 : AV_PIX_FMT_NONE; yading@10: break; yading@10: case 8: yading@10: avctx->pix_fmt = maplength ? AV_PIX_FMT_PAL8 : AV_PIX_FMT_GRAY8; yading@10: break; yading@10: case 24: yading@10: avctx->pix_fmt = (type == RT_FORMAT_RGB) ? AV_PIX_FMT_RGB24 : AV_PIX_FMT_BGR24; yading@10: break; yading@10: case 32: yading@10: avctx->pix_fmt = (type == RT_FORMAT_RGB) ? AV_PIX_FMT_0RGB : AV_PIX_FMT_0BGR; yading@10: break; yading@10: default: yading@10: av_log(avctx, AV_LOG_ERROR, "invalid depth\n"); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: yading@10: if (w != avctx->width || h != avctx->height) yading@10: avcodec_set_dimensions(avctx, w, h); yading@10: if ((ret = ff_get_buffer(avctx, p, 0)) < 0) yading@10: return ret; yading@10: yading@10: p->pict_type = AV_PICTURE_TYPE_I; yading@10: yading@10: if (buf_end - buf < maplength) yading@10: return AVERROR_INVALIDDATA; yading@10: yading@10: if (depth > 8 && maplength) { yading@10: av_log(avctx, AV_LOG_WARNING, "useless colormap found or file is corrupted, trying to recover\n"); yading@10: yading@10: } else if (maplength) { yading@10: unsigned int len = maplength / 3; yading@10: yading@10: if (maplength % 3 || maplength > 768) { yading@10: av_log(avctx, AV_LOG_WARNING, "invalid colormap length\n"); yading@10: return AVERROR_INVALIDDATA; yading@10: } yading@10: yading@10: ptr = p->data[1]; yading@10: for (x = 0; x < len; x++, ptr += 4) yading@10: *(uint32_t *)ptr = (0xFFU<<24) + (buf[x]<<16) + (buf[len+x]<<8) + buf[len+len+x]; yading@10: } yading@10: yading@10: buf += maplength; yading@10: yading@10: if (maplength && depth < 8) { yading@10: ptr = ptr2 = av_malloc((w + 15) * h); yading@10: if (!ptr) yading@10: return AVERROR(ENOMEM); yading@10: stride = (w + 15 >> 3) * depth; yading@10: } else { yading@10: ptr = p->data[0]; yading@10: stride = p->linesize[0]; yading@10: } yading@10: yading@10: /* scanlines are aligned on 16 bit boundaries */ yading@10: len = (depth * w + 7) >> 3; yading@10: alen = len + (len & 1); yading@10: yading@10: if (type == RT_BYTE_ENCODED) { yading@10: int value, run; yading@10: uint8_t *end = ptr + h * stride; yading@10: yading@10: x = 0; yading@10: while (ptr != end && buf < buf_end) { yading@10: run = 1; yading@10: if (buf_end - buf < 1) yading@10: return AVERROR_INVALIDDATA; yading@10: yading@10: if ((value = *buf++) == RLE_TRIGGER) { yading@10: run = *buf++ + 1; yading@10: if (run != 1) yading@10: value = *buf++; yading@10: } yading@10: while (run--) { yading@10: if (x < len) yading@10: ptr[x] = value; yading@10: if (++x >= alen) { yading@10: x = 0; yading@10: ptr += stride; yading@10: if (ptr == end) yading@10: break; yading@10: } yading@10: } yading@10: } yading@10: } else { yading@10: for (y = 0; y < h; y++) { yading@10: if (buf_end - buf < len) yading@10: break; yading@10: memcpy(ptr, buf, len); yading@10: ptr += stride; yading@10: buf += alen; yading@10: } yading@10: } yading@10: if (avctx->pix_fmt == AV_PIX_FMT_PAL8 && depth < 8) { yading@10: uint8_t *ptr_free = ptr2; yading@10: ptr = p->data[0]; yading@10: for (y=0; y> 3) * depth; x++) { yading@10: if (depth == 1) { yading@10: ptr[8*x] = ptr2[x] >> 7; yading@10: ptr[8*x+1] = ptr2[x] >> 6 & 1; yading@10: ptr[8*x+2] = ptr2[x] >> 5 & 1; yading@10: ptr[8*x+3] = ptr2[x] >> 4 & 1; yading@10: ptr[8*x+4] = ptr2[x] >> 3 & 1; yading@10: ptr[8*x+5] = ptr2[x] >> 2 & 1; yading@10: ptr[8*x+6] = ptr2[x] >> 1 & 1; yading@10: ptr[8*x+7] = ptr2[x] & 1; yading@10: } else { yading@10: ptr[2*x] = ptr2[x] >> 4; yading@10: ptr[2*x+1] = ptr2[x] & 0xF; yading@10: } yading@10: } yading@10: ptr += p->linesize[0]; yading@10: ptr2 += (w + 15 >> 3) * depth; yading@10: } yading@10: av_freep(&ptr_free); yading@10: } yading@10: yading@10: *got_frame = 1; yading@10: yading@10: return buf - bufstart; yading@10: } yading@10: yading@10: AVCodec ff_sunrast_decoder = { yading@10: .name = "sunrast", yading@10: .type = AVMEDIA_TYPE_VIDEO, yading@10: .id = AV_CODEC_ID_SUNRAST, yading@10: .decode = sunrast_decode_frame, yading@10: .capabilities = CODEC_CAP_DR1, yading@10: .long_name = NULL_IF_CONFIG_SMALL("Sun Rasterfile image"), yading@10: };