Statistics
| Branch: | Revision:

ffmpeg / libavformat / sgi.c @ 0d9f8633

History | View | Annotate | Download (10.7 KB)

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