|
808
|
1 /*
|
|
|
2 * SGI image format
|
|
|
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 "avformat.h"
|
|
|
23 #include "avio.h"
|
|
|
24
|
|
|
25 /* #define DEBUG */
|
|
|
26
|
|
|
27 /* sgi image file signature */
|
|
|
28 #define SGI_MAGIC 474
|
|
|
29
|
|
|
30 #define SGI_HEADER_SIZE 512
|
|
|
31
|
|
|
32 #define SGI_GRAYSCALE 1
|
|
|
33 #define SGI_RGB 3
|
|
|
34 #define SGI_RGBA 4
|
|
|
35
|
|
|
36 #define SGI_SINGLE_CHAN 2
|
|
|
37 #define SGI_MULTI_CHAN 3
|
|
|
38
|
|
|
39 typedef struct SGIInfo{
|
|
|
40 short magic;
|
|
|
41 char rle;
|
|
|
42 char bytes_per_channel;
|
|
|
43 unsigned short dimension;
|
|
|
44 unsigned short xsize;
|
|
|
45 unsigned short ysize;
|
|
|
46 unsigned short zsize;
|
|
|
47 } SGIInfo;
|
|
|
48
|
|
|
49
|
|
|
50 static int sgi_probe(AVProbeData *pd)
|
|
|
51 {
|
|
|
52 /* test for sgi magic */
|
|
|
53 if (pd->buf_size >= 2 && BE_16(&pd->buf[0]) == SGI_MAGIC) {
|
|
|
54 return AVPROBE_SCORE_MAX;
|
|
|
55 } else {
|
|
|
56 return 0;
|
|
|
57 }
|
|
|
58 }
|
|
|
59
|
|
|
60 /* read sgi header fields */
|
|
|
61 static void read_sgi_header(ByteIOContext *f, SGIInfo *info)
|
|
|
62 {
|
|
|
63 info->magic = (unsigned short) get_be16(f);
|
|
|
64 info->rle = get_byte(f);
|
|
|
65 info->bytes_per_channel = get_byte(f);
|
|
|
66 info->dimension = (unsigned short)get_be16(f);
|
|
|
67 info->xsize = (unsigned short) get_be16(f);
|
|
|
68 info->ysize = (unsigned short) get_be16(f);
|
|
|
69 info->zsize = (unsigned short) get_be16(f);
|
|
|
70
|
|
|
71 if(info->zsize > 4096)
|
|
|
72 info->zsize= 0;
|
|
|
73
|
|
|
74 #ifdef DEBUG
|
|
|
75 printf("sgi header fields:\n");
|
|
|
76 printf(" magic: %d\n", info->magic);
|
|
|
77 printf(" rle: %d\n", info->rle);
|
|
|
78 printf(" bpc: %d\n", info->bytes_per_channel);
|
|
|
79 printf(" dim: %d\n", info->dimension);
|
|
|
80 printf(" xsize: %d\n", info->xsize);
|
|
|
81 printf(" ysize: %d\n", info->ysize);
|
|
|
82 printf(" zsize: %d\n", info->zsize);
|
|
|
83 #endif
|
|
|
84
|
|
|
85 return;
|
|
|
86 }
|
|
|
87
|
|
|
88
|
|
|
89 /* read an uncompressed sgi image */
|
|
|
90 static int read_uncompressed_sgi(const SGIInfo *si,
|
|
|
91 AVPicture *pict, ByteIOContext *f)
|
|
|
92 {
|
|
|
93 int x, y, z, chan_offset, ret = 0;
|
|
|
94 uint8_t *dest_row;
|
|
|
95
|
|
|
96 /* skip header */
|
|
|
97 url_fseek(f, SGI_HEADER_SIZE, SEEK_SET);
|
|
|
98
|
|
|
99 pict->linesize[0] = si->xsize;
|
|
|
100
|
|
|
101 for (z = 0; z < si->zsize; z++) {
|
|
|
102
|
|
|
103 #ifndef WORDS_BIGENDIAN
|
|
|
104 /* rgba -> bgra for rgba32 on little endian cpus */
|
|
|
105 if (si->zsize == 4 && z != 3)
|
|
|
106 chan_offset = 2 - z;
|
|
|
107 else
|
|
|
108 #endif
|
|
|
109 chan_offset = z;
|
|
|
110
|
|
|
111 for (y = si->ysize - 1; y >= 0; y--) {
|
|
|
112 dest_row = pict->data[0] + (y * si->xsize * si->zsize);
|
|
|
113
|
|
|
114 for (x = 0; x < si->xsize; x++) {
|
|
|
115 dest_row[chan_offset] = get_byte(f);
|
|
|
116 dest_row += si->zsize;
|
|
|
117 }
|
|
|
118 }
|
|
|
119 }
|
|
|
120
|
|
|
121 return ret;
|
|
|
122 }
|
|
|
123
|
|
|
124
|
|
|
125 /* expand an rle row into a channel */
|
|
|
126 static int expand_rle_row(ByteIOContext *f, unsigned char *optr,
|
|
|
127 int chan_offset, int pixelstride)
|
|
|
128 {
|
|
|
129 unsigned char pixel, count;
|
|
|
130 int length = 0;
|
|
|
131
|
|
|
132 #ifndef WORDS_BIGENDIAN
|
|
|
133 /* rgba -> bgra for rgba32 on little endian cpus */
|
|
|
134 if (pixelstride == 4 && chan_offset != 3) {
|
|
|
135 chan_offset = 2 - chan_offset;
|
|
|
136 }
|
|
|
137 #endif
|
|
|
138
|
|
|
139 optr += chan_offset;
|
|
|
140
|
|
|
141 while (1) {
|
|
|
142 pixel = get_byte(f);
|
|
|
143
|
|
|
144 if (!(count = (pixel & 0x7f))) {
|
|
|
145 return length;
|
|
|
146 }
|
|
|
147 if (pixel & 0x80) {
|
|
|
148 while (count--) {
|
|
|
149 *optr = get_byte(f);
|
|
|
150 length++;
|
|
|
151 optr += pixelstride;
|
|
|
152 }
|
|
|
153 } else {
|
|
|
154 pixel = get_byte(f);
|
|
|
155
|
|
|
156 while (count--) {
|
|
|
157 *optr = pixel;
|
|
|
158 length++;
|
|
|
159 optr += pixelstride;
|
|
|
160 }
|
|
|
161 }
|
|
|
162 }
|
|
|
163 }
|
|
|
164
|
|
|
165
|
|
|
166 /* read a run length encoded sgi image */
|
|
|
167 static int read_rle_sgi(const SGIInfo *sgi_info,
|
|
|
168 AVPicture *pict, ByteIOContext *f)
|
|
|
169 {
|
|
|
170 uint8_t *dest_row;
|
|
|
171 unsigned long *start_table;
|
|
|
172 int y, z, xsize, ysize, zsize, tablen;
|
|
|
173 long start_offset;
|
|
|
174 int ret = 0;
|
|
|
175
|
|
|
176 xsize = sgi_info->xsize;
|
|
|
177 ysize = sgi_info->ysize;
|
|
|
178 zsize = sgi_info->zsize;
|
|
|
179
|
|
|
180 /* skip header */
|
|
|
181 url_fseek(f, SGI_HEADER_SIZE, SEEK_SET);
|
|
|
182
|
|
|
183 /* size of rle offset and length tables */
|
|
|
184 tablen = ysize * zsize * sizeof(long);
|
|
|
185
|
|
|
186 start_table = (unsigned long *)av_malloc(tablen);
|
|
|
187
|
|
|
188 if (!get_buffer(f, (uint8_t *)start_table, tablen)) {
|
|
|
189 ret = AVERROR_IO;
|
|
|
190 goto fail;
|
|
|
191 }
|
|
|
192
|
|
|
193 /* skip run length table */
|
|
|
194 url_fseek(f, tablen, SEEK_CUR);
|
|
|
195
|
|
|
196 for (z = 0; z < zsize; z++) {
|
|
|
197 for (y = 0; y < ysize; y++) {
|
|
|
198 dest_row = pict->data[0] + (ysize - 1 - y) * (xsize * zsize);
|
|
|
199
|
|
|
200 start_offset = BE_32(&start_table[y + z * ysize]);
|
|
|
201
|
|
|
202 /* don't seek if already at the next rle start offset */
|
|
|
203 if (url_ftell(f) != start_offset) {
|
|
|
204 url_fseek(f, start_offset, SEEK_SET);
|
|
|
205 }
|
|
|
206
|
|
|
207 if (expand_rle_row(f, dest_row, z, zsize) != xsize) {
|
|
|
208 ret = AVERROR_INVALIDDATA;
|
|
|
209 goto fail;
|
|
|
210 }
|
|
|
211 }
|
|
|
212 }
|
|
|
213
|
|
|
214 fail:
|
|
|
215 av_free(start_table);
|
|
|
216
|
|
|
217 return ret;
|
|
|
218 }
|
|
|
219
|
|
|
220
|
|
|
221 static int sgi_read(ByteIOContext *f,
|
|
|
222 int (*alloc_cb)(void *opaque, AVImageInfo *info), void *opaque)
|
|
|
223 {
|
|
|
224 SGIInfo sgi_info, *s = &sgi_info;
|
|
|
225 AVImageInfo info1, *info = &info1;
|
|
|
226 int ret;
|
|
|
227
|
|
|
228 read_sgi_header(f, s);
|
|
|
229
|
|
|
230 if (s->bytes_per_channel != 1) {
|
|
|
231 return AVERROR_INVALIDDATA;
|
|
|
232 }
|
|
|
233
|
|
|
234 /* check for supported image dimensions */
|
|
|
235 if (s->dimension != 2 && s->dimension != 3) {
|
|
|
236 return AVERROR_INVALIDDATA;
|
|
|
237 }
|
|
|
238
|
|
|
239 if (s->zsize == SGI_GRAYSCALE) {
|
|
|
240 info->pix_fmt = PIX_FMT_GRAY8;
|
|
|
241 } else if (s->zsize == SGI_RGB) {
|
|
|
242 info->pix_fmt = PIX_FMT_RGB24;
|
|
|
243 } else if (s->zsize == SGI_RGBA) {
|
|
|
244 info->pix_fmt = PIX_FMT_RGBA32;
|
|
|
245 } else {
|
|
|
246 return AVERROR_INVALIDDATA;
|
|
|
247 }
|
|
|
248
|
|
|
249 info->width = s->xsize;
|
|
|
250 info->height = s->ysize;
|
|
|
251
|
|
|
252 ret = alloc_cb(opaque, info);
|
|
|
253 if (ret)
|
|
|
254 return ret;
|
|
|
255
|
|
|
256 if (s->rle) {
|
|
|
257 return read_rle_sgi(s, &info->pict, f);
|
|
|
258 } else {
|
|
|
259 return read_uncompressed_sgi(s, &info->pict, f);
|
|
|
260 }
|
|
|
261
|
|
|
262 return 0; /* not reached */
|
|
|
263 }
|
|
|
264
|
|
|
265 #ifdef CONFIG_MUXERS
|
|
|
266 static void write_sgi_header(ByteIOContext *f, const SGIInfo *info)
|
|
|
267 {
|
|
|
268 int i;
|
|
|
269
|
|
|
270 put_be16(f, SGI_MAGIC);
|
|
|
271 put_byte(f, info->rle);
|
|
|
272 put_byte(f, info->bytes_per_channel);
|
|
|
273 put_be16(f, info->dimension);
|
|
|
274 put_be16(f, info->xsize);
|
|
|
275 put_be16(f, info->ysize);
|
|
|
276 put_be16(f, info->zsize);
|
|
|
277
|
|
|
278 /* The rest are constant in this implementation */
|
|
|
279 put_be32(f, 0L); /* pixmin */
|
|
|
280 put_be32(f, 255L); /* pixmax */
|
|
|
281 put_be32(f, 0L); /* dummy */
|
|
|
282
|
|
|
283 /* name */
|
|
|
284 for (i = 0; i < 80; i++) {
|
|
|
285 put_byte(f, 0);
|
|
|
286 }
|
|
|
287
|
|
|
288 put_be32(f, 0L); /* colormap */
|
|
|
289
|
|
|
290 /* The rest of the 512 byte header is unused. */
|
|
|
291 for (i = 0; i < 404; i++) {
|
|
|
292 put_byte(f, 0);
|
|
|
293 }
|
|
|
294 }
|
|
|
295
|
|
|
296
|
|
|
297 static int rle_row(ByteIOContext *f, char *row, int stride, int rowsize)
|
|
|
298 {
|
|
|
299 int length, count, i, x;
|
|
|
300 char *start, repeat = 0;
|
|
|
301
|
|
|
302 for (x = rowsize, length = 0; x > 0;) {
|
|
|
303 start = row;
|
|
|
304 row += (2 * stride);
|
|
|
305 x -= 2;
|
|
|
306
|
|
|
307 while (x > 0 && (row[-2 * stride] != row[-1 * stride] ||
|
|
|
308 row[-1 * stride] != row[0])) {
|
|
|
309 row += stride;
|
|
|
310 x--;
|
|
|
311 };
|
|
|
312
|
|
|
313 row -= (2 * stride);
|
|
|
314 x += 2;
|
|
|
315
|
|
|
316 count = (row - start) / stride;
|
|
|
317 while (count > 0) {
|
|
|
318 i = count > 126 ? 126 : count;
|
|
|
319 count -= i;
|
|
|
320
|
|
|
321 put_byte(f, 0x80 | i);
|
|
|
322 length++;
|
|
|
323
|
|
|
324 while (i > 0) {
|
|
|
325 put_byte(f, *start);
|
|
|
326 start += stride;
|
|
|
327 i--;
|
|
|
328 length++;
|
|
|
329 };
|
|
|
330 };
|
|
|
331
|
|
|
332 if (x <= 0) {
|
|
|
333 break;
|
|
|
334 }
|
|
|
335
|
|
|
336 start = row;
|
|
|
337 repeat = row[0];
|
|
|
338
|
|
|
339 row += stride;
|
|
|
340 x--;
|
|
|
341
|
|
|
342 while (x > 0 && *row == repeat) {
|
|
|
343 row += stride;
|
|
|
344 x--;
|
|
|
345 };
|
|
|
346
|
|
|
347 count = (row - start) / stride;
|
|
|
348 while (count > 0) {
|
|
|
349 i = count > 126 ? 126 : count;
|
|
|
350 count -= i;
|
|
|
351
|
|
|
352 put_byte(f, i);
|
|
|
353 length++;
|
|
|
354
|
|
|
355 put_byte(f, repeat);
|
|
|
356 length++;
|
|
|
357 };
|
|
|
358 };
|
|
|
359
|
|
|
360 length++;
|
|
|
361
|
|
|
362 put_byte(f, 0);
|
|
|
363 return (length);
|
|
|
364 }
|
|
|
365
|
|
|
366
|
|
|
367 static int sgi_write(ByteIOContext *pb, AVImageInfo *info)
|
|
|
368 {
|
|
|
369 SGIInfo sgi_info, *si = &sgi_info;
|
|
|
370 long *offsettab, *lengthtab;
|
|
|
371 int i, y, z;
|
|
|
372 int tablesize, chan_offset;
|
|
|
373 uint8_t *srcrow;
|
|
|
374
|
|
|
375 si->xsize = info->width;
|
|
|
376 si->ysize = info->height;
|
|
|
377 si->rle = 1;
|
|
|
378 si->bytes_per_channel = 1;
|
|
|
379
|
|
|
380 switch(info->pix_fmt) {
|
|
|
381 case PIX_FMT_GRAY8:
|
|
|
382 si->dimension = SGI_SINGLE_CHAN;
|
|
|
383 si->zsize = SGI_GRAYSCALE;
|
|
|
384 break;
|
|
|
385 case PIX_FMT_RGB24:
|
|
|
386 si->dimension = SGI_MULTI_CHAN;
|
|
|
387 si->zsize = SGI_RGB;
|
|
|
388 break;
|
|
|
389 case PIX_FMT_RGBA32:
|
|
|
390 si->dimension = SGI_MULTI_CHAN;
|
|
|
391 si->zsize = SGI_RGBA;
|
|
|
392 break;
|
|
|
393 default:
|
|
|
394 return AVERROR_INVALIDDATA;
|
|
|
395 }
|
|
|
396
|
|
|
397 write_sgi_header(pb, si);
|
|
|
398
|
|
|
399 tablesize = si->zsize * si->ysize * sizeof(long);
|
|
|
400
|
|
|
401 /* skip rle offset and length tables, write them at the end. */
|
|
|
402 url_fseek(pb, tablesize * 2, SEEK_CUR);
|
|
|
403 put_flush_packet(pb);
|
|
|
404
|
|
|
405 lengthtab = av_malloc(tablesize);
|
|
|
406 offsettab = av_malloc(tablesize);
|
|
|
407
|
|
|
408 for (z = 0; z < si->zsize; z++) {
|
|
|
409
|
|
|
410 #ifndef WORDS_BIGENDIAN
|
|
|
411 /* rgba -> bgra for rgba32 on little endian cpus */
|
|
|
412 if (si->zsize == 4 && z != 3)
|
|
|
413 chan_offset = 2 - z;
|
|
|
414 else
|
|
|
415 #endif
|
|
|
416 chan_offset = z;
|
|
|
417
|
|
|
418 srcrow = info->pict.data[0] + chan_offset;
|
|
|
419
|
|
|
420 for (y = si->ysize -1; y >= 0; y--) {
|
|
|
421 offsettab[(z * si->ysize) + y] = url_ftell(pb);
|
|
|
422 lengthtab[(z * si->ysize) + y] = rle_row(pb, srcrow,
|
|
|
423 si->zsize, si->xsize);
|
|
|
424 srcrow += info->pict.linesize[0];
|
|
|
425 }
|
|
|
426 }
|
|
|
427
|
|
|
428 url_fseek(pb, 512, SEEK_SET);
|
|
|
429
|
|
|
430 /* write offset table */
|
|
|
431 for (i = 0; i < (si->ysize * si->zsize); i++) {
|
|
|
432 put_be32(pb, offsettab[i]);
|
|
|
433 }
|
|
|
434
|
|
|
435 /* write length table */
|
|
|
436 for (i = 0; i < (si->ysize * si->zsize); i++) {
|
|
|
437 put_be32(pb, lengthtab[i]);
|
|
|
438 }
|
|
|
439
|
|
|
440 put_flush_packet(pb);
|
|
|
441
|
|
|
442 av_free(lengthtab);
|
|
|
443 av_free(offsettab);
|
|
|
444
|
|
|
445 return 0;
|
|
|
446 }
|
|
|
447 #endif // CONFIG_MUXERS
|
|
|
448
|
|
|
449 AVImageFormat sgi_image_format = {
|
|
|
450 "sgi",
|
|
|
451 "sgi,rgb,rgba,bw",
|
|
|
452 sgi_probe,
|
|
|
453 sgi_read,
|
|
|
454 (1 << PIX_FMT_GRAY8) | (1 << PIX_FMT_RGB24) | (1 << PIX_FMT_RGBA32),
|
|
|
455 #ifdef CONFIG_MUXERS
|
|
|
456 sgi_write,
|
|
|
457 #else
|
|
|
458 NULL,
|
|
|
459 #endif // CONFIG_MUXERS
|
|
|
460 };
|