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;
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
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)) {
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;
.decode = decode_frame_apng,
.init_thread_copy = ONLY_IF_THREADS_ENABLED(png_dec_init),
.update_thread_context = ONLY_IF_THREADS_ENABLED(update_thread_context),
- .capabilities = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS /*| CODEC_CAP_DRAW_HORIZ_BAND*/,
+ .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS /*| AV_CODEC_CAP_DRAW_HORIZ_BAND*/,
};
#endif
.decode = decode_frame_png,
.init_thread_copy = ONLY_IF_THREADS_ENABLED(png_dec_init),
.update_thread_context = ONLY_IF_THREADS_ENABLED(update_thread_context),
- .capabilities = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS /*| CODEC_CAP_DRAW_HORIZ_BAND*/,
+ .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS /*| AV_CODEC_CAP_DRAW_HORIZ_BAND*/,
};
#endif