diff options
author | Benoit Fouet <benoit.fouet@free.fr> | 2014-12-03 14:16:55 +0100 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2014-12-04 00:30:38 +0100 |
commit | 08aec6f68e6a3a1e94ce9f08c980987f6eeb9aec (patch) | |
tree | df45029e94dcf6f39ceb52dc4b7014f5788c1991 | |
parent | 49d9cbe55d670ca778422a1d2aed5da5eb15b1e2 (diff) | |
download | ffmpeg-08aec6f68e6a3a1e94ce9f08c980987f6eeb9aec.tar.gz |
libavcodec/pngdec: support 'previous' dispose operation for APNG.
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
-rw-r--r-- | libavcodec/pngdec.c | 72 |
1 files changed, 50 insertions, 22 deletions
diff --git a/libavcodec/pngdec.c b/libavcodec/pngdec.c index 229a6d6884..b1e77e5144 100644 --- a/libavcodec/pngdec.c +++ b/libavcodec/pngdec.c @@ -38,6 +38,7 @@ typedef struct PNGDecContext { AVCodecContext *avctx; GetByteContext gb; + ThreadFrame previous_picture; ThreadFrame last_picture; ThreadFrame picture; @@ -55,6 +56,7 @@ typedef struct PNGDecContext { int bits_per_pixel; int bpp; + int frame_id; uint8_t *image_buf; int image_linesize; uint32_t palette[256]; @@ -827,13 +829,14 @@ static int decode_fctl_chunk(AVCodecContext *avctx, PNGDecContext *s, return AVERROR_INVALIDDATA; /* always (re)start with a clean frame */ - if (sequence_number == 0) + if (sequence_number == 0) { s->dispose_op = APNG_DISPOSE_OP_BACKGROUND; - - if (s->dispose_op == APNG_DISPOSE_OP_PREVIOUS) { - av_log(avctx, AV_LOG_ERROR, - "Dispose operation 'previous' is not yet implemented, using 'none'.\n"); - s->dispose_op = APNG_DISPOSE_OP_NONE; + s->frame_id = 0; + } else { + s->frame_id++; + if (s->frame_id == 1 && s->dispose_op == APNG_DISPOSE_OP_PREVIOUS) + /* previous for the second frame is the first frame */ + s->dispose_op = APNG_DISPOSE_OP_NONE; } return 0; @@ -864,8 +867,9 @@ static int handle_p_frame_apng(AVCodecContext *avctx, PNGDecContext *s, { int i, j; uint8_t *pd = p->data[0]; - /* TODO make pd_last point to the one before for APNG_DISPOSE_OP_PREVIOUS */ uint8_t *pd_last = s->last_picture.f->data[0]; + uint8_t *pd_last_region = s->dispose_op == APNG_DISPOSE_OP_PREVIOUS ? + s->previous_picture.f->data[0] : s->last_picture.f->data[0]; int ls = FFMIN(av_image_get_linesize(p->format, s->width, 0), s->width * s->bpp); if (s->blend_op == APNG_BLEND_OP_OVER && @@ -876,6 +880,9 @@ static int handle_p_frame_apng(AVCodecContext *avctx, PNGDecContext *s, } ff_thread_await_progress(&s->last_picture, INT_MAX, 0); + if (s->dispose_op == APNG_DISPOSE_OP_PREVIOUS) + ff_thread_await_progress(&s->previous_picture, INT_MAX, 0); + for (j = 0; j < s->y_offset; j++) { for (i = 0; i < ls; i++) pd[i] = pd_last[i]; @@ -886,6 +893,7 @@ static int handle_p_frame_apng(AVCodecContext *avctx, PNGDecContext *s, if (s->dispose_op != APNG_DISPOSE_OP_BACKGROUND && s->blend_op == APNG_BLEND_OP_OVER) { uint8_t ri, gi, bi, ai; + pd_last_region += s->y_offset * s->image_linesize; if (avctx->pix_fmt == AV_PIX_FMT_RGBA) { ri = 0; gi = 1; @@ -907,17 +915,17 @@ static int handle_p_frame_apng(AVCodecContext *avctx, PNGDecContext *s, /* output = alpha * foreground + (1-alpha) * background */ switch (alpha) { case 0: - pd[i+ri] = pd_last[i+ri]; - pd[i+gi] = pd_last[i+gi]; - pd[i+bi] = pd_last[i+bi]; + pd[i+ri] = pd_last_region[i+ri]; + pd[i+gi] = pd_last_region[i+gi]; + pd[i+bi] = pd_last_region[i+bi]; pd[i+ai] = 0xff; break; case 255: break; default: - pd[i+ri] = FAST_DIV255(alpha * pd[i+ri] + (255 - alpha) * pd_last[i+ri]); - pd[i+gi] = FAST_DIV255(alpha * pd[i+gi] + (255 - alpha) * pd_last[i+gi]); - pd[i+bi] = FAST_DIV255(alpha * pd[i+bi] + (255 - alpha) * pd_last[i+bi]); + pd[i+ri] = FAST_DIV255(alpha * pd[i+ri] + (255 - alpha) * pd_last_region[i+ri]); + pd[i+gi] = FAST_DIV255(alpha * pd[i+gi] + (255 - alpha) * pd_last_region[i+gi]); + pd[i+bi] = FAST_DIV255(alpha * pd[i+bi] + (255 - alpha) * pd_last_region[i+bi]); pd[i+ai] = 0xff; break; } @@ -926,6 +934,7 @@ static int handle_p_frame_apng(AVCodecContext *avctx, PNGDecContext *s, pd[i] = pd_last[i]; pd += s->image_linesize; pd_last += s->image_linesize; + pd_last_region += s->image_linesize; } } else { for (j = s->y_offset; j < s->y_offset + s->cur_h; j++) { @@ -955,6 +964,7 @@ static int decode_frame_common(AVCodecContext *avctx, PNGDecContext *s, uint32_t tag, length; int decode_next_dat = 0; int ret = AVERROR_INVALIDDATA; + AVFrame *ref; for (;;) { length = bytestream2_get_bytes_left(&s->gb); @@ -1053,11 +1063,13 @@ exit_loop: handle_small_bpp(s, p); /* handle p-frames only if a predecessor frame is available */ - if (s->last_picture.f->data[0]) { + ref = s->dispose_op == APNG_DISPOSE_OP_PREVIOUS ? + s->previous_picture.f : s->last_picture.f; + if (ref->data[0]) { if ( !(avpkt->flags & AV_PKT_FLAG_KEY) && avctx->codec_tag != AV_RL32("MPNG") - && s->last_picture.f->width == p->width - && s->last_picture.f->height== p->height - && s->last_picture.f->format== p->format + && ref->width == p->width + && ref->height== p->height + && ref->format== p->format ) { if (CONFIG_PNG_DECODER && avctx->codec_id != AV_CODEC_ID_APNG) handle_p_frame_png(s, p); @@ -1141,9 +1153,13 @@ 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->last_picture); - FFSWAP(ThreadFrame, s->picture, s->last_picture); + 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; p = s->picture.f; if (!(s->state & PNG_IHDR)) { @@ -1193,13 +1209,22 @@ static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src) { PNGDecContext *psrc = src->priv_data; PNGDecContext *pdst = dst->priv_data; + int ret; if (dst == src) return 0; + pdst->frame_id = psrc->frame_id; + ff_thread_release_buffer(dst, &pdst->picture); - if (psrc->picture.f->data[0]) - return ff_thread_ref_frame(&pdst->picture, &psrc->picture); + if (psrc->picture.f->data[0] && + (ret = ff_thread_ref_frame(&pdst->picture, &psrc->picture)) < 0) + return ret; + if (CONFIG_APNG_DECODER && dst->codec_id == AV_CODEC_ID_APNG) { + 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); + } return 0; } @@ -1209,9 +1234,10 @@ static av_cold int png_dec_init(AVCodecContext *avctx) PNGDecContext *s = avctx->priv_data; s->avctx = avctx; + s->previous_picture.f = av_frame_alloc(); s->last_picture.f = av_frame_alloc(); s->picture.f = av_frame_alloc(); - if (!s->last_picture.f || !s->picture.f) + if (!s->previous_picture.f || !s->last_picture.f || !s->picture.f) return AVERROR(ENOMEM); if (!avctx->internal->is_copy) { @@ -1226,6 +1252,8 @@ static av_cold int png_dec_end(AVCodecContext *avctx) { PNGDecContext *s = avctx->priv_data; + ff_thread_release_buffer(avctx, &s->previous_picture); + av_frame_free(&s->previous_picture.f); ff_thread_release_buffer(avctx, &s->last_picture); av_frame_free(&s->last_picture.f); ff_thread_release_buffer(avctx, &s->picture); |