~ubuntu-branches/ubuntu/jaunty/xvidcap/jaunty-proposed

« back to all changes in this revision

Viewing changes to ffmpeg/libavformat/png.c

  • Committer: Bazaar Package Importer
  • Author(s): John Dong
  • Date: 2008-02-25 15:47:12 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20080225154712-qvr11ekcea4c9ry8
Tags: 1.1.6-0.1ubuntu1
* Merge from debian-multimedia (LP: #120003), Ubuntu Changes:
 - For ffmpeg-related build-deps, remove cvs from package names.
 - Standards-Version 3.7.3
 - Maintainer Spec

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * PNG image format
3
 
 * Copyright (c) 2003 Fabrice Bellard.
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
 
#include "avformat.h"
20
 
 
21
 
/* TODO:
22
 
 * - add 2, 4 and 16 bit depth support
23
 
 * - use filters when generating a png (better compression)
24
 
 */
25
 
 
26
 
#ifdef CONFIG_ZLIB
27
 
#include <zlib.h>
28
 
 
29
 
//#define DEBUG
30
 
 
31
 
#define PNG_COLOR_MASK_PALETTE    1
32
 
#define PNG_COLOR_MASK_COLOR      2
33
 
#define PNG_COLOR_MASK_ALPHA      4
34
 
 
35
 
#define PNG_COLOR_TYPE_GRAY 0
36
 
#define PNG_COLOR_TYPE_PALETTE  (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE)
37
 
#define PNG_COLOR_TYPE_RGB        (PNG_COLOR_MASK_COLOR)
38
 
#define PNG_COLOR_TYPE_RGB_ALPHA  (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_ALPHA)
39
 
#define PNG_COLOR_TYPE_GRAY_ALPHA (PNG_COLOR_MASK_ALPHA)
40
 
 
41
 
#define PNG_FILTER_VALUE_NONE  0
42
 
#define PNG_FILTER_VALUE_SUB   1
43
 
#define PNG_FILTER_VALUE_UP    2
44
 
#define PNG_FILTER_VALUE_AVG   3
45
 
#define PNG_FILTER_VALUE_PAETH 4
46
 
 
47
 
#define PNG_IHDR      0x0001
48
 
#define PNG_IDAT      0x0002
49
 
#define PNG_ALLIMAGE  0x0004
50
 
#define PNG_PLTE      0x0008
51
 
 
52
 
#define NB_PASSES 7
53
 
 
54
 
#define IOBUF_SIZE 4096
55
 
 
56
 
typedef struct PNGDecodeState {
57
 
    int state;
58
 
    int width, height;
59
 
    int bit_depth;
60
 
    int color_type;
61
 
    int compression_type;
62
 
    int interlace_type;
63
 
    int filter_type;
64
 
    int channels;
65
 
    int bits_per_pixel;
66
 
    int bpp;
67
 
    
68
 
    uint8_t *image_buf;
69
 
    int image_linesize;
70
 
    uint32_t palette[256];
71
 
    uint8_t *crow_buf;
72
 
    uint8_t *last_row;
73
 
    uint8_t *tmp_row;
74
 
    int pass;
75
 
    int crow_size; /* compressed row size (include filter type) */
76
 
    int row_size; /* decompressed row size */
77
 
    int pass_row_size; /* decompress row size of the current pass */
78
 
    int y;
79
 
    z_stream zstream;
80
 
} PNGDecodeState;
81
 
 
82
 
static const uint8_t pngsig[8] = {137, 80, 78, 71, 13, 10, 26, 10};
83
 
 
84
 
/* Mask to determine which y pixels are valid in a pass */
85
 
static const uint8_t png_pass_ymask[NB_PASSES] = {
86
 
    0x80, 0x80, 0x08, 0x88, 0x22, 0xaa, 0x55,
87
 
};
88
 
 
89
 
/* Mask to determine which y pixels can be written in a pass */
90
 
static const uint8_t png_pass_dsp_ymask[NB_PASSES] = {
91
 
    0xff, 0xff, 0x0f, 0xcc, 0x33, 0xff, 0x55,
92
 
};
93
 
 
94
 
/* minimum x value */
95
 
static const uint8_t png_pass_xmin[NB_PASSES] = {
96
 
    0, 4, 0, 2, 0, 1, 0
97
 
};
98
 
 
99
 
/* x shift to get row width */
100
 
static const uint8_t png_pass_xshift[NB_PASSES] = {
101
 
    3, 3, 2, 2, 1, 1, 0
102
 
};
103
 
 
104
 
/* Mask to determine which pixels are valid in a pass */
105
 
static const uint8_t png_pass_mask[NB_PASSES] = {
106
 
    0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff
107
 
};
108
 
 
109
 
/* Mask to determine which pixels to overwrite while displaying */
110
 
static const uint8_t png_pass_dsp_mask[NB_PASSES] = { 
111
 
    0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff
112
 
};
113
 
 
114
 
static int png_probe(AVProbeData *pd)
115
 
{
116
 
    if (pd->buf_size >= 8 &&
117
 
        memcmp(pd->buf, pngsig, 8) == 0)
118
 
        return AVPROBE_SCORE_MAX;
119
 
    else
120
 
        return 0;
121
 
}
122
 
 
123
 
static void *png_zalloc(void *opaque, unsigned int items, unsigned int size)
124
 
{
125
 
    return av_malloc(items * size);
126
 
}
127
 
 
128
 
static void png_zfree(void *opaque, void *ptr)
129
 
{
130
 
    av_free(ptr);
131
 
}
132
 
 
133
 
static int png_get_nb_channels(int color_type)
134
 
{
135
 
    int channels;
136
 
    channels = 1;
137
 
    if ((color_type & (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE)) ==
138
 
        PNG_COLOR_MASK_COLOR)
139
 
        channels = 3;
140
 
    if (color_type & PNG_COLOR_MASK_ALPHA)
141
 
        channels++;
142
 
    return channels;
143
 
}
144
 
 
145
 
/* compute the row size of an interleaved pass */
146
 
static int png_pass_row_size(int pass, int bits_per_pixel, int width)
147
 
{
148
 
    int shift, xmin, pass_width;
149
 
 
150
 
    xmin = png_pass_xmin[pass];
151
 
    if (width <= xmin)
152
 
        return 0;
153
 
    shift = png_pass_xshift[pass];
154
 
    pass_width = (width - xmin + (1 << shift) - 1) >> shift;
155
 
    return (pass_width * bits_per_pixel + 7) >> 3;
156
 
}
157
 
 
158
 
/* NOTE: we try to construct a good looking image at each pass. width
159
 
   is the original image width. We also do pixel format convertion at
160
 
   this stage */
161
 
static void png_put_interlaced_row(uint8_t *dst, int width, 
162
 
                                   int bits_per_pixel, int pass, 
163
 
                                   int color_type, const uint8_t *src)
164
 
{
165
 
    int x, mask, dsp_mask, j, src_x, b, bpp;
166
 
    uint8_t *d;
167
 
    const uint8_t *s;
168
 
    
169
 
    mask = png_pass_mask[pass];
170
 
    dsp_mask = png_pass_dsp_mask[pass];
171
 
    switch(bits_per_pixel) {
172
 
    case 1:
173
 
        /* we must intialize the line to zero before writing to it */
174
 
        if (pass == 0)
175
 
            memset(dst, 0, (width + 7) >> 3);
176
 
        src_x = 0;
177
 
        for(x = 0; x < width; x++) {
178
 
            j = (x & 7);
179
 
            if ((dsp_mask << j) & 0x80) {
180
 
                b = (src[src_x >> 3] >> (7 - (src_x & 7))) & 1;
181
 
                dst[x >> 3] |= b << (7 - j);
182
 
            }
183
 
            if ((mask << j) & 0x80)
184
 
                src_x++;
185
 
        }
186
 
        break;
187
 
    default:
188
 
        bpp = bits_per_pixel >> 3;
189
 
        d = dst;
190
 
        s = src;
191
 
        if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
192
 
            for(x = 0; x < width; x++) {
193
 
                j = x & 7;
194
 
                if ((dsp_mask << j) & 0x80) {
195
 
                    *(uint32_t *)d = (s[3] << 24) | (s[0] << 16) | (s[1] << 8) | s[2];
196
 
                }
197
 
                d += bpp;
198
 
                if ((mask << j) & 0x80)
199
 
                    s += bpp;
200
 
            }
201
 
        } else {
202
 
            for(x = 0; x < width; x++) {
203
 
                j = x & 7;
204
 
                if ((dsp_mask << j) & 0x80) {
205
 
                    memcpy(d, s, bpp);
206
 
                }
207
 
                d += bpp;
208
 
                if ((mask << j) & 0x80)
209
 
                    s += bpp;
210
 
            }
211
 
        }
212
 
        break;
213
 
    }
214
 
}
215
 
 
216
 
