Statistics
| Branch: | Revision:

ffmpeg / libavformat / sgi.c @ 6a045bf3

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