apng: Fix decoding images with the PREVIOUS dispose op

This commit is contained in:
Donny Yang 2015-07-19 02:43:20 +00:00 committed by Paul B Mahol
parent 1d7fa1ac89
commit a906e86a8d

View File

@ -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;