diff options
Diffstat (limited to 'ffmpeg/libavcodec/pngdec.c')
| -rw-r--r-- | ffmpeg/libavcodec/pngdec.c | 122 |
1 files changed, 80 insertions, 42 deletions
diff --git a/ffmpeg/libavcodec/pngdec.c b/ffmpeg/libavcodec/pngdec.c index 086f3b4..516dd41 100644 --- a/ffmpeg/libavcodec/pngdec.c +++ b/ffmpeg/libavcodec/pngdec.c @@ -28,21 +28,17 @@ #include "internal.h" #include "png.h" #include "pngdsp.h" - -/* TODO: - * - add 16 bit depth support - */ +#include "thread.h" #include <zlib.h> -//#define DEBUG - typedef struct PNGDecContext { PNGDSPContext dsp; AVCodecContext *avctx; GetByteContext gb; - AVFrame *prev; + ThreadFrame last_picture; + ThreadFrame picture; int state; int width, height; @@ -60,7 +56,11 @@ typedef struct PNGDecContext { uint32_t palette[256]; uint8_t *crow_buf; uint8_t *last_row; + unsigned int last_row_size; uint8_t *tmp_row; + unsigned int tmp_row_size; + uint8_t *buffer; + int buffer_size; int pass; int crow_size; /* compressed row size (include filter type) */ int row_size; /* decompressed row size */ @@ -226,7 +226,7 @@ static void png_filter_row(PNGDSPContext *dsp, uint8_t *dst, int filter_type, if (bpp == 4) { p = *(int*)dst; for (; i < size; i += bpp) { - int s = *(int*)(src + i); + unsigned s = *(int*)(src + i); p = ((s & 0x7f7f7f7f) + (p & 0x7f7f7f7f)) ^ ((s ^ p) & 0x80808080); *(int*)(dst + i) = p; } @@ -328,6 +328,7 @@ static void png_handle_row(PNGDecContext *s) png_filter_row(&s->dsp, s->tmp_row, s->crow_buf[0], s->crow_buf + 1, s->last_row, s->pass_row_size, s->bpp); FFSWAP(uint8_t*, s->last_row, s->tmp_row); + FFSWAP(unsigned int, s->last_row_size, s->tmp_row_size); got_line = 1; } if ((png_pass_dsp_ymask[s->pass] << (s->y & 7)) & 0x80) { @@ -370,8 +371,8 @@ static int png_decode_idat(PNGDecContext *s, int length) while (s->zstream.avail_in > 0) { ret = inflate(&s->zstream, Z_PARTIAL_FLUSH); if (ret != Z_OK && ret != Z_STREAM_END) { - av_log(s->avctx, AV_LOG_ERROR, "inflate returned %d\n", ret); - return -1; + av_log(s->avctx, AV_LOG_ERROR, "inflate returned error %d\n", ret); + return AVERROR_EXTERNAL; } if (s->zstream.avail_out == 0) { if (!(s->state & PNG_ALLIMAGE)) { @@ -380,6 +381,10 @@ static int png_decode_idat(PNGDecContext *s, int length) s->zstream.avail_out = s->crow_size; 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; } @@ -507,13 +512,16 @@ static int decode_frame(AVCodecContext *avctx, PNGDecContext * const s = avctx->priv_data; const uint8_t *buf = avpkt->data; int buf_size = avpkt->size; - AVFrame *p = data; + AVFrame *p; AVDictionary *metadata = NULL; - uint8_t *crow_buf_base = NULL; uint32_t tag, length; int64_t sig; int ret; + ff_thread_release_buffer(avctx, &s->last_picture); + FFSWAP(ThreadFrame, s->picture, s->last_picture); + p = s->picture.f; + bytestream2_init(&s->gb, buf, buf_size); /* check signature */ @@ -521,7 +529,7 @@ static int decode_frame(AVCodecContext *avctx, if (sig != PNGSIG && sig != MNGSIG) { av_log(avctx, AV_LOG_ERROR, "Missing png signature\n"); - return -1; + return AVERROR_INVALIDDATA; } s->y = s->state = 0; @@ -532,8 +540,8 @@ static int decode_frame(AVCodecContext *avctx, s->zstream.opaque = NULL; ret = inflateInit(&s->zstream); if (ret != Z_OK) { - av_log(avctx, AV_LOG_ERROR, "inflateInit returned %d\n", ret); - return -1; + av_log(avctx, AV_LOG_ERROR, "inflateInit returned error %d\n", ret); + return AVERROR_EXTERNAL; } for (;;) { if (bytestream2_get_bytes_left(&s->gb) <= 0) { @@ -637,8 +645,10 @@ static int decode_frame(AVCodecContext *avctx, goto fail; } - if (ff_get_buffer(avctx, p, AV_GET_BUFFER_FLAG_REF) < 0) + 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; @@ -661,22 +671,22 @@ static int decode_frame(AVCodecContext *avctx, 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 */ - s->last_row = av_mallocz(s->row_size); + 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) { - s->tmp_row = av_malloc(s->row_size); + av_fast_padded_malloc(&s->tmp_row, &s->tmp_row_size, s->row_size); if (!s->tmp_row) goto fail; } /* compressed row */ - crow_buf_base = av_malloc(s->row_size + 16); - if (!crow_buf_base) + 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 = crow_buf_base + 15; + s->crow_buf = s->buffer + 15; s->zstream.avail_out = s->crow_size; s->zstream.next_out = s->crow_buf; } @@ -822,16 +832,17 @@ static int decode_frame(AVCodecContext *avctx, } /* handle p-frames only if a predecessor frame is available */ - if (s->prev->data[0]) { - if ( !(avpkt->flags & AV_PKT_FLAG_KEY) - && s->prev->width == p->width - && s->prev->height== p->height - && s->prev->format== p->format + if (s->last_picture.f->data[0]) { + if ( !(avpkt->flags & AV_PKT_FLAG_KEY) && avctx->codec_tag != AV_RL32("MPNG") + && s->last_picture.f->width == p->width + && s->last_picture.f->height== p->height + && s->last_picture.f->format== p->format ) { int i, j; uint8_t *pd = p->data[0]; - uint8_t *pd_last = s->prev->data[0]; + uint8_t *pd_last = s->last_picture.f->data[0]; + ff_thread_await_progress(&s->last_picture, INT_MAX, 0); for (j = 0; j < s->height; j++) { for (i = 0; i < s->width * s->bpp; i++) { pd[i] += pd_last[i]; @@ -841,41 +852,57 @@ static int decode_frame(AVCodecContext *avctx, } } } + ff_thread_report_progress(&s->picture, INT_MAX, 0); av_frame_set_metadata(p, metadata); metadata = NULL; - av_frame_unref(s->prev); - if ((ret = av_frame_ref(s->prev, p)) < 0) - goto fail; + if ((ret = av_frame_ref(data, s->picture.f)) < 0) + return ret; *got_frame = 1; ret = bytestream2_tell(&s->gb); the_end: inflateEnd(&s->zstream); - av_free(crow_buf_base); s->crow_buf = NULL; - av_freep(&s->last_row); - av_freep(&s->tmp_row); return ret; fail: av_dict_free(&metadata); - ret = -1; + ff_thread_report_progress(&s->picture, INT_MAX, 0); + ret = AVERROR_INVALIDDATA; goto the_end; } +static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src) +{ + PNGDecContext *psrc = src->priv_data; + PNGDecContext *pdst = dst->priv_data; + + if (dst == src) + return 0; + + ff_thread_release_buffer(dst, &pdst->picture); + if (psrc->picture.f->data[0]) + return ff_thread_ref_frame(&pdst->picture, &psrc->picture); + + return 0; +} + static av_cold int png_dec_init(AVCodecContext *avctx) { PNGDecContext *s = avctx->priv_data; - s->prev = av_frame_alloc(); - if (!s->prev) + s->avctx = avctx; + s->last_picture.f = av_frame_alloc(); + s->picture.f = av_frame_alloc(); + if (!s->last_picture.f || !s->picture.f) return AVERROR(ENOMEM); - ff_pngdsp_init(&s->dsp); - - s->avctx = avctx; + if (!avctx->internal->is_copy) { + avctx->internal->allocate_progress = 1; + ff_pngdsp_init(&s->dsp); + } return 0; } @@ -884,19 +911,30 @@ static av_cold int png_dec_end(AVCodecContext *avctx) { PNGDecContext *s = avctx->priv_data; - av_frame_free(&s->prev); + ff_thread_release_buffer(avctx, &s->last_picture); + av_frame_free(&s->last_picture.f); + ff_thread_release_buffer(avctx, &s->picture); + av_frame_free(&s->picture.f); + av_freep(&s->buffer); + s->buffer_size = 0; + av_freep(&s->last_row); + s->last_row_size = 0; + av_freep(&s->tmp_row); + s->tmp_row_size = 0; return 0; } AVCodec ff_png_decoder = { .name = "png", + .long_name = NULL_IF_CONFIG_SMALL("PNG (Portable Network Graphics) image"), .type = AVMEDIA_TYPE_VIDEO, .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"), + .init_thread_copy = ONLY_IF_THREADS_ENABLED(png_dec_init), + .update_thread_context = ONLY_IF_THREADS_ENABLED(update_thread_context), + .capabilities = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS /*| CODEC_CAP_DRAW_HORIZ_BAND*/, }; |