static void png_get_interlaced_row(uint8_t *dst, int row_size, 
217
 
                                   int bits_per_pixel, int pass, 
218
 
                                   const uint8_t *src, int width)
219
 
{
220
 
    int x, mask, dst_x, j, b, bpp;
221
 
    uint8_t *d;
222
 
    const uint8_t *s;
223
 
 
224
 
    mask = png_pass_mask[pass];
225
 
    switch(bits_per_pixel) {
226
 
    case 1:
227
 
        memset(dst, 0, row_size);
228
 
        dst_x = 0;
229
 
        for(x = 0; x < width; x++) {
230
 
            j = (x & 7);
231
 
            if ((mask << j) & 0x80) {
232
 
                b = (src[x >> 3] >> (7 - j)) & 1;
233
 
                dst[dst_x >> 3] |= b << (7 - (dst_x & 7));
234
 
                dst_x++;
235
 
            }
236
 
        }
237
 
        break;
238
 
    default:
239
 
        bpp = bits_per_pixel >> 3;
240
 
        d = dst;
241
 
        s = src;
242
 
        for(x = 0; x < width; x++) {
243
 
            j = x & 7;
244
 
            if ((mask << j) & 0x80) {
245
 
                memcpy(d, s, bpp);
246
 
                d += bpp;
247
 
            }
248
 
            s += bpp;
249
 
        }
250
 
        break;
251
 
    }
252
 
}
253
 
 
254
 
