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