]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/pngdec.c
Merge commit '219b39a71a5694b1c14a07b86477f665a5b6849b'
[ffmpeg] / libavcodec / pngdec.c
index ceda383209a63ab2755188ebb91391d30d6a0095..b8011fea59108961aa98f58d4ecbadc4e5b3504f 100644 (file)
@@ -542,18 +542,18 @@ static int decode_ihdr_chunk(AVCodecContext *avctx, PNGDecContext *s,
         return AVERROR_INVALIDDATA;
     }
 
-    s->width  = bytestream2_get_be32(&s->gb);
-    s->height = bytestream2_get_be32(&s->gb);
+    if (s->state & PNG_IHDR) {
+        av_log(avctx, AV_LOG_ERROR, "Multiple IHDR\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    s->width  = s->cur_w = bytestream2_get_be32(&s->gb);
+    s->height = s->cur_h = bytestream2_get_be32(&s->gb);
     if (av_image_check_size(s->width, s->height, 0, avctx)) {
-        s->width = s->height = 0;
+        s->cur_w = s->cur_h = s->width = s->height = 0;
         av_log(avctx, AV_LOG_ERROR, "Invalid image size\n");
         return AVERROR_INVALIDDATA;
     }
-    if (s->cur_w == 0 && s->cur_h == 0) {
-        // Only set cur_w/h if update_thread_context() has not set it
-        s->cur_w = s->width;
-        s->cur_h = s->height;
-    }
     s->bit_depth        = bytestream2_get_byte(&s->gb);
     s->color_type       = bytestream2_get_byte(&s->gb);
     s->compression_type = bytestream2_get_byte(&s->gb);
@@ -815,10 +815,16 @@ static int decode_fctl_chunk(AVCodecContext *avctx, PNGDecContext *s,
                              uint32_t length)
 {
     uint32_t sequence_number;
+    int cur_w, cur_h, x_offset, y_offset, dispose_op, blend_op;
 
     if (length != 26)
         return AVERROR_INVALIDDATA;
 
+    if (!(s->state & PNG_IHDR)) {
+        av_log(avctx, AV_LOG_ERROR, "fctl before IHDR\n");
+        return AVERROR_INVALIDDATA;
+    }
+
     s->last_w = s->cur_w;
     s->last_h = s->cur_h;
     s->last_x_offset = s->x_offset;
@@ -826,32 +832,32 @@ static int decode_fctl_chunk(AVCodecContext *avctx, PNGDecContext *s,
     s->last_dispose_op = s->dispose_op;
 
     sequence_number = bytestream2_get_be32(&s->gb);
-    s->cur_w        = bytestream2_get_be32(&s->gb);
-    s->cur_h        = bytestream2_get_be32(&s->gb);
-    s->x_offset     = bytestream2_get_be32(&s->gb);
-    s->y_offset     = bytestream2_get_be32(&s->gb);
+    cur_w           = bytestream2_get_be32(&s->gb);
+    cur_h           = bytestream2_get_be32(&s->gb);
+    x_offset        = bytestream2_get_be32(&s->gb);
+    y_offset        = bytestream2_get_be32(&s->gb);
     bytestream2_skip(&s->gb, 4); /* delay_num (2), delay_den (2) */
-    s->dispose_op   = bytestream2_get_byte(&s->gb);
-    s->blend_op     = bytestream2_get_byte(&s->gb);
+    dispose_op      = bytestream2_get_byte(&s->gb);
+    blend_op        = bytestream2_get_byte(&s->gb);
     bytestream2_skip(&s->gb, 4); /* crc */
 
     if (sequence_number == 0 &&
-        (s->cur_w != s->width ||
-         s->cur_h != s->height ||
-         s->x_offset != 0 ||
-         s->y_offset != 0) ||
-        s->cur_w <= 0 || s->cur_h <= 0 ||
-        s->x_offset < 0 || s->y_offset < 0 ||
-        s->cur_w > s->width - s->x_offset|| s->cur_h > s->height - s->y_offset)
+        (cur_w != s->width ||
+         cur_h != s->height ||
+         x_offset != 0 ||
+         y_offset != 0) ||
+        cur_w <= 0 || cur_h <= 0 ||
+        x_offset < 0 || y_offset < 0 ||
+        cur_w > s->width - x_offset|| cur_h > s->height - y_offset)
             return AVERROR_INVALIDDATA;
 
-    if (sequence_number == 0 && s->dispose_op == APNG_DISPOSE_OP_PREVIOUS) {
+    if (sequence_number == 0 && dispose_op == APNG_DISPOSE_OP_PREVIOUS) {
         // No previous frame to revert to for the first frame
         // Spec says to just treat it as a APNG_DISPOSE_OP_BACKGROUND
-        s->dispose_op = APNG_DISPOSE_OP_BACKGROUND;
+        dispose_op = APNG_DISPOSE_OP_BACKGROUND;
     }
 
-    if (s->dispose_op == APNG_BLEND_OP_OVER && !s->has_trns && (
+    if (blend_op == APNG_BLEND_OP_OVER && !s->has_trns && (
             avctx->pix_fmt == AV_PIX_FMT_RGB24 ||
             avctx->pix_fmt == AV_PIX_FMT_RGB48BE ||
             avctx->pix_fmt == AV_PIX_FMT_PAL8 ||
@@ -859,10 +865,17 @@ static int decode_fctl_chunk(AVCodecContext *avctx, PNGDecContext *s,
             avctx->pix_fmt == AV_PIX_FMT_GRAY16BE ||
             avctx->pix_fmt == AV_PIX_FMT_MONOBLACK
         )) {
-        // APNG_DISPOSE_OP_OVER is the same as APNG_DISPOSE_OP_SOURCE when there is no alpha channel
-        s->dispose_op = APNG_BLEND_OP_SOURCE;
+        // APNG_BLEND_OP_OVER is the same as APNG_BLEND_OP_SOURCE when there is no alpha channel
+        blend_op = APNG_BLEND_OP_SOURCE;
     }
 
+    s->cur_w      = cur_w;
+    s->cur_h      = cur_h;
+    s->x_offset   = x_offset;
+    s->y_offset   = y_offset;
+    s->dispose_op = dispose_op;
+    s->blend_op   = blend_op;
+
     return 0;
 }
 
@@ -1259,12 +1272,25 @@ static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src)
         (ret = ff_thread_ref_frame(&pdst->picture, &psrc->picture)) < 0)
         return ret;
     if (CONFIG_APNG_DECODER && dst->codec_id == AV_CODEC_ID_APNG) {
+        pdst->width             = psrc->width;
+        pdst->height            = psrc->height;
+        pdst->bit_depth         = psrc->bit_depth;
+        pdst->color_type        = psrc->color_type;
+        pdst->compression_type  = psrc->compression_type;
+        pdst->interlace_type    = psrc->interlace_type;
+        pdst->filter_type       = psrc->filter_type;
         pdst->cur_w = psrc->cur_w;
         pdst->cur_h = psrc->cur_h;
         pdst->x_offset = psrc->x_offset;
         pdst->y_offset = psrc->y_offset;
+        pdst->has_trns = psrc->has_trns;
+
         pdst->dispose_op = psrc->dispose_op;
 
+        memcpy(pdst->palette, psrc->palette, sizeof(pdst->palette));
+
+        pdst->state |= psrc->state & (PNG_IHDR | PNG_PLTE);
+
         ff_thread_release_buffer(dst, &pdst->last_picture);
         if (psrc->last_picture.f->data[0])
             return ff_thread_ref_frame(&pdst->last_picture, &psrc->last_picture);