/* XXX: optimize */
255
 
/* NOTE: 'dst' can be equal to 'last' */
256
 
static void png_filter_row(uint8_t *dst, int filter_type, 
257
 
                           uint8_t *src, uint8_t *last, int size, int bpp)
258
 
{
259
 
    int i, p;
260
 
 
261
 
    switch(filter_type) {
262
 
    case PNG_FILTER_VALUE_NONE:
263
 
        memcpy(dst, src, size);
264
 
        break;
265
 
    case PNG_FILTER_VALUE_SUB:
266
 
        for(i = 0; i < bpp; i++) {
267
 
            dst[i] = src[i];
268
 
        }
269
 
        for(i = bpp; i < size; i++) {
270
 
            p = dst[i - bpp];
271
 
            dst[i] = p + src[i];
272
 
        }
273
 
        break;
274
 
    case PNG_FILTER_VALUE_UP:
275
 
        for(i = 0; i < size; i++) {
276
 
            p = last[i];
277
 
            dst[i] = p + src[i];
278
 
        }
279
 
        break;
280
 
    case PNG_FILTER_VALUE_AVG:
281
 
        for(i = 0; i < bpp; i++) {
282
 
            p = (last[i] >> 1);
283
 
            dst[i] = p + src[i];
284
 
        }
285
 
        for(i = bpp; i < size; i++) {
286
 
            p = ((dst[i - bpp] + last[i]) >> 1);
287
 
            dst[i] = p + src[i];
288
 
        }
289
 
        break;
290
 
    case PNG_FILTER_VALUE_PAETH:
291
 
        for(i = 0; i < bpp; i++) {
292
 
            p = last[i];
293
 
            dst[i] = p + src[i];
294
 
        }
295
 
        for(i = bpp; i < size; i++) {
296
 
            int a, b, c, pa, pb, pc;
297
 
 
298
 
            a = dst[i - bpp];
299
 
            b = last[i];
300
 
            c = last[i - bpp];
301
 
 
302
 
            p = b - c;
303
 
            pc = a - c;
304
 
 
305
 
            pa = abs(p);
306
 
            pb = abs(pc);
307
 
            pc = abs(p + pc);
308
 
 
309
 
            if (pa <= pb && pa <= pc)
310
 
                p = a;
311
 
            else if (pb <= pc)
312
 
                p = b;
313
 
            else
314
 
                p = c;
315
 
            dst[i] = p + src[i];
316
 
        }
317
 
        break;
318
 
    }
319
 
}
320
 
 
321
 
static void convert_from_rgba32(uint8_t *dst, const uint8_t *src, int width)
322
 
{
323
 
    uint8_t *d;
324
 
    int j;
325
 
    unsigned int v;
326
 
    
327
 
    d = dst;
328
 
    for(j = 0; j < width; j++) {
329
 
        v = ((uint32_t *)src)[j];
330
 
        d[0] = v >> 16;
331
 
        d[1] = v >> 8;
332
 
        d[2] = v;
333
 
        d[3] = v >> 24;
334
 
        d += 4;
335
 
    }
336
 
}
337
 
 
338
 
static void convert_to_rgba32(uint8_t *dst, const uint8_t *src, int width)
339
 
{
340
 
    int j;
341
 
    unsigned int r, g, b, a;
342
 
 
343
 
    for(j = 0;j < width; j++) {
344
 
        r = src[0];
345
 
        g = src[1];
346
 
        b = src[2];
347
 
        a = src[3];
348
 
        *(uint32_t *)dst = (a << 24) | (r << 16) | (g << 8) | b;
349
 
        dst += 4;
350
 
        src += 4;
351
 
    }
352
 
}
353
 
 
354
 
/* process exactly one decompressed row */
355
 
static void png_handle_row(PNGDecodeState *s)
356
 
