~ubuntu-dev/mplayer/ubuntu-feisty

« back to all changes in this revision

Viewing changes to libavcodec/png.c

  • Committer: Reinhard Tartler
  • Date: 2006-07-08 08:45:33 UTC
  • Revision ID: siretart@tauware.de-20060708084533-dbc155bde7122e78
imported mplayer_0.99+1.0pre7try2+cvs20060117

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