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