{
357
 
    uint8_t *ptr, *last_row;
358
 
    int got_line;
359
 
    
360
 
    if (!s->interlace_type) {
361
 
        ptr = s->image_buf + s->image_linesize * s->y;
362
 
        /* need to swap bytes correctly for RGB_ALPHA */
363
 
        if (s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
364
 
            png_filter_row(s->tmp_row, s->crow_buf[0], s->crow_buf + 1, 
365
 
                           s->last_row, s->row_size, s->bpp);
366
 
            memcpy(s->last_row, s->tmp_row, s->row_size);
367
 
            convert_to_rgba32(ptr, s->tmp_row, s->width);
368
 
        } else {
369
 
            /* in normal case, we avoid one copy */
370
 
            if (s->y == 0)
371
 
                last_row = s->last_row;
372
 
            else
373
 
                last_row = ptr - s->image_linesize;
374
 
            
375
 
            png_filter_row(ptr, s->crow_buf[0], s->crow_buf + 1, 
376
 
                           last_row, s->row_size, s->bpp);
377
 
        }
378
 
        s->y++;
379
 
        if (s->y == s->height) {
380
 
            s->state |= PNG_ALLIMAGE;
381
 
        }
382
 
    } else {
383
 
        got_line = 0;
384
 
        for(;;) {
385
 
            ptr = s->image_buf + s->image_linesize * s->y;
386
 
            if ((png_pass_ymask[s->pass] << (s->y & 7)) & 0x80) {
387
 
                /* if we already read one row, it is time to stop to
388
 
                   wait for the next one */
389
 
                if (got_line)
390
 
                    break;
391
 
                png_filter_row(s->tmp_row, s->crow_buf[0], s->crow_buf + 1, 
392
 
                               s->last_row, s->pass_row_size, s->bpp);
393
 
                memcpy(s->last_row, s->tmp_row, s->pass_row_size);
394
 
                got_line = 1;
395
 
            }
396
 
            if ((png_pass_dsp_ymask[s->pass] << (s->y & 7)) & 0x80) {
397
 
                /* NOTE: rgba32 is handled directly in png_put_interlaced_row */
398
 
                png_put_interlaced_row(ptr, s->width, s->bits_per_pixel, s->pass, 
399
 
                                       s->color_type, s->last_row);
400
 
            }
401
 
            s->y++;
402
 
            if (s->y == s->height) {
403
 
                for(;;) {
404
 
                    if (s->pass == NB_PASSES - 1) {
405
 
                        s->state |= PNG_ALLIMAGE;
406
 
                        goto the_end;
407
 
                    } else {
408
 
                        s->pass++;
409
 
                        s->y = 0;
410
 
                        s->pass_row_size = png_pass_row_size(s->pass, 
411
 
                                                             s->bits_per_pixel, 
412
 
                                                             s->width);
413
 
                        s->crow_size = s->pass_row_size + 1;
414
 
                        if (s->pass_row_size != 0)
415
 
                            break;
416
 
                        /* skip pass if empty row */
417
 
                    }
418
 
                }
419
 
            }
420
 
        }
421
 
    the_end: ;
422
 
    }
423
 
}
424
 
 
425
 
static int png_decode_idat(PNGDecodeState *s, ByteIOContext *f, int length)
426
 
{
427
 
    uint8_t buf[IOBUF_SIZE];
428
 
    int buf_size;
429
 
    int ret;
430
 
    while (length > 0) {
431
 
        /* read the buffer */
432
 
        buf_size = IOBUF_SIZE;
433
 
        if (buf_size > length)
434
 
            buf_size = length;
435
 
        ret = get_buffer(f, buf, buf_size);
436
 
        if (ret != buf_size)
437
 
            return -1;
438
 
        s->zstream.avail_in = buf_size;
439
 
        s->zstream.next_in = buf;
440
 
        /* decode one line if possible */
441
 
        while (s->zstream.avail_in > 0) {
442
 
            ret = inflate(&s->zstream, Z_PARTIAL_FLUSH);
443
 
            if (ret != Z_OK && ret != Z_STREAM_END) {
444
 
                return -1;
445
 
            }
446
 
            if (s->zstream.avail_out == 0) {
447
 
                if (!(s->state & PNG_ALLIMAGE)) {
448
 
                    png_handle_row(s);
449
 
                }
450
 
                s->zstream.avail_out = s->crow_size;
451
 
                s->zstream.next_out = s->crow_buf;
452
 
            }
453
 
        }
454
 
        length -= buf_size;
455
 
    }
456
 
    return 0;
457
 
}
458
 
 
459
 
static int png_read(ByteIOContext *f, 
460
 
                    int (*alloc_cb)(void *opaque, AVImageInfo *info), void *opaque)
461
 
