OSDN Git Service

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