Mercurial > libavcodec.hg
annotate sgidec.c @ 6963:cc2c5a21a0eb libavcodec
memcpy considering output width, not src linesize, fix segv with av_picture_pad
author | bcoudurier |
---|---|
date | Sun, 01 Jun 2008 02:28:33 +0000 |
parents | 6eeb19edcee3 |
children | e943e1409077 |
rev | line source |
---|---|
4790 | 1 /* |
2 * SGI image decoder | |
3 * Todd Kirby <doubleshot@pacbell.net> | |
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 "avcodec.h" | |
23 #include "bytestream.h" | |
24 #include "sgi.h" | |
25 | |
26 typedef struct SgiState { | |
27 AVFrame picture; | |
28 unsigned int width; | |
29 unsigned int height; | |
30 unsigned int depth; | |
31 int linesize; | |
32 } SgiState; | |
33 | |
34 /** | |
35 * Expand an RLE row into a channel. | |
36 * @param in_buf input buffer | |
37 * @param in_end end of input buffer | |
38 * @param out_buf Points to one line after the output buffer. | |
39 * @param out_end end of line in output buffer | |
40 * @param pixelstride pixel stride of input buffer | |
41 * @return size of output in bytes, -1 if buffer overflows | |
42 */ | |
6218 | 43 static int expand_rle_row(const uint8_t *in_buf, const uint8_t* in_end, |
4790 | 44 unsigned char *out_buf, uint8_t* out_end, int pixelstride) |
45 { | |
46 unsigned char pixel, count; | |
47 unsigned char *orig = out_buf; | |
48 | |
49 while (1) { | |
50 if(in_buf + 1 > in_end) return -1; | |
51 pixel = bytestream_get_byte(&in_buf); | |
52 if (!(count = (pixel & 0x7f))) { | |
53 return (out_buf - orig) / pixelstride; | |
54 } | |
55 | |
56 /* Check for buffer overflow. */ | |
57 if(out_buf + pixelstride * count >= out_end) return -1; | |
58 | |
59 if (pixel & 0x80) { | |
60 while (count--) { | |
61 *out_buf = bytestream_get_byte(&in_buf); | |
62 out_buf += pixelstride; | |
63 } | |
64 } else { | |
65 pixel = bytestream_get_byte(&in_buf); | |
66 | |
67 while (count--) { | |
68 *out_buf = pixel; | |
69 out_buf += pixelstride; | |
70 } | |
71 } | |
72 } | |
73 } | |
74 | |
75 /** | |
76 * Read a run length encoded SGI image. | |
77 * @param out_buf output buffer | |
78 * @param in_buf input buffer | |
79 * @param in_end end of input buffer | |
80 * @param s the current image state | |
81 * @return 0 if no error, else return error number. | |
82 */ | |
6218 | 83 static int read_rle_sgi(unsigned char* out_buf, const uint8_t *in_buf, |
84 const uint8_t *in_end, SgiState* s) | |
4790 | 85 { |
86 uint8_t *dest_row; | |
87 unsigned int len = s->height * s->depth * 4; | |
6218 | 88 const uint8_t *start_table = in_buf; |
4790 | 89 unsigned int y, z; |
90 unsigned int start_offset; | |
91 | |
92 /* size of RLE offset and length tables */ | |
93 if(len * 2 > in_end - in_buf) { | |
94 return AVERROR_INVALIDDATA; | |
95 } | |
96 | |
97 in_buf -= SGI_HEADER_SIZE; | |
98 for (z = 0; z < s->depth; z++) { | |
99 dest_row = out_buf; | |
100 for (y = 0; y < s->height; y++) { | |
101 dest_row -= s->linesize; | |
102 start_offset = bytestream_get_be32(&start_table); | |
103 if(start_offset > in_end - in_buf) { | |
104 return AVERROR_INVALIDDATA; | |
105 } | |
106 if (expand_rle_row(in_buf + start_offset, in_end, dest_row + z, | |
107 dest_row + FFABS(s->linesize), s->depth) != s->width) | |
108 return AVERROR_INVALIDDATA; | |
109 } | |
110 } | |
111 return 0; | |
112 } | |
113 | |
114 /** | |
115 * Read an uncompressed SGI image. | |
116 * @param out_buf output buffer | |
117 * @param out_end end ofoutput buffer | |
118 * @param in_buf input buffer | |
119 * @param in_end end of input buffer | |
120 * @param s the current image state | |
121 * @return 0 if read success, otherwise return -1. | |
122 */ | |
123 static int read_uncompressed_sgi(unsigned char* out_buf, uint8_t* out_end, | |
6218 | 124 const uint8_t *in_buf, const uint8_t *in_end, SgiState* s) |
4790 | 125 { |
126 int x, y, z; | |
6218 | 127 const uint8_t *ptr; |
4790 | 128 unsigned int offset = s->height * s->width; |
129 | |
130 /* Test buffer size. */ | |
131 if (offset * s->depth > in_end - in_buf) { | |
132 return -1; | |
133 } | |
134 | |
135 for (y = s->height - 1; y >= 0; y--) { | |
136 out_end = out_buf + (y * s->linesize); | |
137 for (x = s->width; x > 0; x--) { | |
138 ptr = in_buf++; | |
139 for(z = 0; z < s->depth; z ++) { | |
140 bytestream_put_byte(&out_end, *ptr); | |
141 ptr += offset; | |
142 } | |
143 } | |
144 } | |
145 return 0; | |
146 } | |
147 | |
148 static int decode_frame(AVCodecContext *avctx, | |
149 void *data, int *data_size, | |
6218 | 150 const uint8_t *in_buf, int buf_size) |
4790 | 151 { |
152 SgiState *s = avctx->priv_data; | |
153 AVFrame *picture = data; | |
154 AVFrame *p = &s->picture; | |
6218 | 155 const uint8_t *in_end = in_buf + buf_size; |
4790 | 156 unsigned int dimension, bytes_per_channel, rle; |
157 int ret = 0; | |
158 uint8_t *out_buf, *out_end; | |
159 | |
160 if (buf_size < SGI_HEADER_SIZE){ | |
161 av_log(avctx, AV_LOG_ERROR, "buf_size too small (%d)\n", buf_size); | |
162 return -1; | |
163 } | |
164 | |
165 /* Test for SGI magic. */ | |
166 if (bytestream_get_be16(&in_buf) != SGI_MAGIC) { | |
167 av_log(avctx, AV_LOG_ERROR, "bad magic number\n"); | |
168 return -1; | |
169 } | |
170 | |
171 rle = bytestream_get_byte(&in_buf); | |
172 bytes_per_channel = bytestream_get_byte(&in_buf); | |
173 dimension = bytestream_get_be16(&in_buf); | |
174 s->width = bytestream_get_be16(&in_buf); | |
175 s->height = bytestream_get_be16(&in_buf); | |
176 s->depth = bytestream_get_be16(&in_buf); | |
177 | |
178 if (bytes_per_channel != 1) { | |
179 av_log(avctx, AV_LOG_ERROR, "wrong channel number\n"); | |
180 return -1; | |
181 } | |
182 | |
183 /* Check for supported image dimensions. */ | |
184 if (dimension != 2 && dimension != 3) { | |
185 av_log(avctx, AV_LOG_ERROR, "wrong dimension number\n"); | |
186 return -1; | |
187 } | |
188 | |
189 if (s->depth == SGI_GRAYSCALE) { | |
190 avctx->pix_fmt = PIX_FMT_GRAY8; | |
191 } else if (s->depth == SGI_RGB) { | |
192 avctx->pix_fmt = PIX_FMT_RGB24; | |
193 } else if (s->depth == SGI_RGBA) { | |
194 avctx->pix_fmt = PIX_FMT_RGBA; | |
195 } else { | |
196 av_log(avctx, AV_LOG_ERROR, "wrong picture format\n"); | |
197 return -1; | |
198 } | |
199 | |
200 if (avcodec_check_dimensions(avctx, s->width, s->height)) | |
201 return -1; | |
202 avcodec_set_dimensions(avctx, s->width, s->height); | |
203 | |
204 if (p->data[0]) | |
205 avctx->release_buffer(avctx, p); | |
206 | |
207 p->reference = 0; | |
208 if (avctx->get_buffer(avctx, p) < 0) { | |
209 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed.\n"); | |
210 return -1; | |
211 } | |
212 | |
213 p->pict_type = FF_I_TYPE; | |
214 p->key_frame = 1; | |
215 out_buf = p->data[0]; | |
216 | |
217 out_end = out_buf + p->linesize[0] * s->height; | |
218 | |
219 s->linesize = p->linesize[0]; | |
220 | |
221 /* Skip header. */ | |
222 in_buf += SGI_HEADER_SIZE - 12; | |
223 if (rle) { | |
224 ret = read_rle_sgi(out_end, in_buf, in_end, s); | |
225 } else { | |
226 ret = read_uncompressed_sgi(out_buf, out_end, in_buf, in_end, s); | |
227 } | |
228 | |
229 if (ret == 0) { | |
230 *picture = s->picture; | |
231 *data_size = sizeof(AVPicture); | |
232 return buf_size; | |
233 } else { | |
234 return -1; | |
235 } | |
236 } | |
237 | |
6517
48759bfbd073
Apply 'cold' attribute to init/uninit functions in libavcodec
zuxy
parents:
6218
diff
changeset
|
238 static av_cold int sgi_init(AVCodecContext *avctx){ |
4790 | 239 SgiState *s = avctx->priv_data; |
240 | |
241 avcodec_get_frame_defaults(&s->picture); | |
242 avctx->coded_frame = &s->picture; | |
243 | |
244 return 0; | |
245 } | |
246 | |
6517
48759bfbd073
Apply 'cold' attribute to init/uninit functions in libavcodec
zuxy
parents:
6218
diff
changeset
|
247 static av_cold int sgi_end(AVCodecContext *avctx) |
4790 | 248 { |
249 SgiState * const s = avctx->priv_data; | |
250 | |
251 if (s->picture.data[0]) | |
252 avctx->release_buffer(avctx, &s->picture); | |
253 | |
254 return 0; | |
255 } | |
256 | |
257 AVCodec sgi_decoder = { | |
258 "sgi", | |
259 CODEC_TYPE_VIDEO, | |
260 CODEC_ID_SGI, | |
261 sizeof(SgiState), | |
262 sgi_init, | |
263 NULL, | |
264 sgi_end, | |
265 decode_frame, | |
6722 | 266 .long_name = "SGI image", |
4790 | 267 }; |
268 |