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