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