Libav
|
00001 /* 00002 * Sun Rasterfile (.sun/.ras/im{1,8,24}/.sunras) image decoder 00003 * Copyright (c) 2007, 2008 Ivo van Poorten 00004 * 00005 * This file is part of FFmpeg. 00006 * 00007 * FFmpeg is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * FFmpeg is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with FFmpeg; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 00022 #include "libavutil/intreadwrite.h" 00023 #include "avcodec.h" 00024 00025 #define RT_OLD 0 00026 #define RT_STANDARD 1 00027 #define RT_BYTE_ENCODED 2 00028 #define RT_FORMAT_RGB 3 00029 #define RT_FORMAT_TIFF 4 00030 #define RT_FORMAT_IFF 5 00031 00032 typedef struct SUNRASTContext { 00033 AVFrame picture; 00034 } SUNRASTContext; 00035 00036 static av_cold int sunrast_init(AVCodecContext *avctx) { 00037 SUNRASTContext *s = avctx->priv_data; 00038 00039 avcodec_get_frame_defaults(&s->picture); 00040 avctx->coded_frame= &s->picture; 00041 00042 return 0; 00043 } 00044 00045 static int sunrast_decode_frame(AVCodecContext *avctx, void *data, 00046 int *data_size, AVPacket *avpkt) { 00047 const uint8_t *buf = avpkt->data; 00048 SUNRASTContext * const s = avctx->priv_data; 00049 AVFrame *picture = data; 00050 AVFrame * const p = &s->picture; 00051 unsigned int w, h, depth, type, maptype, maplength, stride, x, y, len, alen; 00052 uint8_t *ptr; 00053 const uint8_t *bufstart = buf; 00054 00055 if (AV_RB32(buf) != 0x59a66a95) { 00056 av_log(avctx, AV_LOG_ERROR, "this is not sunras encoded data\n"); 00057 return -1; 00058 } 00059 00060 w = AV_RB32(buf+4); 00061 h = AV_RB32(buf+8); 00062 depth = AV_RB32(buf+12); 00063 type = AV_RB32(buf+20); 00064 maptype = AV_RB32(buf+24); 00065 maplength = AV_RB32(buf+28); 00066 00067 if (type == RT_FORMAT_TIFF || type == RT_FORMAT_IFF) { 00068 av_log(avctx, AV_LOG_ERROR, "unsupported (compression) type\n"); 00069 return -1; 00070 } 00071 if (type > RT_FORMAT_IFF) { 00072 av_log(avctx, AV_LOG_ERROR, "invalid (compression) type\n"); 00073 return -1; 00074 } 00075 if (maptype & ~1) { 00076 av_log(avctx, AV_LOG_ERROR, "invalid colormap type\n"); 00077 return -1; 00078 } 00079 00080 buf += 32; 00081 00082 switch (depth) { 00083 case 1: 00084 avctx->pix_fmt = PIX_FMT_MONOWHITE; 00085 break; 00086 case 8: 00087 avctx->pix_fmt = PIX_FMT_PAL8; 00088 break; 00089 case 24: 00090 avctx->pix_fmt = (type == RT_FORMAT_RGB) ? PIX_FMT_RGB24 : PIX_FMT_BGR24; 00091 break; 00092 default: 00093 av_log(avctx, AV_LOG_ERROR, "invalid depth\n"); 00094 return -1; 00095 } 00096 00097 if (p->data[0]) 00098 avctx->release_buffer(avctx, p); 00099 00100 if (avcodec_check_dimensions(avctx, w, h)) 00101 return -1; 00102 if (w != avctx->width || h != avctx->height) 00103 avcodec_set_dimensions(avctx, w, h); 00104 if (avctx->get_buffer(avctx, p) < 0) { 00105 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); 00106 return -1; 00107 } 00108 00109 p->pict_type = FF_I_TYPE; 00110 00111 if (depth != 8 && maplength) { 00112 av_log(avctx, AV_LOG_WARNING, "useless colormap found or file is corrupted, trying to recover\n"); 00113 00114 } else if (depth == 8) { 00115 unsigned int len = maplength / 3; 00116 00117 if (!maplength) { 00118 av_log(avctx, AV_LOG_ERROR, "colormap expected\n"); 00119 return -1; 00120 } 00121 if (maplength % 3 || maplength > 768) { 00122 av_log(avctx, AV_LOG_WARNING, "invalid colormap length\n"); 00123 return -1; 00124 } 00125 00126 ptr = p->data[1]; 00127 for (x=0; x<len; x++, ptr+=4) 00128 *(uint32_t *)ptr = (buf[x]<<16) + (buf[len+x]<<8) + buf[len+len+x]; 00129 } 00130 00131 buf += maplength; 00132 00133 ptr = p->data[0]; 00134 stride = p->linesize[0]; 00135 00136 /* scanlines are aligned on 16 bit boundaries */ 00137 len = (depth * w + 7) >> 3; 00138 alen = len + (len&1); 00139 00140 if (type == RT_BYTE_ENCODED) { 00141 int value, run; 00142 uint8_t *end = ptr + h*stride; 00143 00144 x = 0; 00145 while (ptr != end) { 00146 run = 1; 00147 if ((value = *buf++) == 0x80) { 00148 run = *buf++ + 1; 00149 if (run != 1) 00150 value = *buf++; 00151 } 00152 while (run--) { 00153 if (x < len) 00154 ptr[x] = value; 00155 if (++x >= alen) { 00156 x = 0; 00157 ptr += stride; 00158 if (ptr == end) 00159 break; 00160 } 00161 } 00162 } 00163 } else { 00164 for (y=0; y<h; y++) { 00165 memcpy(ptr, buf, len); 00166 ptr += stride; 00167 buf += alen; 00168 } 00169 } 00170 00171 *picture = s->picture; 00172 *data_size = sizeof(AVFrame); 00173 00174 return buf - bufstart; 00175 } 00176 00177 static av_cold int sunrast_end(AVCodecContext *avctx) { 00178 SUNRASTContext *s = avctx->priv_data; 00179 00180 if(s->picture.data[0]) 00181 avctx->release_buffer(avctx, &s->picture); 00182 00183 return 0; 00184 } 00185 00186 AVCodec sunrast_decoder = { 00187 "sunrast", 00188 AVMEDIA_TYPE_VIDEO, 00189 CODEC_ID_SUNRAST, 00190 sizeof(SUNRASTContext), 00191 sunrast_init, 00192 NULL, 00193 sunrast_end, 00194 sunrast_decode_frame, 00195 CODEC_CAP_DR1, 00196 NULL, 00197 .long_name = NULL_IF_CONFIG_SMALL("Sun Rasterfile image"), 00198 };