Statistics
| Branch: | Revision:

ffmpeg / libavformat / sgi.c @ 6a045bf3

History | View | Annotate | Download (10.7 KB)

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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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
    if(info->zsize > 4096)
70
        info->zsize= 0;
71

    
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
static int read_uncompressed_sgi(const SGIInfo *si,
89
        AVPicture *pict, ByteIOContext *f)
90
{
91
    int x, y, z, chan_offset, ret = 0;
92
    uint8_t *dest_row;
93

    
94
    /* skip header */
95
    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
        if (si->zsize == 4 && z != 3)
104
            chan_offset = 2 - z;
105
        else
106
#endif
107
            chan_offset = z;
108

    
109
        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
                dest_row[chan_offset] = get_byte(f);
114
                dest_row += si->zsize;
115
            }
116
        }
117
    }
118

    
119
    return ret;
120
}
121

    
122

    
123
/* expand an rle row into a channel */
124
static int expand_rle_row(ByteIOContext *f, unsigned char *optr,
125
        int chan_offset, int pixelstride)
126
{
127
    unsigned char pixel, count;
128
    int length = 0;
129

    
130
#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

    
137
    optr += chan_offset;
138

    
139
    while (1) {
140
        pixel = get_byte(f);
141

    
142
        if (!(count = (pixel & 0x7f))) {
143
            return length;
144
        }
145
        if (pixel & 0x80) {
146
            while (count--) {
147
                *optr = get_byte(f);
148
                length++;
149
                optr += pixelstride;
150
            }
151
        } else {
152
            pixel = get_byte(f);
153

    
154
            while (count--) {
155
                *optr = pixel;
156
                length++;
157
                optr += pixelstride;
158
            }
159
        }
160
    }
161
}
162

    
163

    
164
/* read a run length encoded sgi image */
165
static int read_rle_sgi(const SGIInfo *sgi_info,
166
        AVPicture *pict, ByteIOContext *f)
167
{
168
    uint8_t *dest_row;
169
    unsigned long *start_table;
170
    int y, z, xsize, ysize, zsize, tablen;
171
    long start_offset;
172
    int ret = 0;
173

    
174
    xsize = sgi_info->xsize;
175
    ysize = sgi_info->ysize;
176
    zsize = sgi_info->zsize;
177

    
178
    /* skip header */
179
    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
        ret = AVERROR_IO;
188
        goto fail;
189
    }
190

    
191
    /* skip run length table */
192
    url_fseek(f, tablen, SEEK_CUR);
193

    
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
            /* don't seek if already at the next rle start offset */
201
            if (url_ftell(f) != start_offset) {
202
                url_fseek(f, start_offset, SEEK_SET);
203
            }
204

    
205
            if (expand_rle_row(f, dest_row, z, zsize) != xsize) {
206
              ret =  AVERROR_INVALIDDATA;
207
              goto fail;
208
            }
209
        }
210
    }
211

    
212
fail:
213
    av_free(start_table);
214

    
215
    return ret;
216
}
217

    
218

    
219
static int sgi_read(ByteIOContext *f,
220
        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
#ifdef CONFIG_MUXERS
264
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
    put_byte(f, info->bytes_per_channel);
271
    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
    put_be32(f, 0L); /* pixmin */
278
    put_be32(f, 255L); /* pixmax */
279
    put_be32(f, 0L); /* dummy */
280

    
281
    /* name */
282
    for (i = 0; i < 80; i++) {
283
        put_byte(f, 0);
284
    }
285

    
286
    put_be32(f, 0L); /* colormap */
287

    
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
        while (x > 0 && (row[-2 * stride] != row[-1 * stride] ||
306
                    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
            put_byte(f, 0x80 | i);
320
            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
            put_byte(f, repeat);
354
            length++;
355
        };
356
    };
357

    
358
    length++;
359

    
360
    put_byte(f, 0);
361
    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

    
378
    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
    write_sgi_header(pb, si);
396

    
397
    tablesize = si->zsize * si->ysize * sizeof(long);
398

    
399
    /* 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

    
403
    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
        if (si->zsize == 4 && z != 3)
411
            chan_offset = 2 - z;
412
        else
413
#endif
414
            chan_offset = z;
415

    
416
        srcrow = info->pict.data[0] + chan_offset;
417

    
418
        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
            srcrow += info->pict.linesize[0];
423
        }
424
    }
425

    
426
    url_fseek(pb, 512, SEEK_SET);
427

    
428
    /* write offset table */
429
    for (i = 0; i < (si->ysize * si->zsize); i++) {
430
        put_be32(pb, offsettab[i]);
431
    }
432

    
433
    /* 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

    
440
    av_free(lengthtab);
441
    av_free(offsettab);
442

    
443
    return 0;
444
}
445
#endif // CONFIG_MUXERS
446

    
447
AVImageFormat sgi_image_format = {
448
    "sgi",
449
    "sgi,rgb,rgba,bw",
450
    sgi_probe,
451
    sgi_read,
452
    (1 << PIX_FMT_GRAY8) | (1 << PIX_FMT_RGB24) | (1 << PIX_FMT_RGBA32),
453
#ifdef CONFIG_MUXERS
454
    sgi_write,
455
#else
456
    NULL,
457
#endif // CONFIG_MUXERS
458
};