diff options
author | Donny Yang <work@kota.moe> | 2015-07-19 02:43:20 +0000 |
---|---|---|
committer | Paul B Mahol <onemda@gmail.com> | 2015-07-22 16:42:24 +0000 |
commit | a906e86a8dbd70d1ca858abc498c25e536fa87a9 (patch) | |
tree | 9fbf3df37830f97834be83979923c01bc0b298cb | |
parent | 1d7fa1ac8932d37fd6b6dde6b3cef33d38c21536 (diff) | |
download | ffmpeg-a906e86a8dbd70d1ca858abc498c25e536fa87a9.tar.gz |
apng: Fix decoding images with the PREVIOUS dispose op
-rw-r--r-- | libavcodec/pngdec.c | 47 |
1 files changed, 27 insertions, 20 deletions
diff --git a/libavcodec/pngdec.c b/libavcodec/pngdec.c index b8011fea59..cb1cebb238 100644 --- a/libavcodec/pngdec.c +++ b/libavcodec/pngdec.c @@ -643,6 +643,11 @@ static int decode_idat_chunk(AVCodecContext *avctx, PNGDecContext *s, if ((ret = ff_thread_get_buffer(avctx, &s->picture, AV_GET_BUFFER_FLAG_REF)) < 0) return ret; + if (avctx->codec_id == AV_CODEC_ID_APNG && s->last_dispose_op != APNG_DISPOSE_OP_PREVIOUS) { + ff_thread_release_buffer(avctx, &s->previous_picture); + if ((ret = ff_thread_get_buffer(avctx, &s->previous_picture, AV_GET_BUFFER_FLAG_REF)) < 0) + return ret; + } ff_thread_finish_setup(avctx); p->pict_type = AV_PICTURE_TYPE_I; @@ -917,20 +922,20 @@ static int handle_p_frame_apng(AVCodecContext *avctx, PNGDecContext *s, return AVERROR_PATCHWELCOME; } - // Copy the previous frame to the buffer - ff_thread_await_progress(&s->last_picture, INT_MAX, 0); - memcpy(buffer, s->last_picture.f->data[0], s->image_linesize * s->height); - // Do the disposal operation specified by the last frame on the frame - if (s->last_dispose_op == APNG_DISPOSE_OP_BACKGROUND) { - for (y = s->last_y_offset; y < s->last_y_offset + s->last_h; ++y) - memset(buffer + s->image_linesize * y + s->bpp * s->last_x_offset, 0, s->bpp * s->last_w); - } else if (s->last_dispose_op == APNG_DISPOSE_OP_PREVIOUS) { + if (s->last_dispose_op != APNG_DISPOSE_OP_PREVIOUS) { + ff_thread_await_progress(&s->last_picture, INT_MAX, 0); + memcpy(buffer, s->last_picture.f->data[0], s->image_linesize * s->height); + + if (s->last_dispose_op == APNG_DISPOSE_OP_BACKGROUND) + for (y = s->last_y_offset; y < s->last_y_offset + s->last_h; ++y) + memset(buffer + s->image_linesize * y + s->bpp * s->last_x_offset, 0, s->bpp * s->last_w); + + memcpy(s->previous_picture.f->data[0], buffer, s->image_linesize * s->height); + ff_thread_report_progress(&s->previous_picture, INT_MAX, 0); + } else { ff_thread_await_progress(&s->previous_picture, INT_MAX, 0); - for (y = s->last_y_offset; y < s->last_y_offset + s->last_h; ++y) { - size_t row_start = s->image_linesize * y + s->bpp * s->last_x_offset; - memcpy(buffer + row_start, s->previous_picture.f->data[0] + row_start, s->bpp * s->last_w); - } + memcpy(buffer, s->previous_picture.f->data[0], s->image_linesize * s->height); } // Perform blending @@ -1206,13 +1211,9 @@ static int decode_frame_apng(AVCodecContext *avctx, PNGDecContext *const s = avctx->priv_data; int ret; AVFrame *p; - ThreadFrame tmp; - ff_thread_release_buffer(avctx, &s->previous_picture); - tmp = s->previous_picture; - s->previous_picture = s->last_picture; - s->last_picture = s->picture; - s->picture = tmp; + ff_thread_release_buffer(avctx, &s->last_picture); + FFSWAP(ThreadFrame, s->picture, s->last_picture); p = s->picture.f; if (!(s->state & PNG_IHDR)) { @@ -1292,8 +1293,14 @@ static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src) pdst->state |= psrc->state & (PNG_IHDR | PNG_PLTE); ff_thread_release_buffer(dst, &pdst->last_picture); - if (psrc->last_picture.f->data[0]) - return ff_thread_ref_frame(&pdst->last_picture, &psrc->last_picture); + if (psrc->last_picture.f->data[0] && + (ret = ff_thread_ref_frame(&pdst->last_picture, &psrc->last_picture)) < 0) + return ret; + + ff_thread_release_buffer(dst, &pdst->previous_picture); + if (psrc->previous_picture.f->data[0] && + (ret = ff_thread_ref_frame(&pdst->previous_picture, &psrc->previous_picture)) < 0) + return ret; } return 0; |