{
462
 
    AVImageInfo info1, *info = &info1;
463
 
    PNGDecodeState s1, *s = &s1;
464
 
    uint32_t tag, length;
465
 
    int ret, crc;
466
 
    uint8_t buf[8];
467
 
 
468
 
    /* check signature */
469
 
    ret = get_buffer(f, buf, 8);
470
 
    if (ret != 8)
471
 
        return -1;
472
 
    if (memcmp(buf, pngsig, 8) != 0)
473
 
        return -1;
474
 
    memset(s, 0, sizeof(PNGDecodeState));
475
 
    /* init the zlib */
476
 
    s->zstream.zalloc = png_zalloc;
477
 
    s->zstream.zfree = png_zfree;
478
 
    s->zstream.opaque = NULL;
479
 
    ret = inflateInit(&s->zstream);
480
 
    if (ret != Z_OK)
481
 
        return -1;
482
 
    for(;;) {
483
 
        if (url_feof(f))
484
 
            goto fail;
485
 
        length = get_be32(f);
486
 
        if (length > 0x7fffffff)
487
 
            goto fail;
488
 
        tag = get_le32(f);
489
 
#ifdef DEBUG
490
 
        printf("png: tag=%c%c%c%c length=%u\n", 
491
 
               (tag & 0xff),
492
 
               ((tag >> 8) & 0xff),
493
 
               ((tag >> 16) & 0xff),
494
 
               ((tag >> 24) & 0xff), length);
495
 
#endif
496
 
        switch(tag) {
497
 
        case MKTAG('I', 'H', 'D', 'R'):
498
 
            if (length != 13)
499
 
                goto fail;
500
 
            s->width = get_be32(f);
501
 
            s->height = get_be32(f);
502
 
            s->bit_depth = get_byte(f);
503
 
            s->color_type = get_byte(f);
504
 
            s->compression_type = get_byte(f);
505
 
            s->filter_type = get_byte(f);
506
 
            s->interlace_type = get_byte(f);
507
 
            crc = get_be32(f);
508
 
            s->state |= PNG_IHDR;
509
 
#ifdef DEBUG
510
 
            printf("width=%d height=%d depth=%d color_type=%d compression_type=%d filter_type=%d interlace_type=%d\n", 
511
 
                   s->width, s->height, s->bit_depth, s->color_type, 
512
 
                   s->compression_type, s->filter_type, s->interlace_type);
513
 
#endif
514
 
            break;
515
 
        case MKTAG('I', 'D', 'A', 'T'):
516
 
            if (!(s->state & PNG_IHDR))
517
 
                goto fail;
518
 
            if (!(s->state & PNG_IDAT)) {
519
 
                /* init image info */
520
 
                info->width = s->width;
521
 
                info->height = s->height;
522
 
                info->interleaved = (s->interlace_type != 0);
523
 
 
524
 
                s->channels = png_get_nb_channels(s->color_type);
525
 
                s->bits_per_pixel = s->bit_depth * s->channels;
526
 
                s->bpp = (s->bits_per_pixel + 7) >> 3;
527
 
                s->row_size = (info->width * s->bits_per_pixel + 7) >> 3;
528
 
 
529
 
                if (s->bit_depth == 8 && 
530
 
                    s->color_type == PNG_COLOR_TYPE_RGB) {
531
 
                    info->pix_fmt = PIX_FMT_RGB24;
532
 
                } else if (s->bit_depth == 8 && 
533
 
                           s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
534
 
                    info->pix_fmt = PIX_FMT_RGBA32;
535
 
                } else if (s->bit_depth == 8 && 
536
 
                           s->color_type == PNG_COLOR_TYPE_GRAY) {
537
 
                    info->pix_fmt = PIX_FMT_GRAY8;
538
 
                } else if (s->bit_depth == 1 && 
539
 
                           s->color_type == PNG_COLOR_TYPE_GRAY) {
540
 
                    info->pix_fmt = PIX_FMT_MONOBLACK;
541
 
                } else if (s->color_type == PNG_COLOR_TYPE_PALETTE) {
542
 
                    info->pix_fmt = PIX_FMT_PAL8;
543
 
                } else {
544
 
                    goto fail;
545
 
                }
546
 
                ret = alloc_cb(opaque, info);
547
 
                if (ret) 
548
 
                    goto the_end;
549
 
 
550
 
                /* compute the compressed row size */
551
 
                if (!s->interlace_type) {
552
 
                    s->crow_size = s->row_size + 1;
553
 
                } else {
554
 
                    s->pass = 0;
555
 
                    s->pass_row_size = png_pass_row_size(s->pass, 
556
 
                                                         s->bits_per_pixel, 
557
 
                                                         s->width);
558
 
                    s->crow_size = s->pass_row_size + 1;
559
 
                }
560
 
#ifdef DEBUG
561
 
                printf("row_size=%d crow_size =%d\n", 
562
 
                       s->row_size, s->crow_size);
563
 
#endif
564
 
                s->image_buf = info->pict.data[0];
565
 
                s->image_linesize = info->pict.linesize[0];
566
 
                /* copy the palette if needed */
567
 
                if (s->color_type == PNG_COLOR_TYPE_PALETTE)
568
 
                    memcpy(info->pict.data[1], s->palette, 256 * sizeof(uint32_t));
569
 
                /* empty row is used if differencing to the first row */
570
 
                s->last_row = av_mallocz(s->row_size);
571
 
                if (!s->last_row)
572
 
                    goto fail;
573
 
                if (s->interlace_type ||
574
 
                    s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
575
 
                    s->tmp_row = av_malloc(s->row_size);
576
 
                    if (!s->tmp_row)
577
 
                        goto fail;
578
 
                }
579
 
                /* compressed row */
580
 
                s->crow_buf = av_malloc(s->row_size + 1);
581
 
                if (!s->crow_buf)
582
 
                    goto fail;
583
 
                s->zstream.avail_out = s->crow_size;
584
 
                s->zstream.next_out = s->crow_buf;
585
 
            }
586
 
            s->state |= PNG_IDAT;
587
 
            if (png_decode_idat(s, f, length) < 0)
588
 
                goto fail;
589
 
            /* skip crc */
590
 
            crc = get_be32(f);
591
 
            break;
592
 
        case MKTAG('P', 'L', 'T', 'E'):
593
 
            {
594
 
                int n, i, r, g, b;
595
 
                
596
 
                if ((length % 3) != 0 || length > 256 * 3)
597
 
                    goto skip_tag;
598
 
                /* read the palette */
599
 
                n = length / 3;
600
 
                for(i=0;i<n;i++) {
601
 
                    r = get_byte(f);
602
 
                    g = get_byte(f);
603
 
                    b = get_byte(f);
604
 
                    s->palette[i] = (0xff << 24) | (r << 16) | (g << 8) | b;
605
 
                }
606
 
                for(;i<256;i++) {
607
 
                    s->palette[i] = (0xff << 24);
608
 
                }
609
 
                s->state |= PNG_PLTE;
610
 
                crc = get_be32(f);
611
 
            }
612
 
            break;
613
 
        case MKTAG('t', 'R', 'N', 'S'):
614
 
            {
615
 
                int v, i;
616
 
 
617
 
                /* read the transparency. XXX: Only palette mode supported */
618
 
                if (s->color_type != PNG_COLOR_TYPE_PALETTE ||
619
 
                    length > 256 ||
620
 
                    !(s->state & PNG_PLTE))
621
 
                    goto skip_tag;
622
 
                for(i=0;i<length;i++) {
623
 
                    v = get_byte(f);
624
 
                    s->palette[i] = (s->palette[i] & 0x00ffffff) | (v << 24);
625
 
                }
626
 
                crc = get_be32(f);
627
 
            }
628
 
            break;
629
 
        case MKTAG('I', 'E', 'N', 'D'):
630
 
            if (!(s->state & PNG_ALLIMAGE))
631
 
                goto fail;
632
 
            crc = get_be32(f);
633
 
            goto exit_loop;
634
 
        default:
635
 
            /* skip tag */
636
 
        skip_tag:
637
 
            url_fskip(f, length + 4);
638
 
            break;
639
 
        }
640
 
    }
641
 
 exit_loop:
642
 
    ret = 0;
643
 
 the_end:
644
 
    inflateEnd(&s->zstream);
645
 
    av_free(s->crow_buf);
646
 
    av_free(s->last_row);
647
 
    av_free(s->tmp_row);
648
 
    return ret;
649
 
 fail:
650
 
    ret = -1;
651
 
    goto the_end;
652
 
}
653
 
 
654
 
