Mercurial > libavcodec.hg
annotate sgidec.c @ 12092:de9e45d04063 libavcodec
DCA: Occasionally a false XCH sync word can turn up after the core DTS data,
to verify the sync word the extension fsize field should be compared to
the core data length field.
Patch by nick.nbrereton@net
author | banan |
---|---|
date | Mon, 05 Jul 2010 08:16:43 +0000 |
parents | 8a4984c5cacc |
children | 914f484bb476 |
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; | |
10194
5b05416fcb6b
Support uncompressed 16 bit sgi image format, as e.g. used by the files at
reimar
parents:
9355
diff
changeset
|
31 unsigned int bytes_per_channel; |
4790 | 32 int linesize; |
33 } SgiState; | |
34 | |
35 /** | |
36 * Expand an RLE row into a channel. | |
37 * @param in_buf input buffer | |
38 * @param in_end end of input buffer | |
39 * @param out_buf Points to one line after the output buffer. | |
40 * @param out_end end of line in output buffer | |
41 * @param pixelstride pixel stride of input buffer | |
42 * @return size of output in bytes, -1 if buffer overflows | |
43 */ | |
6218 | 44 static int expand_rle_row(const uint8_t *in_buf, const uint8_t* in_end, |
4790 | 45 unsigned char *out_buf, uint8_t* out_end, int pixelstride) |
46 { | |
47 unsigned char pixel, count; | |
48 unsigned char *orig = out_buf; | |
49 | |
50 while (1) { | |
51 if(in_buf + 1 > in_end) return -1; | |
52 pixel = bytestream_get_byte(&in_buf); | |
53 if (!(count = (pixel & 0x7f))) { | |
54 return (out_buf - orig) / pixelstride; | |
55 } | |
56 | |
57 /* Check for buffer overflow. */ | |
58 if(out_buf + pixelstride * count >= out_end) return -1; | |
59 | |
60 if (pixel & 0x80) { | |
61 while (count--) { | |
62 *out_buf = bytestream_get_byte(&in_buf); | |
63 out_buf += pixelstride; | |
64 } | |
65 } else { | |
66 pixel = bytestream_get_byte(&in_buf); | |
67 | |
68 while (count--) { | |
69 *out_buf = pixel; | |
70 out_buf += pixelstride; | |
71 } | |
72 } | |
73 } | |
74 } | |
75 | |
76 /** | |
77 * Read a run length encoded SGI image. | |
78 * @param out_buf output buffer | |
79 * @param in_buf input buffer | |
80 * @param in_end end of input buffer | |
81 * @param s the current image state | |
82 * @return 0 if no error, else return error number. | |
83 */ | |
6218 | 84 static int read_rle_sgi(unsigned char* out_buf, const uint8_t *in_buf, |
85 const uint8_t *in_end, SgiState* s) | |
4790 | 86 { |
87 uint8_t *dest_row; | |
88 unsigned int len = s->height * s->depth * 4; | |
6218 | 89 const uint8_t *start_table = in_buf; |
4790 | 90 unsigned int y, z; |
91 unsigned int start_offset; | |
92 | |
93 /* size of RLE offset and length tables */ | |
94 if(len * 2 > in_end - in_buf) { | |
95 return AVERROR_INVALIDDATA; | |
96 } | |
97 | |
98 in_buf -= SGI_HEADER_SIZE; | |
99 for (z = 0; z < s->depth; z++) { | |
100 dest_row = out_buf; | |
101 for (y = 0; y < s->height; y++) { | |
102 dest_row -= s->linesize; | |
103 start_offset = bytestream_get_be32(&start_table); | |
104 if(start_offset > in_end - in_buf) { | |
105 return AVERROR_INVALIDDATA; | |
106 } | |
107 if (expand_rle_row(in_buf + start_offset, in_end, dest_row + z, | |
108 dest_row + FFABS(s->linesize), s->depth) != s->width) | |
109 return AVERROR_INVALIDDATA; | |
110 } | |
111 } | |
112 return 0; | |
113 } | |
114 | |
115 /** | |
116 * Read an uncompressed SGI image. | |
117 * @param out_buf output buffer | |
118 * @param out_end end ofoutput buffer | |
119 * @param in_buf input buffer | |
120 * @param in_end end of input buffer | |
121 * @param s the current image state | |
122 * @return 0 if read success, otherwise return -1. | |
123 */ | |
124 static int read_uncompressed_sgi(unsigned char* out_buf, uint8_t* out_end, | |
6218 | 125 const uint8_t *in_buf, const uint8_t *in_end, SgiState* s) |
4790 | 126 { |
127 int x, y, z; | |
6218 | 128 const uint8_t *ptr; |
10194
5b05416fcb6b
Support uncompressed 16 bit sgi image format, as e.g. used by the files at
reimar
parents:
9355
diff
changeset
|
129 unsigned int offset = s->height * s->width * s->bytes_per_channel; |
4790 | 130 |
131 /* Test buffer size. */ | |
132 if (offset * s->depth > in_end - in_buf) { | |
133 return -1; | |
134 } | |
135 | |
136 for (y = s->height - 1; y >= 0; y--) { | |
137 out_end = out_buf + (y * s->linesize); | |
138 for (x = s->width; x > 0; x--) { | |
10194
5b05416fcb6b
Support uncompressed 16 bit sgi image format, as e.g. used by the files at
reimar
parents:
9355
diff
changeset
|
139 ptr = in_buf += s->bytes_per_channel; |
4790 | 140 for(z = 0; z < s->depth; z ++) { |
10194
5b05416fcb6b
Support uncompressed 16 bit sgi image format, as e.g. used by the files at
reimar
parents:
9355
diff
changeset
|
141 memcpy(out_end, ptr, s->bytes_per_channel); |
5b05416fcb6b
Support uncompressed 16 bit sgi image format, as e.g. used by the files at
reimar
parents:
9355
diff
changeset
|
142 out_end += s->bytes_per_channel; |
4790 | 143 ptr += offset; |
144 } | |
145 } | |
146 } | |
147 return 0; | |
148 } | |
149 | |
150 static int decode_frame(AVCodecContext *avctx, | |
151 void *data, int *data_size, | |
9355
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
7040
diff
changeset
|
152 AVPacket *avpkt) |
4790 | 153 { |
9355
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
7040
diff
changeset
|
154 const uint8_t *in_buf = avpkt->data; |
54bc8a2727b0
Implement avcodec_decode_video2(), _audio3() and _subtitle2() which takes an
rbultje
parents:
7040
diff
changeset
|
155 int buf_size = avpkt->size; |
4790 | 156 SgiState *s = avctx->priv_data; |
157 AVFrame *picture = data; | |
158 AVFrame *p = &s->picture; | |
6218 | 159 const uint8_t *in_end = in_buf + buf_size; |
10194
5b05416fcb6b
Support uncompressed 16 bit sgi image format, as e.g. used by the files at
reimar
parents:
9355
diff
changeset
|
160 unsigned int dimension, rle; |
4790 | 161 int ret = 0; |
162 uint8_t *out_buf, *out_end; | |
163 | |
164 if (buf_size < SGI_HEADER_SIZE){ | |
165 av_log(avctx, AV_LOG_ERROR, "buf_size too small (%d)\n", buf_size); | |
166 return -1; | |
167 } | |
168 | |
169 /* Test for SGI magic. */ | |
170 if (bytestream_get_be16(&in_buf) != SGI_MAGIC) { | |
171 av_log(avctx, AV_LOG_ERROR, "bad magic number\n"); | |
172 return -1; | |
173 } | |
174 | |
175 rle = bytestream_get_byte(&in_buf); | |
10194
5b05416fcb6b
Support uncompressed 16 bit sgi image format, as e.g. used by the files at
reimar
parents:
9355
diff
changeset
|
176 s->bytes_per_channel = bytestream_get_byte(&in_buf); |
4790 | 177 dimension = bytestream_get_be16(&in_buf); |
178 s->width = bytestream_get_be16(&in_buf); | |
179 s->height = bytestream_get_be16(&in_buf); | |
180 s->depth = bytestream_get_be16(&in_buf); | |
181 | |
10194
5b05416fcb6b
Support uncompressed 16 bit sgi image format, as e.g. used by the files at
reimar
parents:
9355
diff
changeset
|
182 if (s->bytes_per_channel != 1 && (s->bytes_per_channel != 2 || rle)) { |
4790 | 183 av_log(avctx, AV_LOG_ERROR, "wrong channel number\n"); |
184 return -1; | |
185 } | |
186 | |
187 /* Check for supported image dimensions. */ | |
188 if (dimension != 2 && dimension != 3) { | |
189 av_log(avctx, AV_LOG_ERROR, "wrong dimension number\n"); | |
190 return -1; | |
191 } | |
192 | |
193 if (s->depth == SGI_GRAYSCALE) { | |
10194
5b05416fcb6b
Support uncompressed 16 bit sgi image format, as e.g. used by the files at
reimar
parents:
9355
diff
changeset
|
194 avctx->pix_fmt = s->bytes_per_channel == 2 ? PIX_FMT_GRAY16BE : PIX_FMT_GRAY8; |
4790 | 195 } else if (s->depth == SGI_RGB) { |
10194
5b05416fcb6b
Support uncompressed 16 bit sgi image format, as e.g. used by the files at
reimar
parents:
9355
diff
changeset
|
196 avctx->pix_fmt = s->bytes_per_channel == 2 ? PIX_FMT_RGB48BE : PIX_FMT_RGB24; |
5b05416fcb6b
Support uncompressed 16 bit sgi image format, as e.g. used by the files at
reimar
parents:
9355
diff
changeset
|
197 } else if (s->depth == SGI_RGBA && s->bytes_per_channel == 1) { |
4790 | 198 avctx->pix_fmt = PIX_FMT_RGBA; |
199 } else { | |
200 av_log(avctx, AV_LOG_ERROR, "wrong picture format\n"); | |
201 return -1; | |
202 } | |
203 | |
204 if (avcodec_check_dimensions(avctx, s->width, s->height)) | |
205 return -1; | |
206 avcodec_set_dimensions(avctx, s->width, s->height); | |
207 | |
208 if (p->data[0]) | |
209 avctx->release_buffer(avctx, p); | |
210 | |
211 p->reference = 0; | |
212 if (avctx->get_buffer(avctx, p) < 0) { | |
213 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed.\n"); | |
214 return -1; | |
215 } | |
216 | |
217 p->pict_type = FF_I_TYPE; | |
218 p->key_frame = 1; | |
219 out_buf = p->data[0]; | |
220 | |
221 out_end = out_buf + p->linesize[0] * s->height; | |
222 | |
223 s->linesize = p->linesize[0]; | |
224 | |
225 /* Skip header. */ | |
226 in_buf += SGI_HEADER_SIZE - 12; | |
227 if (rle) { | |
228 ret = read_rle_sgi(out_end, in_buf, in_end, s); | |
229 } else { | |
230 ret = read_uncompressed_sgi(out_buf, out_end, in_buf, in_end, s); | |
231 } | |
232 | |
233 if (ret == 0) { | |
234 *picture = s->picture; | |
235 *data_size = sizeof(AVPicture); | |
236 return buf_size; | |
237 } else { | |
238 return -1; | |
239 } | |
240 } | |
241 | |
6517
48759bfbd073
Apply 'cold' attribute to init/uninit functions in libavcodec
zuxy
parents:
6218
diff
changeset
|
242 static av_cold int sgi_init(AVCodecContext *avctx){ |
4790 | 243 SgiState *s = avctx->priv_data; |
244 | |
245 avcodec_get_frame_defaults(&s->picture); | |
246 avctx->coded_frame = &s->picture; | |
247 | |
248 return 0; | |
249 } | |
250 | |
6517
48759bfbd073
Apply 'cold' attribute to init/uninit functions in libavcodec
zuxy
parents:
6218
diff
changeset
|
251 static av_cold int sgi_end(AVCodecContext *avctx) |
4790 | 252 { |
253 SgiState * const s = avctx->priv_data; | |
254 | |
255 if (s->picture.data[0]) | |
256 avctx->release_buffer(avctx, &s->picture); | |
257 | |
258 return 0; | |
259 } | |
260 | |
261 AVCodec sgi_decoder = { | |
262 "sgi", | |
11560
8a4984c5cacc
Define AVMediaType enum, and use it instead of enum CodecType, which
stefano
parents:
10194
diff
changeset
|
263 AVMEDIA_TYPE_VIDEO, |
4790 | 264 CODEC_ID_SGI, |
265 sizeof(SgiState), | |
266 sgi_init, | |
267 NULL, | |
268 sgi_end, | |
269 decode_frame, | |
7040
e943e1409077
Make AVCodec long_names definition conditional depending on CONFIG_SMALL.
stefano
parents:
6722
diff
changeset
|
270 .long_name = NULL_IF_CONFIG_SMALL("SGI image"), |
4790 | 271 }; |
272 |