From b35fa041521cf2b183e94697d57584c63c64dc3f Mon Sep 17 00:00:00 2001 From: Benoit Fouet Date: Fri, 14 Nov 2014 10:17:33 +0100 Subject: [PATCH] avcodec/pngdec: create a function to decode IDAT chunk. Signed-off-by: Michael Niedermayer --- libavcodec/pngdec.c | 207 +++++++++++++++++++++++--------------------- 1 file changed, 109 insertions(+), 98 deletions(-) diff --git a/libavcodec/pngdec.c b/libavcodec/pngdec.c index 99a3a72389..8199bd8236 100644 --- a/libavcodec/pngdec.c +++ b/libavcodec/pngdec.c @@ -563,6 +563,114 @@ static int decode_phys_chunk(AVCodecContext *avctx, PNGDecContext *s) return 0; } +static int decode_idat_chunk(AVCodecContext *avctx, PNGDecContext *s, + uint32_t length, AVFrame *p) +{ + int ret; + + if (!(s->state & PNG_IHDR)) { + av_log(avctx, AV_LOG_ERROR, "IDAT without IHDR\n"); + return AVERROR_INVALIDDATA; + } + if (!(s->state & PNG_IDAT)) { + /* init image info */ + avctx->width = s->width; + avctx->height = s->height; + + s->channels = ff_png_get_nb_channels(s->color_type); + s->bits_per_pixel = s->bit_depth * s->channels; + s->bpp = (s->bits_per_pixel + 7) >> 3; + s->row_size = (avctx->width * s->bits_per_pixel + 7) >> 3; + + if ((s->bit_depth == 2 || s->bit_depth == 4 || s->bit_depth == 8) && + s->color_type == PNG_COLOR_TYPE_RGB) { + avctx->pix_fmt = AV_PIX_FMT_RGB24; + } else if ((s->bit_depth == 2 || s->bit_depth == 4 || s->bit_depth == 8) && + s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { + avctx->pix_fmt = AV_PIX_FMT_RGBA; + } else if ((s->bit_depth == 2 || s->bit_depth == 4 || s->bit_depth == 8) && + s->color_type == PNG_COLOR_TYPE_GRAY) { + avctx->pix_fmt = AV_PIX_FMT_GRAY8; + } else if (s->bit_depth == 16 && + s->color_type == PNG_COLOR_TYPE_GRAY) { + avctx->pix_fmt = AV_PIX_FMT_GRAY16BE; + } else if (s->bit_depth == 16 && + s->color_type == PNG_COLOR_TYPE_RGB) { + avctx->pix_fmt = AV_PIX_FMT_RGB48BE; + } else if (s->bit_depth == 16 && + s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { + avctx->pix_fmt = AV_PIX_FMT_RGBA64BE; + } else if ((s->bits_per_pixel == 1 || s->bits_per_pixel == 2 || s->bits_per_pixel == 4 || s->bits_per_pixel == 8) && + s->color_type == PNG_COLOR_TYPE_PALETTE) { + avctx->pix_fmt = AV_PIX_FMT_PAL8; + } else if (s->bit_depth == 1 && s->bits_per_pixel == 1) { + avctx->pix_fmt = AV_PIX_FMT_MONOBLACK; + } else if (s->bit_depth == 8 && + s->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { + avctx->pix_fmt = AV_PIX_FMT_YA8; + } else if (s->bit_depth == 16 && + s->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { + avctx->pix_fmt = AV_PIX_FMT_YA16BE; + } else { + av_log(avctx, AV_LOG_ERROR, "unsupported bit depth %d " + "and color type %d\n", + s->bit_depth, s->color_type); + return AVERROR_INVALIDDATA; + } + + if ((ret = ff_thread_get_buffer(avctx, &s->picture, AV_GET_BUFFER_FLAG_REF)) < 0) + return ret; + ff_thread_finish_setup(avctx); + + p->pict_type = AV_PICTURE_TYPE_I; + p->key_frame = 1; + p->interlaced_frame = !!s->interlace_type; + + /* compute the compressed row size */ + if (!s->interlace_type) { + s->crow_size = s->row_size + 1; + } else { + s->pass = 0; + s->pass_row_size = ff_png_pass_row_size(s->pass, + s->bits_per_pixel, + s->width); + s->crow_size = s->pass_row_size + 1; + } + av_dlog(avctx, "row_size=%d crow_size =%d\n", + s->row_size, s->crow_size); + s->image_buf = p->data[0]; + s->image_linesize = p->linesize[0]; + /* copy the palette if needed */ + if (avctx->pix_fmt == AV_PIX_FMT_PAL8) + memcpy(p->data[1], s->palette, 256 * sizeof(uint32_t)); + /* empty row is used if differencing to the first row */ + av_fast_padded_mallocz(&s->last_row, &s->last_row_size, s->row_size); + if (!s->last_row) + return AVERROR_INVALIDDATA; + if (s->interlace_type || + s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { + av_fast_padded_malloc(&s->tmp_row, &s->tmp_row_size, s->row_size); + if (!s->tmp_row) + return AVERROR_INVALIDDATA; + } + /* compressed row */ + av_fast_padded_malloc(&s->buffer, &s->buffer_size, s->row_size + 16); + if (!s->buffer) + return AVERROR(ENOMEM); + + /* we want crow_buf+1 to be 16-byte aligned */ + s->crow_buf = s->buffer + 15; + s->zstream.avail_out = s->crow_size; + s->zstream.next_out = s->crow_buf; + } + s->state |= PNG_IDAT; + if ((ret = png_decode_idat(s, length)) < 0) + return ret; + bytestream2_skip(&s->gb, 4); /* crc */ + + return 0; +} + static int decode_frame_png(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt) @@ -632,105 +740,8 @@ static int decode_frame_png(AVCodecContext *avctx, goto fail; break; case MKTAG('I', 'D', 'A', 'T'): - if (!(s->state & PNG_IHDR)) { - av_log(avctx, AV_LOG_ERROR, "IDAT without IHDR\n"); + if (decode_idat_chunk(avctx, s, length, p) < 0) goto fail; - } - if (!(s->state & PNG_IDAT)) { - /* init image info */ - avctx->width = s->width; - avctx->height = s->height; - - s->channels = ff_png_get_nb_channels(s->color_type); - s->bits_per_pixel = s->bit_depth * s->channels; - s->bpp = (s->bits_per_pixel + 7) >> 3; - s->row_size = (avctx->width * s->bits_per_pixel + 7) >> 3; - - if ((s->bit_depth == 2 || s->bit_depth == 4 || s->bit_depth == 8) && - s->color_type == PNG_COLOR_TYPE_RGB) { - avctx->pix_fmt = AV_PIX_FMT_RGB24; - } else if ((s->bit_depth == 2 || s->bit_depth == 4 || s->bit_depth == 8) && - s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { - avctx->pix_fmt = AV_PIX_FMT_RGBA; - } else if ((s->bit_depth == 2 || s->bit_depth == 4 || s->bit_depth == 8) && - s->color_type == PNG_COLOR_TYPE_GRAY) { - avctx->pix_fmt = AV_PIX_FMT_GRAY8; - } else if (s->bit_depth == 16 && - s->color_type == PNG_COLOR_TYPE_GRAY) { - avctx->pix_fmt = AV_PIX_FMT_GRAY16BE; - } else if (s->bit_depth == 16 && - s->color_type == PNG_COLOR_TYPE_RGB) { - avctx->pix_fmt = AV_PIX_FMT_RGB48BE; - } else if (s->bit_depth == 16 && - s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { - avctx->pix_fmt = AV_PIX_FMT_RGBA64BE; - } else if ((s->bits_per_pixel == 1 || s->bits_per_pixel == 2 || s->bits_per_pixel == 4 || s->bits_per_pixel == 8) && - s->color_type == PNG_COLOR_TYPE_PALETTE) { - avctx->pix_fmt = AV_PIX_FMT_PAL8; - } else if (s->bit_depth == 1 && s->bits_per_pixel == 1) { - avctx->pix_fmt = AV_PIX_FMT_MONOBLACK; - } else if (s->bit_depth == 8 && - s->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { - avctx->pix_fmt = AV_PIX_FMT_YA8; - } else if (s->bit_depth == 16 && - s->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { - avctx->pix_fmt = AV_PIX_FMT_YA16BE; - } else { - av_log(avctx, AV_LOG_ERROR, "unsupported bit depth %d " - "and color type %d\n", - s->bit_depth, s->color_type); - goto fail; - } - - if (ff_thread_get_buffer(avctx, &s->picture, AV_GET_BUFFER_FLAG_REF) < 0) - goto fail; - ff_thread_finish_setup(avctx); - - p->pict_type = AV_PICTURE_TYPE_I; - p->key_frame = 1; - p->interlaced_frame = !!s->interlace_type; - - /* compute the compressed row size */ - if (!s->interlace_type) { - s->crow_size = s->row_size + 1; - } else { - s->pass = 0; - s->pass_row_size = ff_png_pass_row_size(s->pass, - s->bits_per_pixel, - s->width); - s->crow_size = s->pass_row_size + 1; - } - av_dlog(avctx, "row_size=%d crow_size =%d\n", - s->row_size, s->crow_size); - s->image_buf = p->data[0]; - s->image_linesize = p->linesize[0]; - /* copy the palette if needed */ - if (avctx->pix_fmt == AV_PIX_FMT_PAL8) - memcpy(p->data[1], s->palette, 256 * sizeof(uint32_t)); - /* empty row is used if differencing to the first row */ - av_fast_padded_mallocz(&s->last_row, &s->last_row_size, s->row_size); - if (!s->last_row) - goto fail; - if (s->interlace_type || - s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { - av_fast_padded_malloc(&s->tmp_row, &s->tmp_row_size, s->row_size); - if (!s->tmp_row) - goto fail; - } - /* compressed row */ - av_fast_padded_malloc(&s->buffer, &s->buffer_size, s->row_size + 16); - if (!s->buffer) - goto fail; - - /* we want crow_buf+1 to be 16-byte aligned */ - s->crow_buf = s->buffer + 15; - s->zstream.avail_out = s->crow_size; - s->zstream.next_out = s->crow_buf; - } - s->state |= PNG_IDAT; - if (png_decode_idat(s, length) < 0) - goto fail; - bytestream2_skip(&s->gb, 4); /* crc */ break; case MKTAG('P', 'L', 'T', 'E'): {