png: disable broken MMX/SIMD code for bpp <= 2
[ffmpeg.git] / libavcodec / pngdec.c
1 /*
2  * PNG image format
3  * Copyright (c) 2003 Fabrice Bellard
4  *
5  * This file is part of Libav.
6  *
7  * Libav is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * Libav is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with Libav; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 #include "libavutil/imgutils.h"
22 #include "avcodec.h"
23 #include "bytestream.h"
24 #include "internal.h"
25 #include "png.h"
26 #include "pngdsp.h"
27
28 /* TODO:
29  * - add 2, 4 and 16 bit depth support
30  */
31
32 #include <zlib.h>
33
34 typedef struct PNGDecContext {
35     PNGDSPContext dsp;
36
37     GetByteContext gb;
38     AVFrame *prev;
39
40     int state;
41     int width, height;
42     int bit_depth;
43     int color_type;
44     int compression_type;
45     int interlace_type;
46     int filter_type;
47     int channels;
48     int bits_per_pixel;
49     int bpp;
50
51     uint8_t *image_buf;
52     int image_linesize;
53     uint32_t palette[256];
54     uint8_t *crow_buf;
55     uint8_t *last_row;
56     uint8_t *tmp_row;
57     int pass;
58     int crow_size; /* compressed row size (include filter type) */
59     int row_size; /* decompressed row size */
60     int pass_row_size; /* decompress row size of the current pass */
61     int y;
62     z_stream zstream;
63 } PNGDecContext;
64
65 /* Mask to determine which y pixels can be written in a pass */
66 static const uint8_t png_pass_dsp_ymask[NB_PASSES] = {
67     0xff, 0xff, 0x0f, 0xcc, 0x33, 0xff, 0x55,
68 };
69
70 /* Mask to determine which pixels to overwrite while displaying */
71 static const uint8_t png_pass_dsp_mask[NB_PASSES] = {
72     0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff
73 };
74
75 /* NOTE: we try to construct a good looking image at each pass. width
76  * is the original image width. We also do pixel format conversion at
77  * this stage */
78 static void png_put_interlaced_row(uint8_t *dst, int width,
79                                    int bits_per_pixel, int pass,
80                                    int color_type, const uint8_t *src)
81 {
82     int x, mask, dsp_mask, j, src_x, b, bpp;
83     uint8_t *d;
84     const uint8_t *s;
85
86     mask     = ff_png_pass_mask[pass];
87     dsp_mask = png_pass_dsp_mask[pass];
88
89     switch (bits_per_pixel) {
90     case 1:
91         /* we must initialize the line to zero before writing to it */
92         if (pass == 0)
93             memset(dst, 0, (width + 7) >> 3);
94         src_x = 0;
95         for (x = 0; x < width; x++) {
96             j = (x & 7);
97             if ((dsp_mask << j) & 0x80) {
98                 b = (src[src_x >> 3] >> (7 - (src_x & 7))) & 1;
99                 dst[x >> 3] |= b << (7 - j);
100             }
101             if ((mask << j) & 0x80)
102                 src_x++;
103         }
104         break;
105     default:
106         bpp = bits_per_pixel >> 3;
107         d   = dst;
108         s   = src;
109         if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
110             for (x = 0; x < width; x++) {
111                 j = x & 7;
112                 if ((dsp_mask << j) & 0x80) {
113                     *(uint32_t *)d = (s[3] << 24) | (s[0] << 16) | (s[1] << 8) | s[2];
114                 }
115                 d += bpp;
116                 if ((mask << j) & 0x80)
117                     s += bpp;
118             }
119         } else {
120             for (x = 0; x < width; x++) {
121                 j = x & 7;
122                 if ((dsp_mask << j) & 0x80) {
123                     memcpy(d, s, bpp);
124                 }
125                 d += bpp;
126                 if ((mask << j) & 0x80)
127                     s += bpp;
128             }
129         }
130         break;
131     }
132 }
133
134 void ff_add_png_paeth_prediction(uint8_t *dst, uint8_t *src, uint8_t *top,
135                                  int w, int bpp)
136 {
137     int i;
138     for (i = 0; i < w; i++) {
139         int a, b, c, p, pa, pb, pc;
140
141         a = dst[i - bpp];
142         b = top[i];
143         c = top[i - bpp];
144
145         p  = b - c;
146         pc = a - c;
147
148         pa = abs(p);
149         pb = abs(pc);
150         pc = abs(p + pc);
151
152         if (pa <= pb && pa <= pc)
153             p = a;
154         else if (pb <= pc)
155             p = b;
156         else
157             p = c;
158         dst[i] = p + src[i];
159     }
160 }
161
162 #define UNROLL1(bpp, op)                                                      \
163     {                                                                         \
164         r = dst[0];                                                           \
165         if (bpp >= 2)                                                         \
166             g = dst[1];                                                       \
167         if (bpp >= 3)                                                         \
168             b = dst[2];                                                       \
169         if (bpp >= 4)                                                         \
170             a = dst[3];                                                       \
171         for (; i < size; i += bpp) {                                          \
172             dst[i + 0] = r = op(r, src[i + 0], last[i + 0]);                  \
173             if (bpp == 1)                                                     \
174                 continue;                                                     \
175             dst[i + 1] = g = op(g, src[i + 1], last[i + 1]);                  \
176             if (bpp == 2)                                                     \
177                 continue;                                                     \
178             dst[i + 2] = b = op(b, src[i + 2], last[i + 2]);                  \
179             if (bpp == 3)                                                     \
180                 continue;                                                     \
181             dst[i + 3] = a = op(a, src[i + 3], last[i + 3]);                  \
182         }                                                                     \
183     }
184
185 #define UNROLL_FILTER(op)                                                     \
186     if (bpp == 1) {                                                           \
187         UNROLL1(1, op)                                                        \
188     } else if (bpp == 2) {                                                    \
189         UNROLL1(2, op)                                                        \
190     } else if (bpp == 3) {                                                    \
191         UNROLL1(3, op)                                                        \
192     } else if (bpp == 4) {                                                    \
193         UNROLL1(4, op)                                                        \
194     } else {                                                                  \
195         for (; i < size; i += bpp) {                                          \
196             int j;                                                            \
197             for (j = 0; j < bpp; j++)                                         \
198                 dst[i + j] = op(dst[i + j - bpp], src[i + j], last[i + j]);   \
199         }                                                                     \
200     }
201
202 /* NOTE: 'dst' can be equal to 'last' */
203 static void png_filter_row(PNGDSPContext *dsp, uint8_t *dst, int filter_type,
204                            uint8_t *src, uint8_t *last, int size, int bpp)
205 {
206     int i, p, r, g, b, a;
207
208     switch (filter_type) {
209     case PNG_FILTER_VALUE_NONE:
210         memcpy(dst, src, size);
211         break;
212     case PNG_FILTER_VALUE_SUB:
213         for (i = 0; i < bpp; i++)
214             dst[i] = src[i];
215         if (bpp == 4) {
216             p = *(int *)dst;
217             for (; i < size; i += bpp) {
218                 int s = *(int *)(src + i);
219                 p = ((s & 0x7f7f7f7f) + (p & 0x7f7f7f7f)) ^ ((s ^ p) & 0x80808080);
220                 *(int *)(dst + i) = p;
221             }
222         } else {
223 #define OP_SUB(x, s, l) x + s
224             UNROLL_FILTER(OP_SUB);
225         }
226         break;
227     case PNG_FILTER_VALUE_UP:
228         dsp->add_bytes_l2(dst, src, last, size);
229         break;
230     case PNG_FILTER_VALUE_AVG:
231         for (i = 0; i < bpp; i++) {
232             p      = (last[i] >> 1);
233             dst[i] = p + src[i];
234         }
235 #define OP_AVG(x, s, l) (((x + l) >> 1) + s) & 0xff
236         UNROLL_FILTER(OP_AVG);
237         break;
238     case PNG_FILTER_VALUE_PAETH:
239         for (i = 0; i < bpp; i++) {
240             p      = last[i];
241             dst[i] = p + src[i];
242         }
243         if (bpp > 2 && size > 4) {
244             /* would write off the end of the array if we let it process
245              * the last pixel with bpp=3 */
246             int w = bpp == 4 ? size : size - 3;
247             dsp->add_paeth_prediction(dst + i, src + i, last + i, w - i, bpp);
248             i = w;
249         }
250         ff_add_png_paeth_prediction(dst + i, src + i, last + i, size - i, bpp);
251         break;
252     }
253 }
254
255 static av_always_inline void convert_to_rgb32_loco(uint8_t *dst,
256                                                    const uint8_t *src,
257                                                    int width, int loco)
258 {
259     int j;
260     unsigned int r, g, b, a;
261
262     for (j = 0; j < width; j++) {
263         r = src[0];
264         g = src[1];
265         b = src[2];
266         a = src[3];
267         if (loco) {
268             r = (r + g) & 0xff;
269             b = (b + g) & 0xff;
270         }
271         *(uint32_t *) dst = (a << 24) | (r << 16) | (g << 8) | b;
272         dst += 4;
273         src += 4;
274     }
275 }
276
277 static void convert_to_rgb32(uint8_t *dst, const uint8_t *src,
278                              int width, int loco)
279 {
280     if (loco)
281         convert_to_rgb32_loco(dst, src, width, 1);
282     else
283         convert_to_rgb32_loco(dst, src, width, 0);
284 }
285
286 static void deloco_rgb24(uint8_t *dst, int size)
287 {
288     int i;
289     for (i = 0; i < size; i += 3) {
290         int g = dst[i + 1];
291         dst[i + 0] += g;
292         dst[i + 2] += g;
293     }
294 }
295
296 /* process exactly one decompressed row */
297 static void png_handle_row(PNGDecContext *s)
298 {
299     uint8_t *ptr, *last_row;
300     int got_line;
301
302     if (!s->interlace_type) {
303         ptr = s->image_buf + s->image_linesize * s->y;
304         /* need to swap bytes correctly for RGB_ALPHA */
305         if (s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
306             png_filter_row(&s->dsp, s->tmp_row, s->crow_buf[0], s->crow_buf + 1,
307                            s->last_row, s->row_size, s->bpp);
308             convert_to_rgb32(ptr, s->tmp_row, s->width,
309                              s->filter_type == PNG_FILTER_TYPE_LOCO);
310             FFSWAP(uint8_t *, s->last_row, s->tmp_row);
311         } else {
312             /* in normal case, we avoid one copy */
313             if (s->y == 0)
314                 last_row = s->last_row;
315             else
316                 last_row = ptr - s->image_linesize;
317
318             png_filter_row(&s->dsp, ptr, s->crow_buf[0], s->crow_buf + 1,
319                            last_row, s->row_size, s->bpp);
320         }
321         /* loco lags by 1 row so that it doesn't interfere with top prediction */
322         if (s->filter_type == PNG_FILTER_TYPE_LOCO &&
323             s->color_type == PNG_COLOR_TYPE_RGB && s->y > 0)
324             deloco_rgb24(ptr - s->image_linesize, s->row_size);
325         s->y++;
326         if (s->y == s->height) {
327             s->state |= PNG_ALLIMAGE;
328             if (s->filter_type == PNG_FILTER_TYPE_LOCO &&
329                 s->color_type == PNG_COLOR_TYPE_RGB)
330                 deloco_rgb24(ptr, s->row_size);
331         }
332     } else {
333         got_line = 0;
334         for (;;) {
335             ptr = s->image_buf + s->image_linesize * s->y;
336             if ((ff_png_pass_ymask[s->pass] << (s->y & 7)) & 0x80) {
337                 /* if we already read one row, it is time to stop to
338                  * wait for the next one */
339                 if (got_line)
340                     break;
341                 png_filter_row(&s->dsp, s->tmp_row, s->crow_buf[0], s->crow_buf + 1,
342                                s->last_row, s->pass_row_size, s->bpp);
343                 FFSWAP(uint8_t *, s->last_row, s->tmp_row);
344                 got_line = 1;
345             }
346             if ((png_pass_dsp_ymask[s->pass] << (s->y & 7)) & 0x80) {
347                 /* NOTE: RGB32 is handled directly in png_put_interlaced_row */
348                 png_put_interlaced_row(ptr, s->width, s->bits_per_pixel, s->pass,
349                                        s->color_type, s->last_row);
350             }
351             s->y++;
352             if (s->y == s->height) {
353                 for (;;) {
354                     if (s->pass == NB_PASSES - 1) {
355                         s->state |= PNG_ALLIMAGE;
356                         goto the_end;
357                     } else {
358                         s->pass++;
359                         s->y = 0;
360                         s->pass_row_size = ff_png_pass_row_size(s->pass,
361                                                                 s->bits_per_pixel,
362                                                                 s->width);
363                         s->crow_size = s->pass_row_size + 1;
364                         if (s->pass_row_size != 0)
365                             break;
366                         /* skip pass if empty row */
367                     }
368                 }
369             }
370         }
371 the_end:;
372     }
373 }
374
375 static int png_decode_idat(PNGDecContext *s, int length)
376 {
377     int ret;
378     s->zstream.avail_in = FFMIN(length, bytestream2_get_bytes_left(&s->gb));
379     s->zstream.next_in  = s->gb.buffer;
380     bytestream2_skip(&s->gb, length);
381
382     /* decode one line if possible */
383     while (s->zstream.avail_in > 0) {
384         ret = inflate(&s->zstream, Z_PARTIAL_FLUSH);
385         if (ret != Z_OK && ret != Z_STREAM_END) {
386             return -1;
387         }
388         if (s->zstream.avail_out == 0) {
389             if (!(s->state & PNG_ALLIMAGE)) {
390                 png_handle_row(s);
391             }
392             s->zstream.avail_out = s->crow_size;
393             s->zstream.next_out  = s->crow_buf;
394         }
395         if (ret == Z_STREAM_END && s->zstream.avail_in > 0) {
396             av_log(NULL, AV_LOG_WARNING,
397                    "%d undecompressed bytes left in buffer\n", s->zstream.avail_in);
398             return 0;
399         }
400     }
401     return 0;
402 }
403
404 static int decode_frame(AVCodecContext *avctx,
405                         void *data, int *got_frame,
406                         AVPacket *avpkt)
407 {
408     PNGDecContext *const s = avctx->priv_data;
409     const uint8_t *buf     = avpkt->data;
410     int buf_size           = avpkt->size;
411     AVFrame *p             = data;
412     uint8_t *crow_buf_base = NULL;
413     uint32_t tag, length;
414     int ret;
415
416     /* check signature */
417     if (buf_size < 8 ||
418         memcmp(buf, ff_pngsig, 8) != 0 &&
419         memcmp(buf, ff_mngsig, 8) != 0)
420         return -1;
421
422     bytestream2_init(&s->gb, buf + 8, buf_size - 8);
423     s->y = s->state = 0;
424
425     /* init the zlib */
426     s->zstream.zalloc = ff_png_zalloc;
427     s->zstream.zfree  = ff_png_zfree;
428     s->zstream.opaque = NULL;
429     ret = inflateInit(&s->zstream);
430     if (ret != Z_OK)
431         return -1;
432     for (;;) {
433         if (bytestream2_get_bytes_left(&s->gb) <= 0)
434             goto fail;
435         length = bytestream2_get_be32(&s->gb);
436         if (length > 0x7fffffff)
437             goto fail;
438         tag = bytestream2_get_le32(&s->gb);
439         av_dlog(avctx, "png: tag=%c%c%c%c length=%u\n",
440                 (tag & 0xff),
441                 ((tag >> 8) & 0xff),
442                 ((tag >> 16) & 0xff),
443                 ((tag >> 24) & 0xff), length);
444         switch (tag) {
445         case MKTAG('I', 'H', 'D', 'R'):
446             if (length != 13)
447                 goto fail;
448             s->width  = bytestream2_get_be32(&s->gb);
449             s->height = bytestream2_get_be32(&s->gb);
450             if (av_image_check_size(s->width, s->height, 0, avctx)) {
451                 s->width = s->height = 0;
452                 goto fail;
453             }
454             s->bit_depth        = bytestream2_get_byte(&s->gb);
455             s->color_type       = bytestream2_get_byte(&s->gb);
456             s->compression_type = bytestream2_get_byte(&s->gb);
457             s->filter_type      = bytestream2_get_byte(&s->gb);
458             s->interlace_type   = bytestream2_get_byte(&s->gb);
459             bytestream2_skip(&s->gb, 4); /* crc */
460             s->state |= PNG_IHDR;
461             av_dlog(avctx, "width=%d height=%d depth=%d color_type=%d "
462                            "compression_type=%d filter_type=%d interlace_type=%d\n",
463                     s->width, s->height, s->bit_depth, s->color_type,
464                     s->compression_type, s->filter_type, s->interlace_type);
465             break;
466         case MKTAG('I', 'D', 'A', 'T'):
467             if (!(s->state & PNG_IHDR))
468                 goto fail;
469             if (!(s->state & PNG_IDAT)) {
470                 /* init image info */
471                 avctx->width  = s->width;
472                 avctx->height = s->height;
473
474                 s->channels       = ff_png_get_nb_channels(s->color_type);
475                 s->bits_per_pixel = s->bit_depth * s->channels;
476                 s->bpp            = (s->bits_per_pixel + 7) >> 3;
477                 s->row_size       = (avctx->width * s->bits_per_pixel + 7) >> 3;
478
479                 if (s->bit_depth == 8 &&
480                     s->color_type == PNG_COLOR_TYPE_RGB) {
481                     avctx->pix_fmt = AV_PIX_FMT_RGB24;
482                 } else if (s->bit_depth == 8 &&
483                            s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
484                     avctx->pix_fmt = AV_PIX_FMT_RGB32;
485                 } else if (s->bit_depth == 8 &&
486                            s->color_type == PNG_COLOR_TYPE_GRAY) {
487                     avctx->pix_fmt = AV_PIX_FMT_GRAY8;
488                 } else if (s->bit_depth == 16 &&
489                            s->color_type == PNG_COLOR_TYPE_GRAY) {
490                     avctx->pix_fmt = AV_PIX_FMT_GRAY16BE;
491                 } else if (s->bit_depth == 16 &&
492                            s->color_type == PNG_COLOR_TYPE_RGB) {
493                     avctx->pix_fmt = AV_PIX_FMT_RGB48BE;
494                 } else if (s->bit_depth == 1 &&
495                            s->color_type == PNG_COLOR_TYPE_GRAY) {
496                     avctx->pix_fmt = AV_PIX_FMT_MONOBLACK;
497                 } else if (s->bit_depth == 8 &&
498                            s->color_type == PNG_COLOR_TYPE_PALETTE) {
499                     avctx->pix_fmt = AV_PIX_FMT_PAL8;
500                 } else if (s->bit_depth == 8 &&
501                            s->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
502                     avctx->pix_fmt = AV_PIX_FMT_YA8;
503                 } else {
504                     goto fail;
505                 }
506
507                 if (ff_get_buffer(avctx, p, AV_GET_BUFFER_FLAG_REF) < 0) {
508                     av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
509                     goto fail;
510                 }
511                 p->pict_type        = AV_PICTURE_TYPE_I;
512                 p->key_frame        = 1;
513                 p->interlaced_frame = !!s->interlace_type;
514
515                 /* compute the compressed row size */
516                 if (!s->interlace_type) {
517                     s->crow_size = s->row_size + 1;
518                 } else {
519                     s->pass          = 0;
520                     s->pass_row_size = ff_png_pass_row_size(s->pass,
521                                                             s->bits_per_pixel,
522                                                             s->width);
523                     s->crow_size = s->pass_row_size + 1;
524                 }
525                 av_dlog(avctx, "row_size=%d crow_size =%d\n",
526                         s->row_size, s->crow_size);
527                 s->image_buf      = p->data[0];
528                 s->image_linesize = p->linesize[0];
529                 /* copy the palette if needed */
530                 if (s->color_type == PNG_COLOR_TYPE_PALETTE)
531                     memcpy(p->data[1], s->palette, 256 * sizeof(uint32_t));
532                 /* empty row is used if differencing to the first row */
533                 s->last_row = av_mallocz(s->row_size);
534                 if (!s->last_row)
535                     goto fail;
536                 if (s->interlace_type ||
537                     s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
538                     s->tmp_row = av_malloc(s->row_size);
539                     if (!s->tmp_row)
540                         goto fail;
541                 }
542                 /* compressed row */
543                 crow_buf_base = av_malloc(s->row_size + 16);
544                 if (!crow_buf_base)
545                     goto fail;
546
547                 /* we want crow_buf+1 to be 16-byte aligned */
548                 s->crow_buf          = crow_buf_base + 15;
549                 s->zstream.avail_out = s->crow_size;
550                 s->zstream.next_out  = s->crow_buf;
551             }
552             s->state |= PNG_IDAT;
553             if (png_decode_idat(s, length) < 0)
554                 goto fail;
555             bytestream2_skip(&s->gb, 4); /* crc */
556             break;
557         case MKTAG('P', 'L', 'T', 'E'):
558         {
559             int n, i, r, g, b;
560
561             if ((length % 3) != 0 || length > 256 * 3)
562                 goto skip_tag;
563             /* read the palette */
564             n = length / 3;
565             for (i = 0; i < n; i++) {
566                 r = bytestream2_get_byte(&s->gb);
567                 g = bytestream2_get_byte(&s->gb);
568                 b = bytestream2_get_byte(&s->gb);
569                 s->palette[i] = (0xff << 24) | (r << 16) | (g << 8) | b;
570             }
571             for (; i < 256; i++)
572                 s->palette[i] = (0xff << 24);
573             s->state |= PNG_PLTE;
574             bytestream2_skip(&s->gb, 4);     /* crc */
575         }
576         break;
577         case MKTAG('t', 'R', 'N', 'S'):
578         {
579             int v, i;
580
581             /* read the transparency. XXX: Only palette mode supported */
582             if (s->color_type != PNG_COLOR_TYPE_PALETTE ||
583                 length > 256 ||
584                 !(s->state & PNG_PLTE))
585                 goto skip_tag;
586             for (i = 0; i < length; i++) {
587                 v = bytestream2_get_byte(&s->gb);
588                 s->palette[i] = (s->palette[i] & 0x00ffffff) | (v << 24);
589             }
590             bytestream2_skip(&s->gb, 4);     /* crc */
591         }
592         break;
593         case MKTAG('I', 'E', 'N', 'D'):
594             if (!(s->state & PNG_ALLIMAGE))
595                 goto fail;
596             bytestream2_skip(&s->gb, 4); /* crc */
597             goto exit_loop;
598         default:
599             /* skip tag */
600 skip_tag:
601             bytestream2_skip(&s->gb, length + 4);
602             break;
603         }
604     }
605 exit_loop:
606     /* handle p-frames only if a predecessor frame is available */
607     if (s->prev->data[0]) {
608         if (!(avpkt->flags & AV_PKT_FLAG_KEY)) {
609             int i, j;
610             uint8_t *pd      = p->data[0];
611             uint8_t *pd_last = s->prev->data[0];
612
613             for (j = 0; j < s->height; j++) {
614                 for (i = 0; i < s->width * s->bpp; i++)
615                     pd[i] += pd_last[i];
616                 pd      += s->image_linesize;
617                 pd_last += s->image_linesize;
618             }
619         }
620     }
621
622     av_frame_unref(s->prev);
623     if ((ret = av_frame_ref(s->prev, p)) < 0)
624         goto fail;
625
626     *got_frame = 1;
627
628     ret = bytestream2_tell(&s->gb);
629 the_end:
630     inflateEnd(&s->zstream);
631     av_free(crow_buf_base);
632     s->crow_buf = NULL;
633     av_freep(&s->last_row);
634     av_freep(&s->tmp_row);
635     return ret;
636 fail:
637     ret = -1;
638     goto the_end;
639 }
640
641 static av_cold int png_dec_init(AVCodecContext *avctx)
642 {
643     PNGDecContext *s = avctx->priv_data;
644
645     s->prev = av_frame_alloc();
646     if (!s->prev)
647         return AVERROR(ENOMEM);
648
649     ff_pngdsp_init(&s->dsp);
650
651     return 0;
652 }
653
654 static av_cold int png_dec_end(AVCodecContext *avctx)
655 {
656     PNGDecContext *s = avctx->priv_data;
657
658     av_frame_free(&s->prev);
659
660     return 0;
661 }
662
663 AVCodec ff_png_decoder = {
664     .name           = "png",
665     .long_name      = NULL_IF_CONFIG_SMALL("PNG (Portable Network Graphics) image"),
666     .type           = AVMEDIA_TYPE_VIDEO,
667     .id             = AV_CODEC_ID_PNG,
668     .priv_data_size = sizeof(PNGDecContext),
669     .init           = png_dec_init,
670     .close          = png_dec_end,
671     .decode         = decode_frame,
672     .capabilities   = CODEC_CAP_DR1 /*| CODEC_CAP_DRAW_HORIZ_BAND*/,
673 };