1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * PNG image format
3cabdff1aSopenharmony_ci * Copyright (c) 2003 Fabrice Bellard
4cabdff1aSopenharmony_ci *
5cabdff1aSopenharmony_ci * This file is part of FFmpeg.
6cabdff1aSopenharmony_ci *
7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
11cabdff1aSopenharmony_ci *
12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15cabdff1aSopenharmony_ci * Lesser General Public License for more details.
16cabdff1aSopenharmony_ci *
17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20cabdff1aSopenharmony_ci */
21cabdff1aSopenharmony_ci
22cabdff1aSopenharmony_ci//#define DEBUG
23cabdff1aSopenharmony_ci
24cabdff1aSopenharmony_ci#include "config_components.h"
25cabdff1aSopenharmony_ci
26cabdff1aSopenharmony_ci#include "libavutil/avassert.h"
27cabdff1aSopenharmony_ci#include "libavutil/bprint.h"
28cabdff1aSopenharmony_ci#include "libavutil/crc.h"
29cabdff1aSopenharmony_ci#include "libavutil/imgutils.h"
30cabdff1aSopenharmony_ci#include "libavutil/intreadwrite.h"
31cabdff1aSopenharmony_ci#include "libavutil/stereo3d.h"
32cabdff1aSopenharmony_ci#include "libavutil/mastering_display_metadata.h"
33cabdff1aSopenharmony_ci
34cabdff1aSopenharmony_ci#include "avcodec.h"
35cabdff1aSopenharmony_ci#include "bytestream.h"
36cabdff1aSopenharmony_ci#include "codec_internal.h"
37cabdff1aSopenharmony_ci#include "internal.h"
38cabdff1aSopenharmony_ci#include "apng.h"
39cabdff1aSopenharmony_ci#include "png.h"
40cabdff1aSopenharmony_ci#include "pngdsp.h"
41cabdff1aSopenharmony_ci#include "thread.h"
42cabdff1aSopenharmony_ci#include "threadframe.h"
43cabdff1aSopenharmony_ci#include "zlib_wrapper.h"
44cabdff1aSopenharmony_ci
45cabdff1aSopenharmony_ci#include <zlib.h>
46cabdff1aSopenharmony_ci
47cabdff1aSopenharmony_cienum PNGHeaderState {
48cabdff1aSopenharmony_ci    PNG_IHDR = 1 << 0,
49cabdff1aSopenharmony_ci    PNG_PLTE = 1 << 1,
50cabdff1aSopenharmony_ci};
51cabdff1aSopenharmony_ci
52cabdff1aSopenharmony_cienum PNGImageState {
53cabdff1aSopenharmony_ci    PNG_IDAT     = 1 << 0,
54cabdff1aSopenharmony_ci    PNG_ALLIMAGE = 1 << 1,
55cabdff1aSopenharmony_ci};
56cabdff1aSopenharmony_ci
57cabdff1aSopenharmony_citypedef struct PNGDecContext {
58cabdff1aSopenharmony_ci    PNGDSPContext dsp;
59cabdff1aSopenharmony_ci    AVCodecContext *avctx;
60cabdff1aSopenharmony_ci
61cabdff1aSopenharmony_ci    GetByteContext gb;
62cabdff1aSopenharmony_ci    ThreadFrame last_picture;
63cabdff1aSopenharmony_ci    ThreadFrame picture;
64cabdff1aSopenharmony_ci
65cabdff1aSopenharmony_ci    AVDictionary *frame_metadata;
66cabdff1aSopenharmony_ci
67cabdff1aSopenharmony_ci    uint8_t  iccp_name[82];
68cabdff1aSopenharmony_ci    uint8_t *iccp_data;
69cabdff1aSopenharmony_ci    size_t   iccp_data_len;
70cabdff1aSopenharmony_ci
71cabdff1aSopenharmony_ci    int stereo_mode;
72cabdff1aSopenharmony_ci
73cabdff1aSopenharmony_ci    int have_chrm;
74cabdff1aSopenharmony_ci    uint32_t white_point[2];
75cabdff1aSopenharmony_ci    uint32_t display_primaries[3][2];
76cabdff1aSopenharmony_ci
77cabdff1aSopenharmony_ci    enum PNGHeaderState hdr_state;
78cabdff1aSopenharmony_ci    enum PNGImageState pic_state;
79cabdff1aSopenharmony_ci    int width, height;
80cabdff1aSopenharmony_ci    int cur_w, cur_h;
81cabdff1aSopenharmony_ci    int x_offset, y_offset;
82cabdff1aSopenharmony_ci    uint8_t dispose_op, blend_op;
83cabdff1aSopenharmony_ci    int bit_depth;
84cabdff1aSopenharmony_ci    int color_type;
85cabdff1aSopenharmony_ci    int compression_type;
86cabdff1aSopenharmony_ci    int interlace_type;
87cabdff1aSopenharmony_ci    int filter_type;
88cabdff1aSopenharmony_ci    int channels;
89cabdff1aSopenharmony_ci    int bits_per_pixel;
90cabdff1aSopenharmony_ci    int bpp;
91cabdff1aSopenharmony_ci    int has_trns;
92cabdff1aSopenharmony_ci    uint8_t transparent_color_be[6];
93cabdff1aSopenharmony_ci
94cabdff1aSopenharmony_ci    uint32_t palette[256];
95cabdff1aSopenharmony_ci    uint8_t *crow_buf;
96cabdff1aSopenharmony_ci    uint8_t *last_row;
97cabdff1aSopenharmony_ci    unsigned int last_row_size;
98cabdff1aSopenharmony_ci    uint8_t *tmp_row;
99cabdff1aSopenharmony_ci    unsigned int tmp_row_size;
100cabdff1aSopenharmony_ci    uint8_t *buffer;
101cabdff1aSopenharmony_ci    int buffer_size;
102cabdff1aSopenharmony_ci    int pass;
103cabdff1aSopenharmony_ci    int crow_size; /* compressed row size (include filter type) */
104cabdff1aSopenharmony_ci    int row_size; /* decompressed row size */
105cabdff1aSopenharmony_ci    int pass_row_size; /* decompress row size of the current pass */
106cabdff1aSopenharmony_ci    int y;
107cabdff1aSopenharmony_ci    FFZStream zstream;
108cabdff1aSopenharmony_ci} PNGDecContext;
109cabdff1aSopenharmony_ci
110cabdff1aSopenharmony_ci/* Mask to determine which pixels are valid in a pass */
111cabdff1aSopenharmony_cistatic const uint8_t png_pass_mask[NB_PASSES] = {
112cabdff1aSopenharmony_ci    0x01, 0x01, 0x11, 0x11, 0x55, 0x55, 0xff,
113cabdff1aSopenharmony_ci};
114cabdff1aSopenharmony_ci
115cabdff1aSopenharmony_ci/* Mask to determine which y pixels can be written in a pass */
116cabdff1aSopenharmony_cistatic const uint8_t png_pass_dsp_ymask[NB_PASSES] = {
117cabdff1aSopenharmony_ci    0xff, 0xff, 0x0f, 0xff, 0x33, 0xff, 0x55,
118cabdff1aSopenharmony_ci};
119cabdff1aSopenharmony_ci
120cabdff1aSopenharmony_ci/* Mask to determine which pixels to overwrite while displaying */
121cabdff1aSopenharmony_cistatic const uint8_t png_pass_dsp_mask[NB_PASSES] = {
122cabdff1aSopenharmony_ci    0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff
123cabdff1aSopenharmony_ci};
124cabdff1aSopenharmony_ci
125cabdff1aSopenharmony_ci/* NOTE: we try to construct a good looking image at each pass. width
126cabdff1aSopenharmony_ci * is the original image width. We also do pixel format conversion at
127cabdff1aSopenharmony_ci * this stage */
128cabdff1aSopenharmony_cistatic void png_put_interlaced_row(uint8_t *dst, int width,
129cabdff1aSopenharmony_ci                                   int bits_per_pixel, int pass,
130cabdff1aSopenharmony_ci                                   int color_type, const uint8_t *src)
131cabdff1aSopenharmony_ci{
132cabdff1aSopenharmony_ci    int x, mask, dsp_mask, j, src_x, b, bpp;
133cabdff1aSopenharmony_ci    uint8_t *d;
134cabdff1aSopenharmony_ci    const uint8_t *s;
135cabdff1aSopenharmony_ci
136cabdff1aSopenharmony_ci    mask     = png_pass_mask[pass];
137cabdff1aSopenharmony_ci    dsp_mask = png_pass_dsp_mask[pass];
138cabdff1aSopenharmony_ci
139cabdff1aSopenharmony_ci    switch (bits_per_pixel) {
140cabdff1aSopenharmony_ci    case 1:
141cabdff1aSopenharmony_ci        src_x = 0;
142cabdff1aSopenharmony_ci        for (x = 0; x < width; x++) {
143cabdff1aSopenharmony_ci            j = (x & 7);
144cabdff1aSopenharmony_ci            if ((dsp_mask << j) & 0x80) {
145cabdff1aSopenharmony_ci                b = (src[src_x >> 3] >> (7 - (src_x & 7))) & 1;
146cabdff1aSopenharmony_ci                dst[x >> 3] &= 0xFF7F>>j;
147cabdff1aSopenharmony_ci                dst[x >> 3] |= b << (7 - j);
148cabdff1aSopenharmony_ci            }
149cabdff1aSopenharmony_ci            if ((mask << j) & 0x80)
150cabdff1aSopenharmony_ci                src_x++;
151cabdff1aSopenharmony_ci        }
152cabdff1aSopenharmony_ci        break;
153cabdff1aSopenharmony_ci    case 2:
154cabdff1aSopenharmony_ci        src_x = 0;
155cabdff1aSopenharmony_ci        for (x = 0; x < width; x++) {
156cabdff1aSopenharmony_ci            int j2 = 2 * (x & 3);
157cabdff1aSopenharmony_ci            j = (x & 7);
158cabdff1aSopenharmony_ci            if ((dsp_mask << j) & 0x80) {
159cabdff1aSopenharmony_ci                b = (src[src_x >> 2] >> (6 - 2*(src_x & 3))) & 3;
160cabdff1aSopenharmony_ci                dst[x >> 2] &= 0xFF3F>>j2;
161cabdff1aSopenharmony_ci                dst[x >> 2] |= b << (6 - j2);
162cabdff1aSopenharmony_ci            }
163cabdff1aSopenharmony_ci            if ((mask << j) & 0x80)
164cabdff1aSopenharmony_ci                src_x++;
165cabdff1aSopenharmony_ci        }
166cabdff1aSopenharmony_ci        break;
167cabdff1aSopenharmony_ci    case 4:
168cabdff1aSopenharmony_ci        src_x = 0;
169cabdff1aSopenharmony_ci        for (x = 0; x < width; x++) {
170cabdff1aSopenharmony_ci            int j2 = 4*(x&1);
171cabdff1aSopenharmony_ci            j = (x & 7);
172cabdff1aSopenharmony_ci            if ((dsp_mask << j) & 0x80) {
173cabdff1aSopenharmony_ci                b = (src[src_x >> 1] >> (4 - 4*(src_x & 1))) & 15;
174cabdff1aSopenharmony_ci                dst[x >> 1] &= 0xFF0F>>j2;
175cabdff1aSopenharmony_ci                dst[x >> 1] |= b << (4 - j2);
176cabdff1aSopenharmony_ci            }
177cabdff1aSopenharmony_ci            if ((mask << j) & 0x80)
178cabdff1aSopenharmony_ci                src_x++;
179cabdff1aSopenharmony_ci        }
180cabdff1aSopenharmony_ci        break;
181cabdff1aSopenharmony_ci    default:
182cabdff1aSopenharmony_ci        bpp = bits_per_pixel >> 3;
183cabdff1aSopenharmony_ci        d   = dst;
184cabdff1aSopenharmony_ci        s   = src;
185cabdff1aSopenharmony_ci            for (x = 0; x < width; x++) {
186cabdff1aSopenharmony_ci                j = x & 7;
187cabdff1aSopenharmony_ci                if ((dsp_mask << j) & 0x80) {
188cabdff1aSopenharmony_ci                    memcpy(d, s, bpp);
189cabdff1aSopenharmony_ci                }
190cabdff1aSopenharmony_ci                d += bpp;
191cabdff1aSopenharmony_ci                if ((mask << j) & 0x80)
192cabdff1aSopenharmony_ci                    s += bpp;
193cabdff1aSopenharmony_ci            }
194cabdff1aSopenharmony_ci        break;
195cabdff1aSopenharmony_ci    }
196cabdff1aSopenharmony_ci}
197cabdff1aSopenharmony_ci
198cabdff1aSopenharmony_civoid ff_add_png_paeth_prediction(uint8_t *dst, uint8_t *src, uint8_t *top,
199cabdff1aSopenharmony_ci                                 int w, int bpp)
200cabdff1aSopenharmony_ci{
201cabdff1aSopenharmony_ci    int i;
202cabdff1aSopenharmony_ci    for (i = 0; i < w; i++) {
203cabdff1aSopenharmony_ci        int a, b, c, p, pa, pb, pc;
204cabdff1aSopenharmony_ci
205cabdff1aSopenharmony_ci        a = dst[i - bpp];
206cabdff1aSopenharmony_ci        b = top[i];
207cabdff1aSopenharmony_ci        c = top[i - bpp];
208cabdff1aSopenharmony_ci
209cabdff1aSopenharmony_ci        p  = b - c;
210cabdff1aSopenharmony_ci        pc = a - c;
211cabdff1aSopenharmony_ci
212cabdff1aSopenharmony_ci        pa = abs(p);
213cabdff1aSopenharmony_ci        pb = abs(pc);
214cabdff1aSopenharmony_ci        pc = abs(p + pc);
215cabdff1aSopenharmony_ci
216cabdff1aSopenharmony_ci        if (pa <= pb && pa <= pc)
217cabdff1aSopenharmony_ci            p = a;
218cabdff1aSopenharmony_ci        else if (pb <= pc)
219cabdff1aSopenharmony_ci            p = b;
220cabdff1aSopenharmony_ci        else
221cabdff1aSopenharmony_ci            p = c;
222cabdff1aSopenharmony_ci        dst[i] = p + src[i];
223cabdff1aSopenharmony_ci    }
224cabdff1aSopenharmony_ci}
225cabdff1aSopenharmony_ci
226cabdff1aSopenharmony_ci#define UNROLL1(bpp, op)                                                      \
227cabdff1aSopenharmony_ci    {                                                                         \
228cabdff1aSopenharmony_ci        r = dst[0];                                                           \
229cabdff1aSopenharmony_ci        if (bpp >= 2)                                                         \
230cabdff1aSopenharmony_ci            g = dst[1];                                                       \
231cabdff1aSopenharmony_ci        if (bpp >= 3)                                                         \
232cabdff1aSopenharmony_ci            b = dst[2];                                                       \
233cabdff1aSopenharmony_ci        if (bpp >= 4)                                                         \
234cabdff1aSopenharmony_ci            a = dst[3];                                                       \
235cabdff1aSopenharmony_ci        for (; i <= size - bpp; i += bpp) {                                   \
236cabdff1aSopenharmony_ci            dst[i + 0] = r = op(r, src[i + 0], last[i + 0]);                  \
237cabdff1aSopenharmony_ci            if (bpp == 1)                                                     \
238cabdff1aSopenharmony_ci                continue;                                                     \
239cabdff1aSopenharmony_ci            dst[i + 1] = g = op(g, src[i + 1], last[i + 1]);                  \
240cabdff1aSopenharmony_ci            if (bpp == 2)                                                     \
241cabdff1aSopenharmony_ci                continue;                                                     \
242cabdff1aSopenharmony_ci            dst[i + 2] = b = op(b, src[i + 2], last[i + 2]);                  \
243cabdff1aSopenharmony_ci            if (bpp == 3)                                                     \
244cabdff1aSopenharmony_ci                continue;                                                     \
245cabdff1aSopenharmony_ci            dst[i + 3] = a = op(a, src[i + 3], last[i + 3]);                  \
246cabdff1aSopenharmony_ci        }                                                                     \
247cabdff1aSopenharmony_ci    }
248cabdff1aSopenharmony_ci
249cabdff1aSopenharmony_ci#define UNROLL_FILTER(op)                                                     \
250cabdff1aSopenharmony_ci    if (bpp == 1) {                                                           \
251cabdff1aSopenharmony_ci        UNROLL1(1, op)                                                        \
252cabdff1aSopenharmony_ci    } else if (bpp == 2) {                                                    \
253cabdff1aSopenharmony_ci        UNROLL1(2, op)                                                        \
254cabdff1aSopenharmony_ci    } else if (bpp == 3) {                                                    \
255cabdff1aSopenharmony_ci        UNROLL1(3, op)                                                        \
256cabdff1aSopenharmony_ci    } else if (bpp == 4) {                                                    \
257cabdff1aSopenharmony_ci        UNROLL1(4, op)                                                        \
258cabdff1aSopenharmony_ci    }                                                                         \
259cabdff1aSopenharmony_ci    for (; i < size; i++) {                                                   \
260cabdff1aSopenharmony_ci        dst[i] = op(dst[i - bpp], src[i], last[i]);                           \
261cabdff1aSopenharmony_ci    }
262cabdff1aSopenharmony_ci
263cabdff1aSopenharmony_ci/* NOTE: 'dst' can be equal to 'last' */
264cabdff1aSopenharmony_civoid ff_png_filter_row(PNGDSPContext *dsp, uint8_t *dst, int filter_type,
265cabdff1aSopenharmony_ci                       uint8_t *src, uint8_t *last, int size, int bpp)
266cabdff1aSopenharmony_ci{
267cabdff1aSopenharmony_ci    int i, p, r, g, b, a;
268cabdff1aSopenharmony_ci
269cabdff1aSopenharmony_ci    switch (filter_type) {
270cabdff1aSopenharmony_ci    case PNG_FILTER_VALUE_NONE:
271cabdff1aSopenharmony_ci        memcpy(dst, src, size);
272cabdff1aSopenharmony_ci        break;
273cabdff1aSopenharmony_ci    case PNG_FILTER_VALUE_SUB:
274cabdff1aSopenharmony_ci        for (i = 0; i < bpp; i++)
275cabdff1aSopenharmony_ci            dst[i] = src[i];
276cabdff1aSopenharmony_ci        if (bpp == 4) {
277cabdff1aSopenharmony_ci            p = *(int *)dst;
278cabdff1aSopenharmony_ci            for (; i < size; i += bpp) {
279cabdff1aSopenharmony_ci                unsigned s = *(int *)(src + i);
280cabdff1aSopenharmony_ci                p = ((s & 0x7f7f7f7f) + (p & 0x7f7f7f7f)) ^ ((s ^ p) & 0x80808080);
281cabdff1aSopenharmony_ci                *(int *)(dst + i) = p;
282cabdff1aSopenharmony_ci            }
283cabdff1aSopenharmony_ci        } else {
284cabdff1aSopenharmony_ci#define OP_SUB(x, s, l) ((x) + (s))
285cabdff1aSopenharmony_ci            UNROLL_FILTER(OP_SUB);
286cabdff1aSopenharmony_ci        }
287cabdff1aSopenharmony_ci        break;
288cabdff1aSopenharmony_ci    case PNG_FILTER_VALUE_UP:
289cabdff1aSopenharmony_ci        dsp->add_bytes_l2(dst, src, last, size);
290cabdff1aSopenharmony_ci        break;
291cabdff1aSopenharmony_ci    case PNG_FILTER_VALUE_AVG:
292cabdff1aSopenharmony_ci        for (i = 0; i < bpp; i++) {
293cabdff1aSopenharmony_ci            p      = (last[i] >> 1);
294cabdff1aSopenharmony_ci            dst[i] = p + src[i];
295cabdff1aSopenharmony_ci        }
296cabdff1aSopenharmony_ci#define OP_AVG(x, s, l) (((((x) + (l)) >> 1) + (s)) & 0xff)
297cabdff1aSopenharmony_ci        UNROLL_FILTER(OP_AVG);
298cabdff1aSopenharmony_ci        break;
299cabdff1aSopenharmony_ci    case PNG_FILTER_VALUE_PAETH:
300cabdff1aSopenharmony_ci        for (i = 0; i < bpp; i++) {
301cabdff1aSopenharmony_ci            p      = last[i];
302cabdff1aSopenharmony_ci            dst[i] = p + src[i];
303cabdff1aSopenharmony_ci        }
304cabdff1aSopenharmony_ci        if (bpp > 2 && size > 4) {
305cabdff1aSopenharmony_ci            /* would write off the end of the array if we let it process
306cabdff1aSopenharmony_ci             * the last pixel with bpp=3 */
307cabdff1aSopenharmony_ci            int w = (bpp & 3) ? size - 3 : size;
308cabdff1aSopenharmony_ci
309cabdff1aSopenharmony_ci            if (w > i) {
310cabdff1aSopenharmony_ci                dsp->add_paeth_prediction(dst + i, src + i, last + i, size - i, bpp);
311cabdff1aSopenharmony_ci                i = w;
312cabdff1aSopenharmony_ci            }
313cabdff1aSopenharmony_ci        }
314cabdff1aSopenharmony_ci        ff_add_png_paeth_prediction(dst + i, src + i, last + i, size - i, bpp);
315cabdff1aSopenharmony_ci        break;
316cabdff1aSopenharmony_ci    }
317cabdff1aSopenharmony_ci}
318cabdff1aSopenharmony_ci
319cabdff1aSopenharmony_ci/* This used to be called "deloco" in FFmpeg
320cabdff1aSopenharmony_ci * and is actually an inverse reversible colorspace transformation */
321cabdff1aSopenharmony_ci#define YUV2RGB(NAME, TYPE) \
322cabdff1aSopenharmony_cistatic void deloco_ ## NAME(TYPE *dst, int size, int alpha) \
323cabdff1aSopenharmony_ci{ \
324cabdff1aSopenharmony_ci    int i; \
325cabdff1aSopenharmony_ci    for (i = 0; i < size - 2; i += 3 + alpha) { \
326cabdff1aSopenharmony_ci        int g = dst [i + 1]; \
327cabdff1aSopenharmony_ci        dst[i + 0] += g; \
328cabdff1aSopenharmony_ci        dst[i + 2] += g; \
329cabdff1aSopenharmony_ci    } \
330cabdff1aSopenharmony_ci}
331cabdff1aSopenharmony_ci
332cabdff1aSopenharmony_ciYUV2RGB(rgb8, uint8_t)
333cabdff1aSopenharmony_ciYUV2RGB(rgb16, uint16_t)
334cabdff1aSopenharmony_ci
335cabdff1aSopenharmony_cistatic int percent_missing(PNGDecContext *s)
336cabdff1aSopenharmony_ci{
337cabdff1aSopenharmony_ci    if (s->interlace_type) {
338cabdff1aSopenharmony_ci        return 100 - 100 * s->pass / (NB_PASSES - 1);
339cabdff1aSopenharmony_ci    } else {
340cabdff1aSopenharmony_ci        return 100 - 100 * s->y / s->cur_h;
341cabdff1aSopenharmony_ci    }
342cabdff1aSopenharmony_ci}
343cabdff1aSopenharmony_ci
344cabdff1aSopenharmony_ci/* process exactly one decompressed row */
345cabdff1aSopenharmony_cistatic void png_handle_row(PNGDecContext *s, uint8_t *dst, ptrdiff_t dst_stride)
346cabdff1aSopenharmony_ci{
347cabdff1aSopenharmony_ci    uint8_t *ptr, *last_row;
348cabdff1aSopenharmony_ci    int got_line;
349cabdff1aSopenharmony_ci
350cabdff1aSopenharmony_ci    if (!s->interlace_type) {
351cabdff1aSopenharmony_ci        ptr = dst + dst_stride * (s->y + s->y_offset) + s->x_offset * s->bpp;
352cabdff1aSopenharmony_ci        if (s->y == 0)
353cabdff1aSopenharmony_ci            last_row = s->last_row;
354cabdff1aSopenharmony_ci        else
355cabdff1aSopenharmony_ci            last_row = ptr - dst_stride;
356cabdff1aSopenharmony_ci
357cabdff1aSopenharmony_ci        ff_png_filter_row(&s->dsp, ptr, s->crow_buf[0], s->crow_buf + 1,
358cabdff1aSopenharmony_ci                          last_row, s->row_size, s->bpp);
359cabdff1aSopenharmony_ci        /* loco lags by 1 row so that it doesn't interfere with top prediction */
360cabdff1aSopenharmony_ci        if (s->filter_type == PNG_FILTER_TYPE_LOCO && s->y > 0) {
361cabdff1aSopenharmony_ci            if (s->bit_depth == 16) {
362cabdff1aSopenharmony_ci                deloco_rgb16((uint16_t *)(ptr - dst_stride), s->row_size / 2,
363cabdff1aSopenharmony_ci                             s->color_type == PNG_COLOR_TYPE_RGB_ALPHA);
364cabdff1aSopenharmony_ci            } else {
365cabdff1aSopenharmony_ci                deloco_rgb8(ptr - dst_stride, s->row_size,
366cabdff1aSopenharmony_ci                            s->color_type == PNG_COLOR_TYPE_RGB_ALPHA);
367cabdff1aSopenharmony_ci            }
368cabdff1aSopenharmony_ci        }
369cabdff1aSopenharmony_ci        s->y++;
370cabdff1aSopenharmony_ci        if (s->y == s->cur_h) {
371cabdff1aSopenharmony_ci            s->pic_state |= PNG_ALLIMAGE;
372cabdff1aSopenharmony_ci            if (s->filter_type == PNG_FILTER_TYPE_LOCO) {
373cabdff1aSopenharmony_ci                if (s->bit_depth == 16) {
374cabdff1aSopenharmony_ci                    deloco_rgb16((uint16_t *)ptr, s->row_size / 2,
375cabdff1aSopenharmony_ci                                 s->color_type == PNG_COLOR_TYPE_RGB_ALPHA);
376cabdff1aSopenharmony_ci                } else {
377cabdff1aSopenharmony_ci                    deloco_rgb8(ptr, s->row_size,
378cabdff1aSopenharmony_ci                                s->color_type == PNG_COLOR_TYPE_RGB_ALPHA);
379cabdff1aSopenharmony_ci                }
380cabdff1aSopenharmony_ci            }
381cabdff1aSopenharmony_ci        }
382cabdff1aSopenharmony_ci    } else {
383cabdff1aSopenharmony_ci        got_line = 0;
384cabdff1aSopenharmony_ci        for (;;) {
385cabdff1aSopenharmony_ci            ptr = dst + dst_stride * (s->y + s->y_offset) + s->x_offset * s->bpp;
386cabdff1aSopenharmony_ci            if ((ff_png_pass_ymask[s->pass] << (s->y & 7)) & 0x80) {
387cabdff1aSopenharmony_ci                /* if we already read one row, it is time to stop to
388cabdff1aSopenharmony_ci                 * wait for the next one */
389cabdff1aSopenharmony_ci                if (got_line)
390cabdff1aSopenharmony_ci                    break;
391cabdff1aSopenharmony_ci                ff_png_filter_row(&s->dsp, s->tmp_row, s->crow_buf[0], s->crow_buf + 1,
392cabdff1aSopenharmony_ci                                  s->last_row, s->pass_row_size, s->bpp);
393cabdff1aSopenharmony_ci                FFSWAP(uint8_t *, s->last_row, s->tmp_row);
394cabdff1aSopenharmony_ci                FFSWAP(unsigned int, s->last_row_size, s->tmp_row_size);
395cabdff1aSopenharmony_ci                got_line = 1;
396cabdff1aSopenharmony_ci            }
397cabdff1aSopenharmony_ci            if ((png_pass_dsp_ymask[s->pass] << (s->y & 7)) & 0x80) {
398cabdff1aSopenharmony_ci                png_put_interlaced_row(ptr, s->cur_w, s->bits_per_pixel, s->pass,
399cabdff1aSopenharmony_ci                                       s->color_type, s->last_row);
400cabdff1aSopenharmony_ci            }
401cabdff1aSopenharmony_ci            s->y++;
402cabdff1aSopenharmony_ci            if (s->y == s->cur_h) {
403cabdff1aSopenharmony_ci                memset(s->last_row, 0, s->row_size);
404cabdff1aSopenharmony_ci                for (;;) {
405cabdff1aSopenharmony_ci                    if (s->pass == NB_PASSES - 1) {
406cabdff1aSopenharmony_ci                        s->pic_state |= PNG_ALLIMAGE;
407cabdff1aSopenharmony_ci                        goto the_end;
408cabdff1aSopenharmony_ci                    } else {
409cabdff1aSopenharmony_ci                        s->pass++;
410cabdff1aSopenharmony_ci                        s->y = 0;
411cabdff1aSopenharmony_ci                        s->pass_row_size = ff_png_pass_row_size(s->pass,
412cabdff1aSopenharmony_ci                                                                s->bits_per_pixel,
413cabdff1aSopenharmony_ci                                                                s->cur_w);
414cabdff1aSopenharmony_ci                        s->crow_size = s->pass_row_size + 1;
415cabdff1aSopenharmony_ci                        if (s->pass_row_size != 0)
416cabdff1aSopenharmony_ci                            break;
417cabdff1aSopenharmony_ci                        /* skip pass if empty row */
418cabdff1aSopenharmony_ci                    }
419cabdff1aSopenharmony_ci                }
420cabdff1aSopenharmony_ci            }
421cabdff1aSopenharmony_ci        }
422cabdff1aSopenharmony_cithe_end:;
423cabdff1aSopenharmony_ci    }
424cabdff1aSopenharmony_ci}
425cabdff1aSopenharmony_ci
426cabdff1aSopenharmony_cistatic int png_decode_idat(PNGDecContext *s, GetByteContext *gb,
427cabdff1aSopenharmony_ci                           uint8_t *dst, ptrdiff_t dst_stride)
428cabdff1aSopenharmony_ci{
429cabdff1aSopenharmony_ci    z_stream *const zstream = &s->zstream.zstream;
430cabdff1aSopenharmony_ci    int ret;
431cabdff1aSopenharmony_ci    zstream->avail_in = bytestream2_get_bytes_left(gb);
432cabdff1aSopenharmony_ci    zstream->next_in  = gb->buffer;
433cabdff1aSopenharmony_ci
434cabdff1aSopenharmony_ci    /* decode one line if possible */
435cabdff1aSopenharmony_ci    while (zstream->avail_in > 0) {
436cabdff1aSopenharmony_ci        ret = inflate(zstream, Z_PARTIAL_FLUSH);
437cabdff1aSopenharmony_ci        if (ret != Z_OK && ret != Z_STREAM_END) {
438cabdff1aSopenharmony_ci            av_log(s->avctx, AV_LOG_ERROR, "inflate returned error %d\n", ret);
439cabdff1aSopenharmony_ci            return AVERROR_EXTERNAL;
440cabdff1aSopenharmony_ci        }
441cabdff1aSopenharmony_ci        if (zstream->avail_out == 0) {
442cabdff1aSopenharmony_ci            if (!(s->pic_state & PNG_ALLIMAGE)) {
443cabdff1aSopenharmony_ci                png_handle_row(s, dst, dst_stride);
444cabdff1aSopenharmony_ci            }
445cabdff1aSopenharmony_ci            zstream->avail_out = s->crow_size;
446cabdff1aSopenharmony_ci            zstream->next_out  = s->crow_buf;
447cabdff1aSopenharmony_ci        }
448cabdff1aSopenharmony_ci        if (ret == Z_STREAM_END && zstream->avail_in > 0) {
449cabdff1aSopenharmony_ci            av_log(s->avctx, AV_LOG_WARNING,
450cabdff1aSopenharmony_ci                   "%d undecompressed bytes left in buffer\n", zstream->avail_in);
451cabdff1aSopenharmony_ci            return 0;
452cabdff1aSopenharmony_ci        }
453cabdff1aSopenharmony_ci    }
454cabdff1aSopenharmony_ci    return 0;
455cabdff1aSopenharmony_ci}
456cabdff1aSopenharmony_ci
457cabdff1aSopenharmony_cistatic int decode_zbuf(AVBPrint *bp, const uint8_t *data,
458cabdff1aSopenharmony_ci                       const uint8_t *data_end, void *logctx)
459cabdff1aSopenharmony_ci{
460cabdff1aSopenharmony_ci    FFZStream z;
461cabdff1aSopenharmony_ci    z_stream *const zstream = &z.zstream;
462cabdff1aSopenharmony_ci    unsigned char *buf;
463cabdff1aSopenharmony_ci    unsigned buf_size;
464cabdff1aSopenharmony_ci    int ret = ff_inflate_init(&z, logctx);
465cabdff1aSopenharmony_ci    if (ret < 0)
466cabdff1aSopenharmony_ci        return ret;
467cabdff1aSopenharmony_ci
468cabdff1aSopenharmony_ci    zstream->next_in  = data;
469cabdff1aSopenharmony_ci    zstream->avail_in = data_end - data;
470cabdff1aSopenharmony_ci    av_bprint_init(bp, 0, AV_BPRINT_SIZE_UNLIMITED);
471cabdff1aSopenharmony_ci
472cabdff1aSopenharmony_ci    while (zstream->avail_in > 0) {
473cabdff1aSopenharmony_ci        av_bprint_get_buffer(bp, 2, &buf, &buf_size);
474cabdff1aSopenharmony_ci        if (buf_size < 2) {
475cabdff1aSopenharmony_ci            ret = AVERROR(ENOMEM);
476cabdff1aSopenharmony_ci            goto fail;
477cabdff1aSopenharmony_ci        }
478cabdff1aSopenharmony_ci        zstream->next_out  = buf;
479cabdff1aSopenharmony_ci        zstream->avail_out = buf_size - 1;
480cabdff1aSopenharmony_ci        ret = inflate(zstream, Z_PARTIAL_FLUSH);
481cabdff1aSopenharmony_ci        if (ret != Z_OK && ret != Z_STREAM_END) {
482cabdff1aSopenharmony_ci            ret = AVERROR_EXTERNAL;
483cabdff1aSopenharmony_ci            goto fail;
484cabdff1aSopenharmony_ci        }
485cabdff1aSopenharmony_ci        bp->len += zstream->next_out - buf;
486cabdff1aSopenharmony_ci        if (ret == Z_STREAM_END)
487cabdff1aSopenharmony_ci            break;
488cabdff1aSopenharmony_ci    }
489cabdff1aSopenharmony_ci    ff_inflate_end(&z);
490cabdff1aSopenharmony_ci    bp->str[bp->len] = 0;
491cabdff1aSopenharmony_ci    return 0;
492cabdff1aSopenharmony_ci
493cabdff1aSopenharmony_cifail:
494cabdff1aSopenharmony_ci    ff_inflate_end(&z);
495cabdff1aSopenharmony_ci    av_bprint_finalize(bp, NULL);
496cabdff1aSopenharmony_ci    return ret;
497cabdff1aSopenharmony_ci}
498cabdff1aSopenharmony_ci
499cabdff1aSopenharmony_cistatic uint8_t *iso88591_to_utf8(const uint8_t *in, size_t size_in)
500cabdff1aSopenharmony_ci{
501cabdff1aSopenharmony_ci    size_t extra = 0, i;
502cabdff1aSopenharmony_ci    uint8_t *out, *q;
503cabdff1aSopenharmony_ci
504cabdff1aSopenharmony_ci    for (i = 0; i < size_in; i++)
505cabdff1aSopenharmony_ci        extra += in[i] >= 0x80;
506cabdff1aSopenharmony_ci    if (size_in == SIZE_MAX || extra > SIZE_MAX - size_in - 1)
507cabdff1aSopenharmony_ci        return NULL;
508cabdff1aSopenharmony_ci    q = out = av_malloc(size_in + extra + 1);
509cabdff1aSopenharmony_ci    if (!out)
510cabdff1aSopenharmony_ci        return NULL;
511cabdff1aSopenharmony_ci    for (i = 0; i < size_in; i++) {
512cabdff1aSopenharmony_ci        if (in[i] >= 0x80) {
513cabdff1aSopenharmony_ci            *(q++) = 0xC0 | (in[i] >> 6);
514cabdff1aSopenharmony_ci            *(q++) = 0x80 | (in[i] & 0x3F);
515cabdff1aSopenharmony_ci        } else {
516cabdff1aSopenharmony_ci            *(q++) = in[i];
517cabdff1aSopenharmony_ci        }
518cabdff1aSopenharmony_ci    }
519cabdff1aSopenharmony_ci    *(q++) = 0;
520cabdff1aSopenharmony_ci    return out;
521cabdff1aSopenharmony_ci}
522cabdff1aSopenharmony_ci
523cabdff1aSopenharmony_cistatic int decode_text_chunk(PNGDecContext *s, GetByteContext *gb, int compressed)
524cabdff1aSopenharmony_ci{
525cabdff1aSopenharmony_ci    int ret, method;
526cabdff1aSopenharmony_ci    const uint8_t *data        = gb->buffer;
527cabdff1aSopenharmony_ci    const uint8_t *data_end    = gb->buffer_end;
528cabdff1aSopenharmony_ci    const uint8_t *keyword     = data;
529cabdff1aSopenharmony_ci    const uint8_t *keyword_end = memchr(keyword, 0, data_end - keyword);
530cabdff1aSopenharmony_ci    uint8_t *kw_utf8 = NULL, *text, *txt_utf8 = NULL;
531cabdff1aSopenharmony_ci    unsigned text_len;
532cabdff1aSopenharmony_ci    AVBPrint bp;
533cabdff1aSopenharmony_ci
534cabdff1aSopenharmony_ci    if (!keyword_end)
535cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
536cabdff1aSopenharmony_ci    data = keyword_end + 1;
537cabdff1aSopenharmony_ci
538cabdff1aSopenharmony_ci    if (compressed) {
539cabdff1aSopenharmony_ci        if (data == data_end)
540cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
541cabdff1aSopenharmony_ci        method = *(data++);
542cabdff1aSopenharmony_ci        if (method)
543cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
544cabdff1aSopenharmony_ci        if ((ret = decode_zbuf(&bp, data, data_end, s->avctx)) < 0)
545cabdff1aSopenharmony_ci            return ret;
546cabdff1aSopenharmony_ci        text_len = bp.len;
547cabdff1aSopenharmony_ci        ret = av_bprint_finalize(&bp, (char **)&text);
548cabdff1aSopenharmony_ci        if (ret < 0)
549cabdff1aSopenharmony_ci            return ret;
550cabdff1aSopenharmony_ci    } else {
551cabdff1aSopenharmony_ci        text = (uint8_t *)data;
552cabdff1aSopenharmony_ci        text_len = data_end - text;
553cabdff1aSopenharmony_ci    }
554cabdff1aSopenharmony_ci
555cabdff1aSopenharmony_ci    kw_utf8  = iso88591_to_utf8(keyword, keyword_end - keyword);
556cabdff1aSopenharmony_ci    txt_utf8 = iso88591_to_utf8(text, text_len);
557cabdff1aSopenharmony_ci    if (text != data)
558cabdff1aSopenharmony_ci        av_free(text);
559cabdff1aSopenharmony_ci    if (!(kw_utf8 && txt_utf8)) {
560cabdff1aSopenharmony_ci        av_free(kw_utf8);
561cabdff1aSopenharmony_ci        av_free(txt_utf8);
562cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
563cabdff1aSopenharmony_ci    }
564cabdff1aSopenharmony_ci
565cabdff1aSopenharmony_ci    av_dict_set(&s->frame_metadata, kw_utf8, txt_utf8,
566cabdff1aSopenharmony_ci                AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL);
567cabdff1aSopenharmony_ci    return 0;
568cabdff1aSopenharmony_ci}
569cabdff1aSopenharmony_ci
570cabdff1aSopenharmony_cistatic int decode_ihdr_chunk(AVCodecContext *avctx, PNGDecContext *s,
571cabdff1aSopenharmony_ci                             GetByteContext *gb)
572cabdff1aSopenharmony_ci{
573cabdff1aSopenharmony_ci    if (bytestream2_get_bytes_left(gb) != 13)
574cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
575cabdff1aSopenharmony_ci
576cabdff1aSopenharmony_ci    if (s->pic_state & PNG_IDAT) {
577cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "IHDR after IDAT\n");
578cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
579cabdff1aSopenharmony_ci    }
580cabdff1aSopenharmony_ci
581cabdff1aSopenharmony_ci    if (s->hdr_state & PNG_IHDR) {
582cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Multiple IHDR\n");
583cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
584cabdff1aSopenharmony_ci    }
585cabdff1aSopenharmony_ci
586cabdff1aSopenharmony_ci    s->width  = s->cur_w = bytestream2_get_be32(gb);
587cabdff1aSopenharmony_ci    s->height = s->cur_h = bytestream2_get_be32(gb);
588cabdff1aSopenharmony_ci    if (av_image_check_size(s->width, s->height, 0, avctx)) {
589cabdff1aSopenharmony_ci        s->cur_w = s->cur_h = s->width = s->height = 0;
590cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Invalid image size\n");
591cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
592cabdff1aSopenharmony_ci    }
593cabdff1aSopenharmony_ci    s->bit_depth        = bytestream2_get_byte(gb);
594cabdff1aSopenharmony_ci    if (s->bit_depth != 1 && s->bit_depth != 2 && s->bit_depth != 4 &&
595cabdff1aSopenharmony_ci        s->bit_depth != 8 && s->bit_depth != 16) {
596cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Invalid bit depth\n");
597cabdff1aSopenharmony_ci        goto error;
598cabdff1aSopenharmony_ci    }
599cabdff1aSopenharmony_ci    s->color_type       = bytestream2_get_byte(gb);
600cabdff1aSopenharmony_ci    s->compression_type = bytestream2_get_byte(gb);
601cabdff1aSopenharmony_ci    if (s->compression_type) {
602cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Invalid compression method %d\n", s->compression_type);
603cabdff1aSopenharmony_ci        goto error;
604cabdff1aSopenharmony_ci    }
605cabdff1aSopenharmony_ci    s->filter_type      = bytestream2_get_byte(gb);
606cabdff1aSopenharmony_ci    s->interlace_type   = bytestream2_get_byte(gb);
607cabdff1aSopenharmony_ci    s->hdr_state |= PNG_IHDR;
608cabdff1aSopenharmony_ci    if (avctx->debug & FF_DEBUG_PICT_INFO)
609cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_DEBUG, "width=%d height=%d depth=%d color_type=%d "
610cabdff1aSopenharmony_ci                "compression_type=%d filter_type=%d interlace_type=%d\n",
611cabdff1aSopenharmony_ci                s->width, s->height, s->bit_depth, s->color_type,
612cabdff1aSopenharmony_ci                s->compression_type, s->filter_type, s->interlace_type);
613cabdff1aSopenharmony_ci
614cabdff1aSopenharmony_ci    return 0;
615cabdff1aSopenharmony_cierror:
616cabdff1aSopenharmony_ci    s->cur_w = s->cur_h = s->width = s->height = 0;
617cabdff1aSopenharmony_ci    s->bit_depth = 8;
618cabdff1aSopenharmony_ci    return AVERROR_INVALIDDATA;
619cabdff1aSopenharmony_ci}
620cabdff1aSopenharmony_ci
621cabdff1aSopenharmony_cistatic int decode_phys_chunk(AVCodecContext *avctx, PNGDecContext *s,
622cabdff1aSopenharmony_ci                             GetByteContext *gb)
623cabdff1aSopenharmony_ci{
624cabdff1aSopenharmony_ci    if (s->pic_state & PNG_IDAT) {
625cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "pHYs after IDAT\n");
626cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
627cabdff1aSopenharmony_ci    }
628cabdff1aSopenharmony_ci    avctx->sample_aspect_ratio.num = bytestream2_get_be32(gb);
629cabdff1aSopenharmony_ci    avctx->sample_aspect_ratio.den = bytestream2_get_be32(gb);
630cabdff1aSopenharmony_ci    if (avctx->sample_aspect_ratio.num < 0 || avctx->sample_aspect_ratio.den < 0)
631cabdff1aSopenharmony_ci        avctx->sample_aspect_ratio = (AVRational){ 0, 1 };
632cabdff1aSopenharmony_ci    bytestream2_skip(gb, 1); /* unit specifier */
633cabdff1aSopenharmony_ci
634cabdff1aSopenharmony_ci    return 0;
635cabdff1aSopenharmony_ci}
636cabdff1aSopenharmony_ci
637cabdff1aSopenharmony_cistatic int decode_idat_chunk(AVCodecContext *avctx, PNGDecContext *s,
638cabdff1aSopenharmony_ci                             GetByteContext *gb, AVFrame *p)
639cabdff1aSopenharmony_ci{
640cabdff1aSopenharmony_ci    int ret;
641cabdff1aSopenharmony_ci    size_t byte_depth = s->bit_depth > 8 ? 2 : 1;
642cabdff1aSopenharmony_ci
643cabdff1aSopenharmony_ci    if (!p)
644cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
645cabdff1aSopenharmony_ci    if (!(s->hdr_state & PNG_IHDR)) {
646cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "IDAT without IHDR\n");
647cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
648cabdff1aSopenharmony_ci    }
649cabdff1aSopenharmony_ci    if (!(s->pic_state & PNG_IDAT)) {
650cabdff1aSopenharmony_ci        /* init image info */
651cabdff1aSopenharmony_ci        ret = ff_set_dimensions(avctx, s->width, s->height);
652cabdff1aSopenharmony_ci        if (ret < 0)
653cabdff1aSopenharmony_ci            return ret;
654cabdff1aSopenharmony_ci
655cabdff1aSopenharmony_ci        s->channels       = ff_png_get_nb_channels(s->color_type);
656cabdff1aSopenharmony_ci        s->bits_per_pixel = s->bit_depth * s->channels;
657cabdff1aSopenharmony_ci        s->bpp            = (s->bits_per_pixel + 7) >> 3;
658cabdff1aSopenharmony_ci        s->row_size       = (s->cur_w * s->bits_per_pixel + 7) >> 3;
659cabdff1aSopenharmony_ci
660cabdff1aSopenharmony_ci        if ((s->bit_depth == 2 || s->bit_depth == 4 || s->bit_depth == 8) &&
661cabdff1aSopenharmony_ci                s->color_type == PNG_COLOR_TYPE_RGB) {
662cabdff1aSopenharmony_ci            avctx->pix_fmt = AV_PIX_FMT_RGB24;
663cabdff1aSopenharmony_ci        } else if ((s->bit_depth == 2 || s->bit_depth == 4 || s->bit_depth == 8) &&
664cabdff1aSopenharmony_ci                s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
665cabdff1aSopenharmony_ci            avctx->pix_fmt = AV_PIX_FMT_RGBA;
666cabdff1aSopenharmony_ci        } else if ((s->bit_depth == 2 || s->bit_depth == 4 || s->bit_depth == 8) &&
667cabdff1aSopenharmony_ci                s->color_type == PNG_COLOR_TYPE_GRAY) {
668cabdff1aSopenharmony_ci            avctx->pix_fmt = AV_PIX_FMT_GRAY8;
669cabdff1aSopenharmony_ci        } else if (s->bit_depth == 16 &&
670cabdff1aSopenharmony_ci                s->color_type == PNG_COLOR_TYPE_GRAY) {
671cabdff1aSopenharmony_ci            avctx->pix_fmt = AV_PIX_FMT_GRAY16BE;
672cabdff1aSopenharmony_ci        } else if (s->bit_depth == 16 &&
673cabdff1aSopenharmony_ci                s->color_type == PNG_COLOR_TYPE_RGB) {
674cabdff1aSopenharmony_ci            avctx->pix_fmt = AV_PIX_FMT_RGB48BE;
675cabdff1aSopenharmony_ci        } else if (s->bit_depth == 16 &&
676cabdff1aSopenharmony_ci                s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
677cabdff1aSopenharmony_ci            avctx->pix_fmt = AV_PIX_FMT_RGBA64BE;
678cabdff1aSopenharmony_ci        } else if ((s->bits_per_pixel == 1 || s->bits_per_pixel == 2 || s->bits_per_pixel == 4 || s->bits_per_pixel == 8) &&
679cabdff1aSopenharmony_ci                s->color_type == PNG_COLOR_TYPE_PALETTE) {
680cabdff1aSopenharmony_ci            avctx->pix_fmt = avctx->codec_id == AV_CODEC_ID_APNG ? AV_PIX_FMT_RGBA : AV_PIX_FMT_PAL8;
681cabdff1aSopenharmony_ci        } else if (s->bit_depth == 1 && s->bits_per_pixel == 1 && avctx->codec_id != AV_CODEC_ID_APNG) {
682cabdff1aSopenharmony_ci            avctx->pix_fmt = AV_PIX_FMT_MONOBLACK;
683cabdff1aSopenharmony_ci        } else if (s->bit_depth == 8 &&
684cabdff1aSopenharmony_ci                s->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
685cabdff1aSopenharmony_ci            avctx->pix_fmt = AV_PIX_FMT_YA8;
686cabdff1aSopenharmony_ci        } else if (s->bit_depth == 16 &&
687cabdff1aSopenharmony_ci                s->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
688cabdff1aSopenharmony_ci            avctx->pix_fmt = AV_PIX_FMT_YA16BE;
689cabdff1aSopenharmony_ci        } else {
690cabdff1aSopenharmony_ci            avpriv_report_missing_feature(avctx,
691cabdff1aSopenharmony_ci                                          "Bit depth %d color type %d",
692cabdff1aSopenharmony_ci                                          s->bit_depth, s->color_type);
693cabdff1aSopenharmony_ci            return AVERROR_PATCHWELCOME;
694cabdff1aSopenharmony_ci        }
695cabdff1aSopenharmony_ci
696cabdff1aSopenharmony_ci        if (s->has_trns && s->color_type != PNG_COLOR_TYPE_PALETTE) {
697cabdff1aSopenharmony_ci            switch (avctx->pix_fmt) {
698cabdff1aSopenharmony_ci            case AV_PIX_FMT_RGB24:
699cabdff1aSopenharmony_ci                avctx->pix_fmt = AV_PIX_FMT_RGBA;
700cabdff1aSopenharmony_ci                break;
701cabdff1aSopenharmony_ci
702cabdff1aSopenharmony_ci            case AV_PIX_FMT_RGB48BE:
703cabdff1aSopenharmony_ci                avctx->pix_fmt = AV_PIX_FMT_RGBA64BE;
704cabdff1aSopenharmony_ci                break;
705cabdff1aSopenharmony_ci
706cabdff1aSopenharmony_ci            case AV_PIX_FMT_GRAY8:
707cabdff1aSopenharmony_ci                avctx->pix_fmt = AV_PIX_FMT_YA8;
708cabdff1aSopenharmony_ci                break;
709cabdff1aSopenharmony_ci
710cabdff1aSopenharmony_ci            case AV_PIX_FMT_GRAY16BE:
711cabdff1aSopenharmony_ci                avctx->pix_fmt = AV_PIX_FMT_YA16BE;
712cabdff1aSopenharmony_ci                break;
713cabdff1aSopenharmony_ci
714cabdff1aSopenharmony_ci            default:
715cabdff1aSopenharmony_ci                avpriv_request_sample(avctx, "bit depth %d "
716cabdff1aSopenharmony_ci                        "and color type %d with TRNS",
717cabdff1aSopenharmony_ci                        s->bit_depth, s->color_type);
718cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
719cabdff1aSopenharmony_ci            }
720cabdff1aSopenharmony_ci
721cabdff1aSopenharmony_ci            s->bpp += byte_depth;
722cabdff1aSopenharmony_ci        }
723cabdff1aSopenharmony_ci
724cabdff1aSopenharmony_ci        ff_thread_release_ext_buffer(avctx, &s->picture);
725cabdff1aSopenharmony_ci        if (s->dispose_op == APNG_DISPOSE_OP_PREVIOUS) {
726cabdff1aSopenharmony_ci            /* We only need a buffer for the current picture. */
727cabdff1aSopenharmony_ci            ret = ff_thread_get_buffer(avctx, p, 0);
728cabdff1aSopenharmony_ci            if (ret < 0)
729cabdff1aSopenharmony_ci                return ret;
730cabdff1aSopenharmony_ci        } else if (s->dispose_op == APNG_DISPOSE_OP_BACKGROUND) {
731cabdff1aSopenharmony_ci            /* We need a buffer for the current picture as well as
732cabdff1aSopenharmony_ci             * a buffer for the reference to retain. */
733cabdff1aSopenharmony_ci            ret = ff_thread_get_ext_buffer(avctx, &s->picture,
734cabdff1aSopenharmony_ci                                           AV_GET_BUFFER_FLAG_REF);
735cabdff1aSopenharmony_ci            if (ret < 0)
736cabdff1aSopenharmony_ci                return ret;
737cabdff1aSopenharmony_ci            ret = ff_thread_get_buffer(avctx, p, 0);
738cabdff1aSopenharmony_ci            if (ret < 0)
739cabdff1aSopenharmony_ci                return ret;
740cabdff1aSopenharmony_ci        } else {
741cabdff1aSopenharmony_ci            /* The picture output this time and the reference to retain coincide. */
742cabdff1aSopenharmony_ci            if ((ret = ff_thread_get_ext_buffer(avctx, &s->picture,
743cabdff1aSopenharmony_ci                                                AV_GET_BUFFER_FLAG_REF)) < 0)
744cabdff1aSopenharmony_ci                return ret;
745cabdff1aSopenharmony_ci            ret = av_frame_ref(p, s->picture.f);
746cabdff1aSopenharmony_ci            if (ret < 0)
747cabdff1aSopenharmony_ci                return ret;
748cabdff1aSopenharmony_ci        }
749cabdff1aSopenharmony_ci
750cabdff1aSopenharmony_ci        p->pict_type        = AV_PICTURE_TYPE_I;
751cabdff1aSopenharmony_ci        p->key_frame        = 1;
752cabdff1aSopenharmony_ci        p->interlaced_frame = !!s->interlace_type;
753cabdff1aSopenharmony_ci
754cabdff1aSopenharmony_ci        ff_thread_finish_setup(avctx);
755cabdff1aSopenharmony_ci
756cabdff1aSopenharmony_ci        /* compute the compressed row size */
757cabdff1aSopenharmony_ci        if (!s->interlace_type) {
758cabdff1aSopenharmony_ci            s->crow_size = s->row_size + 1;
759cabdff1aSopenharmony_ci        } else {
760cabdff1aSopenharmony_ci            s->pass          = 0;
761cabdff1aSopenharmony_ci            s->pass_row_size = ff_png_pass_row_size(s->pass,
762cabdff1aSopenharmony_ci                    s->bits_per_pixel,
763cabdff1aSopenharmony_ci                    s->cur_w);
764cabdff1aSopenharmony_ci            s->crow_size = s->pass_row_size + 1;
765cabdff1aSopenharmony_ci        }
766cabdff1aSopenharmony_ci        ff_dlog(avctx, "row_size=%d crow_size =%d\n",
767cabdff1aSopenharmony_ci                s->row_size, s->crow_size);
768cabdff1aSopenharmony_ci
769cabdff1aSopenharmony_ci        /* copy the palette if needed */
770cabdff1aSopenharmony_ci        if (avctx->pix_fmt == AV_PIX_FMT_PAL8)
771cabdff1aSopenharmony_ci            memcpy(p->data[1], s->palette, 256 * sizeof(uint32_t));
772cabdff1aSopenharmony_ci        /* empty row is used if differencing to the first row */
773cabdff1aSopenharmony_ci        av_fast_padded_mallocz(&s->last_row, &s->last_row_size, s->row_size);
774cabdff1aSopenharmony_ci        if (!s->last_row)
775cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
776cabdff1aSopenharmony_ci        if (s->interlace_type ||
777cabdff1aSopenharmony_ci                s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
778cabdff1aSopenharmony_ci            av_fast_padded_malloc(&s->tmp_row, &s->tmp_row_size, s->row_size);
779cabdff1aSopenharmony_ci            if (!s->tmp_row)
780cabdff1aSopenharmony_ci                return AVERROR_INVALIDDATA;
781cabdff1aSopenharmony_ci        }
782cabdff1aSopenharmony_ci        /* compressed row */
783cabdff1aSopenharmony_ci        av_fast_padded_malloc(&s->buffer, &s->buffer_size, s->row_size + 16);
784cabdff1aSopenharmony_ci        if (!s->buffer)
785cabdff1aSopenharmony_ci            return AVERROR(ENOMEM);
786cabdff1aSopenharmony_ci
787cabdff1aSopenharmony_ci        /* we want crow_buf+1 to be 16-byte aligned */
788cabdff1aSopenharmony_ci        s->crow_buf          = s->buffer + 15;
789cabdff1aSopenharmony_ci        s->zstream.zstream.avail_out = s->crow_size;
790cabdff1aSopenharmony_ci        s->zstream.zstream.next_out  = s->crow_buf;
791cabdff1aSopenharmony_ci    }
792cabdff1aSopenharmony_ci
793cabdff1aSopenharmony_ci    s->pic_state |= PNG_IDAT;
794cabdff1aSopenharmony_ci
795cabdff1aSopenharmony_ci    /* set image to non-transparent bpp while decompressing */
796cabdff1aSopenharmony_ci    if (s->has_trns && s->color_type != PNG_COLOR_TYPE_PALETTE)
797cabdff1aSopenharmony_ci        s->bpp -= byte_depth;
798cabdff1aSopenharmony_ci
799cabdff1aSopenharmony_ci    ret = png_decode_idat(s, gb, p->data[0], p->linesize[0]);
800cabdff1aSopenharmony_ci
801cabdff1aSopenharmony_ci    if (s->has_trns && s->color_type != PNG_COLOR_TYPE_PALETTE)
802cabdff1aSopenharmony_ci        s->bpp += byte_depth;
803cabdff1aSopenharmony_ci
804cabdff1aSopenharmony_ci    if (ret < 0)
805cabdff1aSopenharmony_ci        return ret;
806cabdff1aSopenharmony_ci
807cabdff1aSopenharmony_ci    return 0;
808cabdff1aSopenharmony_ci}
809cabdff1aSopenharmony_ci
810cabdff1aSopenharmony_cistatic int decode_plte_chunk(AVCodecContext *avctx, PNGDecContext *s,
811cabdff1aSopenharmony_ci                             GetByteContext *gb)
812cabdff1aSopenharmony_ci{
813cabdff1aSopenharmony_ci    int length = bytestream2_get_bytes_left(gb);
814cabdff1aSopenharmony_ci    int n, i, r, g, b;
815cabdff1aSopenharmony_ci
816cabdff1aSopenharmony_ci    if ((length % 3) != 0 || length > 256 * 3)
817cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
818cabdff1aSopenharmony_ci    /* read the palette */
819cabdff1aSopenharmony_ci    n = length / 3;
820cabdff1aSopenharmony_ci    for (i = 0; i < n; i++) {
821cabdff1aSopenharmony_ci        r = bytestream2_get_byte(gb);
822cabdff1aSopenharmony_ci        g = bytestream2_get_byte(gb);
823cabdff1aSopenharmony_ci        b = bytestream2_get_byte(gb);
824cabdff1aSopenharmony_ci        s->palette[i] = (0xFFU << 24) | (r << 16) | (g << 8) | b;
825cabdff1aSopenharmony_ci    }
826cabdff1aSopenharmony_ci    for (; i < 256; i++)
827cabdff1aSopenharmony_ci        s->palette[i] = (0xFFU << 24);
828cabdff1aSopenharmony_ci    s->hdr_state |= PNG_PLTE;
829cabdff1aSopenharmony_ci
830cabdff1aSopenharmony_ci    return 0;
831cabdff1aSopenharmony_ci}
832cabdff1aSopenharmony_ci
833cabdff1aSopenharmony_cistatic int decode_trns_chunk(AVCodecContext *avctx, PNGDecContext *s,
834cabdff1aSopenharmony_ci                             GetByteContext *gb)
835cabdff1aSopenharmony_ci{
836cabdff1aSopenharmony_ci    int length = bytestream2_get_bytes_left(gb);
837cabdff1aSopenharmony_ci    int v, i;
838cabdff1aSopenharmony_ci
839cabdff1aSopenharmony_ci    if (!(s->hdr_state & PNG_IHDR)) {
840cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "trns before IHDR\n");
841cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
842cabdff1aSopenharmony_ci    }
843cabdff1aSopenharmony_ci
844cabdff1aSopenharmony_ci    if (s->pic_state & PNG_IDAT) {
845cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "trns after IDAT\n");
846cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
847cabdff1aSopenharmony_ci    }
848cabdff1aSopenharmony_ci
849cabdff1aSopenharmony_ci    if (s->color_type == PNG_COLOR_TYPE_PALETTE) {
850cabdff1aSopenharmony_ci        if (length > 256 || !(s->hdr_state & PNG_PLTE))
851cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
852cabdff1aSopenharmony_ci
853cabdff1aSopenharmony_ci        for (i = 0; i < length; i++) {
854cabdff1aSopenharmony_ci            unsigned v = bytestream2_get_byte(gb);
855cabdff1aSopenharmony_ci            s->palette[i] = (s->palette[i] & 0x00ffffff) | (v << 24);
856cabdff1aSopenharmony_ci        }
857cabdff1aSopenharmony_ci    } else if (s->color_type == PNG_COLOR_TYPE_GRAY || s->color_type == PNG_COLOR_TYPE_RGB) {
858cabdff1aSopenharmony_ci        if ((s->color_type == PNG_COLOR_TYPE_GRAY && length != 2) ||
859cabdff1aSopenharmony_ci            (s->color_type == PNG_COLOR_TYPE_RGB && length != 6) ||
860cabdff1aSopenharmony_ci            s->bit_depth == 1)
861cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
862cabdff1aSopenharmony_ci
863cabdff1aSopenharmony_ci        for (i = 0; i < length / 2; i++) {
864cabdff1aSopenharmony_ci            /* only use the least significant bits */
865cabdff1aSopenharmony_ci            v = av_mod_uintp2(bytestream2_get_be16(gb), s->bit_depth);
866cabdff1aSopenharmony_ci
867cabdff1aSopenharmony_ci            if (s->bit_depth > 8)
868cabdff1aSopenharmony_ci                AV_WB16(&s->transparent_color_be[2 * i], v);
869cabdff1aSopenharmony_ci            else
870cabdff1aSopenharmony_ci                s->transparent_color_be[i] = v;
871cabdff1aSopenharmony_ci        }
872cabdff1aSopenharmony_ci    } else {
873cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
874cabdff1aSopenharmony_ci    }
875cabdff1aSopenharmony_ci
876cabdff1aSopenharmony_ci    s->has_trns = 1;
877cabdff1aSopenharmony_ci
878cabdff1aSopenharmony_ci    return 0;
879cabdff1aSopenharmony_ci}
880cabdff1aSopenharmony_ci
881cabdff1aSopenharmony_cistatic int decode_iccp_chunk(PNGDecContext *s, GetByteContext *gb)
882cabdff1aSopenharmony_ci{
883cabdff1aSopenharmony_ci    int ret, cnt = 0;
884cabdff1aSopenharmony_ci    AVBPrint bp;
885cabdff1aSopenharmony_ci
886cabdff1aSopenharmony_ci    while ((s->iccp_name[cnt++] = bytestream2_get_byte(gb)) && cnt < 81);
887cabdff1aSopenharmony_ci    if (cnt > 80) {
888cabdff1aSopenharmony_ci        av_log(s->avctx, AV_LOG_ERROR, "iCCP with invalid name!\n");
889cabdff1aSopenharmony_ci        ret = AVERROR_INVALIDDATA;
890cabdff1aSopenharmony_ci        goto fail;
891cabdff1aSopenharmony_ci    }
892cabdff1aSopenharmony_ci
893cabdff1aSopenharmony_ci    if (bytestream2_get_byte(gb) != 0) {
894cabdff1aSopenharmony_ci        av_log(s->avctx, AV_LOG_ERROR, "iCCP with invalid compression!\n");
895cabdff1aSopenharmony_ci        ret =  AVERROR_INVALIDDATA;
896cabdff1aSopenharmony_ci        goto fail;
897cabdff1aSopenharmony_ci    }
898cabdff1aSopenharmony_ci
899cabdff1aSopenharmony_ci    if ((ret = decode_zbuf(&bp, gb->buffer, gb->buffer_end, s->avctx)) < 0)
900cabdff1aSopenharmony_ci        return ret;
901cabdff1aSopenharmony_ci
902cabdff1aSopenharmony_ci    av_freep(&s->iccp_data);
903cabdff1aSopenharmony_ci    ret = av_bprint_finalize(&bp, (char **)&s->iccp_data);
904cabdff1aSopenharmony_ci    if (ret < 0)
905cabdff1aSopenharmony_ci        return ret;
906cabdff1aSopenharmony_ci    s->iccp_data_len = bp.len;
907cabdff1aSopenharmony_ci
908cabdff1aSopenharmony_ci    return 0;
909cabdff1aSopenharmony_cifail:
910cabdff1aSopenharmony_ci    s->iccp_name[0] = 0;
911cabdff1aSopenharmony_ci    return ret;
912cabdff1aSopenharmony_ci}
913cabdff1aSopenharmony_ci
914cabdff1aSopenharmony_cistatic void handle_small_bpp(PNGDecContext *s, AVFrame *p)
915cabdff1aSopenharmony_ci{
916cabdff1aSopenharmony_ci    if (s->bits_per_pixel == 1 && s->color_type == PNG_COLOR_TYPE_PALETTE) {
917cabdff1aSopenharmony_ci        int i, j, k;
918cabdff1aSopenharmony_ci        uint8_t *pd = p->data[0];
919cabdff1aSopenharmony_ci        for (j = 0; j < s->height; j++) {
920cabdff1aSopenharmony_ci            i = s->width / 8;
921cabdff1aSopenharmony_ci            for (k = 7; k >= 1; k--)
922cabdff1aSopenharmony_ci                if ((s->width&7) >= k)
923cabdff1aSopenharmony_ci                    pd[8*i + k - 1] = (pd[i]>>8-k) & 1;
924cabdff1aSopenharmony_ci            for (i--; i >= 0; i--) {
925cabdff1aSopenharmony_ci                pd[8*i + 7]=  pd[i]     & 1;
926cabdff1aSopenharmony_ci                pd[8*i + 6]= (pd[i]>>1) & 1;
927cabdff1aSopenharmony_ci                pd[8*i + 5]= (pd[i]>>2) & 1;
928cabdff1aSopenharmony_ci                pd[8*i + 4]= (pd[i]>>3) & 1;
929cabdff1aSopenharmony_ci                pd[8*i + 3]= (pd[i]>>4) & 1;
930cabdff1aSopenharmony_ci                pd[8*i + 2]= (pd[i]>>5) & 1;
931cabdff1aSopenharmony_ci                pd[8*i + 1]= (pd[i]>>6) & 1;
932cabdff1aSopenharmony_ci                pd[8*i + 0]=  pd[i]>>7;
933cabdff1aSopenharmony_ci            }
934cabdff1aSopenharmony_ci            pd += p->linesize[0];
935cabdff1aSopenharmony_ci        }
936cabdff1aSopenharmony_ci    } else if (s->bits_per_pixel == 2) {
937cabdff1aSopenharmony_ci        int i, j;
938cabdff1aSopenharmony_ci        uint8_t *pd = p->data[0];
939cabdff1aSopenharmony_ci        for (j = 0; j < s->height; j++) {
940cabdff1aSopenharmony_ci            i = s->width / 4;
941cabdff1aSopenharmony_ci            if (s->color_type == PNG_COLOR_TYPE_PALETTE) {
942cabdff1aSopenharmony_ci                if ((s->width&3) >= 3) pd[4*i + 2]= (pd[i] >> 2) & 3;
943cabdff1aSopenharmony_ci                if ((s->width&3) >= 2) pd[4*i + 1]= (pd[i] >> 4) & 3;
944cabdff1aSopenharmony_ci                if ((s->width&3) >= 1) pd[4*i + 0]=  pd[i] >> 6;
945cabdff1aSopenharmony_ci                for (i--; i >= 0; i--) {
946cabdff1aSopenharmony_ci                    pd[4*i + 3]=  pd[i]     & 3;
947cabdff1aSopenharmony_ci                    pd[4*i + 2]= (pd[i]>>2) & 3;
948cabdff1aSopenharmony_ci                    pd[4*i + 1]= (pd[i]>>4) & 3;
949cabdff1aSopenharmony_ci                    pd[4*i + 0]=  pd[i]>>6;
950cabdff1aSopenharmony_ci                }
951cabdff1aSopenharmony_ci            } else {
952cabdff1aSopenharmony_ci                if ((s->width&3) >= 3) pd[4*i + 2]= ((pd[i]>>2) & 3)*0x55;
953cabdff1aSopenharmony_ci                if ((s->width&3) >= 2) pd[4*i + 1]= ((pd[i]>>4) & 3)*0x55;
954cabdff1aSopenharmony_ci                if ((s->width&3) >= 1) pd[4*i + 0]= ( pd[i]>>6     )*0x55;
955cabdff1aSopenharmony_ci                for (i--; i >= 0; i--) {
956cabdff1aSopenharmony_ci                    pd[4*i + 3]= ( pd[i]     & 3)*0x55;
957cabdff1aSopenharmony_ci                    pd[4*i + 2]= ((pd[i]>>2) & 3)*0x55;
958cabdff1aSopenharmony_ci                    pd[4*i + 1]= ((pd[i]>>4) & 3)*0x55;
959cabdff1aSopenharmony_ci                    pd[4*i + 0]= ( pd[i]>>6     )*0x55;
960cabdff1aSopenharmony_ci                }
961cabdff1aSopenharmony_ci            }
962cabdff1aSopenharmony_ci            pd += p->linesize[0];
963cabdff1aSopenharmony_ci        }
964cabdff1aSopenharmony_ci    } else if (s->bits_per_pixel == 4) {
965cabdff1aSopenharmony_ci        int i, j;
966cabdff1aSopenharmony_ci        uint8_t *pd = p->data[0];
967cabdff1aSopenharmony_ci        for (j = 0; j < s->height; j++) {
968cabdff1aSopenharmony_ci            i = s->width/2;
969cabdff1aSopenharmony_ci            if (s->color_type == PNG_COLOR_TYPE_PALETTE) {
970cabdff1aSopenharmony_ci                if (s->width&1) pd[2*i+0]= pd[i]>>4;
971cabdff1aSopenharmony_ci                for (i--; i >= 0; i--) {
972cabdff1aSopenharmony_ci                    pd[2*i + 1] = pd[i] & 15;
973cabdff1aSopenharmony_ci                    pd[2*i + 0] = pd[i] >> 4;
974cabdff1aSopenharmony_ci                }
975cabdff1aSopenharmony_ci            } else {
976cabdff1aSopenharmony_ci                if (s->width & 1) pd[2*i + 0]= (pd[i] >> 4) * 0x11;
977cabdff1aSopenharmony_ci                for (i--; i >= 0; i--) {
978cabdff1aSopenharmony_ci                    pd[2*i + 1] = (pd[i] & 15) * 0x11;
979cabdff1aSopenharmony_ci                    pd[2*i + 0] = (pd[i] >> 4) * 0x11;
980cabdff1aSopenharmony_ci                }
981cabdff1aSopenharmony_ci            }
982cabdff1aSopenharmony_ci            pd += p->linesize[0];
983cabdff1aSopenharmony_ci        }
984cabdff1aSopenharmony_ci    }
985cabdff1aSopenharmony_ci}
986cabdff1aSopenharmony_ci
987cabdff1aSopenharmony_cistatic int decode_fctl_chunk(AVCodecContext *avctx, PNGDecContext *s,
988cabdff1aSopenharmony_ci                             GetByteContext *gb)
989cabdff1aSopenharmony_ci{
990cabdff1aSopenharmony_ci    uint32_t sequence_number;
991cabdff1aSopenharmony_ci    int cur_w, cur_h, x_offset, y_offset, dispose_op, blend_op;
992cabdff1aSopenharmony_ci
993cabdff1aSopenharmony_ci    if (bytestream2_get_bytes_left(gb) != APNG_FCTL_CHUNK_SIZE)
994cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
995cabdff1aSopenharmony_ci
996cabdff1aSopenharmony_ci    if (!(s->hdr_state & PNG_IHDR)) {
997cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "fctl before IHDR\n");
998cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
999cabdff1aSopenharmony_ci    }
1000cabdff1aSopenharmony_ci
1001cabdff1aSopenharmony_ci    if (s->pic_state & PNG_IDAT) {
1002cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "fctl after IDAT\n");
1003cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
1004cabdff1aSopenharmony_ci    }
1005cabdff1aSopenharmony_ci
1006cabdff1aSopenharmony_ci    sequence_number = bytestream2_get_be32(gb);
1007cabdff1aSopenharmony_ci    cur_w           = bytestream2_get_be32(gb);
1008cabdff1aSopenharmony_ci    cur_h           = bytestream2_get_be32(gb);
1009cabdff1aSopenharmony_ci    x_offset        = bytestream2_get_be32(gb);
1010cabdff1aSopenharmony_ci    y_offset        = bytestream2_get_be32(gb);
1011cabdff1aSopenharmony_ci    bytestream2_skip(gb, 4); /* delay_num (2), delay_den (2) */
1012cabdff1aSopenharmony_ci    dispose_op      = bytestream2_get_byte(gb);
1013cabdff1aSopenharmony_ci    blend_op        = bytestream2_get_byte(gb);
1014cabdff1aSopenharmony_ci
1015cabdff1aSopenharmony_ci    if (sequence_number == 0 &&
1016cabdff1aSopenharmony_ci        (cur_w != s->width ||
1017cabdff1aSopenharmony_ci         cur_h != s->height ||
1018cabdff1aSopenharmony_ci         x_offset != 0 ||
1019cabdff1aSopenharmony_ci         y_offset != 0) ||
1020cabdff1aSopenharmony_ci        cur_w <= 0 || cur_h <= 0 ||
1021cabdff1aSopenharmony_ci        x_offset < 0 || y_offset < 0 ||
1022cabdff1aSopenharmony_ci        cur_w > s->width - x_offset|| cur_h > s->height - y_offset)
1023cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
1024cabdff1aSopenharmony_ci
1025cabdff1aSopenharmony_ci    if (blend_op != APNG_BLEND_OP_OVER && blend_op != APNG_BLEND_OP_SOURCE) {
1026cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Invalid blend_op %d\n", blend_op);
1027cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
1028cabdff1aSopenharmony_ci    }
1029cabdff1aSopenharmony_ci
1030cabdff1aSopenharmony_ci    if ((sequence_number == 0 || !s->last_picture.f) &&
1031cabdff1aSopenharmony_ci        dispose_op == APNG_DISPOSE_OP_PREVIOUS) {
1032cabdff1aSopenharmony_ci        // No previous frame to revert to for the first frame
1033cabdff1aSopenharmony_ci        // Spec says to just treat it as a APNG_DISPOSE_OP_BACKGROUND
1034cabdff1aSopenharmony_ci        dispose_op = APNG_DISPOSE_OP_BACKGROUND;
1035cabdff1aSopenharmony_ci    }
1036cabdff1aSopenharmony_ci
1037cabdff1aSopenharmony_ci    if (blend_op == APNG_BLEND_OP_OVER && !s->has_trns && (
1038cabdff1aSopenharmony_ci            avctx->pix_fmt == AV_PIX_FMT_RGB24 ||
1039cabdff1aSopenharmony_ci            avctx->pix_fmt == AV_PIX_FMT_RGB48BE ||
1040cabdff1aSopenharmony_ci            avctx->pix_fmt == AV_PIX_FMT_GRAY8 ||
1041cabdff1aSopenharmony_ci            avctx->pix_fmt == AV_PIX_FMT_GRAY16BE ||
1042cabdff1aSopenharmony_ci            avctx->pix_fmt == AV_PIX_FMT_MONOBLACK
1043cabdff1aSopenharmony_ci        )) {
1044cabdff1aSopenharmony_ci        // APNG_BLEND_OP_OVER is the same as APNG_BLEND_OP_SOURCE when there is no alpha channel
1045cabdff1aSopenharmony_ci        blend_op = APNG_BLEND_OP_SOURCE;
1046cabdff1aSopenharmony_ci    }
1047cabdff1aSopenharmony_ci
1048cabdff1aSopenharmony_ci    s->cur_w      = cur_w;
1049cabdff1aSopenharmony_ci    s->cur_h      = cur_h;
1050cabdff1aSopenharmony_ci    s->x_offset   = x_offset;
1051cabdff1aSopenharmony_ci    s->y_offset   = y_offset;
1052cabdff1aSopenharmony_ci    s->dispose_op = dispose_op;
1053cabdff1aSopenharmony_ci    s->blend_op   = blend_op;
1054cabdff1aSopenharmony_ci
1055cabdff1aSopenharmony_ci    return 0;
1056cabdff1aSopenharmony_ci}
1057cabdff1aSopenharmony_ci
1058cabdff1aSopenharmony_cistatic void handle_p_frame_png(PNGDecContext *s, AVFrame *p)
1059cabdff1aSopenharmony_ci{
1060cabdff1aSopenharmony_ci    int i, j;
1061cabdff1aSopenharmony_ci    uint8_t *pd      = p->data[0];
1062cabdff1aSopenharmony_ci    uint8_t *pd_last = s->last_picture.f->data[0];
1063cabdff1aSopenharmony_ci    int ls = av_image_get_linesize(p->format, s->width, 0);
1064cabdff1aSopenharmony_ci
1065cabdff1aSopenharmony_ci    ls = FFMIN(ls, s->width * s->bpp);
1066cabdff1aSopenharmony_ci
1067cabdff1aSopenharmony_ci    ff_thread_await_progress(&s->last_picture, INT_MAX, 0);
1068cabdff1aSopenharmony_ci    for (j = 0; j < s->height; j++) {
1069cabdff1aSopenharmony_ci        for (i = 0; i < ls; i++)
1070cabdff1aSopenharmony_ci            pd[i] += pd_last[i];
1071cabdff1aSopenharmony_ci        pd      += p->linesize[0];
1072cabdff1aSopenharmony_ci        pd_last += s->last_picture.f->linesize[0];
1073cabdff1aSopenharmony_ci    }
1074cabdff1aSopenharmony_ci}
1075cabdff1aSopenharmony_ci
1076cabdff1aSopenharmony_ci// divide by 255 and round to nearest
1077cabdff1aSopenharmony_ci// apply a fast variant: (X+127)/255 = ((X+127)*257+257)>>16 = ((X+128)*257)>>16
1078cabdff1aSopenharmony_ci#define FAST_DIV255(x) ((((x) + 128) * 257) >> 16)
1079cabdff1aSopenharmony_ci
1080cabdff1aSopenharmony_cistatic int handle_p_frame_apng(AVCodecContext *avctx, PNGDecContext *s,
1081cabdff1aSopenharmony_ci                               AVFrame *p)
1082cabdff1aSopenharmony_ci{
1083cabdff1aSopenharmony_ci    uint8_t       *dst        = p->data[0];
1084cabdff1aSopenharmony_ci    ptrdiff_t      dst_stride = p->linesize[0];
1085cabdff1aSopenharmony_ci    const uint8_t *src        = s->last_picture.f->data[0];
1086cabdff1aSopenharmony_ci    ptrdiff_t      src_stride = s->last_picture.f->linesize[0];
1087cabdff1aSopenharmony_ci    const int      bpp        = s->color_type == PNG_COLOR_TYPE_PALETTE ? 4 : s->bpp;
1088cabdff1aSopenharmony_ci
1089cabdff1aSopenharmony_ci    size_t x, y;
1090cabdff1aSopenharmony_ci
1091cabdff1aSopenharmony_ci    if (s->blend_op == APNG_BLEND_OP_OVER &&
1092cabdff1aSopenharmony_ci        avctx->pix_fmt != AV_PIX_FMT_RGBA &&
1093cabdff1aSopenharmony_ci        avctx->pix_fmt != AV_PIX_FMT_GRAY8A) {
1094cabdff1aSopenharmony_ci        avpriv_request_sample(avctx, "Blending with pixel format %s",
1095cabdff1aSopenharmony_ci                              av_get_pix_fmt_name(avctx->pix_fmt));
1096cabdff1aSopenharmony_ci        return AVERROR_PATCHWELCOME;
1097cabdff1aSopenharmony_ci    }
1098cabdff1aSopenharmony_ci
1099cabdff1aSopenharmony_ci    ff_thread_await_progress(&s->last_picture, INT_MAX, 0);
1100cabdff1aSopenharmony_ci
1101cabdff1aSopenharmony_ci    // copy unchanged rectangles from the last frame
1102cabdff1aSopenharmony_ci    for (y = 0; y < s->y_offset; y++)
1103cabdff1aSopenharmony_ci        memcpy(dst + y * dst_stride, src + y * src_stride, p->width * bpp);
1104cabdff1aSopenharmony_ci    for (y = s->y_offset; y < s->y_offset + s->cur_h; y++) {
1105cabdff1aSopenharmony_ci        memcpy(dst + y * dst_stride, src + y * src_stride, s->x_offset * bpp);
1106cabdff1aSopenharmony_ci        memcpy(dst + y * dst_stride + (s->x_offset + s->cur_w) * bpp,
1107cabdff1aSopenharmony_ci               src + y * src_stride + (s->x_offset + s->cur_w) * bpp,
1108cabdff1aSopenharmony_ci               (p->width - s->cur_w - s->x_offset) * bpp);
1109cabdff1aSopenharmony_ci    }
1110cabdff1aSopenharmony_ci    for (y = s->y_offset + s->cur_h; y < p->height; y++)
1111cabdff1aSopenharmony_ci        memcpy(dst + y * dst_stride, src + y * src_stride, p->width * bpp);
1112cabdff1aSopenharmony_ci
1113cabdff1aSopenharmony_ci    if (s->blend_op == APNG_BLEND_OP_OVER) {
1114cabdff1aSopenharmony_ci        // Perform blending
1115cabdff1aSopenharmony_ci        for (y = s->y_offset; y < s->y_offset + s->cur_h; ++y) {
1116cabdff1aSopenharmony_ci            uint8_t       *foreground = dst + dst_stride * y + bpp * s->x_offset;
1117cabdff1aSopenharmony_ci            const uint8_t *background = src + src_stride * y + bpp * s->x_offset;
1118cabdff1aSopenharmony_ci            for (x = s->x_offset; x < s->x_offset + s->cur_w; ++x, foreground += bpp, background += bpp) {
1119cabdff1aSopenharmony_ci                size_t b;
1120cabdff1aSopenharmony_ci                uint8_t foreground_alpha, background_alpha, output_alpha;
1121cabdff1aSopenharmony_ci                uint8_t output[10];
1122cabdff1aSopenharmony_ci
1123cabdff1aSopenharmony_ci                // Since we might be blending alpha onto alpha, we use the following equations:
1124cabdff1aSopenharmony_ci                // output_alpha = foreground_alpha + (1 - foreground_alpha) * background_alpha
1125cabdff1aSopenharmony_ci                // output = (foreground_alpha * foreground + (1 - foreground_alpha) * background_alpha * background) / output_alpha
1126cabdff1aSopenharmony_ci
1127cabdff1aSopenharmony_ci                switch (avctx->pix_fmt) {
1128cabdff1aSopenharmony_ci                case AV_PIX_FMT_RGBA:
1129cabdff1aSopenharmony_ci                    foreground_alpha = foreground[3];
1130cabdff1aSopenharmony_ci                    background_alpha = background[3];
1131cabdff1aSopenharmony_ci                    break;
1132cabdff1aSopenharmony_ci
1133cabdff1aSopenharmony_ci                case AV_PIX_FMT_GRAY8A:
1134cabdff1aSopenharmony_ci                    foreground_alpha = foreground[1];
1135cabdff1aSopenharmony_ci                    background_alpha = background[1];
1136cabdff1aSopenharmony_ci                    break;
1137cabdff1aSopenharmony_ci                }
1138cabdff1aSopenharmony_ci
1139cabdff1aSopenharmony_ci                if (foreground_alpha == 255)
1140cabdff1aSopenharmony_ci                    continue;
1141cabdff1aSopenharmony_ci
1142cabdff1aSopenharmony_ci                if (foreground_alpha == 0) {
1143cabdff1aSopenharmony_ci                    memcpy(foreground, background, bpp);
1144cabdff1aSopenharmony_ci                    continue;
1145cabdff1aSopenharmony_ci                }
1146cabdff1aSopenharmony_ci
1147cabdff1aSopenharmony_ci                output_alpha = foreground_alpha + FAST_DIV255((255 - foreground_alpha) * background_alpha);
1148cabdff1aSopenharmony_ci
1149cabdff1aSopenharmony_ci                av_assert0(bpp <= 10);
1150cabdff1aSopenharmony_ci
1151cabdff1aSopenharmony_ci                for (b = 0; b < bpp - 1; ++b) {
1152cabdff1aSopenharmony_ci                    if (output_alpha == 0) {
1153cabdff1aSopenharmony_ci                        output[b] = 0;
1154cabdff1aSopenharmony_ci                    } else if (background_alpha == 255) {
1155cabdff1aSopenharmony_ci                        output[b] = FAST_DIV255(foreground_alpha * foreground[b] + (255 - foreground_alpha) * background[b]);
1156cabdff1aSopenharmony_ci                    } else {
1157cabdff1aSopenharmony_ci                        output[b] = (255 * foreground_alpha * foreground[b] + (255 - foreground_alpha) * background_alpha * background[b]) / (255 * output_alpha);
1158cabdff1aSopenharmony_ci                    }
1159cabdff1aSopenharmony_ci                }
1160cabdff1aSopenharmony_ci                output[b] = output_alpha;
1161cabdff1aSopenharmony_ci                memcpy(foreground, output, bpp);
1162cabdff1aSopenharmony_ci            }
1163cabdff1aSopenharmony_ci        }
1164cabdff1aSopenharmony_ci    }
1165cabdff1aSopenharmony_ci
1166cabdff1aSopenharmony_ci    return 0;
1167cabdff1aSopenharmony_ci}
1168cabdff1aSopenharmony_ci
1169cabdff1aSopenharmony_cistatic void apng_reset_background(PNGDecContext *s, const AVFrame *p)
1170cabdff1aSopenharmony_ci{
1171cabdff1aSopenharmony_ci    // need to reset a rectangle to black
1172cabdff1aSopenharmony_ci    av_unused int ret = av_frame_copy(s->picture.f, p);
1173cabdff1aSopenharmony_ci    const int bpp = s->color_type == PNG_COLOR_TYPE_PALETTE ? 4 : s->bpp;
1174cabdff1aSopenharmony_ci    const ptrdiff_t dst_stride = s->picture.f->linesize[0];
1175cabdff1aSopenharmony_ci    uint8_t *dst = s->picture.f->data[0] + s->y_offset * dst_stride + bpp * s->x_offset;
1176cabdff1aSopenharmony_ci
1177cabdff1aSopenharmony_ci    av_assert1(ret >= 0);
1178cabdff1aSopenharmony_ci
1179cabdff1aSopenharmony_ci    for (size_t y = 0; y < s->cur_h; y++) {
1180cabdff1aSopenharmony_ci        memset(dst, 0, bpp * s->cur_w);
1181cabdff1aSopenharmony_ci        dst += dst_stride;
1182cabdff1aSopenharmony_ci    }
1183cabdff1aSopenharmony_ci}
1184cabdff1aSopenharmony_ci
1185cabdff1aSopenharmony_cistatic int decode_frame_common(AVCodecContext *avctx, PNGDecContext *s,
1186cabdff1aSopenharmony_ci                               AVFrame *p, const AVPacket *avpkt)
1187cabdff1aSopenharmony_ci{
1188cabdff1aSopenharmony_ci    const AVCRC *crc_tab = av_crc_get_table(AV_CRC_32_IEEE_LE);
1189cabdff1aSopenharmony_ci    uint32_t tag, length;
1190cabdff1aSopenharmony_ci    int decode_next_dat = 0;
1191cabdff1aSopenharmony_ci    int i, ret;
1192cabdff1aSopenharmony_ci
1193cabdff1aSopenharmony_ci    for (;;) {
1194cabdff1aSopenharmony_ci        GetByteContext gb_chunk;
1195cabdff1aSopenharmony_ci
1196cabdff1aSopenharmony_ci        length = bytestream2_get_bytes_left(&s->gb);
1197cabdff1aSopenharmony_ci        if (length <= 0) {
1198cabdff1aSopenharmony_ci
1199cabdff1aSopenharmony_ci            if (avctx->codec_id == AV_CODEC_ID_PNG &&
1200cabdff1aSopenharmony_ci                avctx->skip_frame == AVDISCARD_ALL) {
1201cabdff1aSopenharmony_ci                return 0;
1202cabdff1aSopenharmony_ci            }
1203cabdff1aSopenharmony_ci
1204cabdff1aSopenharmony_ci            if (CONFIG_APNG_DECODER && avctx->codec_id == AV_CODEC_ID_APNG && length == 0) {
1205cabdff1aSopenharmony_ci                if (!(s->pic_state & PNG_IDAT))
1206cabdff1aSopenharmony_ci                    return 0;
1207cabdff1aSopenharmony_ci                else
1208cabdff1aSopenharmony_ci                    goto exit_loop;
1209cabdff1aSopenharmony_ci            }
1210cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "%d bytes left\n", length);
1211cabdff1aSopenharmony_ci            if (   s->pic_state & PNG_ALLIMAGE
1212cabdff1aSopenharmony_ci                && avctx->strict_std_compliance <= FF_COMPLIANCE_NORMAL)
1213cabdff1aSopenharmony_ci                goto exit_loop;
1214cabdff1aSopenharmony_ci            ret = AVERROR_INVALIDDATA;
1215cabdff1aSopenharmony_ci            goto fail;
1216cabdff1aSopenharmony_ci        }
1217cabdff1aSopenharmony_ci
1218cabdff1aSopenharmony_ci        length = bytestream2_get_be32(&s->gb);
1219cabdff1aSopenharmony_ci        if (length > 0x7fffffff || length + 8 > bytestream2_get_bytes_left(&s->gb)) {
1220cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "chunk too big\n");
1221cabdff1aSopenharmony_ci            ret = AVERROR_INVALIDDATA;
1222cabdff1aSopenharmony_ci            goto fail;
1223cabdff1aSopenharmony_ci        }
1224cabdff1aSopenharmony_ci        if (avctx->err_recognition & (AV_EF_CRCCHECK | AV_EF_IGNORE_ERR)) {
1225cabdff1aSopenharmony_ci            uint32_t crc_sig = AV_RB32(s->gb.buffer + length + 4);
1226cabdff1aSopenharmony_ci            uint32_t crc_cal = ~av_crc(crc_tab, UINT32_MAX, s->gb.buffer, length + 4);
1227cabdff1aSopenharmony_ci            if (crc_sig ^ crc_cal) {
1228cabdff1aSopenharmony_ci                av_log(avctx, AV_LOG_ERROR, "CRC mismatch in chunk");
1229cabdff1aSopenharmony_ci                if (avctx->err_recognition & AV_EF_EXPLODE) {
1230cabdff1aSopenharmony_ci                    av_log(avctx, AV_LOG_ERROR, ", quitting\n");
1231cabdff1aSopenharmony_ci                    ret = AVERROR_INVALIDDATA;
1232cabdff1aSopenharmony_ci                    goto fail;
1233cabdff1aSopenharmony_ci                }
1234cabdff1aSopenharmony_ci                av_log(avctx, AV_LOG_ERROR, ", skipping\n");
1235cabdff1aSopenharmony_ci                bytestream2_skip(&s->gb, length + 8); /* tag */
1236cabdff1aSopenharmony_ci                continue;
1237cabdff1aSopenharmony_ci            }
1238cabdff1aSopenharmony_ci        }
1239cabdff1aSopenharmony_ci        tag = bytestream2_get_le32(&s->gb);
1240cabdff1aSopenharmony_ci        if (avctx->debug & FF_DEBUG_STARTCODE)
1241cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_DEBUG, "png: tag=%s length=%u\n",
1242cabdff1aSopenharmony_ci                   av_fourcc2str(tag), length);
1243cabdff1aSopenharmony_ci
1244cabdff1aSopenharmony_ci        bytestream2_init(&gb_chunk, s->gb.buffer, length);
1245cabdff1aSopenharmony_ci        bytestream2_skip(&s->gb, length + 4);
1246cabdff1aSopenharmony_ci
1247cabdff1aSopenharmony_ci        if (avctx->codec_id == AV_CODEC_ID_PNG &&
1248cabdff1aSopenharmony_ci            avctx->skip_frame == AVDISCARD_ALL) {
1249cabdff1aSopenharmony_ci            switch(tag) {
1250cabdff1aSopenharmony_ci            case MKTAG('I', 'H', 'D', 'R'):
1251cabdff1aSopenharmony_ci            case MKTAG('p', 'H', 'Y', 's'):
1252cabdff1aSopenharmony_ci            case MKTAG('t', 'E', 'X', 't'):
1253cabdff1aSopenharmony_ci            case MKTAG('I', 'D', 'A', 'T'):
1254cabdff1aSopenharmony_ci            case MKTAG('t', 'R', 'N', 'S'):
1255cabdff1aSopenharmony_ci                break;
1256cabdff1aSopenharmony_ci            default:
1257cabdff1aSopenharmony_ci                continue;
1258cabdff1aSopenharmony_ci            }
1259cabdff1aSopenharmony_ci        }
1260cabdff1aSopenharmony_ci
1261cabdff1aSopenharmony_ci        switch (tag) {
1262cabdff1aSopenharmony_ci        case MKTAG('I', 'H', 'D', 'R'):
1263cabdff1aSopenharmony_ci            if ((ret = decode_ihdr_chunk(avctx, s, &gb_chunk)) < 0)
1264cabdff1aSopenharmony_ci                goto fail;
1265cabdff1aSopenharmony_ci            break;
1266cabdff1aSopenharmony_ci        case MKTAG('p', 'H', 'Y', 's'):
1267cabdff1aSopenharmony_ci            if ((ret = decode_phys_chunk(avctx, s, &gb_chunk)) < 0)
1268cabdff1aSopenharmony_ci                goto fail;
1269cabdff1aSopenharmony_ci            break;
1270cabdff1aSopenharmony_ci        case MKTAG('f', 'c', 'T', 'L'):
1271cabdff1aSopenharmony_ci            if (!CONFIG_APNG_DECODER || avctx->codec_id != AV_CODEC_ID_APNG)
1272cabdff1aSopenharmony_ci                continue;
1273cabdff1aSopenharmony_ci            if ((ret = decode_fctl_chunk(avctx, s, &gb_chunk)) < 0)
1274cabdff1aSopenharmony_ci                goto fail;
1275cabdff1aSopenharmony_ci            decode_next_dat = 1;
1276cabdff1aSopenharmony_ci            break;
1277cabdff1aSopenharmony_ci        case MKTAG('f', 'd', 'A', 'T'):
1278cabdff1aSopenharmony_ci            if (!CONFIG_APNG_DECODER || avctx->codec_id != AV_CODEC_ID_APNG)
1279cabdff1aSopenharmony_ci                continue;
1280cabdff1aSopenharmony_ci            if (!decode_next_dat || bytestream2_get_bytes_left(&gb_chunk) < 4) {
1281cabdff1aSopenharmony_ci                ret = AVERROR_INVALIDDATA;
1282cabdff1aSopenharmony_ci                goto fail;
1283cabdff1aSopenharmony_ci            }
1284cabdff1aSopenharmony_ci            bytestream2_get_be32(&gb_chunk);
1285cabdff1aSopenharmony_ci            /* fallthrough */
1286cabdff1aSopenharmony_ci        case MKTAG('I', 'D', 'A', 'T'):
1287cabdff1aSopenharmony_ci            if (CONFIG_APNG_DECODER && avctx->codec_id == AV_CODEC_ID_APNG && !decode_next_dat)
1288cabdff1aSopenharmony_ci                continue;
1289cabdff1aSopenharmony_ci            if ((ret = decode_idat_chunk(avctx, s, &gb_chunk, p)) < 0)
1290cabdff1aSopenharmony_ci                goto fail;
1291cabdff1aSopenharmony_ci            break;
1292cabdff1aSopenharmony_ci        case MKTAG('P', 'L', 'T', 'E'):
1293cabdff1aSopenharmony_ci            decode_plte_chunk(avctx, s, &gb_chunk);
1294cabdff1aSopenharmony_ci            break;
1295cabdff1aSopenharmony_ci        case MKTAG('t', 'R', 'N', 'S'):
1296cabdff1aSopenharmony_ci            decode_trns_chunk(avctx, s, &gb_chunk);
1297cabdff1aSopenharmony_ci            break;
1298cabdff1aSopenharmony_ci        case MKTAG('t', 'E', 'X', 't'):
1299cabdff1aSopenharmony_ci            if (decode_text_chunk(s, &gb_chunk, 0) < 0)
1300cabdff1aSopenharmony_ci                av_log(avctx, AV_LOG_WARNING, "Broken tEXt chunk\n");
1301cabdff1aSopenharmony_ci            break;
1302cabdff1aSopenharmony_ci        case MKTAG('z', 'T', 'X', 't'):
1303cabdff1aSopenharmony_ci            if (decode_text_chunk(s, &gb_chunk, 1) < 0)
1304cabdff1aSopenharmony_ci                av_log(avctx, AV_LOG_WARNING, "Broken zTXt chunk\n");
1305cabdff1aSopenharmony_ci            break;
1306cabdff1aSopenharmony_ci        case MKTAG('s', 'T', 'E', 'R'): {
1307cabdff1aSopenharmony_ci            int mode = bytestream2_get_byte(&gb_chunk);
1308cabdff1aSopenharmony_ci
1309cabdff1aSopenharmony_ci            if (mode == 0 || mode == 1) {
1310cabdff1aSopenharmony_ci                s->stereo_mode = mode;
1311cabdff1aSopenharmony_ci            } else {
1312cabdff1aSopenharmony_ci                 av_log(avctx, AV_LOG_WARNING,
1313cabdff1aSopenharmony_ci                        "Unknown value in sTER chunk (%d)\n", mode);
1314cabdff1aSopenharmony_ci            }
1315cabdff1aSopenharmony_ci            break;
1316cabdff1aSopenharmony_ci        }
1317cabdff1aSopenharmony_ci        case MKTAG('i', 'C', 'C', 'P'): {
1318cabdff1aSopenharmony_ci            if ((ret = decode_iccp_chunk(s, &gb_chunk)) < 0)
1319cabdff1aSopenharmony_ci                goto fail;
1320cabdff1aSopenharmony_ci            break;
1321cabdff1aSopenharmony_ci        }
1322cabdff1aSopenharmony_ci        case MKTAG('c', 'H', 'R', 'M'): {
1323cabdff1aSopenharmony_ci            s->have_chrm = 1;
1324cabdff1aSopenharmony_ci
1325cabdff1aSopenharmony_ci            s->white_point[0] = bytestream2_get_be32(&gb_chunk);
1326cabdff1aSopenharmony_ci            s->white_point[1] = bytestream2_get_be32(&gb_chunk);
1327cabdff1aSopenharmony_ci
1328cabdff1aSopenharmony_ci            /* RGB Primaries */
1329cabdff1aSopenharmony_ci            for (i = 0; i < 3; i++) {
1330cabdff1aSopenharmony_ci                s->display_primaries[i][0] = bytestream2_get_be32(&gb_chunk);
1331cabdff1aSopenharmony_ci                s->display_primaries[i][1] = bytestream2_get_be32(&gb_chunk);
1332cabdff1aSopenharmony_ci            }
1333cabdff1aSopenharmony_ci
1334cabdff1aSopenharmony_ci            break;
1335cabdff1aSopenharmony_ci        }
1336cabdff1aSopenharmony_ci        case MKTAG('g', 'A', 'M', 'A'): {
1337cabdff1aSopenharmony_ci            AVBPrint bp;
1338cabdff1aSopenharmony_ci            char *gamma_str;
1339cabdff1aSopenharmony_ci            int num = bytestream2_get_be32(&gb_chunk);
1340cabdff1aSopenharmony_ci
1341cabdff1aSopenharmony_ci            av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED);
1342cabdff1aSopenharmony_ci            av_bprintf(&bp, "%i/%i", num, 100000);
1343cabdff1aSopenharmony_ci            ret = av_bprint_finalize(&bp, &gamma_str);
1344cabdff1aSopenharmony_ci            if (ret < 0)
1345cabdff1aSopenharmony_ci                return ret;
1346cabdff1aSopenharmony_ci
1347cabdff1aSopenharmony_ci            av_dict_set(&s->frame_metadata, "gamma", gamma_str, AV_DICT_DONT_STRDUP_VAL);
1348cabdff1aSopenharmony_ci
1349cabdff1aSopenharmony_ci            break;
1350cabdff1aSopenharmony_ci        }
1351cabdff1aSopenharmony_ci        case MKTAG('I', 'E', 'N', 'D'):
1352cabdff1aSopenharmony_ci            if (!(s->pic_state & PNG_ALLIMAGE))
1353cabdff1aSopenharmony_ci                av_log(avctx, AV_LOG_ERROR, "IEND without all image\n");
1354cabdff1aSopenharmony_ci            if (!(s->pic_state & (PNG_ALLIMAGE|PNG_IDAT))) {
1355cabdff1aSopenharmony_ci                ret = AVERROR_INVALIDDATA;
1356cabdff1aSopenharmony_ci                goto fail;
1357cabdff1aSopenharmony_ci            }
1358cabdff1aSopenharmony_ci            goto exit_loop;
1359cabdff1aSopenharmony_ci        }
1360cabdff1aSopenharmony_ci    }
1361cabdff1aSopenharmony_ciexit_loop:
1362cabdff1aSopenharmony_ci
1363cabdff1aSopenharmony_ci    if (!p)
1364cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
1365cabdff1aSopenharmony_ci
1366cabdff1aSopenharmony_ci    if (avctx->codec_id == AV_CODEC_ID_PNG &&
1367cabdff1aSopenharmony_ci        avctx->skip_frame == AVDISCARD_ALL) {
1368cabdff1aSopenharmony_ci        return 0;
1369cabdff1aSopenharmony_ci    }
1370cabdff1aSopenharmony_ci
1371cabdff1aSopenharmony_ci    if (percent_missing(s) > avctx->discard_damaged_percentage)
1372cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
1373cabdff1aSopenharmony_ci
1374cabdff1aSopenharmony_ci    if (s->bits_per_pixel <= 4)
1375cabdff1aSopenharmony_ci        handle_small_bpp(s, p);
1376cabdff1aSopenharmony_ci
1377cabdff1aSopenharmony_ci    if (s->color_type == PNG_COLOR_TYPE_PALETTE && avctx->codec_id == AV_CODEC_ID_APNG) {
1378cabdff1aSopenharmony_ci        for (int y = 0; y < s->height; y++) {
1379cabdff1aSopenharmony_ci            uint8_t *row = &p->data[0][p->linesize[0] * y];
1380cabdff1aSopenharmony_ci
1381cabdff1aSopenharmony_ci            for (int x = s->width - 1; x >= 0; x--) {
1382cabdff1aSopenharmony_ci                const uint8_t idx = row[x];
1383cabdff1aSopenharmony_ci
1384cabdff1aSopenharmony_ci                row[4*x+2] =  s->palette[idx]        & 0xFF;
1385cabdff1aSopenharmony_ci                row[4*x+1] = (s->palette[idx] >> 8 ) & 0xFF;
1386cabdff1aSopenharmony_ci                row[4*x+0] = (s->palette[idx] >> 16) & 0xFF;
1387cabdff1aSopenharmony_ci                row[4*x+3] =  s->palette[idx] >> 24;
1388cabdff1aSopenharmony_ci            }
1389cabdff1aSopenharmony_ci        }
1390cabdff1aSopenharmony_ci    }
1391cabdff1aSopenharmony_ci
1392cabdff1aSopenharmony_ci    /* apply transparency if needed */
1393cabdff1aSopenharmony_ci    if (s->has_trns && s->color_type != PNG_COLOR_TYPE_PALETTE) {
1394cabdff1aSopenharmony_ci        size_t byte_depth = s->bit_depth > 8 ? 2 : 1;
1395cabdff1aSopenharmony_ci        size_t raw_bpp = s->bpp - byte_depth;
1396cabdff1aSopenharmony_ci        unsigned x, y;
1397cabdff1aSopenharmony_ci
1398cabdff1aSopenharmony_ci        av_assert0(s->bit_depth > 1);
1399cabdff1aSopenharmony_ci
1400cabdff1aSopenharmony_ci        for (y = 0; y < s->height; ++y) {
1401cabdff1aSopenharmony_ci            uint8_t *row = &p->data[0][p->linesize[0] * y];
1402cabdff1aSopenharmony_ci
1403cabdff1aSopenharmony_ci            if (s->bpp == 2 && byte_depth == 1) {
1404cabdff1aSopenharmony_ci                uint8_t *pixel = &row[2 * s->width - 1];
1405cabdff1aSopenharmony_ci                uint8_t *rowp  = &row[1 * s->width - 1];
1406cabdff1aSopenharmony_ci                int tcolor = s->transparent_color_be[0];
1407cabdff1aSopenharmony_ci                for (x = s->width; x > 0; --x) {
1408cabdff1aSopenharmony_ci                    *pixel-- = *rowp == tcolor ? 0 : 0xff;
1409cabdff1aSopenharmony_ci                    *pixel-- = *rowp--;
1410cabdff1aSopenharmony_ci                }
1411cabdff1aSopenharmony_ci            } else if (s->bpp == 4 && byte_depth == 1) {
1412cabdff1aSopenharmony_ci                uint8_t *pixel = &row[4 * s->width - 1];
1413cabdff1aSopenharmony_ci                uint8_t *rowp  = &row[3 * s->width - 1];
1414cabdff1aSopenharmony_ci                int tcolor = AV_RL24(s->transparent_color_be);
1415cabdff1aSopenharmony_ci                for (x = s->width; x > 0; --x) {
1416cabdff1aSopenharmony_ci                    *pixel-- = AV_RL24(rowp-2) == tcolor ? 0 : 0xff;
1417cabdff1aSopenharmony_ci                    *pixel-- = *rowp--;
1418cabdff1aSopenharmony_ci                    *pixel-- = *rowp--;
1419cabdff1aSopenharmony_ci                    *pixel-- = *rowp--;
1420cabdff1aSopenharmony_ci                }
1421cabdff1aSopenharmony_ci            } else {
1422cabdff1aSopenharmony_ci                /* since we're updating in-place, we have to go from right to left */
1423cabdff1aSopenharmony_ci                for (x = s->width; x > 0; --x) {
1424cabdff1aSopenharmony_ci                    uint8_t *pixel = &row[s->bpp * (x - 1)];
1425cabdff1aSopenharmony_ci                    memmove(pixel, &row[raw_bpp * (x - 1)], raw_bpp);
1426cabdff1aSopenharmony_ci
1427cabdff1aSopenharmony_ci                    if (!memcmp(pixel, s->transparent_color_be, raw_bpp)) {
1428cabdff1aSopenharmony_ci                        memset(&pixel[raw_bpp], 0, byte_depth);
1429cabdff1aSopenharmony_ci                    } else {
1430cabdff1aSopenharmony_ci                        memset(&pixel[raw_bpp], 0xff, byte_depth);
1431cabdff1aSopenharmony_ci                    }
1432cabdff1aSopenharmony_ci                }
1433cabdff1aSopenharmony_ci            }
1434cabdff1aSopenharmony_ci        }
1435cabdff1aSopenharmony_ci    }
1436cabdff1aSopenharmony_ci
1437cabdff1aSopenharmony_ci    /* handle P-frames only if a predecessor frame is available */
1438cabdff1aSopenharmony_ci    if (s->last_picture.f->data[0]) {
1439cabdff1aSopenharmony_ci        if (   !(avpkt->flags & AV_PKT_FLAG_KEY) && avctx->codec_tag != AV_RL32("MPNG")
1440cabdff1aSopenharmony_ci            && s->last_picture.f->width == p->width
1441cabdff1aSopenharmony_ci            && s->last_picture.f->height== p->height
1442cabdff1aSopenharmony_ci            && s->last_picture.f->format== p->format
1443cabdff1aSopenharmony_ci         ) {
1444cabdff1aSopenharmony_ci            if (CONFIG_PNG_DECODER && avctx->codec_id != AV_CODEC_ID_APNG)
1445cabdff1aSopenharmony_ci                handle_p_frame_png(s, p);
1446cabdff1aSopenharmony_ci            else if (CONFIG_APNG_DECODER &&
1447cabdff1aSopenharmony_ci                     avctx->codec_id == AV_CODEC_ID_APNG &&
1448cabdff1aSopenharmony_ci                     (ret = handle_p_frame_apng(avctx, s, p)) < 0)
1449cabdff1aSopenharmony_ci                goto fail;
1450cabdff1aSopenharmony_ci        }
1451cabdff1aSopenharmony_ci    }
1452cabdff1aSopenharmony_ci    if (CONFIG_APNG_DECODER && s->dispose_op == APNG_DISPOSE_OP_BACKGROUND)
1453cabdff1aSopenharmony_ci        apng_reset_background(s, p);
1454cabdff1aSopenharmony_ci
1455cabdff1aSopenharmony_ci    ff_thread_report_progress(&s->picture, INT_MAX, 0);
1456cabdff1aSopenharmony_ci
1457cabdff1aSopenharmony_ci    return 0;
1458cabdff1aSopenharmony_ci
1459cabdff1aSopenharmony_cifail:
1460cabdff1aSopenharmony_ci    ff_thread_report_progress(&s->picture, INT_MAX, 0);
1461cabdff1aSopenharmony_ci    return ret;
1462cabdff1aSopenharmony_ci}
1463cabdff1aSopenharmony_ci
1464cabdff1aSopenharmony_cistatic void clear_frame_metadata(PNGDecContext *s)
1465cabdff1aSopenharmony_ci{
1466cabdff1aSopenharmony_ci    av_freep(&s->iccp_data);
1467cabdff1aSopenharmony_ci    s->iccp_data_len = 0;
1468cabdff1aSopenharmony_ci    s->iccp_name[0]  = 0;
1469cabdff1aSopenharmony_ci
1470cabdff1aSopenharmony_ci    s->stereo_mode = -1;
1471cabdff1aSopenharmony_ci
1472cabdff1aSopenharmony_ci    s->have_chrm = 0;
1473cabdff1aSopenharmony_ci
1474cabdff1aSopenharmony_ci    av_dict_free(&s->frame_metadata);
1475cabdff1aSopenharmony_ci}
1476cabdff1aSopenharmony_ci
1477cabdff1aSopenharmony_cistatic int output_frame(PNGDecContext *s, AVFrame *f)
1478cabdff1aSopenharmony_ci{
1479cabdff1aSopenharmony_ci    int ret;
1480cabdff1aSopenharmony_ci
1481cabdff1aSopenharmony_ci    if (s->iccp_data) {
1482cabdff1aSopenharmony_ci        AVFrameSideData *sd = av_frame_new_side_data(f, AV_FRAME_DATA_ICC_PROFILE, s->iccp_data_len);
1483cabdff1aSopenharmony_ci        if (!sd) {
1484cabdff1aSopenharmony_ci            ret = AVERROR(ENOMEM);
1485cabdff1aSopenharmony_ci            goto fail;
1486cabdff1aSopenharmony_ci        }
1487cabdff1aSopenharmony_ci        memcpy(sd->data, s->iccp_data, s->iccp_data_len);
1488cabdff1aSopenharmony_ci
1489cabdff1aSopenharmony_ci        av_dict_set(&sd->metadata, "name", s->iccp_name, 0);
1490cabdff1aSopenharmony_ci    }
1491cabdff1aSopenharmony_ci
1492cabdff1aSopenharmony_ci    if (s->stereo_mode >= 0) {
1493cabdff1aSopenharmony_ci        AVStereo3D *stereo3d = av_stereo3d_create_side_data(f);
1494cabdff1aSopenharmony_ci        if (!stereo3d) {
1495cabdff1aSopenharmony_ci            ret = AVERROR(ENOMEM);
1496cabdff1aSopenharmony_ci            goto fail;
1497cabdff1aSopenharmony_ci        }
1498cabdff1aSopenharmony_ci
1499cabdff1aSopenharmony_ci        stereo3d->type  = AV_STEREO3D_SIDEBYSIDE;
1500cabdff1aSopenharmony_ci        stereo3d->flags = s->stereo_mode ? 0 : AV_STEREO3D_FLAG_INVERT;
1501cabdff1aSopenharmony_ci    }
1502cabdff1aSopenharmony_ci
1503cabdff1aSopenharmony_ci    if (s->have_chrm) {
1504cabdff1aSopenharmony_ci        AVMasteringDisplayMetadata *mdm = av_mastering_display_metadata_create_side_data(f);
1505cabdff1aSopenharmony_ci        if (!mdm) {
1506cabdff1aSopenharmony_ci            ret = AVERROR(ENOMEM);
1507cabdff1aSopenharmony_ci            goto fail;
1508cabdff1aSopenharmony_ci        }
1509cabdff1aSopenharmony_ci
1510cabdff1aSopenharmony_ci        mdm->white_point[0] = av_make_q(s->white_point[0], 100000);
1511cabdff1aSopenharmony_ci        mdm->white_point[1] = av_make_q(s->white_point[1], 100000);
1512cabdff1aSopenharmony_ci
1513cabdff1aSopenharmony_ci        /* RGB Primaries */
1514cabdff1aSopenharmony_ci        for (int i = 0; i < 3; i++) {
1515cabdff1aSopenharmony_ci            mdm->display_primaries[i][0] = av_make_q(s->display_primaries[i][0], 100000);
1516cabdff1aSopenharmony_ci            mdm->display_primaries[i][1] = av_make_q(s->display_primaries[i][1], 100000);
1517cabdff1aSopenharmony_ci        }
1518cabdff1aSopenharmony_ci
1519cabdff1aSopenharmony_ci        mdm->has_primaries = 1;
1520cabdff1aSopenharmony_ci    }
1521cabdff1aSopenharmony_ci
1522cabdff1aSopenharmony_ci    FFSWAP(AVDictionary*, f->metadata, s->frame_metadata);
1523cabdff1aSopenharmony_ci
1524cabdff1aSopenharmony_ci    return 0;
1525cabdff1aSopenharmony_cifail:
1526cabdff1aSopenharmony_ci    av_frame_unref(f);
1527cabdff1aSopenharmony_ci    return ret;
1528cabdff1aSopenharmony_ci}
1529cabdff1aSopenharmony_ci
1530cabdff1aSopenharmony_ci#if CONFIG_PNG_DECODER
1531cabdff1aSopenharmony_cistatic int decode_frame_png(AVCodecContext *avctx, AVFrame *p,
1532cabdff1aSopenharmony_ci                            int *got_frame, AVPacket *avpkt)
1533cabdff1aSopenharmony_ci{
1534cabdff1aSopenharmony_ci    PNGDecContext *const s = avctx->priv_data;
1535cabdff1aSopenharmony_ci    const uint8_t *buf     = avpkt->data;
1536cabdff1aSopenharmony_ci    int buf_size           = avpkt->size;
1537cabdff1aSopenharmony_ci    int64_t sig;
1538cabdff1aSopenharmony_ci    int ret;
1539cabdff1aSopenharmony_ci
1540cabdff1aSopenharmony_ci    clear_frame_metadata(s);
1541cabdff1aSopenharmony_ci
1542cabdff1aSopenharmony_ci    bytestream2_init(&s->gb, buf, buf_size);
1543cabdff1aSopenharmony_ci
1544cabdff1aSopenharmony_ci    /* check signature */
1545cabdff1aSopenharmony_ci    sig = bytestream2_get_be64(&s->gb);
1546cabdff1aSopenharmony_ci    if (sig != PNGSIG &&
1547cabdff1aSopenharmony_ci        sig != MNGSIG) {
1548cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Invalid PNG signature 0x%08"PRIX64".\n", sig);
1549cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
1550cabdff1aSopenharmony_ci    }
1551cabdff1aSopenharmony_ci
1552cabdff1aSopenharmony_ci    s->y = s->has_trns = 0;
1553cabdff1aSopenharmony_ci    s->hdr_state = 0;
1554cabdff1aSopenharmony_ci    s->pic_state = 0;
1555cabdff1aSopenharmony_ci
1556cabdff1aSopenharmony_ci    /* Reset z_stream */
1557cabdff1aSopenharmony_ci    ret = inflateReset(&s->zstream.zstream);
1558cabdff1aSopenharmony_ci    if (ret != Z_OK)
1559cabdff1aSopenharmony_ci        return AVERROR_EXTERNAL;
1560cabdff1aSopenharmony_ci
1561cabdff1aSopenharmony_ci    if ((ret = decode_frame_common(avctx, s, p, avpkt)) < 0)
1562cabdff1aSopenharmony_ci        goto the_end;
1563cabdff1aSopenharmony_ci
1564cabdff1aSopenharmony_ci    if (avctx->skip_frame == AVDISCARD_ALL) {
1565cabdff1aSopenharmony_ci        *got_frame = 0;
1566cabdff1aSopenharmony_ci        ret = bytestream2_tell(&s->gb);
1567cabdff1aSopenharmony_ci        goto the_end;
1568cabdff1aSopenharmony_ci    }
1569cabdff1aSopenharmony_ci
1570cabdff1aSopenharmony_ci    ret = output_frame(s, p);
1571cabdff1aSopenharmony_ci    if (ret < 0)
1572cabdff1aSopenharmony_ci        goto the_end;
1573cabdff1aSopenharmony_ci
1574cabdff1aSopenharmony_ci    if (!(avctx->active_thread_type & FF_THREAD_FRAME)) {
1575cabdff1aSopenharmony_ci        ff_thread_release_ext_buffer(avctx, &s->last_picture);
1576cabdff1aSopenharmony_ci        FFSWAP(ThreadFrame, s->picture, s->last_picture);
1577cabdff1aSopenharmony_ci    }
1578cabdff1aSopenharmony_ci
1579cabdff1aSopenharmony_ci    *got_frame = 1;
1580cabdff1aSopenharmony_ci
1581cabdff1aSopenharmony_ci    ret = bytestream2_tell(&s->gb);
1582cabdff1aSopenharmony_cithe_end:
1583cabdff1aSopenharmony_ci    s->crow_buf = NULL;
1584cabdff1aSopenharmony_ci    return ret;
1585cabdff1aSopenharmony_ci}
1586cabdff1aSopenharmony_ci#endif
1587cabdff1aSopenharmony_ci
1588cabdff1aSopenharmony_ci#if CONFIG_APNG_DECODER
1589cabdff1aSopenharmony_cistatic int decode_frame_apng(AVCodecContext *avctx, AVFrame *p,
1590cabdff1aSopenharmony_ci                             int *got_frame, AVPacket *avpkt)
1591cabdff1aSopenharmony_ci{
1592cabdff1aSopenharmony_ci    PNGDecContext *const s = avctx->priv_data;
1593cabdff1aSopenharmony_ci    int ret;
1594cabdff1aSopenharmony_ci
1595cabdff1aSopenharmony_ci    clear_frame_metadata(s);
1596cabdff1aSopenharmony_ci
1597cabdff1aSopenharmony_ci    if (!(s->hdr_state & PNG_IHDR)) {
1598cabdff1aSopenharmony_ci        if (!avctx->extradata_size)
1599cabdff1aSopenharmony_ci            return AVERROR_INVALIDDATA;
1600cabdff1aSopenharmony_ci
1601cabdff1aSopenharmony_ci        if ((ret = inflateReset(&s->zstream.zstream)) != Z_OK)
1602cabdff1aSopenharmony_ci            return AVERROR_EXTERNAL;
1603cabdff1aSopenharmony_ci        bytestream2_init(&s->gb, avctx->extradata, avctx->extradata_size);
1604cabdff1aSopenharmony_ci        if ((ret = decode_frame_common(avctx, s, NULL, avpkt)) < 0)
1605cabdff1aSopenharmony_ci            return ret;
1606cabdff1aSopenharmony_ci    }
1607cabdff1aSopenharmony_ci
1608cabdff1aSopenharmony_ci    /* reset state for a new frame */
1609cabdff1aSopenharmony_ci    if ((ret = inflateReset(&s->zstream.zstream)) != Z_OK)
1610cabdff1aSopenharmony_ci        return AVERROR_EXTERNAL;
1611cabdff1aSopenharmony_ci    s->y = 0;
1612cabdff1aSopenharmony_ci    s->pic_state = 0;
1613cabdff1aSopenharmony_ci    bytestream2_init(&s->gb, avpkt->data, avpkt->size);
1614cabdff1aSopenharmony_ci    if ((ret = decode_frame_common(avctx, s, p, avpkt)) < 0)
1615cabdff1aSopenharmony_ci        return ret;
1616cabdff1aSopenharmony_ci
1617cabdff1aSopenharmony_ci    if (!(s->pic_state & PNG_ALLIMAGE))
1618cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_WARNING, "Frame did not contain a complete image\n");
1619cabdff1aSopenharmony_ci    if (!(s->pic_state & (PNG_ALLIMAGE|PNG_IDAT)))
1620cabdff1aSopenharmony_ci        return AVERROR_INVALIDDATA;
1621cabdff1aSopenharmony_ci
1622cabdff1aSopenharmony_ci    ret = output_frame(s, p);
1623cabdff1aSopenharmony_ci    if (ret < 0)
1624cabdff1aSopenharmony_ci        return ret;
1625cabdff1aSopenharmony_ci
1626cabdff1aSopenharmony_ci    if (!(avctx->active_thread_type & FF_THREAD_FRAME)) {
1627cabdff1aSopenharmony_ci        if (s->dispose_op == APNG_DISPOSE_OP_PREVIOUS) {
1628cabdff1aSopenharmony_ci            ff_thread_release_ext_buffer(avctx, &s->picture);
1629cabdff1aSopenharmony_ci        } else {
1630cabdff1aSopenharmony_ci            ff_thread_release_ext_buffer(avctx, &s->last_picture);
1631cabdff1aSopenharmony_ci            FFSWAP(ThreadFrame, s->picture, s->last_picture);
1632cabdff1aSopenharmony_ci        }
1633cabdff1aSopenharmony_ci    }
1634cabdff1aSopenharmony_ci
1635cabdff1aSopenharmony_ci    *got_frame = 1;
1636cabdff1aSopenharmony_ci    return bytestream2_tell(&s->gb);
1637cabdff1aSopenharmony_ci}
1638cabdff1aSopenharmony_ci#endif
1639cabdff1aSopenharmony_ci
1640cabdff1aSopenharmony_ci#if HAVE_THREADS
1641cabdff1aSopenharmony_cistatic int update_thread_context(AVCodecContext *dst, const AVCodecContext *src)
1642cabdff1aSopenharmony_ci{
1643cabdff1aSopenharmony_ci    PNGDecContext *psrc = src->priv_data;
1644cabdff1aSopenharmony_ci    PNGDecContext *pdst = dst->priv_data;
1645cabdff1aSopenharmony_ci    ThreadFrame *src_frame = NULL;
1646cabdff1aSopenharmony_ci    int ret;
1647cabdff1aSopenharmony_ci
1648cabdff1aSopenharmony_ci    if (dst == src)
1649cabdff1aSopenharmony_ci        return 0;
1650cabdff1aSopenharmony_ci
1651cabdff1aSopenharmony_ci    if (CONFIG_APNG_DECODER && dst->codec_id == AV_CODEC_ID_APNG) {
1652cabdff1aSopenharmony_ci
1653cabdff1aSopenharmony_ci        pdst->width             = psrc->width;
1654cabdff1aSopenharmony_ci        pdst->height            = psrc->height;
1655cabdff1aSopenharmony_ci        pdst->bit_depth         = psrc->bit_depth;
1656cabdff1aSopenharmony_ci        pdst->color_type        = psrc->color_type;
1657cabdff1aSopenharmony_ci        pdst->compression_type  = psrc->compression_type;
1658cabdff1aSopenharmony_ci        pdst->interlace_type    = psrc->interlace_type;
1659cabdff1aSopenharmony_ci        pdst->filter_type       = psrc->filter_type;
1660cabdff1aSopenharmony_ci        pdst->has_trns = psrc->has_trns;
1661cabdff1aSopenharmony_ci        memcpy(pdst->transparent_color_be, psrc->transparent_color_be, sizeof(pdst->transparent_color_be));
1662cabdff1aSopenharmony_ci
1663cabdff1aSopenharmony_ci        memcpy(pdst->palette, psrc->palette, sizeof(pdst->palette));
1664cabdff1aSopenharmony_ci
1665cabdff1aSopenharmony_ci        pdst->hdr_state |= psrc->hdr_state;
1666cabdff1aSopenharmony_ci    }
1667cabdff1aSopenharmony_ci
1668cabdff1aSopenharmony_ci    src_frame = psrc->dispose_op == APNG_DISPOSE_OP_PREVIOUS ?
1669cabdff1aSopenharmony_ci                &psrc->last_picture : &psrc->picture;
1670cabdff1aSopenharmony_ci
1671cabdff1aSopenharmony_ci    ff_thread_release_ext_buffer(dst, &pdst->last_picture);
1672cabdff1aSopenharmony_ci    if (src_frame && src_frame->f->data[0]) {
1673cabdff1aSopenharmony_ci        ret = ff_thread_ref_frame(&pdst->last_picture, src_frame);
1674cabdff1aSopenharmony_ci        if (ret < 0)
1675cabdff1aSopenharmony_ci            return ret;
1676cabdff1aSopenharmony_ci    }
1677cabdff1aSopenharmony_ci
1678cabdff1aSopenharmony_ci    return 0;
1679cabdff1aSopenharmony_ci}
1680cabdff1aSopenharmony_ci#endif
1681cabdff1aSopenharmony_ci
1682cabdff1aSopenharmony_cistatic av_cold int png_dec_init(AVCodecContext *avctx)
1683cabdff1aSopenharmony_ci{
1684cabdff1aSopenharmony_ci    PNGDecContext *s = avctx->priv_data;
1685cabdff1aSopenharmony_ci
1686cabdff1aSopenharmony_ci    avctx->color_range = AVCOL_RANGE_JPEG;
1687cabdff1aSopenharmony_ci
1688cabdff1aSopenharmony_ci    s->avctx = avctx;
1689cabdff1aSopenharmony_ci    s->last_picture.f = av_frame_alloc();
1690cabdff1aSopenharmony_ci    s->picture.f = av_frame_alloc();
1691cabdff1aSopenharmony_ci    if (!s->last_picture.f || !s->picture.f)
1692cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
1693cabdff1aSopenharmony_ci
1694cabdff1aSopenharmony_ci    ff_pngdsp_init(&s->dsp);
1695cabdff1aSopenharmony_ci
1696cabdff1aSopenharmony_ci    return ff_inflate_init(&s->zstream, avctx);
1697cabdff1aSopenharmony_ci}
1698cabdff1aSopenharmony_ci
1699cabdff1aSopenharmony_cistatic av_cold int png_dec_end(AVCodecContext *avctx)
1700cabdff1aSopenharmony_ci{
1701cabdff1aSopenharmony_ci    PNGDecContext *s = avctx->priv_data;
1702cabdff1aSopenharmony_ci
1703cabdff1aSopenharmony_ci    ff_thread_release_ext_buffer(avctx, &s->last_picture);
1704cabdff1aSopenharmony_ci    av_frame_free(&s->last_picture.f);
1705cabdff1aSopenharmony_ci    ff_thread_release_ext_buffer(avctx, &s->picture);
1706cabdff1aSopenharmony_ci    av_frame_free(&s->picture.f);
1707cabdff1aSopenharmony_ci    av_freep(&s->buffer);
1708cabdff1aSopenharmony_ci    s->buffer_size = 0;
1709cabdff1aSopenharmony_ci    av_freep(&s->last_row);
1710cabdff1aSopenharmony_ci    s->last_row_size = 0;
1711cabdff1aSopenharmony_ci    av_freep(&s->tmp_row);
1712cabdff1aSopenharmony_ci    s->tmp_row_size = 0;
1713cabdff1aSopenharmony_ci
1714cabdff1aSopenharmony_ci    av_freep(&s->iccp_data);
1715cabdff1aSopenharmony_ci    av_dict_free(&s->frame_metadata);
1716cabdff1aSopenharmony_ci    ff_inflate_end(&s->zstream);
1717cabdff1aSopenharmony_ci
1718cabdff1aSopenharmony_ci    return 0;
1719cabdff1aSopenharmony_ci}
1720cabdff1aSopenharmony_ci
1721cabdff1aSopenharmony_ci#if CONFIG_APNG_DECODER
1722cabdff1aSopenharmony_ciconst FFCodec ff_apng_decoder = {
1723cabdff1aSopenharmony_ci    .p.name         = "apng",
1724cabdff1aSopenharmony_ci    .p.long_name    = NULL_IF_CONFIG_SMALL("APNG (Animated Portable Network Graphics) image"),
1725cabdff1aSopenharmony_ci    .p.type         = AVMEDIA_TYPE_VIDEO,
1726cabdff1aSopenharmony_ci    .p.id           = AV_CODEC_ID_APNG,
1727cabdff1aSopenharmony_ci    .priv_data_size = sizeof(PNGDecContext),
1728cabdff1aSopenharmony_ci    .init           = png_dec_init,
1729cabdff1aSopenharmony_ci    .close          = png_dec_end,
1730cabdff1aSopenharmony_ci    FF_CODEC_DECODE_CB(decode_frame_apng),
1731cabdff1aSopenharmony_ci    .update_thread_context = ONLY_IF_THREADS_ENABLED(update_thread_context),
1732cabdff1aSopenharmony_ci    .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS /*| AV_CODEC_CAP_DRAW_HORIZ_BAND*/,
1733cabdff1aSopenharmony_ci    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP |
1734cabdff1aSopenharmony_ci                      FF_CODEC_CAP_ALLOCATE_PROGRESS,
1735cabdff1aSopenharmony_ci};
1736cabdff1aSopenharmony_ci#endif
1737cabdff1aSopenharmony_ci
1738cabdff1aSopenharmony_ci#if CONFIG_PNG_DECODER
1739cabdff1aSopenharmony_ciconst FFCodec ff_png_decoder = {
1740cabdff1aSopenharmony_ci    .p.name         = "png",
1741cabdff1aSopenharmony_ci    .p.long_name    = NULL_IF_CONFIG_SMALL("PNG (Portable Network Graphics) image"),
1742cabdff1aSopenharmony_ci    .p.type         = AVMEDIA_TYPE_VIDEO,
1743cabdff1aSopenharmony_ci    .p.id           = AV_CODEC_ID_PNG,
1744cabdff1aSopenharmony_ci    .priv_data_size = sizeof(PNGDecContext),
1745cabdff1aSopenharmony_ci    .init           = png_dec_init,
1746cabdff1aSopenharmony_ci    .close          = png_dec_end,
1747cabdff1aSopenharmony_ci    FF_CODEC_DECODE_CB(decode_frame_png),
1748cabdff1aSopenharmony_ci    .update_thread_context = ONLY_IF_THREADS_ENABLED(update_thread_context),
1749cabdff1aSopenharmony_ci    .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS /*| AV_CODEC_CAP_DRAW_HORIZ_BAND*/,
1750cabdff1aSopenharmony_ci    .caps_internal  = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM | FF_CODEC_CAP_INIT_THREADSAFE |
1751cabdff1aSopenharmony_ci                      FF_CODEC_CAP_ALLOCATE_PROGRESS | FF_CODEC_CAP_INIT_CLEANUP,
1752cabdff1aSopenharmony_ci};
1753cabdff1aSopenharmony_ci#endif
1754