Statistics
| Branch: | Revision:

ffmpeg / libavformat / sgi.c @ 20b02bc6

History | View | Annotate | Download (10.7 KB)

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