* [FFmpeg-devel] [PATCH 1/4] avcodec/pngdec: Fix APNG_DISPOSE_OP_BACKGROUND
@ 2022-08-21 1:29 Andreas Rheinhardt
2022-08-21 1:36 ` [FFmpeg-devel] [PATCH 2/4] avcodec/pngdec: Use internal AVBPrint string when parsing chunks Andreas Rheinhardt
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Andreas Rheinhardt @ 2022-08-21 1:29 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Andreas Rheinhardt
APNG works with a single reference frame and an output frame.
According to the spec, decoding APNG works by decoding
the current IDAT/fdAT chunks (which decodes to a rectangular
subregion of the whole image region), followed by either
overwriting the region of the output frame with the newly
decoded data or by blending the newly decoded data with
the data from the reference frame onto the current subregion
of the output frame. The remainder of the output frame
is just copied from the reference frame.
Then the reference frame might be left untouched
(APNG_DISPOSE_OP_PREVIOUS), it might be replaced by the output
frame (APNG_DISPOSE_OP_NONE) or the rectangular subregion
corresponding to the just decoded frame has to be reset
to black (APNG_DISPOSE_OP_BACKGROUND).
The latter case is not handled correctly by our decoder:
It only performs resetting the rectangle in the reference frame
when decoding the next frame; and since commit
b593abda6c642cb0c3959752dd235c2faf66837f it does not reset
the reference frame permanently, but only temporarily (i.e.
it only affects decoding the frame after the frame with
APNG_DISPOSE_OP_BACKGROUND). This is a problem if the
frame after the APNG_DISPOSE_OP_BACKGROUND frame uses
APNG_DISPOSE_OP_PREVIOUS, because then the frame after
the APNG_DISPOSE_OP_PREVIOUS frame has an incorrect reference
frame. (If it is not followed by an APNG_DISPOSE_OP_PREVIOUS
frame, the decoder only keeps a reference to the output frame,
which is ok.)
This commit fixes this by being much closer to the spec
than the earlier code: Resetting the background is no longer
postponed until the next frame; instead it is applied to
the reference frame.
Fixes ticket #9602.
(For multithreaded decoding it was actually already broken
since commit 5663301560d77486c7f7c03c1aa5f542fab23c24.)
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
Btw: If we had a function that only references a frame's data
(and leaves the dst frame's side data completely untouched),
we could apply the side data directly to the output frame,
making 8d74baccff59192d395735036cd40a131a140391 unnecessary.
I also wonder whether the handle_p_frame stuff should be moved
out of decode_frame_common() and in the codec-specific code.
libavcodec/pngdec.c | 98 ++++++++++++++++++++++-----------------------
1 file changed, 48 insertions(+), 50 deletions(-)
diff --git a/libavcodec/pngdec.c b/libavcodec/pngdec.c
index 3b888199d4..8a197d038d 100644
--- a/libavcodec/pngdec.c
+++ b/libavcodec/pngdec.c
@@ -78,11 +78,8 @@ typedef struct PNGDecContext {
enum PNGImageState pic_state;
int width, height;
int cur_w, cur_h;
- int last_w, last_h;
int x_offset, y_offset;
- int last_x_offset, last_y_offset;
uint8_t dispose_op, blend_op;
- uint8_t last_dispose_op;
int bit_depth;
int color_type;
int compression_type;
@@ -94,8 +91,6 @@ typedef struct PNGDecContext {
int has_trns;
uint8_t transparent_color_be[6];
- uint8_t *background_buf;
- unsigned background_buf_allocated;
uint32_t palette[256];
uint8_t *crow_buf;
uint8_t *last_row;
@@ -725,9 +720,30 @@ static int decode_idat_chunk(AVCodecContext *avctx, PNGDecContext *s,
}
ff_thread_release_ext_buffer(avctx, &s->picture);
- if ((ret = ff_thread_get_ext_buffer(avctx, &s->picture,
- AV_GET_BUFFER_FLAG_REF)) < 0)
- return ret;
+ if (s->dispose_op == APNG_DISPOSE_OP_PREVIOUS) {
+ /* We only need a buffer for the current picture. */
+ ret = ff_thread_get_buffer(avctx, p, 0);
+ if (ret < 0)
+ return ret;
+ } else if (s->dispose_op == APNG_DISPOSE_OP_BACKGROUND) {
+ /* We need a buffer for the current picture as well as
+ * a buffer for the reference to retain. */
+ ret = ff_thread_get_ext_buffer(avctx, &s->picture,
+ AV_GET_BUFFER_FLAG_REF);
+ if (ret < 0)
+ return ret;
+ ret = ff_thread_get_buffer(avctx, p, 0);
+ if (ret < 0)
+ return ret;
+ } else {
+ /* The picture output this time and the reference to retain coincide. */
+ if ((ret = ff_thread_get_ext_buffer(avctx, &s->picture,
+ AV_GET_BUFFER_FLAG_REF)) < 0)
+ return ret;
+ ret = av_frame_ref(p, s->picture.f);
+ if (ret < 0)
+ return ret;
+ }
p->pict_type = AV_PICTURE_TYPE_I;
p->key_frame = 1;
@@ -985,12 +1001,6 @@ static int decode_fctl_chunk(AVCodecContext *avctx, PNGDecContext *s,
return AVERROR_INVALIDDATA;
}
- s->last_w = s->cur_w;
- s->last_h = s->cur_h;
- s->last_x_offset = s->x_offset;
- s->last_y_offset = s->y_offset;
- s->last_dispose_op = s->dispose_op;
-
sequence_number = bytestream2_get_be32(gb);
cur_w = bytestream2_get_be32(gb);
cur_h = bytestream2_get_be32(gb);
@@ -1086,23 +1096,6 @@ static int handle_p_frame_apng(AVCodecContext *avctx, PNGDecContext *s,
ff_thread_await_progress(&s->last_picture, INT_MAX, 0);
- // need to reset a rectangle to background:
- if (s->last_dispose_op == APNG_DISPOSE_OP_BACKGROUND) {
- av_fast_malloc(&s->background_buf, &s->background_buf_allocated,
- src_stride * p->height);
- if (!s->background_buf)
- return AVERROR(ENOMEM);
-
- memcpy(s->background_buf, src, src_stride * p->height);
-
- for (y = s->last_y_offset; y < s->last_y_offset + s->last_h; y++) {
- memset(s->background_buf + src_stride * y +
- bpp * s->last_x_offset, 0, bpp * s->last_w);
- }
-
- src = s->background_buf;
- }
-
// copy unchanged rectangles from the last frame
for (y = 0; y < s->y_offset; y++)
memcpy(dst + y * dst_stride, src + y * src_stride, p->width * bpp);
@@ -1171,6 +1164,22 @@ static int handle_p_frame_apng(AVCodecContext *avctx, PNGDecContext *s,
return 0;
}
+static void apng_reset_background(PNGDecContext *s, const AVFrame *p)
+{
+ // need to reset a rectangle to black
+ av_unused int ret = av_frame_copy(s->picture.f, p);
+ const int bpp = s->color_type == PNG_COLOR_TYPE_PALETTE ? 4 : s->bpp;
+ const ptrdiff_t dst_stride = s->picture.f->linesize[0];
+ uint8_t *dst = s->picture.f->data[0] + s->y_offset * dst_stride + bpp * s->x_offset;
+
+ av_assert1(ret >= 0);
+
+ for (size_t y = 0; y < s->cur_h; y++) {
+ memset(dst, 0, bpp * s->cur_w);
+ dst += dst_stride;
+ }
+}
+
static int decode_frame_common(AVCodecContext *avctx, PNGDecContext *s,
AVFrame *p, const AVPacket *avpkt)
{
@@ -1434,6 +1443,9 @@ exit_loop:
goto fail;
}
}
+ if (CONFIG_APNG_DECODER && s->dispose_op == APNG_DISPOSE_OP_BACKGROUND)
+ apng_reset_background(s, p);
+
ff_thread_report_progress(&s->picture, INT_MAX, 0);
return 0;
@@ -1456,15 +1468,10 @@ static void clear_frame_metadata(PNGDecContext *s)
av_dict_free(&s->frame_metadata);
}
-static int output_frame(PNGDecContext *s, AVFrame *f,
- const AVFrame *src)
+static int output_frame(PNGDecContext *s, AVFrame *f)
{
int ret;
- ret = av_frame_ref(f, src);
- if (ret < 0)
- return ret;
-
if (s->iccp_data) {
AVFrameSideData *sd = av_frame_new_side_data(f, AV_FRAME_DATA_ICC_PROFILE, s->iccp_data_len);
if (!sd) {
@@ -1515,13 +1522,12 @@ fail:
}
#if CONFIG_PNG_DECODER
-static int decode_frame_png(AVCodecContext *avctx, AVFrame *dst_frame,
+static int decode_frame_png(AVCodecContext *avctx, AVFrame *p,
int *got_frame, AVPacket *avpkt)
{
PNGDecContext *const s = avctx->priv_data;
const uint8_t *buf = avpkt->data;
int buf_size = avpkt->size;
- AVFrame *p = s->picture.f;
int64_t sig;
int ret;
@@ -1555,7 +1561,7 @@ static int decode_frame_png(AVCodecContext *avctx, AVFrame *dst_frame,
goto the_end;
}
- ret = output_frame(s, dst_frame, s->picture.f);
+ ret = output_frame(s, p);
if (ret < 0)
goto the_end;
@@ -1574,12 +1580,11 @@ the_end:
#endif
#if CONFIG_APNG_DECODER
-static int decode_frame_apng(AVCodecContext *avctx, AVFrame *dst_frame,
+static int decode_frame_apng(AVCodecContext *avctx, AVFrame *p,
int *got_frame, AVPacket *avpkt)
{
PNGDecContext *const s = avctx->priv_data;
int ret;
- AVFrame *p = s->picture.f;
clear_frame_metadata(s);
@@ -1608,7 +1613,7 @@ static int decode_frame_apng(AVCodecContext *avctx, AVFrame *dst_frame,
if (!(s->pic_state & (PNG_ALLIMAGE|PNG_IDAT)))
return AVERROR_INVALIDDATA;
- ret = output_frame(s, dst_frame, s->picture.f);
+ ret = output_frame(s, p);
if (ret < 0)
return ret;
@@ -1646,15 +1651,9 @@ static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src)
pdst->compression_type = psrc->compression_type;
pdst->interlace_type = psrc->interlace_type;
pdst->filter_type = psrc->filter_type;
- pdst->cur_w = psrc->cur_w;
- pdst->cur_h = psrc->cur_h;
- pdst->x_offset = psrc->x_offset;
- pdst->y_offset = psrc->y_offset;
pdst->has_trns = psrc->has_trns;
memcpy(pdst->transparent_color_be, psrc->transparent_color_be, sizeof(pdst->transparent_color_be));
- pdst->dispose_op = psrc->dispose_op;
-
memcpy(pdst->palette, psrc->palette, sizeof(pdst->palette));
pdst->hdr_state |= psrc->hdr_state;
@@ -1705,7 +1704,6 @@ static av_cold int png_dec_end(AVCodecContext *avctx)
s->last_row_size = 0;
av_freep(&s->tmp_row);
s->tmp_row_size = 0;
- av_freep(&s->background_buf);
av_freep(&s->iccp_data);
av_dict_free(&s->frame_metadata);
--
2.34.1
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 5+ messages in thread
* [FFmpeg-devel] [PATCH 2/4] avcodec/pngdec: Use internal AVBPrint string when parsing chunks
2022-08-21 1:29 [FFmpeg-devel] [PATCH 1/4] avcodec/pngdec: Fix APNG_DISPOSE_OP_BACKGROUND Andreas Rheinhardt
@ 2022-08-21 1:36 ` Andreas Rheinhardt
2022-08-21 1:36 ` [FFmpeg-devel] [PATCH 3/4] avcodec/pngdec: Use char* instead of uint8_t* for text Andreas Rheinhardt
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Andreas Rheinhardt @ 2022-08-21 1:36 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Andreas Rheinhardt
One saves an allocation in case the string fits into the buffer.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
libavcodec/pngdec.c | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/libavcodec/pngdec.c b/libavcodec/pngdec.c
index 8a197d038d..189c3eee89 100644
--- a/libavcodec/pngdec.c
+++ b/libavcodec/pngdec.c
@@ -543,10 +543,8 @@ static int decode_text_chunk(PNGDecContext *s, GetByteContext *gb, int compresse
return AVERROR_INVALIDDATA;
if ((ret = decode_zbuf(&bp, data, data_end, s->avctx)) < 0)
return ret;
+ text = bp.str;
text_len = bp.len;
- ret = av_bprint_finalize(&bp, (char **)&text);
- if (ret < 0)
- return ret;
} else {
text = (uint8_t *)data;
text_len = data_end - text;
@@ -554,8 +552,8 @@ static int decode_text_chunk(PNGDecContext *s, GetByteContext *gb, int compresse
kw_utf8 = iso88591_to_utf8(keyword, keyword_end - keyword);
txt_utf8 = iso88591_to_utf8(text, text_len);
- if (text != data)
- av_free(text);
+ if (compressed)
+ av_bprint_finalize(&bp, NULL);
if (!(kw_utf8 && txt_utf8)) {
av_free(kw_utf8);
av_free(txt_utf8);
--
2.34.1
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 5+ messages in thread
* [FFmpeg-devel] [PATCH 3/4] avcodec/pngdec: Use char* instead of uint8_t* for text
2022-08-21 1:29 [FFmpeg-devel] [PATCH 1/4] avcodec/pngdec: Fix APNG_DISPOSE_OP_BACKGROUND Andreas Rheinhardt
2022-08-21 1:36 ` [FFmpeg-devel] [PATCH 2/4] avcodec/pngdec: Use internal AVBPrint string when parsing chunks Andreas Rheinhardt
@ 2022-08-21 1:36 ` Andreas Rheinhardt
2022-08-21 1:36 ` [FFmpeg-devel] [PATCH 4/4] avcodec/pngdec: Improve decoding text chunks Andreas Rheinhardt
2022-08-22 20:45 ` [FFmpeg-devel] [PATCH 1/4] avcodec/pngdec: Fix APNG_DISPOSE_OP_BACKGROUND Andreas Rheinhardt
3 siblings, 0 replies; 5+ messages in thread
From: Andreas Rheinhardt @ 2022-08-21 1:36 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Andreas Rheinhardt
Also stop casting const away.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
libavcodec/pngdec.c | 19 ++++++++++---------
1 file changed, 10 insertions(+), 9 deletions(-)
diff --git a/libavcodec/pngdec.c b/libavcodec/pngdec.c
index 189c3eee89..132ad40dc9 100644
--- a/libavcodec/pngdec.c
+++ b/libavcodec/pngdec.c
@@ -496,20 +496,20 @@ fail:
return ret;
}
-static uint8_t *iso88591_to_utf8(const uint8_t *in, size_t size_in)
+static char *iso88591_to_utf8(const char *in, size_t size_in)
{
size_t extra = 0, i;
- uint8_t *out, *q;
+ char *out, *q;
for (i = 0; i < size_in; i++)
- extra += in[i] >= 0x80;
+ extra += !!(in[i] & 0x80);
if (size_in == SIZE_MAX || extra > SIZE_MAX - size_in - 1)
return NULL;
q = out = av_malloc(size_in + extra + 1);
if (!out)
return NULL;
for (i = 0; i < size_in; i++) {
- if (in[i] >= 0x80) {
+ if (in[i] & 0x80) {
*(q++) = 0xC0 | (in[i] >> 6);
*(q++) = 0x80 | (in[i] & 0x3F);
} else {
@@ -525,9 +525,10 @@ static int decode_text_chunk(PNGDecContext *s, GetByteContext *gb, int compresse
int ret, method;
const uint8_t *data = gb->buffer;
const uint8_t *data_end = gb->buffer_end;
- const uint8_t *keyword = data;
- const uint8_t *keyword_end = memchr(keyword, 0, data_end - keyword);
- uint8_t *kw_utf8 = NULL, *text, *txt_utf8 = NULL;
+ const char *keyword = data;
+ const char *keyword_end = memchr(keyword, 0, data_end - data);
+ char *kw_utf8 = NULL, *txt_utf8 = NULL;
+ const char *text;
unsigned text_len;
AVBPrint bp;
@@ -546,8 +547,8 @@ static int decode_text_chunk(PNGDecContext *s, GetByteContext *gb, int compresse
text = bp.str;
text_len = bp.len;
} else {
- text = (uint8_t *)data;
- text_len = data_end - text;
+ text = data;
+ text_len = data_end - data;
}
kw_utf8 = iso88591_to_utf8(keyword, keyword_end - keyword);
--
2.34.1
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 5+ messages in thread
* [FFmpeg-devel] [PATCH 4/4] avcodec/pngdec: Improve decoding text chunks
2022-08-21 1:29 [FFmpeg-devel] [PATCH 1/4] avcodec/pngdec: Fix APNG_DISPOSE_OP_BACKGROUND Andreas Rheinhardt
2022-08-21 1:36 ` [FFmpeg-devel] [PATCH 2/4] avcodec/pngdec: Use internal AVBPrint string when parsing chunks Andreas Rheinhardt
2022-08-21 1:36 ` [FFmpeg-devel] [PATCH 3/4] avcodec/pngdec: Use char* instead of uint8_t* for text Andreas Rheinhardt
@ 2022-08-21 1:36 ` Andreas Rheinhardt
2022-08-22 20:45 ` [FFmpeg-devel] [PATCH 1/4] avcodec/pngdec: Fix APNG_DISPOSE_OP_BACKGROUND Andreas Rheinhardt
3 siblings, 0 replies; 5+ messages in thread
From: Andreas Rheinhardt @ 2022-08-21 1:36 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Andreas Rheinhardt
By checking immediately whether the first allocation was successfull
one can simplify the cleanup code in case of errors.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
libavcodec/pngdec.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/libavcodec/pngdec.c b/libavcodec/pngdec.c
index 132ad40dc9..1d6ca7f4c3 100644
--- a/libavcodec/pngdec.c
+++ b/libavcodec/pngdec.c
@@ -551,12 +551,13 @@ static int decode_text_chunk(PNGDecContext *s, GetByteContext *gb, int compresse
text_len = data_end - data;
}
- kw_utf8 = iso88591_to_utf8(keyword, keyword_end - keyword);
txt_utf8 = iso88591_to_utf8(text, text_len);
if (compressed)
av_bprint_finalize(&bp, NULL);
- if (!(kw_utf8 && txt_utf8)) {
- av_free(kw_utf8);
+ if (!txt_utf8)
+ return AVERROR(ENOMEM);
+ kw_utf8 = iso88591_to_utf8(keyword, keyword_end - keyword);
+ if (!kw_utf8) {
av_free(txt_utf8);
return AVERROR(ENOMEM);
}
--
2.34.1
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [FFmpeg-devel] [PATCH 1/4] avcodec/pngdec: Fix APNG_DISPOSE_OP_BACKGROUND
2022-08-21 1:29 [FFmpeg-devel] [PATCH 1/4] avcodec/pngdec: Fix APNG_DISPOSE_OP_BACKGROUND Andreas Rheinhardt
` (2 preceding siblings ...)
2022-08-21 1:36 ` [FFmpeg-devel] [PATCH 4/4] avcodec/pngdec: Improve decoding text chunks Andreas Rheinhardt
@ 2022-08-22 20:45 ` Andreas Rheinhardt
3 siblings, 0 replies; 5+ messages in thread
From: Andreas Rheinhardt @ 2022-08-22 20:45 UTC (permalink / raw)
To: ffmpeg-devel
Andreas Rheinhardt:
> APNG works with a single reference frame and an output frame.
> According to the spec, decoding APNG works by decoding
> the current IDAT/fdAT chunks (which decodes to a rectangular
> subregion of the whole image region), followed by either
> overwriting the region of the output frame with the newly
> decoded data or by blending the newly decoded data with
> the data from the reference frame onto the current subregion
> of the output frame. The remainder of the output frame
> is just copied from the reference frame.
> Then the reference frame might be left untouched
> (APNG_DISPOSE_OP_PREVIOUS), it might be replaced by the output
> frame (APNG_DISPOSE_OP_NONE) or the rectangular subregion
> corresponding to the just decoded frame has to be reset
> to black (APNG_DISPOSE_OP_BACKGROUND).
>
> The latter case is not handled correctly by our decoder:
> It only performs resetting the rectangle in the reference frame
> when decoding the next frame; and since commit
> b593abda6c642cb0c3959752dd235c2faf66837f it does not reset
> the reference frame permanently, but only temporarily (i.e.
> it only affects decoding the frame after the frame with
> APNG_DISPOSE_OP_BACKGROUND). This is a problem if the
> frame after the APNG_DISPOSE_OP_BACKGROUND frame uses
> APNG_DISPOSE_OP_PREVIOUS, because then the frame after
> the APNG_DISPOSE_OP_PREVIOUS frame has an incorrect reference
> frame. (If it is not followed by an APNG_DISPOSE_OP_PREVIOUS
> frame, the decoder only keeps a reference to the output frame,
> which is ok.)
>
> This commit fixes this by being much closer to the spec
> than the earlier code: Resetting the background is no longer
> postponed until the next frame; instead it is applied to
> the reference frame.
>
> Fixes ticket #9602.
>
> (For multithreaded decoding it was actually already broken
> since commit 5663301560d77486c7f7c03c1aa5f542fab23c24.)
>
> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
> ---
> Btw: If we had a function that only references a frame's data
> (and leaves the dst frame's side data completely untouched),
> we could apply the side data directly to the output frame,
> making 8d74baccff59192d395735036cd40a131a140391 unnecessary.
>
> I also wonder whether the handle_p_frame stuff should be moved
> out of decode_frame_common() and in the codec-specific code.
>
> libavcodec/pngdec.c | 98 ++++++++++++++++++++++-----------------------
> 1 file changed, 48 insertions(+), 50 deletions(-)
>
> diff --git a/libavcodec/pngdec.c b/libavcodec/pngdec.c
> index 3b888199d4..8a197d038d 100644
> --- a/libavcodec/pngdec.c
> +++ b/libavcodec/pngdec.c
> @@ -78,11 +78,8 @@ typedef struct PNGDecContext {
> enum PNGImageState pic_state;
> int width, height;
> int cur_w, cur_h;
> - int last_w, last_h;
> int x_offset, y_offset;
> - int last_x_offset, last_y_offset;
> uint8_t dispose_op, blend_op;
> - uint8_t last_dispose_op;
> int bit_depth;
> int color_type;
> int compression_type;
> @@ -94,8 +91,6 @@ typedef struct PNGDecContext {
> int has_trns;
> uint8_t transparent_color_be[6];
>
> - uint8_t *background_buf;
> - unsigned background_buf_allocated;
> uint32_t palette[256];
> uint8_t *crow_buf;
> uint8_t *last_row;
> @@ -725,9 +720,30 @@ static int decode_idat_chunk(AVCodecContext *avctx, PNGDecContext *s,
> }
>
> ff_thread_release_ext_buffer(avctx, &s->picture);
> - if ((ret = ff_thread_get_ext_buffer(avctx, &s->picture,
> - AV_GET_BUFFER_FLAG_REF)) < 0)
> - return ret;
> + if (s->dispose_op == APNG_DISPOSE_OP_PREVIOUS) {
> + /* We only need a buffer for the current picture. */
> + ret = ff_thread_get_buffer(avctx, p, 0);
> + if (ret < 0)
> + return ret;
> + } else if (s->dispose_op == APNG_DISPOSE_OP_BACKGROUND) {
> + /* We need a buffer for the current picture as well as
> + * a buffer for the reference to retain. */
> + ret = ff_thread_get_ext_buffer(avctx, &s->picture,
> + AV_GET_BUFFER_FLAG_REF);
> + if (ret < 0)
> + return ret;
> + ret = ff_thread_get_buffer(avctx, p, 0);
> + if (ret < 0)
> + return ret;
> + } else {
> + /* The picture output this time and the reference to retain coincide. */
> + if ((ret = ff_thread_get_ext_buffer(avctx, &s->picture,
> + AV_GET_BUFFER_FLAG_REF)) < 0)
> + return ret;
> + ret = av_frame_ref(p, s->picture.f);
> + if (ret < 0)
> + return ret;
> + }
>
> p->pict_type = AV_PICTURE_TYPE_I;
> p->key_frame = 1;
> @@ -985,12 +1001,6 @@ static int decode_fctl_chunk(AVCodecContext *avctx, PNGDecContext *s,
> return AVERROR_INVALIDDATA;
> }
>
> - s->last_w = s->cur_w;
> - s->last_h = s->cur_h;
> - s->last_x_offset = s->x_offset;
> - s->last_y_offset = s->y_offset;
> - s->last_dispose_op = s->dispose_op;
> -
> sequence_number = bytestream2_get_be32(gb);
> cur_w = bytestream2_get_be32(gb);
> cur_h = bytestream2_get_be32(gb);
> @@ -1086,23 +1096,6 @@ static int handle_p_frame_apng(AVCodecContext *avctx, PNGDecContext *s,
>
> ff_thread_await_progress(&s->last_picture, INT_MAX, 0);
>
> - // need to reset a rectangle to background:
> - if (s->last_dispose_op == APNG_DISPOSE_OP_BACKGROUND) {
> - av_fast_malloc(&s->background_buf, &s->background_buf_allocated,
> - src_stride * p->height);
> - if (!s->background_buf)
> - return AVERROR(ENOMEM);
> -
> - memcpy(s->background_buf, src, src_stride * p->height);
> -
> - for (y = s->last_y_offset; y < s->last_y_offset + s->last_h; y++) {
> - memset(s->background_buf + src_stride * y +
> - bpp * s->last_x_offset, 0, bpp * s->last_w);
> - }
> -
> - src = s->background_buf;
> - }
> -
> // copy unchanged rectangles from the last frame
> for (y = 0; y < s->y_offset; y++)
> memcpy(dst + y * dst_stride, src + y * src_stride, p->width * bpp);
> @@ -1171,6 +1164,22 @@ static int handle_p_frame_apng(AVCodecContext *avctx, PNGDecContext *s,
> return 0;
> }
>
> +static void apng_reset_background(PNGDecContext *s, const AVFrame *p)
> +{
> + // need to reset a rectangle to black
> + av_unused int ret = av_frame_copy(s->picture.f, p);
> + const int bpp = s->color_type == PNG_COLOR_TYPE_PALETTE ? 4 : s->bpp;
> + const ptrdiff_t dst_stride = s->picture.f->linesize[0];
> + uint8_t *dst = s->picture.f->data[0] + s->y_offset * dst_stride + bpp * s->x_offset;
> +
> + av_assert1(ret >= 0);
> +
> + for (size_t y = 0; y < s->cur_h; y++) {
> + memset(dst, 0, bpp * s->cur_w);
> + dst += dst_stride;
> + }
> +}
> +
> static int decode_frame_common(AVCodecContext *avctx, PNGDecContext *s,
> AVFrame *p, const AVPacket *avpkt)
> {
> @@ -1434,6 +1443,9 @@ exit_loop:
> goto fail;
> }
> }
> + if (CONFIG_APNG_DECODER && s->dispose_op == APNG_DISPOSE_OP_BACKGROUND)
> + apng_reset_background(s, p);
> +
> ff_thread_report_progress(&s->picture, INT_MAX, 0);
>
> return 0;
> @@ -1456,15 +1468,10 @@ static void clear_frame_metadata(PNGDecContext *s)
> av_dict_free(&s->frame_metadata);
> }
>
> -static int output_frame(PNGDecContext *s, AVFrame *f,
> - const AVFrame *src)
> +static int output_frame(PNGDecContext *s, AVFrame *f)
> {
> int ret;
>
> - ret = av_frame_ref(f, src);
> - if (ret < 0)
> - return ret;
> -
> if (s->iccp_data) {
> AVFrameSideData *sd = av_frame_new_side_data(f, AV_FRAME_DATA_ICC_PROFILE, s->iccp_data_len);
> if (!sd) {
> @@ -1515,13 +1522,12 @@ fail:
> }
>
> #if CONFIG_PNG_DECODER
> -static int decode_frame_png(AVCodecContext *avctx, AVFrame *dst_frame,
> +static int decode_frame_png(AVCodecContext *avctx, AVFrame *p,
> int *got_frame, AVPacket *avpkt)
> {
> PNGDecContext *const s = avctx->priv_data;
> const uint8_t *buf = avpkt->data;
> int buf_size = avpkt->size;
> - AVFrame *p = s->picture.f;
> int64_t sig;
> int ret;
>
> @@ -1555,7 +1561,7 @@ static int decode_frame_png(AVCodecContext *avctx, AVFrame *dst_frame,
> goto the_end;
> }
>
> - ret = output_frame(s, dst_frame, s->picture.f);
> + ret = output_frame(s, p);
> if (ret < 0)
> goto the_end;
>
> @@ -1574,12 +1580,11 @@ the_end:
> #endif
>
> #if CONFIG_APNG_DECODER
> -static int decode_frame_apng(AVCodecContext *avctx, AVFrame *dst_frame,
> +static int decode_frame_apng(AVCodecContext *avctx, AVFrame *p,
> int *got_frame, AVPacket *avpkt)
> {
> PNGDecContext *const s = avctx->priv_data;
> int ret;
> - AVFrame *p = s->picture.f;
>
> clear_frame_metadata(s);
>
> @@ -1608,7 +1613,7 @@ static int decode_frame_apng(AVCodecContext *avctx, AVFrame *dst_frame,
> if (!(s->pic_state & (PNG_ALLIMAGE|PNG_IDAT)))
> return AVERROR_INVALIDDATA;
>
> - ret = output_frame(s, dst_frame, s->picture.f);
> + ret = output_frame(s, p);
> if (ret < 0)
> return ret;
>
> @@ -1646,15 +1651,9 @@ static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src)
> pdst->compression_type = psrc->compression_type;
> pdst->interlace_type = psrc->interlace_type;
> pdst->filter_type = psrc->filter_type;
> - pdst->cur_w = psrc->cur_w;
> - pdst->cur_h = psrc->cur_h;
> - pdst->x_offset = psrc->x_offset;
> - pdst->y_offset = psrc->y_offset;
> pdst->has_trns = psrc->has_trns;
> memcpy(pdst->transparent_color_be, psrc->transparent_color_be, sizeof(pdst->transparent_color_be));
>
> - pdst->dispose_op = psrc->dispose_op;
> -
> memcpy(pdst->palette, psrc->palette, sizeof(pdst->palette));
>
> pdst->hdr_state |= psrc->hdr_state;
> @@ -1705,7 +1704,6 @@ static av_cold int png_dec_end(AVCodecContext *avctx)
> s->last_row_size = 0;
> av_freep(&s->tmp_row);
> s->tmp_row_size = 0;
> - av_freep(&s->background_buf);
>
> av_freep(&s->iccp_data);
> av_dict_free(&s->frame_metadata);
Will apply this patchset tomorrow unless there are objections.
- Andreas
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2022-08-22 20:46 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-08-21 1:29 [FFmpeg-devel] [PATCH 1/4] avcodec/pngdec: Fix APNG_DISPOSE_OP_BACKGROUND Andreas Rheinhardt
2022-08-21 1:36 ` [FFmpeg-devel] [PATCH 2/4] avcodec/pngdec: Use internal AVBPrint string when parsing chunks Andreas Rheinhardt
2022-08-21 1:36 ` [FFmpeg-devel] [PATCH 3/4] avcodec/pngdec: Use char* instead of uint8_t* for text Andreas Rheinhardt
2022-08-21 1:36 ` [FFmpeg-devel] [PATCH 4/4] avcodec/pngdec: Improve decoding text chunks Andreas Rheinhardt
2022-08-22 20:45 ` [FFmpeg-devel] [PATCH 1/4] avcodec/pngdec: Fix APNG_DISPOSE_OP_BACKGROUND Andreas Rheinhardt
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git