static void png_write_chunk(ByteIOContext *f, uint32_t tag,
655
 
                            const uint8_t *buf, int length)
656
 
{
657
 
    uint32_t crc;
658
 
    uint8_t tagbuf[4];
659
 
 
660
 
    put_be32(f, length);
661
 
    crc = crc32(0, Z_NULL, 0);
662
 
    tagbuf[0] = tag;
663
 
    tagbuf[1] = tag >> 8;
664
 
    tagbuf[2] = tag >> 16;
665
 
    tagbuf[3] = tag >> 24;
666
 
    crc = crc32(crc, tagbuf, 4);
667
 
    put_le32(f, tag);
668
 
    if (length > 0) {
669
 
        crc = crc32(crc, buf, length);
670
 
        put_buffer(f, buf, length);
671
 
    }
672
 
    put_be32(f, crc);
673
 
}
674
 
 
675
 
/* XXX: use avcodec generic function ? */
676
 
static void to_be32(uint8_t *p, uint32_t v)
677
 
{
678
 
    p[0] = v >> 24;
679
 
    p[1] = v >> 16;
680
 
    p[2] = v >> 8;
681
 
    p[3] = v;
682
 
}
683
 
 
684
 
typedef struct PNGEncodeState {
685
 
    ByteIOContext *f;
686
 
    z_stream zstream;
687
 
    uint8_t buf[IOBUF_SIZE];
688
 
} PNGEncodeState;
689
 
 
690
 
 
691
 
