png: Use libavutil's crc functions instead of zlib's
[ffmpeg.git] / libavcodec / pngenc.c
1 /*
2  * PNG image format
3  * Copyright (c) 2003 Fabrice Bellard
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg 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  * FFmpeg 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 FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21
22 #include "avcodec.h"
23 #include "internal.h"
24 #include "bytestream.h"
25 #include "huffyuvencdsp.h"
26 #include "png.h"
27 #include "apng.h"
28
29 #include "libavutil/avassert.h"
30 #include "libavutil/crc.h"
31 #include "libavutil/libm.h"
32 #include "libavutil/opt.h"
33 #include "libavutil/color_utils.h"
34
35 #include <zlib.h>
36
37 #define IOBUF_SIZE 4096
38
39 typedef struct PNGEncContext {
40     AVClass *class;
41     HuffYUVEncDSPContext hdsp;
42
43     uint8_t *bytestream;
44     uint8_t *bytestream_start;
45     uint8_t *bytestream_end;
46
47     int filter_type;
48
49     z_stream zstream;
50     uint8_t buf[IOBUF_SIZE];
51     int dpi;                     ///< Physical pixel density, in dots per inch, if set
52     int dpm;                     ///< Physical pixel density, in dots per meter, if set
53
54     int is_progressive;
55     int bit_depth;
56     int color_type;
57     int bits_per_pixel;
58
59     // APNG
60     uint32_t palette_checksum;   // Used to ensure a single unique palette
61     uint32_t sequence_number;
62 } PNGEncContext;
63
64 static void png_get_interlaced_row(uint8_t *dst, int row_size,
65                                    int bits_per_pixel, int pass,
66                                    const uint8_t *src, int width)
67 {
68     int x, mask, dst_x, j, b, bpp;
69     uint8_t *d;
70     const uint8_t *s;
71     static const int masks[] = {0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff};
72
73     mask = masks[pass];
74     switch (bits_per_pixel) {
75     case 1:
76         memset(dst, 0, row_size);
77         dst_x = 0;
78         for (x = 0; x < width; x++) {
79             j = (x & 7);
80             if ((mask << j) & 0x80) {
81                 b = (src[x >> 3] >> (7 - j)) & 1;
82                 dst[dst_x >> 3] |= b << (7 - (dst_x & 7));
83                 dst_x++;
84             }
85         }
86         break;
87     default:
88         bpp = bits_per_pixel >> 3;
89         d = dst;
90         s = src;
91         for (x = 0; x < width; x++) {
92             j = x & 7;
93             if ((mask << j) & 0x80) {
94                 memcpy(d, s, bpp);
95                 d += bpp;
96             }
97             s += bpp;
98         }
99         break;
100     }
101 }
102
103 static void sub_png_paeth_prediction(uint8_t *dst, uint8_t *src, uint8_t *top,
104                                      int w, int bpp)
105 {
106     int i;
107     for (i = 0; i < w; i++) {
108         int a, b, c, p, pa, pb, pc;
109
110         a = src[i - bpp];
111         b = top[i];
112         c = top[i - bpp];
113
114         p  = b - c;
115         pc = a - c;
116
117         pa = abs(p);
118         pb = abs(pc);
119         pc = abs(p + pc);
120
121         if (pa <= pb && pa <= pc)
122             p = a;
123         else if (pb <= pc)
124             p = b;
125         else
126             p = c;
127         dst[i] = src[i] - p;
128     }
129 }
130
131 static void sub_left_prediction(PNGEncContext *c, uint8_t *dst, const uint8_t *src, int bpp, int size)
132 {
133     const uint8_t *src1 = src + bpp;
134     const uint8_t *src2 = src;
135     int x, unaligned_w;
136
137     memcpy(dst, src, bpp);
138     dst += bpp;
139     size -= bpp;
140     unaligned_w = FFMIN(32 - bpp, size);
141     for (x = 0; x < unaligned_w; x++)
142         *dst++ = *src1++ - *src2++;
143     size -= unaligned_w;
144     c->hdsp.diff_bytes(dst, src1, src2, size);
145 }
146
147 static void png_filter_row(PNGEncContext *c, uint8_t *dst, int filter_type,
148                            uint8_t *src, uint8_t *top, int size, int bpp)
149 {
150     int i;
151
152     switch (filter_type) {
153     case PNG_FILTER_VALUE_NONE:
154         memcpy(dst, src, size);
155         break;
156     case PNG_FILTER_VALUE_SUB:
157         sub_left_prediction(c, dst, src, bpp, size);
158         break;
159     case PNG_FILTER_VALUE_UP:
160         c->hdsp.diff_bytes(dst, src, top, size);
161         break;
162     case PNG_FILTER_VALUE_AVG:
163         for (i = 0; i < bpp; i++)
164             dst[i] = src[i] - (top[i] >> 1);
165         for (; i < size; i++)
166             dst[i] = src[i] - ((src[i - bpp] + top[i]) >> 1);
167         break;
168     case PNG_FILTER_VALUE_PAETH:
169         for (i = 0; i < bpp; i++)
170             dst[i] = src[i] - top[i];
171         sub_png_paeth_prediction(dst + i, src + i, top + i, size - i, bpp);
172         break;
173     }
174 }
175
176 static uint8_t *png_choose_filter(PNGEncContext *s, uint8_t *dst,
177                                   uint8_t *src, uint8_t *top, int size, int bpp)
178 {
179     int pred = s->filter_type;
180     av_assert0(bpp || !pred);
181     if (!top && pred)
182         pred = PNG_FILTER_VALUE_SUB;
183     if (pred == PNG_FILTER_VALUE_MIXED) {
184         int i;
185         int cost, bcost = INT_MAX;
186         uint8_t *buf1 = dst, *buf2 = dst + size + 16;
187         for (pred = 0; pred < 5; pred++) {
188             png_filter_row(s, buf1 + 1, pred, src, top, size, bpp);
189             buf1[0] = pred;
190             cost = 0;
191             for (i = 0; i <= size; i++)
192                 cost += abs((int8_t) buf1[i]);
193             if (cost < bcost) {
194                 bcost = cost;
195                 FFSWAP(uint8_t *, buf1, buf2);
196             }
197         }
198         return buf2;
199     } else {
200         png_filter_row(s, dst + 1, pred, src, top, size, bpp);
201         dst[0] = pred;
202         return dst;
203     }
204 }
205
206 static void png_write_chunk(uint8_t **f, uint32_t tag,
207                             const uint8_t *buf, int length)
208 {
209     const AVCRC *crc_table = av_crc_get_table(AV_CRC_32_IEEE_LE);
210     uint32_t crc = ~0U;
211     uint8_t tagbuf[4];
212
213     bytestream_put_be32(f, length);
214     AV_WL32(tagbuf, tag);
215     crc = av_crc(crc_table, crc, tagbuf, 4);
216     bytestream_put_be32(f, av_bswap32(tag));
217     if (length > 0) {
218         crc = av_crc(crc_table, crc, buf, length);
219         memcpy(*f, buf, length);
220         *f += length;
221     }
222     bytestream_put_be32(f, ~crc);
223 }
224
225 static void png_write_image_data(AVCodecContext *avctx,
226                                  const uint8_t *buf, int length)
227 {
228     PNGEncContext *s = avctx->priv_data;
229     const AVCRC *crc_table = av_crc_get_table(AV_CRC_32_IEEE_LE);
230     uint32_t crc = ~0U;
231
232     if (avctx->codec_id == AV_CODEC_ID_PNG || avctx->frame_number == 0)
233         return png_write_chunk(&s->bytestream, MKTAG('I', 'D', 'A', 'T'), buf, length);
234
235     bytestream_put_be32(&s->bytestream, length + 4);
236
237     bytestream_put_be32(&s->bytestream, MKBETAG('f', 'd', 'A', 'T'));
238     bytestream_put_be32(&s->bytestream, s->sequence_number);
239     crc = av_crc(crc_table, crc, s->bytestream - 8, 8);
240
241     crc = av_crc(crc_table, crc, buf, length);
242     memcpy(s->bytestream, buf, length);
243     s->bytestream += length;
244
245     bytestream_put_be32(&s->bytestream, ~crc);
246
247     ++s->sequence_number;
248 }
249
250 /* XXX: do filtering */
251 static int png_write_row(AVCodecContext *avctx, const uint8_t *data, int size)
252 {
253     PNGEncContext *s = avctx->priv_data;
254     int ret;
255
256     s->zstream.avail_in = size;
257     s->zstream.next_in  = data;
258     while (s->zstream.avail_in > 0) {
259         ret = deflate(&s->zstream, Z_NO_FLUSH);
260         if (ret != Z_OK)
261             return -1;
262         if (s->zstream.avail_out == 0) {
263             if (s->bytestream_end - s->bytestream > IOBUF_SIZE + 100)
264                 png_write_image_data(avctx, s->buf, IOBUF_SIZE);
265             s->zstream.avail_out = IOBUF_SIZE;
266             s->zstream.next_out  = s->buf;
267         }
268     }
269     return 0;
270 }
271
272 #define AV_WB32_PNG(buf, n) AV_WB32(buf, lrint((n) * 100000))
273 static int png_get_chrm(enum AVColorPrimaries prim,  uint8_t *buf)
274 {
275     double rx, ry, gx, gy, bx, by, wx = 0.3127, wy = 0.3290;
276     switch (prim) {
277         case AVCOL_PRI_BT709:
278             rx = 0.640; ry = 0.330;
279             gx = 0.300; gy = 0.600;
280             bx = 0.150; by = 0.060;
281             break;
282         case AVCOL_PRI_BT470M:
283             rx = 0.670; ry = 0.330;
284             gx = 0.210; gy = 0.710;
285             bx = 0.140; by = 0.080;
286             wx = 0.310; wy = 0.316;
287             break;
288         case AVCOL_PRI_BT470BG:
289             rx = 0.640; ry = 0.330;
290             gx = 0.290; gy = 0.600;
291             bx = 0.150; by = 0.060;
292             break;
293         case AVCOL_PRI_SMPTE170M:
294         case AVCOL_PRI_SMPTE240M:
295             rx = 0.630; ry = 0.340;
296             gx = 0.310; gy = 0.595;
297             bx = 0.155; by = 0.070;
298             break;
299         case AVCOL_PRI_BT2020:
300             rx = 0.708; ry = 0.292;
301             gx = 0.170; gy = 0.797;
302             bx = 0.131; by = 0.046;
303             break;
304         default:
305             return 0;
306     }
307
308     AV_WB32_PNG(buf     , wx); AV_WB32_PNG(buf + 4 , wy);
309     AV_WB32_PNG(buf + 8 , rx); AV_WB32_PNG(buf + 12, ry);
310     AV_WB32_PNG(buf + 16, gx); AV_WB32_PNG(buf + 20, gy);
311     AV_WB32_PNG(buf + 24, bx); AV_WB32_PNG(buf + 28, by);
312     return 1;
313 }
314
315 static int png_get_gama(enum AVColorTransferCharacteristic trc, uint8_t *buf)
316 {
317     double gamma = avpriv_get_gamma_from_trc(trc);
318     if (gamma <= 1e-6)
319         return 0;
320
321     AV_WB32_PNG(buf, 1.0 / gamma);
322     return 1;
323 }
324
325 static int encode_headers(AVCodecContext *avctx, const AVFrame *pict)
326 {
327     PNGEncContext *s = avctx->priv_data;
328
329     /* write png header */
330     AV_WB32(s->buf, avctx->width);
331     AV_WB32(s->buf + 4, avctx->height);
332     s->buf[8]  = s->bit_depth;
333     s->buf[9]  = s->color_type;
334     s->buf[10] = 0; /* compression type */
335     s->buf[11] = 0; /* filter type */
336     s->buf[12] = s->is_progressive; /* interlace type */
337     png_write_chunk(&s->bytestream, MKTAG('I', 'H', 'D', 'R'), s->buf, 13);
338
339     /* write physical information */
340     if (s->dpm) {
341       AV_WB32(s->buf, s->dpm);
342       AV_WB32(s->buf + 4, s->dpm);
343       s->buf[8] = 1; /* unit specifier is meter */
344     } else {
345       AV_WB32(s->buf, avctx->sample_aspect_ratio.num);
346       AV_WB32(s->buf + 4, avctx->sample_aspect_ratio.den);
347       s->buf[8] = 0; /* unit specifier is unknown */
348     }
349     png_write_chunk(&s->bytestream, MKTAG('p', 'H', 'Y', 's'), s->buf, 9);
350
351     /* write colorspace information */
352     if (pict->color_primaries == AVCOL_PRI_BT709 &&
353         pict->color_trc == AVCOL_TRC_IEC61966_2_1) {
354         s->buf[0] = 1; /* rendering intent, relative colorimetric by default */
355         png_write_chunk(&s->bytestream, MKTAG('s', 'R', 'G', 'B'), s->buf, 1);
356     }
357
358     if (png_get_chrm(pict->color_primaries, s->buf))
359         png_write_chunk(&s->bytestream, MKTAG('c', 'H', 'R', 'M'), s->buf, 32);
360     if (png_get_gama(pict->color_trc, s->buf))
361         png_write_chunk(&s->bytestream, MKTAG('g', 'A', 'M', 'A'), s->buf, 4);
362
363     /* put the palette if needed */
364     if (s->color_type == PNG_COLOR_TYPE_PALETTE) {
365         int has_alpha, alpha, i;
366         unsigned int v;
367         uint32_t *palette;
368         uint8_t *ptr, *alpha_ptr;
369
370         palette   = (uint32_t *)pict->data[1];
371         ptr       = s->buf;
372         alpha_ptr = s->buf + 256 * 3;
373         has_alpha = 0;
374         for (i = 0; i < 256; i++) {
375             v     = palette[i];
376             alpha = v >> 24;
377             if (alpha != 0xff)
378                 has_alpha = 1;
379             *alpha_ptr++ = alpha;
380             bytestream_put_be24(&ptr, v);
381         }
382         png_write_chunk(&s->bytestream,
383                         MKTAG('P', 'L', 'T', 'E'), s->buf, 256 * 3);
384         if (has_alpha) {
385             png_write_chunk(&s->bytestream,
386                             MKTAG('t', 'R', 'N', 'S'), s->buf + 256 * 3, 256);
387         }
388     }
389
390     return 0;
391 }
392
393 static int encode_frame(AVCodecContext *avctx, const AVFrame *pict)
394 {
395     PNGEncContext *s       = avctx->priv_data;
396     const AVFrame *const p = pict;
397     int y, len, ret;
398     int row_size, pass_row_size;
399     uint8_t *ptr, *top, *crow_buf, *crow;
400     uint8_t *crow_base       = NULL;
401     uint8_t *progressive_buf = NULL;
402     uint8_t *top_buf         = NULL;
403
404     row_size = (avctx->width * s->bits_per_pixel + 7) >> 3;
405
406     crow_base = av_malloc((row_size + 32) << (s->filter_type == PNG_FILTER_VALUE_MIXED));
407     if (!crow_base) {
408         ret = AVERROR(ENOMEM);
409         goto the_end;
410     }
411     // pixel data should be aligned, but there's a control byte before it
412     crow_buf = crow_base + 15;
413     if (s->is_progressive) {
414         progressive_buf = av_malloc(row_size + 1);
415         top_buf = av_malloc(row_size + 1);
416         if (!progressive_buf || !top_buf) {
417             ret = AVERROR(ENOMEM);
418             goto the_end;
419         }
420     }
421
422     /* put each row */
423     s->zstream.avail_out = IOBUF_SIZE;
424     s->zstream.next_out  = s->buf;
425     if (s->is_progressive) {
426         int pass;
427
428         for (pass = 0; pass < NB_PASSES; pass++) {
429             /* NOTE: a pass is completely omitted if no pixels would be
430              * output */
431             pass_row_size = ff_png_pass_row_size(pass, s->bits_per_pixel, avctx->width);
432             if (pass_row_size > 0) {
433                 top = NULL;
434                 for (y = 0; y < avctx->height; y++)
435                     if ((ff_png_pass_ymask[pass] << (y & 7)) & 0x80) {
436                         ptr = p->data[0] + y * p->linesize[0];
437                         FFSWAP(uint8_t *, progressive_buf, top_buf);
438                         png_get_interlaced_row(progressive_buf, pass_row_size,
439                                                s->bits_per_pixel, pass,
440                                                ptr, avctx->width);
441                         crow = png_choose_filter(s, crow_buf, progressive_buf,
442                                                  top, pass_row_size, s->bits_per_pixel >> 3);
443                         png_write_row(avctx, crow, pass_row_size + 1);
444                         top = progressive_buf;
445                     }
446             }
447         }
448     } else {
449         top = NULL;
450         for (y = 0; y < avctx->height; y++) {
451             ptr = p->data[0] + y * p->linesize[0];
452             crow = png_choose_filter(s, crow_buf, ptr, top,
453                                      row_size, s->bits_per_pixel >> 3);
454             png_write_row(avctx, crow, row_size + 1);
455             top = ptr;
456         }
457     }
458     /* compress last bytes */
459     for (;;) {
460         ret = deflate(&s->zstream, Z_FINISH);
461         if (ret == Z_OK || ret == Z_STREAM_END) {
462             len = IOBUF_SIZE - s->zstream.avail_out;
463             if (len > 0 && s->bytestream_end - s->bytestream > len + 100) {
464                 png_write_image_data(avctx, s->buf, len);
465             }
466             s->zstream.avail_out = IOBUF_SIZE;
467             s->zstream.next_out  = s->buf;
468             if (ret == Z_STREAM_END)
469                 break;
470         } else {
471             ret = -1;
472             goto the_end;
473         }
474     }
475
476     ret = 0;
477
478 the_end:
479     av_freep(&crow_base);
480     av_freep(&progressive_buf);
481     av_freep(&top_buf);
482     deflateReset(&s->zstream);
483     return ret;
484 }
485
486 static int encode_png(AVCodecContext *avctx, AVPacket *pkt,
487                       const AVFrame *pict, int *got_packet)
488 {
489     PNGEncContext *s = avctx->priv_data;
490     int ret;
491     int enc_row_size;
492     size_t max_packet_size;
493
494     enc_row_size    = deflateBound(&s->zstream, (avctx->width * s->bits_per_pixel + 7) >> 3);
495     max_packet_size =
496         FF_MIN_BUFFER_SIZE + // headers
497         avctx->height * (
498             enc_row_size +
499             12 * (((int64_t)enc_row_size + IOBUF_SIZE - 1) / IOBUF_SIZE) // IDAT * ceil(enc_row_size / IOBUF_SIZE)
500         );
501     if (max_packet_size > INT_MAX)
502         return AVERROR(ENOMEM);
503     ret = ff_alloc_packet2(avctx, pkt, max_packet_size);
504     if (ret < 0)
505         return ret;
506
507     s->bytestream_start =
508     s->bytestream       = pkt->data;
509     s->bytestream_end   = pkt->data + pkt->size;
510
511     AV_WB64(s->bytestream, PNGSIG);
512     s->bytestream += 8;
513
514     ret = encode_headers(avctx, pict);
515     if (ret < 0)
516         return ret;
517
518     ret = encode_frame(avctx, pict);
519     if (ret < 0)
520         return ret;
521
522     png_write_chunk(&s->bytestream, MKTAG('I', 'E', 'N', 'D'), NULL, 0);
523
524     pkt->size = s->bytestream - s->bytestream_start;
525     pkt->flags |= AV_PKT_FLAG_KEY;
526     *got_packet = 1;
527
528     return 0;
529 }
530
531 static int encode_apng(AVCodecContext *avctx, AVPacket *pkt,
532                        const AVFrame *pict, int *got_packet)
533 {
534     PNGEncContext *s = avctx->priv_data;
535     int ret;
536     int enc_row_size;
537     size_t max_packet_size;
538     uint8_t buf[26];
539
540     if (avctx->codec_id == AV_CODEC_ID_APNG && s->color_type == PNG_COLOR_TYPE_PALETTE) {
541         uint32_t checksum = ~av_crc(av_crc_get_table(AV_CRC_32_IEEE_LE), ~0U, pict->data[1], 256 * sizeof(uint32_t));
542
543         if (avctx->frame_number == 0) {
544             s->palette_checksum = checksum;
545         } else if (checksum != s->palette_checksum) {
546             av_log(avctx, AV_LOG_ERROR,
547                    "Input contains more than one unique palette. APNG does not support multiple palettes.\n");
548             return -1;
549         }
550     }
551
552     enc_row_size    = deflateBound(&s->zstream, (avctx->width * s->bits_per_pixel + 7) >> 3);
553     max_packet_size =
554         FF_MIN_BUFFER_SIZE + // headers
555         avctx->height * (
556             enc_row_size +
557             (4 + 12) * (((int64_t)enc_row_size + IOBUF_SIZE - 1) / IOBUF_SIZE) // fdAT * ceil(enc_row_size / IOBUF_SIZE)
558         );
559     if (max_packet_size > INT_MAX)
560         return AVERROR(ENOMEM);
561     ret = ff_alloc_packet2(avctx, pkt, max_packet_size);
562     if (ret < 0)
563         return ret;
564
565     s->bytestream_start =
566     s->bytestream       = pkt->data;
567     s->bytestream_end   = pkt->data + pkt->size;
568
569     if (avctx->frame_number == 0) {
570         ret = encode_headers(avctx, pict);
571         if (ret < 0)
572             return ret;
573
574         avctx->extradata = av_malloc(s->bytestream - s->bytestream_start);
575         if (!avctx->extradata)
576             return AVERROR(ENOMEM);
577         avctx->extradata_size = s->bytestream - s->bytestream_start;
578         memcpy(avctx->extradata, s->bytestream_start, s->bytestream - s->bytestream_start);
579
580         s->bytestream = s->bytestream_start;
581     }
582
583     AV_WB32(buf, s->sequence_number);
584     AV_WB32(buf + 4, avctx->width);
585     AV_WB32(buf + 8, avctx->height);
586     AV_WB32(buf + 12, 0); // x offset
587     AV_WB32(buf + 16, 0); // y offset
588     AV_WB16(buf + 20, 0); // delay numerator (filled in during muxing)
589     AV_WB16(buf + 22, 0); // delay denominator
590     buf[24] = APNG_DISPOSE_OP_BACKGROUND;
591     buf[25] = APNG_BLEND_OP_SOURCE;
592     png_write_chunk(&s->bytestream, MKTAG('f', 'c', 'T', 'L'), buf, 26);
593     ++s->sequence_number;
594
595     ret = encode_frame(avctx, pict);
596     if (ret < 0)
597         return ret;
598
599     pkt->size = s->bytestream - s->bytestream_start;
600     pkt->flags |= AV_PKT_FLAG_KEY;
601     *got_packet = 1;
602
603     return 0;
604 }
605
606 static av_cold int png_enc_init(AVCodecContext *avctx)
607 {
608     PNGEncContext *s = avctx->priv_data;
609     int compression_level;
610
611     switch (avctx->pix_fmt) {
612     case AV_PIX_FMT_RGBA:
613         avctx->bits_per_coded_sample = 32;
614         break;
615     case AV_PIX_FMT_RGB24:
616         avctx->bits_per_coded_sample = 24;
617         break;
618     case AV_PIX_FMT_GRAY8:
619         avctx->bits_per_coded_sample = 0x28;
620         break;
621     case AV_PIX_FMT_MONOBLACK:
622         avctx->bits_per_coded_sample = 1;
623         break;
624     case AV_PIX_FMT_PAL8:
625         avctx->bits_per_coded_sample = 8;
626     }
627
628     avctx->coded_frame = av_frame_alloc();
629     if (!avctx->coded_frame)
630         return AVERROR(ENOMEM);
631
632     avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
633     avctx->coded_frame->key_frame = 1;
634
635     ff_huffyuvencdsp_init(&s->hdsp);
636
637     s->filter_type = av_clip(avctx->prediction_method,
638                              PNG_FILTER_VALUE_NONE,
639                              PNG_FILTER_VALUE_MIXED);
640     if (avctx->pix_fmt == AV_PIX_FMT_MONOBLACK)
641         s->filter_type = PNG_FILTER_VALUE_NONE;
642
643     if (s->dpi && s->dpm) {
644       av_log(avctx, AV_LOG_ERROR, "Only one of 'dpi' or 'dpm' options should be set\n");
645       return AVERROR(EINVAL);
646     } else if (s->dpi) {
647       s->dpm = s->dpi * 10000 / 254;
648     }
649
650     s->is_progressive = !!(avctx->flags & CODEC_FLAG_INTERLACED_DCT);
651     switch (avctx->pix_fmt) {
652     case AV_PIX_FMT_RGBA64BE:
653         s->bit_depth = 16;
654         s->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
655         break;
656     case AV_PIX_FMT_RGB48BE:
657         s->bit_depth = 16;
658         s->color_type = PNG_COLOR_TYPE_RGB;
659         break;
660     case AV_PIX_FMT_RGBA:
661         s->bit_depth  = 8;
662         s->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
663         break;
664     case AV_PIX_FMT_RGB24:
665         s->bit_depth  = 8;
666         s->color_type = PNG_COLOR_TYPE_RGB;
667         break;
668     case AV_PIX_FMT_GRAY16BE:
669         s->bit_depth  = 16;
670         s->color_type = PNG_COLOR_TYPE_GRAY;
671         break;
672     case AV_PIX_FMT_GRAY8:
673         s->bit_depth  = 8;
674         s->color_type = PNG_COLOR_TYPE_GRAY;
675         break;
676     case AV_PIX_FMT_GRAY8A:
677         s->bit_depth = 8;
678         s->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
679         break;
680     case AV_PIX_FMT_YA16BE:
681         s->bit_depth = 16;
682         s->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
683         break;
684     case AV_PIX_FMT_MONOBLACK:
685         s->bit_depth  = 1;
686         s->color_type = PNG_COLOR_TYPE_GRAY;
687         break;
688     case AV_PIX_FMT_PAL8:
689         s->bit_depth  = 8;
690         s->color_type = PNG_COLOR_TYPE_PALETTE;
691         break;
692     default:
693         return -1;
694     }
695     s->bits_per_pixel = ff_png_get_nb_channels(s->color_type) * s->bit_depth;
696
697     s->zstream.zalloc = ff_png_zalloc;
698     s->zstream.zfree  = ff_png_zfree;
699     s->zstream.opaque = NULL;
700     compression_level = avctx->compression_level == FF_COMPRESSION_DEFAULT
701                       ? Z_DEFAULT_COMPRESSION
702                       : av_clip(avctx->compression_level, 0, 9);
703     if (deflateInit2(&s->zstream, compression_level, Z_DEFLATED, 15, 8, Z_DEFAULT_STRATEGY) != Z_OK)
704         return -1;
705
706     return 0;
707 }
708
709 static av_cold int png_enc_close(AVCodecContext *avctx)
710 {
711     PNGEncContext *s = avctx->priv_data;
712
713     deflateEnd(&s->zstream);
714     av_frame_free(&avctx->coded_frame);
715     return 0;
716 }
717
718 #define OFFSET(x) offsetof(PNGEncContext, x)
719 #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
720 static const AVOption options[] = {
721     {"dpi", "Set image resolution (in dots per inch)",  OFFSET(dpi), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 0x10000, VE},
722     {"dpm", "Set image resolution (in dots per meter)", OFFSET(dpm), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 0x10000, VE},
723     { NULL }
724 };
725
726 static const AVClass pngenc_class = {
727     .class_name = "PNG encoder",
728     .item_name  = av_default_item_name,
729     .option     = options,
730     .version    = LIBAVUTIL_VERSION_INT,
731 };
732
733 static const AVClass apngenc_class = {
734     .class_name = "APNG encoder",
735     .item_name  = av_default_item_name,
736     .option     = options,
737     .version    = LIBAVUTIL_VERSION_INT,
738 };
739
740 AVCodec ff_png_encoder = {
741     .name           = "png",
742     .long_name      = NULL_IF_CONFIG_SMALL("PNG (Portable Network Graphics) image"),
743     .type           = AVMEDIA_TYPE_VIDEO,
744     .id             = AV_CODEC_ID_PNG,
745     .priv_data_size = sizeof(PNGEncContext),
746     .init           = png_enc_init,
747     .close          = png_enc_close,
748     .encode2        = encode_png,
749     .capabilities   = CODEC_CAP_FRAME_THREADS | CODEC_CAP_INTRA_ONLY,
750     .pix_fmts       = (const enum AVPixelFormat[]) {
751         AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA,
752         AV_PIX_FMT_RGB48BE, AV_PIX_FMT_RGBA64BE,
753         AV_PIX_FMT_PAL8,
754         AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8A,
755         AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_YA16BE,
756         AV_PIX_FMT_MONOBLACK, AV_PIX_FMT_NONE
757     },
758     .priv_class     = &pngenc_class,
759 };
760
761 AVCodec ff_apng_encoder = {
762     .name           = "apng",
763     .long_name      = NULL_IF_CONFIG_SMALL("APNG (Animated Portable Network Graphics) image"),
764     .type           = AVMEDIA_TYPE_VIDEO,
765     .id             = AV_CODEC_ID_APNG,
766     .priv_data_size = sizeof(PNGEncContext),
767     .init           = png_enc_init,
768     .close          = png_enc_close,
769     .encode2        = encode_apng,
770     .pix_fmts       = (const enum AVPixelFormat[]) {
771         AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA,
772         AV_PIX_FMT_RGB48BE, AV_PIX_FMT_RGBA64BE,
773         AV_PIX_FMT_PAL8,
774         AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8A,
775         AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_YA16BE,
776         AV_PIX_FMT_MONOBLACK, AV_PIX_FMT_NONE
777     },
778     .priv_class     = &apngenc_class,
779 };