3 * Todd Kirby <doubleshot@pacbell.net>
5 * This file is part of FFmpeg.
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.
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.
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
27 /* sgi image file signature */
30 #define SGI_HEADER_SIZE 512
32 #define SGI_GRAYSCALE 1
36 #define SGI_SINGLE_CHAN 2
37 #define SGI_MULTI_CHAN 3
39 typedef struct SGIInfo{
42 char bytes_per_channel;
43 unsigned short dimension;
50 static int sgi_probe(AVProbeData *pd)
52 /* test for sgi magic */
53 if (pd->buf_size >= 2 && BE_16(&pd->buf[0]) == SGI_MAGIC) {
54 return AVPROBE_SCORE_MAX;
60 /* read sgi header fields */
61 static void read_sgi_header(ByteIOContext *f, SGIInfo *info)
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);
71 if(info->zsize > 4096)
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);
89 /* read an uncompressed sgi image */
90 static int read_uncompressed_sgi(const SGIInfo *si,
91 AVPicture *pict, ByteIOContext *f)
93 int x, y, z, chan_offset, ret = 0;
97 url_fseek(f, SGI_HEADER_SIZE, SEEK_SET);
99 pict->linesize[0] = si->xsize;
101 for (z = 0; z < si->zsize; z++) {
103 #ifndef WORDS_BIGENDIAN
104 /* rgba -> bgra for rgba32 on little endian cpus */
105 if (si->zsize == 4 && z != 3)
111 for (y = si->ysize - 1; y >= 0; y--) {
112 dest_row = pict->data[0] + (y * si->xsize * si->zsize);
114 for (x = 0; x < si->xsize; x++) {
115 dest_row[chan_offset] = get_byte(f);
116 dest_row += si->zsize;
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)
129 unsigned char pixel, count;
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;
144 if (!(count = (pixel & 0x7f))) {
166 /* read a run length encoded sgi image */
167 static int read_rle_sgi(const SGIInfo *sgi_info,
168 AVPicture *pict, ByteIOContext *f)
171 unsigned long *start_table;
172 int y, z, xsize, ysize, zsize, tablen;
176 xsize = sgi_info->xsize;
177 ysize = sgi_info->ysize;
178 zsize = sgi_info->zsize;
181 url_fseek(f, SGI_HEADER_SIZE, SEEK_SET);
183 /* size of rle offset and length tables */
184 tablen = ysize * zsize * sizeof(long);
186 start_table = (unsigned long *)av_malloc(tablen);
188 if (!get_buffer(f, (uint8_t *)start_table, tablen)) {
193 /* skip run length table */
194 url_fseek(f, tablen, SEEK_CUR);
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);
200 start_offset = BE_32(&start_table[y + z * ysize]);
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);
207 if (expand_rle_row(f, dest_row, z, zsize) != xsize) {
208 ret = AVERROR_INVALIDDATA;
215 av_free(start_table);
221 static int sgi_read(ByteIOContext *f,
222 int (*alloc_cb)(void *opaque, AVImageInfo *info), void *opaque)
224 SGIInfo sgi_info, *s = &sgi_info;
225 AVImageInfo info1, *info = &info1;
228 read_sgi_header(f, s);
230 if (s->bytes_per_channel != 1) {
231 return AVERROR_INVALIDDATA;
234 /* check for supported image dimensions */
235 if (s->dimension != 2 && s->dimension != 3) {
236 return AVERROR_INVALIDDATA;
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;
246 return AVERROR_INVALIDDATA;
249 info->width = s->xsize;
250 info->height = s->ysize;
252 ret = alloc_cb(opaque, info);
257 return read_rle_sgi(s, &info->pict, f);
259 return read_uncompressed_sgi(s, &info->pict, f);
262 return 0; /* not reached */
266 static void write_sgi_header(ByteIOContext *f, const SGIInfo *info)
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);
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 */
284 for (i = 0; i < 80; i++) {
288 put_be32(f, 0L); /* colormap */
290 /* The rest of the 512 byte header is unused. */
291 for (i = 0; i < 404; i++) {
297 static int rle_row(ByteIOContext *f, char *row, int stride, int rowsize)
299 int length, count, i, x;
300 char *start, repeat = 0;
302 for (x = rowsize, length = 0; x > 0;) {
307 while (x > 0 && (row[-2 * stride] != row[-1 * stride] ||
308 row[-1 * stride] != row[0])) {
316 count = (row - start) / stride;
318 i = count > 126 ? 126 : count;
321 put_byte(f, 0x80 | i);
342 while (x > 0 && *row == repeat) {
347 count = (row - start) / stride;
349 i = count > 126 ? 126 : count;
367 static int sgi_write(ByteIOContext *pb, AVImageInfo *info)
369 SGIInfo sgi_info, *si = &sgi_info;
370 long *offsettab, *lengthtab;
372 int tablesize, chan_offset;
375 si->xsize = info->width;
376 si->ysize = info->height;
378 si->bytes_per_channel = 1;
380 switch(info->pix_fmt) {
382 si->dimension = SGI_SINGLE_CHAN;
383 si->zsize = SGI_GRAYSCALE;
386 si->dimension = SGI_MULTI_CHAN;
390 si->dimension = SGI_MULTI_CHAN;
391 si->zsize = SGI_RGBA;
394 return AVERROR_INVALIDDATA;
397 write_sgi_header(pb, si);
399 tablesize = si->zsize * si->ysize * sizeof(long);
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);
405 lengthtab = av_malloc(tablesize);
406 offsettab = av_malloc(tablesize);
408 for (z = 0; z < si->zsize; z++) {
410 #ifndef WORDS_BIGENDIAN
411 /* rgba -> bgra for rgba32 on little endian cpus */
412 if (si->zsize == 4 && z != 3)
418 srcrow = info->pict.data[0] + chan_offset;
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];
428 url_fseek(pb, 512, SEEK_SET);
430 /* write offset table */
431 for (i = 0; i < (si->ysize * si->zsize); i++) {
432 put_be32(pb, offsettab[i]);
435 /* write length table */
436 for (i = 0; i < (si->ysize * si->zsize); i++) {
437 put_be32(pb, lengthtab[i]);
440 put_flush_packet(pb);
447 #endif // CONFIG_MUXERS
449 AVImageFormat sgi_image_format = {
454 (1 << PIX_FMT_GRAY8) | (1 << PIX_FMT_RGB24) | (1 << PIX_FMT_RGBA32),
459 #endif // CONFIG_MUXERS