/* XXX: do filtering */
692
 
static int png_write_row(PNGEncodeState *s, const uint8_t *data, int size)
693
 
{
694
 
    int ret;
695
 
 
696
 
    s->zstream.avail_in = size;
697
 
    s->zstream.next_in = (uint8_t *)data;
698
 
    while (s->zstream.avail_in > 0) {
699
 
        ret = deflate(&s->zstream, Z_NO_FLUSH);
700
 
        if (ret != Z_OK)
701
 
            return -1;
702
 
        if (s->zstream.avail_out == 0) {
703
 
            png_write_chunk(s->f, MKTAG('I', 'D', 'A', 'T'), s->buf, IOBUF_SIZE);
704
 
            s->zstream.avail_out = IOBUF_SIZE;
705
 
            s->zstream.next_out = s->buf;
706
 
        }
707
 
    }
708
 
    return 0;
709
 
}
710
 
 
711
 
static int png_write(ByteIOContext *f, AVImageInfo *info)
712
 
{
713
 
    PNGEncodeState s1, *s = &s1;
714
 
    int bit_depth, color_type, y, len, row_size, ret, is_progressive;
715
 
    int bits_per_pixel, pass_row_size;
716
 
    uint8_t *ptr;
717
 
    uint8_t *crow_buf = NULL;
718
 
    uint8_t *tmp_buf = NULL;
719
 
    
720
 
    s->f = f;
721
 
    is_progressive = info->interleaved;
722
 
    switch(info->pix_fmt) {
723
 
    case PIX_FMT_RGBA32:
724
 
        bit_depth = 8;
725
 
        color_type = PNG_COLOR_TYPE_RGB_ALPHA;
726
 
        break;
727
 
    case PIX_FMT_RGB24:
728
 
        bit_depth = 8;
729
 
        color_type = PNG_COLOR_TYPE_RGB;
730
 
        break;
731
 
    case PIX_FMT_GRAY8:
732
 
        bit_depth = 8;
733
 
        color_type = PNG_COLOR_TYPE_GRAY;
734
 
        break;
735
 
    case PIX_FMT_MONOBLACK:
736
 
        bit_depth = 1;
737
 
        color_type = PNG_COLOR_TYPE_GRAY;
738
 
        break;
739
 
    case PIX_FMT_PAL8:
740
 
        bit_depth = 8;
741
 
        color_type = PNG_COLOR_TYPE_PALETTE;
742
 
        break;
743
 
    default:
744
 
        return -1;
745
 
    }
746
 
    bits_per_pixel = png_get_nb_channels(color_type) * bit_depth;
747
 
    row_size = (info->width * bits_per_pixel + 7) >> 3;
748
 
 
749
 
    s->zstream.zalloc = png_zalloc;
750
 
    s->zstream.zfree = png_zfree;
751
 
    s->zstream.opaque = NULL;
752
 
    ret = deflateInit2(&s->zstream, Z_DEFAULT_COMPRESSION,
753
 
                       Z_DEFLATED, 15, 8, Z_DEFAULT_STRATEGY);
754
 
    if (ret != Z_OK)
755
 
        return -1;
756
 
    crow_buf = av_malloc(row_size + 1);
757
 
    if (!crow_buf)
758
 
        goto fail;
759
 
    if (is_progressive) {
760
 
        tmp_buf = av_malloc(row_size + 1);
761
 
        if (!tmp_buf)
762
 
            goto fail;
763
 
    }
764
 
 
765
 
    /* write png header */
766
 
    put_buffer(f, pngsig, 8);
767
 
    
768
 
    to_be32(s->buf, info->width);
769
 
    to_be32(s->buf + 4, info->height);
770
 
    s->buf[8] = bit_depth;
771
 
    s->buf[9] = color_type;
772
 
    s->buf[10] = 0; /* compression type */
773
 
    s->buf[11] = 0; /* filter type */
774
 
    s->buf[12] = is_progressive; /* interlace type */
775
 
    
776
 
    png_write_chunk(f, MKTAG('I', 'H', 'D', 'R'), s->buf, 13);
777
 
 
778
 
    /* put the palette if needed */
779
 
    if (color_type == PNG_COLOR_TYPE_PALETTE) {
780
 
        int has_alpha, alpha, i;
781
 
        unsigned int v;
782
 
        uint32_t *palette;
783
 
        uint8_t *alpha_ptr;
784
 
        
785
 
        palette = (uint32_t *)info->pict.data[1];
786
 
        ptr = s->buf;
787
 
        alpha_ptr = s->buf + 256 * 3;
788
 
        has_alpha = 0;
789
 
        for(i = 0; i < 256; i++) {
790
 
            v = palette[i];
791
 
            alpha = v >> 24;
792
 
            if (alpha != 0xff)
793
 
                has_alpha = 1;
794
 
            *alpha_ptr++ = alpha;
795
 
            ptr[0] = v >> 16;
796
 
            ptr[1] = v >> 8;
797
 
            ptr[2] = v;
798
 
            ptr += 3;
799
 
        }
800
 
        png_write_chunk(f, MKTAG('P', 'L', 'T', 'E'), s->buf, 256 * 3);
801
 
        if (has_alpha) {
802
 
            png_write_chunk(f, MKTAG('t', 'R', 'N', 'S'), s->buf + 256 * 3, 256);
803
 
        }
804
 
    }
805
 
 
806
 
    /* now put each row */
807
 
    s->zstream.avail_out = IOBUF_SIZE;
808
 
    s->zstream.next_out = s->buf;
809
 
    if (is_progressive) {
810
 
        uint8_t *ptr1;
811
 
        int pass;
812
 
 
813
 
        for(pass = 0; pass < NB_PASSES; pass++) {
814
 
            /* NOTE: a pass is completely omited if no pixels would be
815
 
               output */
816
 
            pass_row_size = png_pass_row_size(pass, bits_per_pixel, info->width);
817
 
            if (pass_row_size > 0) {
818
 
                for(y = 0; y < info->height; y++) {
819
 
                    if ((png_pass_ymask[pass] << (y & 7)) & 0x80) {
820
 
                        ptr = info->pict.data[0] + y * info->pict.linesize[0];
821
 
                        if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
822
 
                            convert_from_rgba32(tmp_buf, ptr, info->width);
823
 
                            ptr1 = tmp_buf;
824
 
                        } else {
825
 
                            ptr1 = ptr;
826
 
                        }
827
 
                        png_get_interlaced_row(crow_buf + 1, pass_row_size, 
828
 
                                               bits_per_pixel, pass, 
829
 
                                               ptr1, info->width);
830
 
                        crow_buf[0] = PNG_FILTER_VALUE_NONE;
831
 
                        png_write_row(s, crow_buf, pass_row_size + 1);
832
 
                    }
833
 
                }
834
 
            }
835
 
        }
836
 
    } else {
837
 
        for(y = 0; y < info->height; y++) {
838
 
            ptr = info->pict.data[0] + y * info->pict.linesize[0];
839
 
            if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
840
 
                convert_from_rgba32(crow_buf + 1, ptr, info->width);
841
 
            else
842
 
                memcpy(crow_buf + 1, ptr, row_size);
843
 
            crow_buf[0] = PNG_FILTER_VALUE_NONE;
844
 
            png_write_row(s, crow_buf, row_size + 1);
845
 
        }
846
 
    }
