]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/pngdec.c
Merge commit 'e46a6fb7732a7caef97a916a4f765ec0f779d195'
[ffmpeg] / libavcodec / pngdec.c
index 83eeb8d322aef97f81af0080594a4c80191bce2d..a4eb6cce1b187764cc4441c7d688c705fe9844bb 100644 (file)
@@ -45,9 +45,6 @@ typedef struct PNGDecContext {
     ThreadFrame last_picture;
     ThreadFrame picture;
 
-    uint8_t* extra_data;
-    int extra_data_size;
-
     int state;
     int width, height;
     int cur_w, cur_h;
@@ -440,13 +437,13 @@ static int decode_zbuf(AVBPrint *bp, const uint8_t *data,
     av_bprint_init(bp, 0, -1);
 
     while (zstream.avail_in > 0) {
-        av_bprint_get_buffer(bp, 1, &buf, &buf_size);
-        if (!buf_size) {
+        av_bprint_get_buffer(bp, 2, &buf, &buf_size);
+        if (buf_size < 2) {
             ret = AVERROR(ENOMEM);
             goto fail;
         }
         zstream.next_out  = buf;
-        zstream.avail_out = buf_size;
+        zstream.avail_out = buf_size - 1;
         ret = inflate(&zstream, Z_PARTIAL_FLUSH);
         if (ret != Z_OK && ret != Z_STREAM_END) {
             ret = AVERROR_EXTERNAL;
@@ -562,6 +559,11 @@ static int decode_ihdr_chunk(AVCodecContext *avctx, PNGDecContext *s,
         return AVERROR_INVALIDDATA;
     }
     s->bit_depth        = bytestream2_get_byte(&s->gb);
+    if (s->bit_depth != 1 && s->bit_depth != 2 && s->bit_depth != 4 &&
+        s->bit_depth != 8 && s->bit_depth != 16) {
+        av_log(avctx, AV_LOG_ERROR, "Invalid bit depth\n");
+        goto error;
+    }
     s->color_type       = bytestream2_get_byte(&s->gb);
     s->compression_type = bytestream2_get_byte(&s->gb);
     s->filter_type      = bytestream2_get_byte(&s->gb);
@@ -575,6 +577,10 @@ static int decode_ihdr_chunk(AVCodecContext *avctx, PNGDecContext *s,
                 s->compression_type, s->filter_type, s->interlace_type);
 
     return 0;
+error:
+    s->cur_w = s->cur_h = s->width = s->height = 0;
+    s->bit_depth = 8;
+    return AVERROR_INVALIDDATA;
 }
 
 static int decode_phys_chunk(AVCodecContext *avctx, PNGDecContext *s)
@@ -775,17 +781,28 @@ static int decode_trns_chunk(AVCodecContext *avctx, PNGDecContext *s,
 {
     int v, i;
 
+    if (!(s->state & PNG_IHDR)) {
+        av_log(avctx, AV_LOG_ERROR, "trns before IHDR\n");
+        return AVERROR_INVALIDDATA;
+    }
+
+    if (s->state & PNG_IDAT) {
+        av_log(avctx, AV_LOG_ERROR, "trns after IDAT\n");
+        return AVERROR_INVALIDDATA;
+    }
+
     if (s->color_type == PNG_COLOR_TYPE_PALETTE) {
         if (length > 256 || !(s->state & PNG_PLTE))
             return AVERROR_INVALIDDATA;
 
         for (i = 0; i < length; i++) {
-            v = bytestream2_get_byte(&s->gb);
+            unsigned v = bytestream2_get_byte(&s->gb);
             s->palette[i] = (s->palette[i] & 0x00ffffff) | (v << 24);
         }
     } else if (s->color_type == PNG_COLOR_TYPE_GRAY || s->color_type == PNG_COLOR_TYPE_RGB) {
         if ((s->color_type == PNG_COLOR_TYPE_GRAY && length != 2) ||
-            (s->color_type == PNG_COLOR_TYPE_RGB && length != 6))
+            (s->color_type == PNG_COLOR_TYPE_RGB && length != 6) ||
+            s->bit_depth == 1)
             return AVERROR_INVALIDDATA;
 
         for (i = 0; i < length / 2; i++) {
@@ -925,7 +942,8 @@ static int decode_fctl_chunk(AVCodecContext *avctx, PNGDecContext *s,
         return AVERROR_INVALIDDATA;
     }
 
-    if (sequence_number == 0 && dispose_op == APNG_DISPOSE_OP_PREVIOUS) {
+    if ((sequence_number == 0 || !s->previous_picture.f->data[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
         dispose_op = APNG_DISPOSE_OP_BACKGROUND;
@@ -1089,7 +1107,7 @@ static int handle_p_frame_apng(AVCodecContext *avctx, PNGDecContext *s,
 static int decode_frame_common(AVCodecContext *avctx, PNGDecContext *s,
                                AVFrame *p, AVPacket *avpkt)
 {
-    AVDictionary *metadata  = NULL;
+    AVDictionary **metadatap = NULL;
     uint32_t tag, length;
     int decode_next_dat = 0;
     int ret;
@@ -1100,7 +1118,6 @@ static int decode_frame_common(AVCodecContext *avctx, PNGDecContext *s,
 
             if (avctx->codec_id == AV_CODEC_ID_PNG &&
                 avctx->skip_frame == AVDISCARD_ALL) {
-                av_frame_set_metadata(p, metadata);
                 return 0;
             }
 
@@ -1146,6 +1163,7 @@ static int decode_frame_common(AVCodecContext *avctx, PNGDecContext *s,
             }
         }
 
+        metadatap = avpriv_frame_get_metadatap(p);
         switch (tag) {
         case MKTAG('I', 'H', 'D', 'R'):
             if ((ret = decode_ihdr_chunk(avctx, s, length)) < 0)
@@ -1187,12 +1205,12 @@ static int decode_frame_common(AVCodecContext *avctx, PNGDecContext *s,
                 goto skip_tag;
             break;
         case MKTAG('t', 'E', 'X', 't'):
-            if (decode_text_chunk(s, length, 0, &metadata) < 0)
+            if (decode_text_chunk(s, length, 0, metadatap) < 0)
                 av_log(avctx, AV_LOG_WARNING, "Broken tEXt chunk\n");
             bytestream2_skip(&s->gb, length + 4);
             break;
         case MKTAG('z', 'T', 'X', 't'):
-            if (decode_text_chunk(s, length, 1, &metadata) < 0)
+            if (decode_text_chunk(s, length, 1, metadatap) < 0)
                 av_log(avctx, AV_LOG_WARNING, "Broken zTXt chunk\n");
             bytestream2_skip(&s->gb, length + 4);
             break;
@@ -1229,9 +1247,9 @@ skip_tag:
         }
     }
 exit_loop:
+
     if (avctx->codec_id == AV_CODEC_ID_PNG &&
         avctx->skip_frame == AVDISCARD_ALL) {
-        av_frame_set_metadata(p, metadata);
         return 0;
     }
 
@@ -1244,6 +1262,8 @@ exit_loop:
         size_t raw_bpp = s->bpp - byte_depth;
         unsigned x, y;
 
+        av_assert0(s->bit_depth > 1);
+
         for (y = 0; y < s->height; ++y) {
             uint8_t *row = &s->image_buf[s->image_linesize * y];
 
@@ -1279,12 +1299,9 @@ exit_loop:
     ff_thread_report_progress(&s->picture, INT_MAX, 0);
     ff_thread_report_progress(&s->previous_picture, INT_MAX, 0);
 
-    av_frame_set_metadata(p, metadata);
-    metadata   = NULL;
     return 0;
 
 fail:
-    av_dict_free(&metadata);
     ff_thread_report_progress(&s->picture, INT_MAX, 0);
     ff_thread_report_progress(&s->previous_picture, INT_MAX, 0);
     return ret;
@@ -1364,28 +1381,14 @@ static int decode_frame_apng(AVCodecContext *avctx,
     p = s->picture.f;
 
     if (!(s->state & PNG_IHDR)) {
-        int side_data_size = 0;
-        uint8_t *side_data = NULL;
-        if (avpkt)
-            side_data = av_packet_get_side_data(avpkt, AV_PKT_DATA_NEW_EXTRADATA, &side_data_size);
-
-        if (side_data_size) {
-            av_freep(&s->extra_data);
-            s->extra_data = av_mallocz(side_data_size + AV_INPUT_BUFFER_PADDING_SIZE);
-            if (!s->extra_data)
-                return AVERROR(ENOMEM);
-            s->extra_data_size = side_data_size;
-            memcpy(s->extra_data, side_data, s->extra_data_size);
-        }
-
-        if (!s->extra_data_size)
+        if (!avctx->extradata_size)
             return AVERROR_INVALIDDATA;
 
         /* only init fields, there is no zlib use in extradata */
         s->zstream.zalloc = ff_png_zalloc;
         s->zstream.zfree  = ff_png_zfree;
 
-        bytestream2_init(&s->gb, s->extra_data, s->extra_data_size);
+        bytestream2_init(&s->gb, avctx->extradata, avctx->extradata_size);
         if ((ret = decode_frame_common(avctx, s, p, avpkt)) < 0)
             goto end;
     }
@@ -1511,8 +1514,6 @@ static av_cold int png_dec_end(AVCodecContext *avctx)
     s->last_row_size = 0;
     av_freep(&s->tmp_row);
     s->tmp_row_size = 0;
-    av_freep(&s->extra_data);
-    s->extra_data_size = 0;
 
     return 0;
 }
@@ -1530,6 +1531,7 @@ AVCodec ff_apng_decoder = {
     .init_thread_copy = ONLY_IF_THREADS_ENABLED(png_dec_init),
     .update_thread_context = ONLY_IF_THREADS_ENABLED(update_thread_context),
     .capabilities   = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS /*| AV_CODEC_CAP_DRAW_HORIZ_BAND*/,
+    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE,
 };
 #endif
 
@@ -1546,6 +1548,6 @@ AVCodec ff_png_decoder = {
     .init_thread_copy = ONLY_IF_THREADS_ENABLED(png_dec_init),
     .update_thread_context = ONLY_IF_THREADS_ENABLED(update_thread_context),
     .capabilities   = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS /*| AV_CODEC_CAP_DRAW_HORIZ_BAND*/,
-    .caps_internal  = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM,
+    .caps_internal  = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM | FF_CODEC_CAP_INIT_THREADSAFE,
 };
 #endif