[FFmpeg-devel] [PATCH 7/8] apng: Make PNG encoder only write headers once in APNG mode

Donny Yang work at kota.moe
Sun Mar 29 13:05:44 CEST 2015


Signed-off-by: Donny Yang <work at kota.moe>
---
 configure              |  1 +
 libavcodec/Makefile    |  1 +
 libavcodec/allcodecs.c |  2 +-
 libavcodec/pngenc.c    | 53 ++++++++++++++++++++++++++++++++++++++++++++++----
 4 files changed, 52 insertions(+), 5 deletions(-)

diff --git a/configure b/configure
index e1849a2..eb37aa5 100755
--- a/configure
+++ b/configure
@@ -2098,6 +2098,7 @@ amv_decoder_select="sp5x_decoder exif"
 amv_encoder_select="aandcttables mpegvideoenc"
 ape_decoder_select="bswapdsp llauddsp"
 apng_decoder_select="zlib"
+apng_encoder_select="huffyuvencdsp zlib"
 asv1_decoder_select="blockdsp bswapdsp idctdsp"
 asv1_encoder_select="bswapdsp fdctdsp pixblockdsp"
 asv2_decoder_select="blockdsp bswapdsp idctdsp"
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 91a40ad..c1b7390 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -144,6 +144,7 @@ OBJS-$(CONFIG_ANM_DECODER)             += anm.o
 OBJS-$(CONFIG_ANSI_DECODER)            += ansi.o cga_data.o
 OBJS-$(CONFIG_APE_DECODER)             += apedec.o
 OBJS-$(CONFIG_APNG_DECODER)            += png.o pngdec.o pngdsp.o
+OBJS-$(CONFIG_APNG_ENCODER)            += png.o pngenc.o
 OBJS-$(CONFIG_SSA_DECODER)             += assdec.o ass.o ass_split.o
 OBJS-$(CONFIG_SSA_ENCODER)             += assenc.o ass.o
 OBJS-$(CONFIG_ASS_DECODER)             += assdec.o ass.o ass_split.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 89acac1..ef3558a 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -108,7 +108,7 @@ void avcodec_register_all(void)
     REGISTER_ENCDEC (AMV,               amv);
     REGISTER_DECODER(ANM,               anm);
     REGISTER_DECODER(ANSI,              ansi);
-    REGISTER_DECODER(APNG,              apng);
+    REGISTER_ENCDEC (APNG,              apng);
     REGISTER_ENCDEC (ASV1,              asv1);
     REGISTER_ENCDEC (ASV2,              asv2);
     REGISTER_DECODER(AURA,              aura);
diff --git a/libavcodec/pngenc.c b/libavcodec/pngenc.c
index 0264575..116ebc5 100644
--- a/libavcodec/pngenc.c
+++ b/libavcodec/pngenc.c
@@ -53,6 +53,8 @@ typedef struct PNGEncContext {
     int bit_depth;
     int color_type;
     int bits_per_pixel;
+
+    uint32_t palette_checksum;   // Used to ensure a single unique palette in APNG mode
 } PNGEncContext;
 
 static void png_get_interlaced_row(uint8_t *dst, int row_size,
@@ -463,6 +465,18 @@ static int encode(AVCodecContext *avctx, AVPacket *pkt,
     int enc_row_size;
     size_t max_packet_size;
 
+    if (avctx->codec_id == AV_CODEC_ID_APNG && s->color_type == PNG_COLOR_TYPE_PALETTE) {
+        uint32_t checksum = crc32(crc32(0, Z_NULL, 0), pict->data[1], 256 * sizeof(uint32_t));
+
+        if (avctx->frame_number == 0) {
+            s->palette_checksum = checksum;
+        } else if (checksum != s->palette_checksum) {
+            av_log(avctx, AV_LOG_ERROR,
+                   "Input contains more than one unique palette. APNG does not support multiple palettes.\n");
+            return -1;
+        }
+    }
+
     enc_row_size = deflateBound(&s->zstream, (avctx->width * s->bits_per_pixel + 7) >> 3);
     max_packet_size =
         8 +             // PNGSIG
@@ -485,15 +499,19 @@ static int encode(AVCodecContext *avctx, AVPacket *pkt,
     s->bytestream       = pkt->data;
     s->bytestream_end   = pkt->data + pkt->size;
 
-    ret = encode_headers(avctx, pict);
-    if (ret)
-        return ret;
+    if (avctx->codec_id == AV_CODEC_ID_PNG || avctx->frame_number == 0) {
+        ret = encode_headers(avctx, pict);
+        if (ret)
+            return ret;
+    }
 
     ret = encode_frame(avctx, pict);
     if (ret)
         return ret;
 
-    png_write_chunk(&s->bytestream, MKTAG('I', 'E', 'N', 'D'), NULL, 0);
+    if (avctx->codec_id == AV_CODEC_ID_PNG) {
+        png_write_chunk(&s->bytestream, MKTAG('I', 'E', 'N', 'D'), NULL, 0);
+    }
 
     pkt->size = s->bytestream - s->bytestream_start;
     pkt->flags |= AV_PKT_FLAG_KEY;
@@ -629,6 +647,13 @@ static const AVClass pngenc_class = {
     .version    = LIBAVUTIL_VERSION_INT,
 };
 
+static const AVClass apngenc_class = {
+    .class_name = "APNG encoder",
+    .item_name  = av_default_item_name,
+    .option     = options,
+    .version    = LIBAVUTIL_VERSION_INT,
+};
+
 AVCodec ff_png_encoder = {
     .name           = "png",
     .long_name      = NULL_IF_CONFIG_SMALL("PNG (Portable Network Graphics) image"),
@@ -649,3 +674,23 @@ AVCodec ff_png_encoder = {
     },
     .priv_class     = &pngenc_class,
 };
+
+AVCodec ff_apng_encoder = {
+    .name           = "apng",
+    .long_name      = NULL_IF_CONFIG_SMALL("APNG (Animated Portable Network Graphics) image"),
+    .type           = AVMEDIA_TYPE_VIDEO,
+    .id             = AV_CODEC_ID_APNG,
+    .priv_data_size = sizeof(PNGEncContext),
+    .init           = png_enc_init,
+    .close          = png_enc_close,
+    .encode2        = encode,
+    .pix_fmts       = (const enum AVPixelFormat[]) {
+        AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA,
+        AV_PIX_FMT_RGB48BE, AV_PIX_FMT_RGBA64BE,
+        AV_PIX_FMT_PAL8,
+        AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8A,
+        AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_YA16BE,
+        AV_PIX_FMT_MONOBLACK, AV_PIX_FMT_NONE
+    },
+    .priv_class     = &apngenc_class,
+};
-- 
2.3.4


More information about the ffmpeg-devel mailing list