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