847
 
    /* compress last bytes */
848
 
    for(;;) {
849
 
        ret = deflate(&s->zstream, Z_FINISH);
850
 
        if (ret == Z_OK || ret == Z_STREAM_END) {
851
 
            len = IOBUF_SIZE - s->zstream.avail_out;
852
 
            if (len > 0) {
853
 
                png_write_chunk(f, MKTAG('I', 'D', 'A', 'T'), s->buf, len);
854
 
            }
855
 
            s->zstream.avail_out = IOBUF_SIZE;
856
 
            s->zstream.next_out = s->buf;
857
 
            if (ret == Z_STREAM_END)
858
 
                break;
859
 
        } else {
860
 
            goto fail;
861
 
        }
862
 
    }
863
 
    png_write_chunk(f, MKTAG('I', 'E', 'N', 'D'), NULL, 0);
864
 
 
865
 
    put_flush_packet(f);
866
 
    ret = 0;
867
 
 the_end:
868
 
    av_free(crow_buf);
869
 
    av_free(tmp_buf);
870
 
    deflateEnd(&s->zstream);
871
 
    return ret;
872
 
 fail:
873
 
    ret = -1;
874
 
    goto the_end;
875
 
}
876
 
 
877
 
AVImageFormat png_image_format = {
878
 
    "png",
879
 
    "png",
880
 
    png_probe,
881
 
    png_read,
882
 
    (1 << PIX_FMT_RGBA32) | (1 << PIX_FMT_RGB24) | (1 << PIX_FMT_GRAY8) | 
883
 
    (1 << PIX_FMT_MONOBLACK) | (1 << PIX_FMT_PAL8),
884
 
    png_write,
885
 
    AVIMAGE_INTERLEAVED,
886
 
};
887
 
#endif