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);
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)
{
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++) {
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;
if (avctx->codec_id == AV_CODEC_ID_PNG &&
avctx->skip_frame == AVDISCARD_ALL) {
- av_frame_set_metadata(p, metadata);
return 0;
}
}
}
+ metadatap = avpriv_frame_get_metadatap(p);
switch (tag) {
case MKTAG('I', 'H', 'D', 'R'):
if ((ret = decode_ihdr_chunk(avctx, s, length)) < 0)
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;
}
}
exit_loop:
+
if (avctx->codec_id == AV_CODEC_ID_PNG &&
avctx->skip_frame == AVDISCARD_ALL) {
- av_frame_set_metadata(p, metadata);
return 0;
}
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];
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;
.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
.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