Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

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