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