FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/pngenc.c
Date: 2021-09-26 18:22:30
Exec Total Coverage
Lines: 377 674 55.9%
Branches: 131 313 41.9%

Line Branch Exec Source
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 "encode.h"
24 #include "internal.h"
25 #include "bytestream.h"
26 #include "lossless_videoencdsp.h"
27 #include "png.h"
28 #include "apng.h"
29
30 #include "libavutil/avassert.h"
31 #include "libavutil/crc.h"
32 #include "libavutil/libm.h"
33 #include "libavutil/opt.h"
34 #include "libavutil/color_utils.h"
35 #include "libavutil/stereo3d.h"
36
37 #include <zlib.h>
38
39 #define IOBUF_SIZE 4096
40
41 typedef struct APNGFctlChunk {
42 uint32_t sequence_number;
43 uint32_t width, height;
44 uint32_t x_offset, y_offset;
45 uint16_t delay_num, delay_den;
46 uint8_t dispose_op, blend_op;
47 } APNGFctlChunk;
48
49 typedef struct PNGEncContext {
50 AVClass *class;
51 LLVidEncDSPContext llvidencdsp;
52
53 uint8_t *bytestream;
54 uint8_t *bytestream_start;
55 uint8_t *bytestream_end;
56
57 int filter_type;
58
59 z_stream zstream;
60 uint8_t buf[IOBUF_SIZE];
61 int dpi; ///< Physical pixel density, in dots per inch, if set
62 int dpm; ///< Physical pixel density, in dots per meter, if set
63
64 int is_progressive;
65 int bit_depth;
66 int color_type;
67 int bits_per_pixel;
68
69 // APNG
70 uint32_t palette_checksum; // Used to ensure a single unique palette
71 uint32_t sequence_number;
72 int extra_data_updated;
73 uint8_t *extra_data;
74 int extra_data_size;
75
76 AVFrame *prev_frame;
77 AVFrame *last_frame;
78 APNGFctlChunk last_frame_fctl;
79 uint8_t *last_frame_packet;
80 size_t last_frame_packet_size;
81 } PNGEncContext;
82
83 static void png_get_interlaced_row(uint8_t *dst, int row_size,
84 int bits_per_pixel, int pass,
85 const uint8_t *src, int width)
86 {
87 int x, mask, dst_x, j, b, bpp;
88 uint8_t *d;
89 const uint8_t *s;
90 static const int masks[] = {0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff};
91
92 mask = masks[pass];
93 switch (bits_per_pixel) {
94 case 1:
95 memset(dst, 0, row_size);
96 dst_x = 0;
97 for (x = 0; x < width; x++) {
98 j = (x & 7);
99 if ((mask << j) & 0x80) {
100 b = (src[x >> 3] >> (7 - j)) & 1;
101 dst[dst_x >> 3] |= b << (7 - (dst_x & 7));
102 dst_x++;
103 }
104 }
105 break;
106 default:
107 bpp = bits_per_pixel >> 3;
108 d = dst;
109 s = src;
110 for (x = 0; x < width; x++) {
111 j = x & 7;
112 if ((mask << j) & 0x80) {
113 memcpy(d, s, bpp);
114 d += bpp;
115 }
116 s += bpp;
117 }
118 break;
119 }
120 }
121
122 static void sub_png_paeth_prediction(uint8_t *dst, uint8_t *src, uint8_t *top,
123 int w, int bpp)
124 {
125 int i;
126 for (i = 0; i < w; i++) {
127 int a, b, c, p, pa, pb, pc;
128
129 a = src[i - bpp];
130 b = top[i];
131 c = top[i - bpp];
132
133 p = b - c;
134 pc = a - c;
135
136 pa = abs(p);
137 pb = abs(pc);
138 pc = abs(p + pc);
139
140 if (pa <= pb && pa <= pc)
141 p = a;
142 else if (pb <= pc)
143 p = b;
144 else
145 p = c;
146 dst[i] = src[i] - p;
147 }
148 }
149
150 static void sub_left_prediction(PNGEncContext *c, uint8_t *dst, const uint8_t *src, int bpp, int size)
151 {
152 const uint8_t *src1 = src + bpp;
153 const uint8_t *src2 = src;
154 int x, unaligned_w;
155
156 memcpy(dst, src, bpp);
157 dst += bpp;
158 size -= bpp;
159 unaligned_w = FFMIN(32 - bpp, size);
160 for (x = 0; x < unaligned_w; x++)
161 *dst++ = *src1++ - *src2++;
162 size -= unaligned_w;
163 c->llvidencdsp.diff_bytes(dst, src1, src2, size);
164 }
165
166 78369 static void png_filter_row(PNGEncContext *c, uint8_t *dst, int filter_type,
167 uint8_t *src, uint8_t *top, int size, int bpp)
168 {
169 int i;
170
171
1/6
✓ Branch 0 taken 78369 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
78369 switch (filter_type) {
172 78369 case PNG_FILTER_VALUE_NONE:
173 78369 memcpy(dst, src, size);
174 78369 break;
175 case PNG_FILTER_VALUE_SUB:
176 sub_left_prediction(c, dst, src, bpp, size);
177 break;
178 case PNG_FILTER_VALUE_UP:
179 c->llvidencdsp.diff_bytes(dst, src, top, size);
180 break;
181 case PNG_FILTER_VALUE_AVG:
182 for (i = 0; i < bpp; i++)
183 dst[i] = src[i] - (top[i] >> 1);
184 for (; i < size; i++)
185 dst[i] = src[i] - ((src[i - bpp] + top[i]) >> 1);
186 break;
187 case PNG_FILTER_VALUE_PAETH:
188 for (i = 0; i < bpp; i++)
189 dst[i] = src[i] - top[i];
190 sub_png_paeth_prediction(dst + i, src + i, top + i, size - i, bpp);
191 break;
192 }
193 78369 }
194
195 78369 static uint8_t *png_choose_filter(PNGEncContext *s, uint8_t *dst,
196 uint8_t *src, uint8_t *top, int size, int bpp)
197 {
198 78369 int pred = s->filter_type;
199
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 78369 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
78369 av_assert0(bpp || !pred);
200
3/4
✓ Branch 0 taken 315 times.
✓ Branch 1 taken 78054 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 315 times.
78369 if (!top && pred)
201 pred = PNG_FILTER_VALUE_SUB;
202
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78369 times.
78369 if (pred == PNG_FILTER_VALUE_MIXED) {
203 int i;
204 int cost, bcost = INT_MAX;
205 uint8_t *buf1 = dst, *buf2 = dst + size + 16;
206 for (pred = 0; pred < 5; pred++) {
207 png_filter_row(s, buf1 + 1, pred, src, top, size, bpp);
208 buf1[0] = pred;
209 cost = 0;
210 for (i = 0; i <= size; i++)
211 cost += abs((int8_t) buf1[i]);
212 if (cost < bcost) {
213 bcost = cost;
214 FFSWAP(uint8_t *, buf1, buf2);
215 }
216 }
217 return buf2;
218 } else {
219 78369 png_filter_row(s, dst + 1, pred, src, top, size, bpp);
220 78369 dst[0] = pred;
221 78369 return dst;
222 }
223 }
224
225 12572 static void png_write_chunk(uint8_t **f, uint32_t tag,
226 const uint8_t *buf, int length)
227 {
228 12572 const AVCRC *crc_table = av_crc_get_table(AV_CRC_32_IEEE_LE);
229 12572 uint32_t crc = ~0U;
230 uint8_t tagbuf[4];
231
232 12572 bytestream_put_be32(f, length);
233 12572 AV_WL32(tagbuf, tag);
234 12572 crc = av_crc(crc_table, crc, tagbuf, 4);
235 12572 bytestream_put_be32(f, av_bswap32(tag));
236
2/2
✓ Branch 0 taken 12330 times.
✓ Branch 1 taken 242 times.
12572 if (length > 0) {
237 12330 crc = av_crc(crc_table, crc, buf, length);
238 12330 memcpy(*f, buf, length);
239 12330 *f += length;
240 }
241 12572 bytestream_put_be32(f, ~crc);
242 12572 }
243
244 16138 static void png_write_image_data(AVCodecContext *avctx,
245 const uint8_t *buf, int length)
246 {
247 16138 PNGEncContext *s = avctx->priv_data;
248 16138 const AVCRC *crc_table = av_crc_get_table(AV_CRC_32_IEEE_LE);
249 16138 uint32_t crc = ~0U;
250
251
4/4
✓ Branch 0 taken 4444 times.
✓ Branch 1 taken 11694 times.
✓ Branch 2 taken 122 times.
✓ Branch 3 taken 4322 times.
16138 if (avctx->codec_id == AV_CODEC_ID_PNG || avctx->frame_number == 0) {
252 11816 png_write_chunk(&s->bytestream, MKTAG('I', 'D', 'A', 'T'), buf, length);
253 11816 return;
254 }
255
256 4322 bytestream_put_be32(&s->bytestream, length + 4);
257
258 4322 bytestream_put_be32(&s->bytestream, MKBETAG('f', 'd', 'A', 'T'));
259 4322 bytestream_put_be32(&s->bytestream, s->sequence_number);
260 4322 crc = av_crc(crc_table, crc, s->bytestream - 8, 8);
261
262 4322 crc = av_crc(crc_table, crc, buf, length);
263 4322 memcpy(s->bytestream, buf, length);
264 4322 s->bytestream += length;
265
266 4322 bytestream_put_be32(&s->bytestream, ~crc);
267
268 4322 ++s->sequence_number;
269 }
270
271 /* XXX: do filtering */
272 78369 static int png_write_row(AVCodecContext *avctx, const uint8_t *data, int size)
273 {
274 78369 PNGEncContext *s = avctx->priv_data;
275 int ret;
276
277 78369 s->zstream.avail_in = size;
278 78369 s->zstream.next_in = data;
279
2/2
✓ Branch 0 taken 89830 times.
✓ Branch 1 taken 78369 times.
168199 while (s->zstream.avail_in > 0) {
280 89830 ret = deflate(&s->zstream, Z_NO_FLUSH);
281
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 89830 times.
89830 if (ret != Z_OK)
282 return -1;
283
2/2
✓ Branch 0 taken 15182 times.
✓ Branch 1 taken 74648 times.
89830 if (s->zstream.avail_out == 0) {
284
1/2
✓ Branch 0 taken 15182 times.
✗ Branch 1 not taken.
15182 if (s->bytestream_end - s->bytestream > IOBUF_SIZE + 100)
285 15182 png_write_image_data(avctx, s->buf, IOBUF_SIZE);
286 15182 s->zstream.avail_out = IOBUF_SIZE;
287 15182 s->zstream.next_out = s->buf;
288 }
289 }
290 78369 return 0;
291 }
292
293 #define AV_WB32_PNG(buf, n) AV_WB32(buf, lrint((n) * 100000))
294 244 static int png_get_chrm(enum AVColorPrimaries prim, uint8_t *buf)
295 {
296 244 double rx, ry, gx, gy, bx, by, wx = 0.3127, wy = 0.3290;
297
1/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 244 times.
244 switch (prim) {
298 case AVCOL_PRI_BT709:
299 rx = 0.640; ry = 0.330;
300 gx = 0.300; gy = 0.600;
301 bx = 0.150; by = 0.060;
302 break;
303 case AVCOL_PRI_BT470M:
304 rx = 0.670; ry = 0.330;
305 gx = 0.210; gy = 0.710;
306 bx = 0.140; by = 0.080;
307 wx = 0.310; wy = 0.316;
308 break;
309 case AVCOL_PRI_BT470BG:
310 rx = 0.640; ry = 0.330;
311 gx = 0.290; gy = 0.600;
312 bx = 0.150; by = 0.060;
313 break;
314 case AVCOL_PRI_SMPTE170M:
315 case AVCOL_PRI_SMPTE240M:
316 rx = 0.630; ry = 0.340;
317 gx = 0.310; gy = 0.595;
318 bx = 0.155; by = 0.070;
319 break;
320 case AVCOL_PRI_BT2020:
321 rx = 0.708; ry = 0.292;
322 gx = 0.170; gy = 0.797;
323 bx = 0.131; by = 0.046;
324 break;
325 244 default:
326 244 return 0;
327 }
328
329 AV_WB32_PNG(buf , wx); AV_WB32_PNG(buf + 4 , wy);
330 AV_WB32_PNG(buf + 8 , rx); AV_WB32_PNG(buf + 12, ry);
331 AV_WB32_PNG(buf + 16, gx); AV_WB32_PNG(buf + 20, gy);
332 AV_WB32_PNG(buf + 24, bx); AV_WB32_PNG(buf + 28, by);
333 return 1;
334 }
335
336 244 static int png_get_gama(enum AVColorTransferCharacteristic trc, uint8_t *buf)
337 {
338 244 double gamma = avpriv_get_gamma_from_trc(trc);
339
1/2
✓ Branch 0 taken 244 times.
✗ Branch 1 not taken.
244 if (gamma <= 1e-6)
340 244 return 0;
341
342 AV_WB32_PNG(buf, 1.0 / gamma);
343 return 1;
344 }
345
346 244 static int encode_headers(AVCodecContext *avctx, const AVFrame *pict)
347 {
348 AVFrameSideData *side_data;
349 244 PNGEncContext *s = avctx->priv_data;
350
351 /* write png header */
352 244 AV_WB32(s->buf, avctx->width);
353 244 AV_WB32(s->buf + 4, avctx->height);
354 244 s->buf[8] = s->bit_depth;
355 244 s->buf[9] = s->color_type;
356 244 s->buf[10] = 0; /* compression type */
357 244 s->buf[11] = 0; /* filter type */
358 244 s->buf[12] = s->is_progressive; /* interlace type */
359 244 png_write_chunk(&s->bytestream, MKTAG('I', 'H', 'D', 'R'), s->buf, 13);
360
361 /* write physical information */
362
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 244 times.
244 if (s->dpm) {
363 AV_WB32(s->buf, s->dpm);
364 AV_WB32(s->buf + 4, s->dpm);
365 s->buf[8] = 1; /* unit specifier is meter */
366 } else {
367 244 AV_WB32(s->buf, avctx->sample_aspect_ratio.num);
368 244 AV_WB32(s->buf + 4, avctx->sample_aspect_ratio.den);
369 244 s->buf[8] = 0; /* unit specifier is unknown */
370 }
371 244 png_write_chunk(&s->bytestream, MKTAG('p', 'H', 'Y', 's'), s->buf, 9);
372
373 /* write stereoscopic information */
374 244 side_data = av_frame_get_side_data(pict, AV_FRAME_DATA_STEREO3D);
375
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 244 times.
244 if (side_data) {
376 AVStereo3D *stereo3d = (AVStereo3D *)side_data->data;
377 switch (stereo3d->type) {
378 case AV_STEREO3D_SIDEBYSIDE:
379 s->buf[0] = ((stereo3d->flags & AV_STEREO3D_FLAG_INVERT) == 0) ? 1 : 0;
380 png_write_chunk(&s->bytestream, MKTAG('s', 'T', 'E', 'R'), s->buf, 1);
381 break;
382 case AV_STEREO3D_2D:
383 break;
384 default:
385 av_log(avctx, AV_LOG_WARNING, "Only side-by-side stereo3d flag can be defined within sTER chunk\n");
386 break;
387 }
388 }
389
390 /* write colorspace information */
391
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 244 times.
244 if (pict->color_primaries == AVCOL_PRI_BT709 &&
392 pict->color_trc == AVCOL_TRC_IEC61966_2_1) {
393 s->buf[0] = 1; /* rendering intent, relative colorimetric by default */
394 png_write_chunk(&s->bytestream, MKTAG('s', 'R', 'G', 'B'), s->buf, 1);
395 }
396
397
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 244 times.
244 if (png_get_chrm(pict->color_primaries, s->buf))
398 png_write_chunk(&s->bytestream, MKTAG('c', 'H', 'R', 'M'), s->buf, 32);
399
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 244 times.
244 if (png_get_gama(pict->color_trc, s->buf))
400 png_write_chunk(&s->bytestream, MKTAG('g', 'A', 'M', 'A'), s->buf, 4);
401
402 /* put the palette if needed */
403
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 244 times.
244 if (s->color_type == PNG_COLOR_TYPE_PALETTE) {
404 int has_alpha, alpha, i;
405 unsigned int v;
406 uint32_t *palette;
407 uint8_t *ptr, *alpha_ptr;
408
409 palette = (uint32_t *)pict->data[1];
410 ptr = s->buf;
411 alpha_ptr = s->buf + 256 * 3;
412 has_alpha = 0;
413 for (i = 0; i < 256; i++) {
414 v = palette[i];
415 alpha = v >> 24;
416 if (alpha != 0xff)
417 has_alpha = 1;
418 *alpha_ptr++ = alpha;
419 bytestream_put_be24(&ptr, v);
420 }
421 png_write_chunk(&s->bytestream,
422 MKTAG('P', 'L', 'T', 'E'), s->buf, 256 * 3);
423 if (has_alpha) {
424 png_write_chunk(&s->bytestream,
425 MKTAG('t', 'R', 'N', 'S'), s->buf + 256 * 3, 256);
426 }
427 }
428
429 244 return 0;
430 }
431
432 315 static int encode_frame(AVCodecContext *avctx, const AVFrame *pict)
433 {
434 315 PNGEncContext *s = avctx->priv_data;
435 315 const AVFrame *const p = pict;
436 int y, len, ret;
437 int row_size, pass_row_size;
438 uint8_t *ptr, *top, *crow_buf, *crow;
439 315 uint8_t *crow_base = NULL;
440 315 uint8_t *progressive_buf = NULL;
441 315 uint8_t *top_buf = NULL;
442
443 315 row_size = (pict->width * s->bits_per_pixel + 7) >> 3;
444
445 315 crow_base = av_malloc((row_size + 32) << (s->filter_type == PNG_FILTER_VALUE_MIXED));
446
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 315 times.
315 if (!crow_base) {
447 ret = AVERROR(ENOMEM);
448 goto the_end;
449 }
450 // pixel data should be aligned, but there's a control byte before it
451 315 crow_buf = crow_base + 15;
452
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 315 times.
315 if (s->is_progressive) {
453 progressive_buf = av_malloc(row_size + 1);
454 top_buf = av_malloc(row_size + 1);
455 if (!progressive_buf || !top_buf) {
456 ret = AVERROR(ENOMEM);
457 goto the_end;
458 }
459 }
460
461 /* put each row */
462 315 s->zstream.avail_out = IOBUF_SIZE;
463 315 s->zstream.next_out = s->buf;
464
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 315 times.
315 if (s->is_progressive) {
465 int pass;
466
467 for (pass = 0; pass < NB_PASSES; pass++) {
468 /* NOTE: a pass is completely omitted if no pixels would be
469 * output */
470 pass_row_size = ff_png_pass_row_size(pass, s->bits_per_pixel, pict->width);
471 if (pass_row_size > 0) {
472 top = NULL;
473 for (y = 0; y < pict->height; y++)
474 if ((ff_png_pass_ymask[pass] << (y & 7)) & 0x80) {
475 ptr = p->data[0] + y * p->linesize[0];
476 FFSWAP(uint8_t *, progressive_buf, top_buf);
477 png_get_interlaced_row(progressive_buf, pass_row_size,
478 s->bits_per_pixel, pass,
479 ptr, pict->width);
480 crow = png_choose_filter(s, crow_buf, progressive_buf,
481 top, pass_row_size, s->bits_per_pixel >> 3);
482 png_write_row(avctx, crow, pass_row_size + 1);
483 top = progressive_buf;
484 }
485 }
486 }
487 } else {
488 315 top = NULL;
489
2/2
✓ Branch 0 taken 78369 times.
✓ Branch 1 taken 315 times.
78684 for (y = 0; y < pict->height; y++) {
490 78369 ptr = p->data[0] + y * p->linesize[0];
491 78369 crow = png_choose_filter(s, crow_buf, ptr, top,
492 78369 row_size, s->bits_per_pixel >> 3);
493 78369 png_write_row(avctx, crow, row_size + 1);
494 78369 top = ptr;
495 }
496 }
497 /* compress last bytes */
498 for (;;) {
499 956 ret = deflate(&s->zstream, Z_FINISH);
500
3/4
✓ Branch 0 taken 315 times.
✓ Branch 1 taken 641 times.
✓ Branch 2 taken 315 times.
✗ Branch 3 not taken.
956 if (ret == Z_OK || ret == Z_STREAM_END) {
501 956 len = IOBUF_SIZE - s->zstream.avail_out;
502
2/4
✓ Branch 0 taken 956 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 956 times.
✗ Branch 3 not taken.
956 if (len > 0 && s->bytestream_end - s->bytestream > len + 100) {
503 956 png_write_image_data(avctx, s->buf, len);
504 }
505 956 s->zstream.avail_out = IOBUF_SIZE;
506 956 s->zstream.next_out = s->buf;
507
2/2
✓ Branch 0 taken 315 times.
✓ Branch 1 taken 641 times.
956 if (ret == Z_STREAM_END)
508 315 break;
509 } else {
510 ret = -1;
511 goto the_end;
512 }
513 }
514
515 315 ret = 0;
516
517 315 the_end:
518 315 av_freep(&crow_base);
519 315 av_freep(&progressive_buf);
520 315 av_freep(&top_buf);
521 315 deflateReset(&s->zstream);
522 315 return ret;
523 }
524
525 242 static int encode_png(AVCodecContext *avctx, AVPacket *pkt,
526 const AVFrame *pict, int *got_packet)
527 {
528 242 PNGEncContext *s = avctx->priv_data;
529 int ret;
530 int enc_row_size;
531 size_t max_packet_size;
532
533 242 enc_row_size = deflateBound(&s->zstream, (avctx->width * s->bits_per_pixel + 7) >> 3);
534 242 max_packet_size =
535 242 AV_INPUT_BUFFER_MIN_SIZE + // headers
536 242 avctx->height * (
537 242 enc_row_size +
538 242 12 * (((int64_t)enc_row_size + IOBUF_SIZE - 1) / IOBUF_SIZE) // IDAT * ceil(enc_row_size / IOBUF_SIZE)
539 );
540
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 242 times.
242 if (max_packet_size > INT_MAX)
541 return AVERROR(ENOMEM);
542 242 ret = ff_alloc_packet(avctx, pkt, max_packet_size);
543
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 242 times.
242 if (ret < 0)
544 return ret;
545
546 242 s->bytestream_start =
547 242 s->bytestream = pkt->data;
548 242 s->bytestream_end = pkt->data + pkt->size;
549
550 242 AV_WB64(s->bytestream, PNGSIG);
551 242 s->bytestream += 8;
552
553 242 ret = encode_headers(avctx, pict);
554
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 242 times.
242 if (ret < 0)
555 return ret;
556
557 242 ret = encode_frame(avctx, pict);
558
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 242 times.
242 if (ret < 0)
559 return ret;
560
561 242 png_write_chunk(&s->bytestream, MKTAG('I', 'E', 'N', 'D'), NULL, 0);
562
563 242 pkt->size = s->bytestream - s->bytestream_start;
564 242 pkt->flags |= AV_PKT_FLAG_KEY;
565 242 *got_packet = 1;
566
567 242 return 0;
568 }
569
570 142 static int apng_do_inverse_blend(AVFrame *output, const AVFrame *input,
571 APNGFctlChunk *fctl_chunk, uint8_t bpp)
572 {
573 // output: background, input: foreground
574 // output the image such that when blended with the background, will produce the foreground
575
576 unsigned int x, y;
577 142 unsigned int leftmost_x = input->width;
578 142 unsigned int rightmost_x = 0;
579 142 unsigned int topmost_y = input->height;
580 142 unsigned int bottommost_y = 0;
581 142 const uint8_t *input_data = input->data[0];
582 142 uint8_t *output_data = output->data[0];
583 142 ptrdiff_t input_linesize = input->linesize[0];
584 142 ptrdiff_t output_linesize = output->linesize[0];
585
586 // Find bounding box of changes
587
2/2
✓ Branch 0 taken 40896 times.
✓ Branch 1 taken 142 times.
41038 for (y = 0; y < input->height; ++y) {
588
2/2
✓ Branch 0 taken 14395392 times.
✓ Branch 1 taken 40896 times.
14436288 for (x = 0; x < input->width; ++x) {
589
2/2
✓ Branch 0 taken 3066 times.
✓ Branch 1 taken 14392326 times.
14395392 if (!memcmp(input_data + bpp * x, output_data + bpp * x, bpp))
590 3066 continue;
591
592
2/2
✓ Branch 0 taken 142 times.
✓ Branch 1 taken 14392184 times.
14392326 if (x < leftmost_x)
593 142 leftmost_x = x;
594
2/2
✓ Branch 0 taken 49984 times.
✓ Branch 1 taken 14342342 times.
14392326 if (x >= rightmost_x)
595 49984 rightmost_x = x + 1;
596
2/2
✓ Branch 0 taken 142 times.
✓ Branch 1 taken 14392184 times.
14392326 if (y < topmost_y)
597 142 topmost_y = y;
598
2/2
✓ Branch 0 taken 40896 times.
✓ Branch 1 taken 14351430 times.
14392326 if (y >= bottommost_y)
599 40896 bottommost_y = y + 1;
600 }
601
602 40896 input_data += input_linesize;
603 40896 output_data += output_linesize;
604 }
605
606
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 142 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
142 if (leftmost_x == input->width && rightmost_x == 0) {
607 // Empty frame
608 // APNG does not support empty frames, so we make it a 1x1 frame
609 leftmost_x = topmost_y = 0;
610 rightmost_x = bottommost_y = 1;
611 }
612
613 // Do actual inverse blending
614
2/2
✓ Branch 0 taken 71 times.
✓ Branch 1 taken 71 times.
142 if (fctl_chunk->blend_op == APNG_BLEND_OP_SOURCE) {
615 71 output_data = output->data[0];
616
2/2
✓ Branch 0 taken 20448 times.
✓ Branch 1 taken 71 times.
20519 for (y = topmost_y; y < bottommost_y; ++y) {
617 20448 memcpy(output_data,
618 20448 input->data[0] + input_linesize * y + bpp * leftmost_x,
619 20448 bpp * (rightmost_x - leftmost_x));
620 20448 output_data += output_linesize;
621 }
622 } else { // APNG_BLEND_OP_OVER
623 size_t transparent_palette_index;
624 uint32_t *palette;
625
626
1/3
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 71 times.
71 switch (input->format) {
627 case AV_PIX_FMT_RGBA64BE:
628 case AV_PIX_FMT_YA16BE:
629 case AV_PIX_FMT_RGBA:
630 case AV_PIX_FMT_GRAY8A:
631 break;
632
633 case AV_PIX_FMT_PAL8:
634 palette = (uint32_t*)input->data[1];
635 for (transparent_palette_index = 0; transparent_palette_index < 256; ++transparent_palette_index)
636 if (palette[transparent_palette_index] >> 24 == 0)
637 break;
638 break;
639
640 71 default:
641 // No alpha, so blending not possible
642 71 return -1;
643 }
644
645 for (y = topmost_y; y < bottommost_y; ++y) {
646 uint8_t *foreground = input->data[0] + input_linesize * y + bpp * leftmost_x;
647 uint8_t *background = output->data[0] + output_linesize * y + bpp * leftmost_x;
648 output_data = output->data[0] + output_linesize * (y - topmost_y);
649 for (x = leftmost_x; x < rightmost_x; ++x, foreground += bpp, background += bpp, output_data += bpp) {
650 if (!memcmp(foreground, background, bpp)) {
651 if (input->format == AV_PIX_FMT_PAL8) {
652 if (transparent_palette_index == 256) {
653 // Need fully transparent colour, but none exists
654 return -1;
655 }
656
657 *output_data = transparent_palette_index;
658 } else {
659 memset(output_data, 0, bpp);
660 }
661 continue;
662 }
663
664 // Check for special alpha values, since full inverse
665 // alpha-on-alpha blending is rarely possible, and when
666 // possible, doesn't compress much better than
667 // APNG_BLEND_OP_SOURCE blending
668 switch (input->format) {
669 case AV_PIX_FMT_RGBA64BE:
670 if (((uint16_t*)foreground)[3] == 0xffff ||
671 ((uint16_t*)background)[3] == 0)
672 break;
673 return -1;
674
675 case AV_PIX_FMT_YA16BE:
676 if (((uint16_t*)foreground)[1] == 0xffff ||
677 ((uint16_t*)background)[1] == 0)
678 break;
679 return -1;
680
681 case AV_PIX_FMT_RGBA:
682 if (foreground[3] == 0xff || background[3] == 0)
683 break;
684 return -1;
685
686 case AV_PIX_FMT_GRAY8A:
687 if (foreground[1] == 0xff || background[1] == 0)
688 break;
689 return -1;
690
691 case AV_PIX_FMT_PAL8:
692 if (palette[*foreground] >> 24 == 0xff ||
693 palette[*background] >> 24 == 0)
694 break;
695 return -1;
696 }
697
698 memmove(output_data, foreground, bpp);
699 }
700 }
701 }
702
703 71 output->width = rightmost_x - leftmost_x;
704 71 output->height = bottommost_y - topmost_y;
705 71 fctl_chunk->width = output->width;
706 71 fctl_chunk->height = output->height;
707 71 fctl_chunk->x_offset = leftmost_x;
708 71 fctl_chunk->y_offset = topmost_y;
709
710 71 return 0;
711 }
712
713 26 static int apng_encode_frame(AVCodecContext *avctx, const AVFrame *pict,
714 APNGFctlChunk *best_fctl_chunk, APNGFctlChunk *best_last_fctl_chunk)
715 {
716 26 PNGEncContext *s = avctx->priv_data;
717 int ret;
718 unsigned int y;
719 AVFrame* diffFrame;
720 26 uint8_t bpp = (s->bits_per_pixel + 7) >> 3;
721 uint8_t *original_bytestream, *original_bytestream_end;
722 26 uint8_t *temp_bytestream = 0, *temp_bytestream_end;
723 uint32_t best_sequence_number;
724 uint8_t *best_bytestream;
725 26 size_t best_bytestream_size = SIZE_MAX;
726 26 APNGFctlChunk last_fctl_chunk = *best_last_fctl_chunk;
727 26 APNGFctlChunk fctl_chunk = *best_fctl_chunk;
728
729
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 24 times.
26 if (avctx->frame_number == 0) {
730 2 best_fctl_chunk->width = pict->width;
731 2 best_fctl_chunk->height = pict->height;
732 2 best_fctl_chunk->x_offset = 0;
733 2 best_fctl_chunk->y_offset = 0;
734 2 best_fctl_chunk->blend_op = APNG_BLEND_OP_SOURCE;
735 2 return encode_frame(avctx, pict);
736 }
737
738 24 diffFrame = av_frame_alloc();
739
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (!diffFrame)
740 return AVERROR(ENOMEM);
741
742 24 diffFrame->format = pict->format;
743 24 diffFrame->width = pict->width;
744 24 diffFrame->height = pict->height;
745
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
24 if ((ret = av_frame_get_buffer(diffFrame, 0)) < 0)
746 goto fail;
747
748 24 original_bytestream = s->bytestream;
749 24 original_bytestream_end = s->bytestream_end;
750
751 24 temp_bytestream = av_malloc(original_bytestream_end - original_bytestream);
752
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (!temp_bytestream) {
753 ret = AVERROR(ENOMEM);
754 goto fail;
755 }
756 24 temp_bytestream_end = temp_bytestream + (original_bytestream_end - original_bytestream);
757
758
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 24 times.
96 for (last_fctl_chunk.dispose_op = 0; last_fctl_chunk.dispose_op < 3; ++last_fctl_chunk.dispose_op) {
759 // 0: APNG_DISPOSE_OP_NONE
760 // 1: APNG_DISPOSE_OP_BACKGROUND
761 // 2: APNG_DISPOSE_OP_PREVIOUS
762
763
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 72 times.
216 for (fctl_chunk.blend_op = 0; fctl_chunk.blend_op < 2; ++fctl_chunk.blend_op) {
764 // 0: APNG_BLEND_OP_SOURCE
765 // 1: APNG_BLEND_OP_OVER
766
767 144 uint32_t original_sequence_number = s->sequence_number, sequence_number;
768 144 uint8_t *bytestream_start = s->bytestream;
769 size_t bytestream_size;
770
771 // Do disposal
772
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 48 times.
144 if (last_fctl_chunk.dispose_op != APNG_DISPOSE_OP_PREVIOUS) {
773 96 diffFrame->width = pict->width;
774 96 diffFrame->height = pict->height;
775 96 ret = av_frame_copy(diffFrame, s->last_frame);
776
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 96 times.
96 if (ret < 0)
777 goto fail;
778
779
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 48 times.
96 if (last_fctl_chunk.dispose_op == APNG_DISPOSE_OP_BACKGROUND) {
780
2/2
✓ Branch 0 taken 13824 times.
✓ Branch 1 taken 48 times.
13872 for (y = last_fctl_chunk.y_offset; y < last_fctl_chunk.y_offset + last_fctl_chunk.height; ++y) {
781 13824 size_t row_start = diffFrame->linesize[0] * y + bpp * last_fctl_chunk.x_offset;
782 13824 memset(diffFrame->data[0] + row_start, 0, bpp * last_fctl_chunk.width);
783 }
784 }
785 } else {
786
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 46 times.
48 if (!s->prev_frame)
787 2 continue;
788
789 46 diffFrame->width = pict->width;
790 46 diffFrame->height = pict->height;
791 46 ret = av_frame_copy(diffFrame, s->prev_frame);
792
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 if (ret < 0)
793 goto fail;
794 }
795
796 // Do inverse blending
797
2/2
✓ Branch 1 taken 71 times.
✓ Branch 2 taken 71 times.
142 if (apng_do_inverse_blend(diffFrame, pict, &fctl_chunk, bpp) < 0)
798 71 continue;
799
800 // Do encoding
801 71 ret = encode_frame(avctx, diffFrame);
802 71 sequence_number = s->sequence_number;
803 71 s->sequence_number = original_sequence_number;
804 71 bytestream_size = s->bytestream - bytestream_start;
805 71 s->bytestream = bytestream_start;
806
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 71 times.
71 if (ret < 0)
807 goto fail;
808
809
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 47 times.
71 if (bytestream_size < best_bytestream_size) {
810 24 *best_fctl_chunk = fctl_chunk;
811 24 *best_last_fctl_chunk = last_fctl_chunk;
812
813 24 best_sequence_number = sequence_number;
814 24 best_bytestream = s->bytestream;
815 24 best_bytestream_size = bytestream_size;
816
817
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 if (best_bytestream == original_bytestream) {
818 24 s->bytestream = temp_bytestream;
819 24 s->bytestream_end = temp_bytestream_end;
820 } else {
821 s->bytestream = original_bytestream;
822 s->bytestream_end = original_bytestream_end;
823 }
824 }
825 }
826 }
827
828 24 s->sequence_number = best_sequence_number;
829 24 s->bytestream = original_bytestream + best_bytestream_size;
830 24 s->bytestream_end = original_bytestream_end;
831
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (best_bytestream != original_bytestream)
832 memcpy(original_bytestream, best_bytestream, best_bytestream_size);
833
834 24 ret = 0;
835
836 24 fail:
837 24 av_freep(&temp_bytestream);
838 24 av_frame_free(&diffFrame);
839 24 return ret;
840 }
841
842 30 static int encode_apng(AVCodecContext *avctx, AVPacket *pkt,
843 const AVFrame *pict, int *got_packet)
844 {
845 30 PNGEncContext *s = avctx->priv_data;
846 int ret;
847 int enc_row_size;
848 size_t max_packet_size;
849 30 APNGFctlChunk fctl_chunk = {0};
850
851
3/4
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 26 times.
30 if (pict && s->color_type == PNG_COLOR_TYPE_PALETTE) {
852 uint32_t checksum = ~av_crc(av_crc_get_table(AV_CRC_32_IEEE_LE), ~0U, pict->data[1], 256 * sizeof(uint32_t));
853
854 if (avctx->frame_number == 0) {
855 s->palette_checksum = checksum;
856 } else if (checksum != s->palette_checksum) {
857 av_log(avctx, AV_LOG_ERROR,
858 "Input contains more than one unique palette. APNG does not support multiple palettes.\n");
859 return -1;
860 }
861 }
862
863 30 enc_row_size = deflateBound(&s->zstream, (avctx->width * s->bits_per_pixel + 7) >> 3);
864 30 max_packet_size =
865 30 AV_INPUT_BUFFER_MIN_SIZE + // headers
866 30 avctx->height * (
867 30 enc_row_size +
868 30 (4 + 12) * (((int64_t)enc_row_size + IOBUF_SIZE - 1) / IOBUF_SIZE) // fdAT * ceil(enc_row_size / IOBUF_SIZE)
869 );
870
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (max_packet_size > INT_MAX)
871 return AVERROR(ENOMEM);
872
873
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 28 times.
30 if (avctx->frame_number == 0) {
874
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!pict)
875 return AVERROR(EINVAL);
876
877 2 s->bytestream = s->extra_data = av_malloc(AV_INPUT_BUFFER_MIN_SIZE);
878
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!s->extra_data)
879 return AVERROR(ENOMEM);
880
881 2 ret = encode_headers(avctx, pict);
882
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret < 0)
883 return ret;
884
885 2 s->extra_data_size = s->bytestream - s->extra_data;
886
887 2 s->last_frame_packet = av_malloc(max_packet_size);
888
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!s->last_frame_packet)
889 return AVERROR(ENOMEM);
890
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 2 times.
28 } else if (s->last_frame) {
891 26 ret = ff_get_encode_buffer(avctx, pkt, s->last_frame_packet_size, 0);
892
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 if (ret < 0)
893 return ret;
894
895 26 memcpy(pkt->data, s->last_frame_packet, s->last_frame_packet_size);
896 26 pkt->pts = pkt->dts = s->last_frame->pts;
897 }
898
899
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 4 times.
30 if (pict) {
900 26 s->bytestream_start =
901 26 s->bytestream = s->last_frame_packet;
902 26 s->bytestream_end = s->bytestream + max_packet_size;
903
904 // We're encoding the frame first, so we have to do a bit of shuffling around
905 // to have the image data write to the correct place in the buffer
906 26 fctl_chunk.sequence_number = s->sequence_number;
907 26 ++s->sequence_number;
908 26 s->bytestream += 26 + 12;
909
910 26 ret = apng_encode_frame(avctx, pict, &fctl_chunk, &s->last_frame_fctl);
911
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 if (ret < 0)
912 return ret;
913
914 26 fctl_chunk.delay_num = 0; // delay filled in during muxing
915 26 fctl_chunk.delay_den = 0;
916 } else {
917 4 s->last_frame_fctl.dispose_op = APNG_DISPOSE_OP_NONE;
918 }
919
920
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 4 times.
30 if (s->last_frame) {
921 26 uint8_t* last_fctl_chunk_start = pkt->data;
922 uint8_t buf[26];
923
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 24 times.
26 if (!s->extra_data_updated) {
924 2 uint8_t *side_data = av_packet_new_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, s->extra_data_size);
925
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!side_data)
926 return AVERROR(ENOMEM);
927 2 memcpy(side_data, s->extra_data, s->extra_data_size);
928 2 s->extra_data_updated = 1;
929 }
930
931 26 AV_WB32(buf + 0, s->last_frame_fctl.sequence_number);
932 26 AV_WB32(buf + 4, s->last_frame_fctl.width);
933 26 AV_WB32(buf + 8, s->last_frame_fctl.height);
934 26 AV_WB32(buf + 12, s->last_frame_fctl.x_offset);
935 26 AV_WB32(buf + 16, s->last_frame_fctl.y_offset);
936 26 AV_WB16(buf + 20, s->last_frame_fctl.delay_num);
937 26 AV_WB16(buf + 22, s->last_frame_fctl.delay_den);
938 26 buf[24] = s->last_frame_fctl.dispose_op;
939 26 buf[25] = s->last_frame_fctl.blend_op;
940 26 png_write_chunk(&last_fctl_chunk_start, MKTAG('f', 'c', 'T', 'L'), buf, 26);
941
942 26 *got_packet = 1;
943 }
944
945
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 4 times.
30 if (pict) {
946
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 24 times.
26 if (!s->last_frame) {
947 2 s->last_frame = av_frame_alloc();
948
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!s->last_frame)
949 return AVERROR(ENOMEM);
950
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 } else if (s->last_frame_fctl.dispose_op != APNG_DISPOSE_OP_PREVIOUS) {
951
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 23 times.
24 if (!s->prev_frame) {
952 1 s->prev_frame = av_frame_alloc();
953
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!s->prev_frame)
954 return AVERROR(ENOMEM);
955
956 1 s->prev_frame->format = pict->format;
957 1 s->prev_frame->width = pict->width;
958 1 s->prev_frame->height = pict->height;
959
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if ((ret = av_frame_get_buffer(s->prev_frame, 0)) < 0)
960 return ret;
961 }
962
963 // Do disposal, but not blending
964 24 av_frame_copy(s->prev_frame, s->last_frame);
965
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (s->last_frame_fctl.dispose_op == APNG_DISPOSE_OP_BACKGROUND) {
966 uint32_t y;
967 uint8_t bpp = (s->bits_per_pixel + 7) >> 3;
968 for (y = s->last_frame_fctl.y_offset; y < s->last_frame_fctl.y_offset + s->last_frame_fctl.height; ++y) {
969 size_t row_start = s->prev_frame->linesize[0] * y + bpp * s->last_frame_fctl.x_offset;
970 memset(s->prev_frame->data[0] + row_start, 0, bpp * s->last_frame_fctl.width);
971 }
972 }
973 }
974
975 26 av_frame_unref(s->last_frame);
976 26 ret = av_frame_ref(s->last_frame, (AVFrame*)pict);
977
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 if (ret < 0)
978 return ret;
979
980 26 s->last_frame_fctl = fctl_chunk;
981 26 s->last_frame_packet_size = s->bytestream - s->bytestream_start;
982 } else {
983 4 av_frame_free(&s->last_frame);
984 }
985
986 30 return 0;
987 }
988
989 12 static av_cold int png_enc_init(AVCodecContext *avctx)
990 {
991 12 PNGEncContext *s = avctx->priv_data;
992 int compression_level;
993
994
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
12 switch (avctx->pix_fmt) {
995 case AV_PIX_FMT_RGBA:
996 avctx->bits_per_coded_sample = 32;
997 break;
998 10 case AV_PIX_FMT_RGB24:
999 10 avctx->bits_per_coded_sample = 24;
1000 10 break;
1001 case AV_PIX_FMT_GRAY8:
1002 avctx->bits_per_coded_sample = 0x28;
1003 break;
1004 case AV_PIX_FMT_MONOBLACK:
1005 avctx->bits_per_coded_sample = 1;
1006 break;
1007 case AV_PIX_FMT_PAL8:
1008 avctx->bits_per_coded_sample = 8;
1009 }
1010
1011 12 ff_llvidencdsp_init(&s->llvidencdsp);
1012
1013
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (avctx->pix_fmt == AV_PIX_FMT_MONOBLACK)
1014 s->filter_type = PNG_FILTER_VALUE_NONE;
1015
1016
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
12 if (s->dpi && s->dpm) {
1017 av_log(avctx, AV_LOG_ERROR, "Only one of 'dpi' or 'dpm' options should be set\n");
1018 return AVERROR(EINVAL);
1019
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 } else if (s->dpi) {
1020 s->dpm = s->dpi * 10000 / 254;
1021 }
1022
1023 12 s->is_progressive = !!(avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT);
1024
3/11
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
12 switch (avctx->pix_fmt) {
1025 case AV_PIX_FMT_RGBA64BE:
1026 s->bit_depth = 16;
1027 s->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
1028 break;
1029 1 case AV_PIX_FMT_RGB48BE:
1030 1 s->bit_depth = 16;
1031 1 s->color_type = PNG_COLOR_TYPE_RGB;
1032 1 break;
1033 case AV_PIX_FMT_RGBA:
1034 s->bit_depth = 8;
1035 s->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
1036 break;
1037 10 case AV_PIX_FMT_RGB24:
1038 10 s->bit_depth = 8;
1039 10 s->color_type = PNG_COLOR_TYPE_RGB;
1040 10 break;
1041 1 case AV_PIX_FMT_GRAY16BE:
1042 1 s->bit_depth = 16;
1043 1 s->color_type = PNG_COLOR_TYPE_GRAY;
1044 1 break;
1045 case AV_PIX_FMT_GRAY8:
1046 s->bit_depth = 8;
1047 s->color_type = PNG_COLOR_TYPE_GRAY;
1048 break;
1049 case AV_PIX_FMT_GRAY8A:
1050 s->bit_depth = 8;
1051 s->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
1052 break;
1053 case AV_PIX_FMT_YA16BE:
1054 s->bit_depth = 16;
1055 s->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
1056 break;
1057 case AV_PIX_FMT_MONOBLACK:
1058 s->bit_depth = 1;
1059 s->color_type = PNG_COLOR_TYPE_GRAY;
1060 break;
1061 case AV_PIX_FMT_PAL8:
1062 s->bit_depth = 8;
1063 s->color_type = PNG_COLOR_TYPE_PALETTE;
1064 break;
1065 default:
1066 return -1;
1067 }
1068 12 s->bits_per_pixel = ff_png_get_nb_channels(s->color_type) * s->bit_depth;
1069
1070 12 s->zstream.zalloc = ff_png_zalloc;
1071 12 s->zstream.zfree = ff_png_zfree;
1072 12 s->zstream.opaque = NULL;
1073 24 compression_level = avctx->compression_level == FF_COMPRESSION_DEFAULT
1074 ? Z_DEFAULT_COMPRESSION
1075
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 : av_clip(avctx->compression_level, 0, 9);
1076
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
12 if (deflateInit2(&s->zstream, compression_level, Z_DEFLATED, 15, 8, Z_DEFAULT_STRATEGY) != Z_OK)
1077 return -1;
1078
1079 12 return 0;
1080 }
1081
1082 12 static av_cold int png_enc_close(AVCodecContext *avctx)
1083 {
1084 12 PNGEncContext *s = avctx->priv_data;
1085
1086 12 deflateEnd(&s->zstream);
1087 12 av_frame_free(&s->last_frame);
1088 12 av_frame_free(&s->prev_frame);
1089 12 av_freep(&s->last_frame_packet);
1090 12 av_freep(&s->extra_data);
1091 12 s->extra_data_size = 0;
1092 12 return 0;
1093 }
1094
1095 #define OFFSET(x) offsetof(PNGEncContext, x)
1096 #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
1097 static const AVOption options[] = {
1098 {"dpi", "Set image resolution (in dots per inch)", OFFSET(dpi), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 0x10000, VE},
1099 {"dpm", "Set image resolution (in dots per meter)", OFFSET(dpm), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 0x10000, VE},
1100 { "pred", "Prediction method", OFFSET(filter_type), AV_OPT_TYPE_INT, { .i64 = PNG_FILTER_VALUE_NONE }, PNG_FILTER_VALUE_NONE, PNG_FILTER_VALUE_MIXED, VE, "pred" },
1101 { "none", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PNG_FILTER_VALUE_NONE }, INT_MIN, INT_MAX, VE, "pred" },
1102 { "sub", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PNG_FILTER_VALUE_SUB }, INT_MIN, INT_MAX, VE, "pred" },
1103 { "up", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PNG_FILTER_VALUE_UP }, INT_MIN, INT_MAX, VE, "pred" },
1104 { "avg", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PNG_FILTER_VALUE_AVG }, INT_MIN, INT_MAX, VE, "pred" },
1105 { "paeth", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PNG_FILTER_VALUE_PAETH }, INT_MIN, INT_MAX, VE, "pred" },
1106 { "mixed", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PNG_FILTER_VALUE_MIXED }, INT_MIN, INT_MAX, VE, "pred" },
1107 { NULL},
1108 };
1109
1110 static const AVClass pngenc_class = {
1111 .class_name = "(A)PNG encoder",
1112 .item_name = av_default_item_name,
1113 .option = options,
1114 .version = LIBAVUTIL_VERSION_INT,
1115 };
1116
1117 const AVCodec ff_png_encoder = {
1118 .name = "png",
1119 .long_name = NULL_IF_CONFIG_SMALL("PNG (Portable Network Graphics) image"),
1120 .type = AVMEDIA_TYPE_VIDEO,
1121 .id = AV_CODEC_ID_PNG,
1122 .priv_data_size = sizeof(PNGEncContext),
1123 .init = png_enc_init,
1124 .close = png_enc_close,
1125 .encode2 = encode_png,
1126 .capabilities = AV_CODEC_CAP_FRAME_THREADS,
1127 .pix_fmts = (const enum AVPixelFormat[]) {
1128 AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA,
1129 AV_PIX_FMT_RGB48BE, AV_PIX_FMT_RGBA64BE,
1130 AV_PIX_FMT_PAL8,
1131 AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8A,
1132 AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_YA16BE,
1133 AV_PIX_FMT_MONOBLACK, AV_PIX_FMT_NONE
1134 },
1135 .priv_class = &pngenc_class,
1136 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
1137 };
1138
1139 const AVCodec ff_apng_encoder = {
1140 .name = "apng",
1141 .long_name = NULL_IF_CONFIG_SMALL("APNG (Animated Portable Network Graphics) image"),
1142 .type = AVMEDIA_TYPE_VIDEO,
1143 .id = AV_CODEC_ID_APNG,
1144 .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY,
1145 .priv_data_size = sizeof(PNGEncContext),
1146 .init = png_enc_init,
1147 .close = png_enc_close,
1148 .encode2 = encode_apng,
1149 .pix_fmts = (const enum AVPixelFormat[]) {
1150 AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA,
1151 AV_PIX_FMT_RGB48BE, AV_PIX_FMT_RGBA64BE,
1152 AV_PIX_FMT_PAL8,
1153 AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8A,
1154 AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_YA16BE,
1155 AV_PIX_FMT_NONE
1156 },
1157 .priv_class = &pngenc_class,
1158 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
1159 };
1160