summaryrefslogtreecommitdiff
path: root/libavcodec
diff options
context:
space:
mode:
authorDonny Yang <work@kota.moe>2015-07-19 02:43:20 +0000
committerPaul B Mahol <onemda@gmail.com>2015-07-22 16:42:24 +0000
commita906e86a8dbd70d1ca858abc498c25e536fa87a9 (patch)
tree9fbf3df37830f97834be83979923c01bc0b298cb /libavcodec
parent1d7fa1ac8932d37fd6b6dde6b3cef33d38c21536 (diff)
apng: Fix decoding images with the PREVIOUS dispose op
Diffstat (limited to 'libavcodec')
-rw-r--r--libavcodec/pngdec.c47
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;