X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fpngdec.c;h=e6462967f6102550e2ed8c3ec293f8e7fbb2b296;hb=3aca10bf762a94d7de555cedf1ff0e4f6792bf41;hp=66afb0e5ad6637493c0f6bbb4116cf6a1b45e2b8;hpb=08630d25a215e45494a754d9f1cffd34e93718a5;p=ffmpeg diff --git a/libavcodec/pngdec.c b/libavcodec/pngdec.c index 66afb0e5ad6..e6462967f61 100644 --- a/libavcodec/pngdec.c +++ b/libavcodec/pngdec.c @@ -21,6 +21,7 @@ #include "libavutil/imgutils.h" #include "avcodec.h" #include "bytestream.h" +#include "internal.h" #include "png.h" #include "pngdsp.h" @@ -30,16 +31,11 @@ #include -//#define DEBUG - typedef struct PNGDecContext { PNGDSPContext dsp; - const uint8_t *bytestream; - const uint8_t *bytestream_start; - const uint8_t *bytestream_end; - AVFrame picture1, picture2; - AVFrame *current_picture, *last_picture; + GetByteContext gb; + AVFrame *prev; int state; int width, height; @@ -87,15 +83,16 @@ static void png_put_interlaced_row(uint8_t *dst, int width, uint8_t *d; const uint8_t *s; - mask = ff_png_pass_mask[pass]; + mask = ff_png_pass_mask[pass]; dsp_mask = png_pass_dsp_mask[pass]; - switch(bits_per_pixel) { + + switch (bits_per_pixel) { case 1: /* we must initialize the line to zero before writing to it */ if (pass == 0) memset(dst, 0, (width + 7) >> 3); src_x = 0; - for(x = 0; x < width; x++) { + for (x = 0; x < width; x++) { j = (x & 7); if ((dsp_mask << j) & 0x80) { b = (src[src_x >> 3] >> (7 - (src_x & 7))) & 1; @@ -107,10 +104,10 @@ static void png_put_interlaced_row(uint8_t *dst, int width, break; default: bpp = bits_per_pixel >> 3; - d = dst; - s = src; + d = dst; + s = src; if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) { - for(x = 0; x < width; x++) { + for (x = 0; x < width; x++) { j = x & 7; if ((dsp_mask << j) & 0x80) { *(uint32_t *)d = (s[3] << 24) | (s[0] << 16) | (s[1] << 8) | s[2]; @@ -137,14 +134,14 @@ static void png_put_interlaced_row(uint8_t *dst, int width, void ff_add_png_paeth_prediction(uint8_t *dst, uint8_t *src, uint8_t *top, int w, int bpp) { int i; - for(i = 0; i < w; i++) { + for (i = 0; i < w; i++) { int a, b, c, p, pa, pb, pc; a = dst[i - bpp]; b = top[i]; c = top[i - bpp]; - p = b - c; + p = b - c; pc = a - c; pa = abs(p); @@ -196,20 +193,20 @@ static void png_filter_row(PNGDSPContext *dsp, uint8_t *dst, int filter_type, { int i, p, r, g, b, a; - switch(filter_type) { + switch (filter_type) { case PNG_FILTER_VALUE_NONE: memcpy(dst, src, size); break; case PNG_FILTER_VALUE_SUB: - for(i = 0; i < bpp; i++) { + for (i = 0; i < bpp; i++) { dst[i] = src[i]; } - if(bpp == 4) { + if (bpp == 4) { p = *(int*)dst; - for(; i < size; i+=bpp) { - int s = *(int*)(src+i); - p = ((s&0x7f7f7f7f) + (p&0x7f7f7f7f)) ^ ((s^p)&0x80808080); - *(int*)(dst+i) = p; + for (; i < size; i += bpp) { + int s = *(int*)(src + i); + p = ((s & 0x7f7f7f7f) + (p & 0x7f7f7f7f)) ^ ((s ^ p) & 0x80808080); + *(int*)(dst + i) = p; } } else { #define OP_SUB(x,s,l) x+s @@ -220,7 +217,7 @@ static void png_filter_row(PNGDSPContext *dsp, uint8_t *dst, int filter_type, dsp->add_bytes_l2(dst, src, last, size); break; case PNG_FILTER_VALUE_AVG: - for(i = 0; i < bpp; i++) { + for (i = 0; i < bpp; i++) { p = (last[i] >> 1); dst[i] = p + src[i]; } @@ -228,34 +225,36 @@ static void png_filter_row(PNGDSPContext *dsp, uint8_t *dst, int filter_type, UNROLL_FILTER(OP_AVG); break; case PNG_FILTER_VALUE_PAETH: - for(i = 0; i < bpp; i++) { + for (i = 0; i < bpp; i++) { p = last[i]; dst[i] = p + src[i]; } - if(bpp > 1 && size > 4) { + if (bpp > 1 && size > 4) { // would write off the end of the array if we let it process the last pixel with bpp=3 - int w = bpp==4 ? size : size-3; - dsp->add_paeth_prediction(dst+i, src+i, last+i, w-i, bpp); + int w = bpp == 4 ? size : size - 3; + dsp->add_paeth_prediction(dst + i, src + i, last + i, w - i, bpp); i = w; } - ff_add_png_paeth_prediction(dst+i, src+i, last+i, size-i, bpp); + ff_add_png_paeth_prediction(dst + i, src + i, last + i, size - i, bpp); break; } } -static av_always_inline void convert_to_rgb32_loco(uint8_t *dst, const uint8_t *src, int width, int loco) +static av_always_inline void convert_to_rgb32_loco(uint8_t *dst, + const uint8_t *src, + int width, int loco) { int j; unsigned int r, g, b, a; - for(j = 0;j < width; j++) { + for (j = 0; j < width; j++) { r = src[0]; g = src[1]; b = src[2]; a = src[3]; - if(loco) { - r = (r+g)&0xff; - b = (b+g)&0xff; + if (loco) { + r = (r + g) & 0xff; + b = (b + g) & 0xff; } *(uint32_t *)dst = (a << 24) | (r << 16) | (g << 8) | b; dst += 4; @@ -265,7 +264,7 @@ static av_always_inline void convert_to_rgb32_loco(uint8_t *dst, const uint8_t * static void convert_to_rgb32(uint8_t *dst, const uint8_t *src, int width, int loco) { - if(loco) + if (loco) convert_to_rgb32_loco(dst, src, width, 1); else convert_to_rgb32_loco(dst, src, width, 0); @@ -274,10 +273,10 @@ static void convert_to_rgb32(uint8_t *dst, const uint8_t *src, int width, int lo static void deloco_rgb24(uint8_t *dst, int size) { int i; - for(i=0; iimage_buf + s->image_linesize * s->y; if ((ff_png_pass_ymask[s->pass] << (s->y & 7)) & 0x80) { /* if we already read one row, it is time to stop to @@ -337,7 +336,7 @@ static void png_handle_row(PNGDecContext *s) } s->y++; if (s->y == s->height) { - for(;;) { + for (;;) { if (s->pass == NB_PASSES - 1) { s->state |= PNG_ALLIMAGE; goto the_end; @@ -362,12 +361,9 @@ static void png_handle_row(PNGDecContext *s) static int png_decode_idat(PNGDecContext *s, int length) { int ret; - s->zstream.avail_in = length; - s->zstream.next_in = s->bytestream; - s->bytestream += length; - - if(s->bytestream > s->bytestream_end) - return -1; + s->zstream.avail_in = FFMIN(length, bytestream2_get_bytes_left(&s->gb)); + s->zstream.next_in = s->gb.buffer; + bytestream2_skip(&s->gb, length); /* decode one line if possible */ while (s->zstream.avail_in > 0) { @@ -380,80 +376,75 @@ static int png_decode_idat(PNGDecContext *s, int length) png_handle_row(s); } s->zstream.avail_out = s->crow_size; - s->zstream.next_out = s->crow_buf; + s->zstream.next_out = s->crow_buf; + } + if (ret == Z_STREAM_END && s->zstream.avail_in > 0) { + av_log(NULL, AV_LOG_WARNING, "%d undecompressed bytes left in buffer\n", s->zstream.avail_in); + return 0; } } return 0; } static int decode_frame(AVCodecContext *avctx, - void *data, int *data_size, + void *data, int *got_frame, AVPacket *avpkt) { - const uint8_t *buf = avpkt->data; - int buf_size = avpkt->size; PNGDecContext * const s = avctx->priv_data; - AVFrame *picture = data; - AVFrame *p; - uint8_t *crow_buf_base = NULL; + const uint8_t *buf = avpkt->data; + int buf_size = avpkt->size; + AVFrame *p = data; + uint8_t *crow_buf_base = NULL; uint32_t tag, length; int ret; - FFSWAP(AVFrame *, s->current_picture, s->last_picture); - avctx->coded_frame= s->current_picture; - p = s->current_picture; - - s->bytestream_start= - s->bytestream= buf; - s->bytestream_end= buf + buf_size; - /* check signature */ - if (memcmp(s->bytestream, ff_pngsig, 8) != 0 && - memcmp(s->bytestream, ff_mngsig, 8) != 0) + if (buf_size < 8 || + memcmp(buf, ff_pngsig, 8) != 0 && + memcmp(buf, ff_mngsig, 8) != 0) return -1; - s->bytestream+= 8; - s->y= - s->state=0; -// memset(s, 0, sizeof(PNGDecContext)); + + bytestream2_init(&s->gb, buf + 8, buf_size - 8); + s->y = s->state = 0; + /* init the zlib */ s->zstream.zalloc = ff_png_zalloc; - s->zstream.zfree = ff_png_zfree; + s->zstream.zfree = ff_png_zfree; s->zstream.opaque = NULL; ret = inflateInit(&s->zstream); if (ret != Z_OK) return -1; - for(;;) { - int tag32; - if (s->bytestream >= s->bytestream_end) + for (;;) { + if (bytestream2_get_bytes_left(&s->gb) <= 0) goto fail; - length = bytestream_get_be32(&s->bytestream); + length = bytestream2_get_be32(&s->gb); if (length > 0x7fffffff) goto fail; - tag32 = bytestream_get_be32(&s->bytestream); - tag = av_bswap32(tag32); + tag = bytestream2_get_le32(&s->gb); av_dlog(avctx, "png: tag=%c%c%c%c length=%u\n", (tag & 0xff), ((tag >> 8) & 0xff), ((tag >> 16) & 0xff), ((tag >> 24) & 0xff), length); - switch(tag) { + switch (tag) { case MKTAG('I', 'H', 'D', 'R'): if (length != 13) goto fail; - s->width = bytestream_get_be32(&s->bytestream); - s->height = bytestream_get_be32(&s->bytestream); - if(av_image_check_size(s->width, s->height, 0, avctx)){ - s->width= s->height= 0; + s->width = bytestream2_get_be32(&s->gb); + s->height = bytestream2_get_be32(&s->gb); + if (av_image_check_size(s->width, s->height, 0, avctx)) { + s->width = s->height = 0; goto fail; } - s->bit_depth = *s->bytestream++; - s->color_type = *s->bytestream++; - s->compression_type = *s->bytestream++; - s->filter_type = *s->bytestream++; - s->interlace_type = *s->bytestream++; - s->bytestream += 4; /* crc */ + s->bit_depth = bytestream2_get_byte(&s->gb); + 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->interlace_type = bytestream2_get_byte(&s->gb); + bytestream2_skip(&s->gb, 4); /* crc */ s->state |= PNG_IHDR; - av_dlog(avctx, "width=%d height=%d depth=%d color_type=%d compression_type=%d filter_type=%d interlace_type=%d\n", + av_dlog(avctx, "width=%d height=%d depth=%d color_type=%d " + "compression_type=%d filter_type=%d interlace_type=%d\n", s->width, s->height, s->bit_depth, s->color_type, s->compression_type, s->filter_type, s->interlace_type); break; @@ -462,49 +453,48 @@ static int decode_frame(AVCodecContext *avctx, goto fail; if (!(s->state & PNG_IDAT)) { /* init image info */ - avctx->width = s->width; + avctx->width = s->width; avctx->height = s->height; - s->channels = ff_png_get_nb_channels(s->color_type); + 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; + s->bpp = (s->bits_per_pixel + 7) >> 3; + s->row_size = (avctx->width * s->bits_per_pixel + 7) >> 3; if (s->bit_depth == 8 && s->color_type == PNG_COLOR_TYPE_RGB) { - avctx->pix_fmt = PIX_FMT_RGB24; + avctx->pix_fmt = AV_PIX_FMT_RGB24; } else if (s->bit_depth == 8 && s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { - avctx->pix_fmt = PIX_FMT_RGB32; + avctx->pix_fmt = AV_PIX_FMT_RGB32; } else if (s->bit_depth == 8 && s->color_type == PNG_COLOR_TYPE_GRAY) { - avctx->pix_fmt = PIX_FMT_GRAY8; + avctx->pix_fmt = AV_PIX_FMT_GRAY8; } else if (s->bit_depth == 16 && s->color_type == PNG_COLOR_TYPE_GRAY) { - avctx->pix_fmt = PIX_FMT_GRAY16BE; + avctx->pix_fmt = AV_PIX_FMT_GRAY16BE; } else if (s->bit_depth == 16 && s->color_type == PNG_COLOR_TYPE_RGB) { - avctx->pix_fmt = PIX_FMT_RGB48BE; + avctx->pix_fmt = AV_PIX_FMT_RGB48BE; } else if (s->bit_depth == 1 && s->color_type == PNG_COLOR_TYPE_GRAY) { - avctx->pix_fmt = PIX_FMT_MONOBLACK; - } else if (s->color_type == PNG_COLOR_TYPE_PALETTE) { - avctx->pix_fmt = PIX_FMT_PAL8; - } else if (s->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { - avctx->pix_fmt = PIX_FMT_Y400A; + avctx->pix_fmt = AV_PIX_FMT_MONOBLACK; + } else if (s->bit_depth == 8 && + s->color_type == PNG_COLOR_TYPE_PALETTE) { + avctx->pix_fmt = AV_PIX_FMT_PAL8; + } else if (s->bit_depth == 8 && + s->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { + avctx->pix_fmt = AV_PIX_FMT_Y400A; } else { goto fail; } - if(p->data[0]) - avctx->release_buffer(avctx, p); - p->reference= 0; - if(avctx->get_buffer(avctx, p) < 0){ + if (ff_get_buffer(avctx, p, AV_GET_BUFFER_FLAG_REF) < 0) { av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); goto fail; } - p->pict_type= AV_PICTURE_TYPE_I; - p->key_frame= 1; + p->pict_type = AV_PICTURE_TYPE_I; + p->key_frame = 1; p->interlaced_frame = !!s->interlace_type; /* compute the compressed row size */ @@ -519,7 +509,7 @@ static int decode_frame(AVCodecContext *avctx, } av_dlog(avctx, "row_size=%d crow_size =%d\n", s->row_size, s->crow_size); - s->image_buf = p->data[0]; + s->image_buf = p->data[0]; s->image_linesize = p->linesize[0]; /* copy the palette if needed */ if (s->color_type == PNG_COLOR_TYPE_PALETTE) @@ -540,14 +530,14 @@ static int decode_frame(AVCodecContext *avctx, goto fail; /* we want crow_buf+1 to be 16-byte aligned */ - s->crow_buf = crow_buf_base + 15; + s->crow_buf = crow_buf_base + 15; s->zstream.avail_out = s->crow_size; - s->zstream.next_out = s->crow_buf; + s->zstream.next_out = s->crow_buf; } s->state |= PNG_IDAT; if (png_decode_idat(s, length) < 0) goto fail; - s->bytestream += 4; /* crc */ + bytestream2_skip(&s->gb, 4); /* crc */ break; case MKTAG('P', 'L', 'T', 'E'): { @@ -557,17 +547,17 @@ static int decode_frame(AVCodecContext *avctx, goto skip_tag; /* read the palette */ n = length / 3; - for(i=0;ibytestream++; - g = *s->bytestream++; - b = *s->bytestream++; + for (i = 0; i < n; i++) { + r = bytestream2_get_byte(&s->gb); + g = bytestream2_get_byte(&s->gb); + b = bytestream2_get_byte(&s->gb); s->palette[i] = (0xff << 24) | (r << 16) | (g << 8) | b; } - for(;i<256;i++) { + for (; i < 256; i++) { s->palette[i] = (0xff << 24); } s->state |= PNG_PLTE; - s->bytestream += 4; /* crc */ + bytestream2_skip(&s->gb, 4); /* crc */ } break; case MKTAG('t', 'R', 'N', 'S'): @@ -579,47 +569,50 @@ static int decode_frame(AVCodecContext *avctx, length > 256 || !(s->state & PNG_PLTE)) goto skip_tag; - for(i=0;ibytestream++; + for (i = 0; i < length; i++) { + v = bytestream2_get_byte(&s->gb); s->palette[i] = (s->palette[i] & 0x00ffffff) | (v << 24); } - s->bytestream += 4; /* crc */ + bytestream2_skip(&s->gb, 4); /* crc */ } break; case MKTAG('I', 'E', 'N', 'D'): if (!(s->state & PNG_ALLIMAGE)) goto fail; - s->bytestream += 4; /* crc */ + bytestream2_skip(&s->gb, 4); /* crc */ goto exit_loop; default: /* skip tag */ skip_tag: - s->bytestream += length + 4; + bytestream2_skip(&s->gb, length + 4); break; } } exit_loop: /* handle p-frames only if a predecessor frame is available */ - if(s->last_picture->data[0] != NULL) { - if(!(avpkt->flags & AV_PKT_FLAG_KEY)) { + if (s->prev->data[0]) { + if (!(avpkt->flags & AV_PKT_FLAG_KEY)) { int i, j; - uint8_t *pd = s->current_picture->data[0]; - uint8_t *pd_last = s->last_picture->data[0]; + uint8_t *pd = p->data[0]; + uint8_t *pd_last = s->prev->data[0]; - for(j=0; j < s->height; j++) { - for(i=0; i < s->width * s->bpp; i++) { + for (j = 0; j < s->height; j++) { + for (i = 0; i < s->width * s->bpp; i++) { pd[i] += pd_last[i]; } - pd += s->image_linesize; + pd += s->image_linesize; pd_last += s->image_linesize; } } } - *picture= *s->current_picture; - *data_size = sizeof(AVFrame); + av_frame_unref(s->prev); + if ((ret = av_frame_ref(s->prev, p)) < 0) + goto fail; - ret = s->bytestream - s->bytestream_start; + *got_frame = 1; + + ret = bytestream2_tell(&s->gb); the_end: inflateEnd(&s->zstream); av_free(crow_buf_base); @@ -632,13 +625,14 @@ static int decode_frame(AVCodecContext *avctx, goto the_end; } -static av_cold int png_dec_init(AVCodecContext *avctx){ +static av_cold int png_dec_init(AVCodecContext *avctx) +{ PNGDecContext *s = avctx->priv_data; - s->current_picture = &s->picture1; - s->last_picture = &s->picture2; - avcodec_get_frame_defaults(&s->picture1); - avcodec_get_frame_defaults(&s->picture2); + s->prev = av_frame_alloc(); + if (!s->prev) + return AVERROR(ENOMEM); + ff_pngdsp_init(&s->dsp); return 0; @@ -648,22 +642,19 @@ static av_cold int png_dec_end(AVCodecContext *avctx) { PNGDecContext *s = avctx->priv_data; - if (s->picture1.data[0]) - avctx->release_buffer(avctx, &s->picture1); - if (s->picture2.data[0]) - avctx->release_buffer(avctx, &s->picture2); + av_frame_free(&s->prev); return 0; } AVCodec ff_png_decoder = { .name = "png", + .long_name = NULL_IF_CONFIG_SMALL("PNG (Portable Network Graphics) image"), .type = AVMEDIA_TYPE_VIDEO, - .id = CODEC_ID_PNG, + .id = AV_CODEC_ID_PNG, .priv_data_size = sizeof(PNGDecContext), .init = png_dec_init, .close = png_dec_end, .decode = decode_frame, .capabilities = CODEC_CAP_DR1 /*| CODEC_CAP_DRAW_HORIZ_BAND*/, - .long_name = NULL_IF_CONFIG_SMALL("PNG (Portable Network Graphics) image"), };