summaryrefslogtreecommitdiff
path: root/ffmpeg/libavcodec/pngdec.c
diff options
context:
space:
mode:
Diffstat (limited to 'ffmpeg/libavcodec/pngdec.c')
-rw-r--r--ffmpeg/libavcodec/pngdec.c122
1 files changed, 80 insertions, 42 deletions
diff --git a/ffmpeg/libavcodec/pngdec.c b/ffmpeg/libavcodec/pngdec.c
index 086f3b4..516dd41 100644
--- a/ffmpeg/libavcodec/pngdec.c
+++ b/ffmpeg/libavcodec/pngdec.c
@@ -28,21 +28,17 @@
#include "internal.h"
#include "png.h"
#include "pngdsp.h"
-
-/* TODO:
- * - add 16 bit depth support
- */
+#include "thread.h"
#include <zlib.h>
-//#define DEBUG
-
typedef struct PNGDecContext {
PNGDSPContext dsp;
AVCodecContext *avctx;
GetByteContext gb;
- AVFrame *prev;
+ ThreadFrame last_picture;
+ ThreadFrame picture;
int state;
int width, height;
@@ -60,7 +56,11 @@ typedef struct PNGDecContext {
uint32_t palette[256];
uint8_t *crow_buf;
uint8_t *last_row;
+ unsigned int last_row_size;
uint8_t *tmp_row;
+ unsigned int tmp_row_size;
+ uint8_t *buffer;
+ int buffer_size;
int pass;
int crow_size; /* compressed row size (include filter type) */
int row_size; /* decompressed row size */
@@ -226,7 +226,7 @@ static void png_filter_row(PNGDSPContext *dsp, uint8_t *dst, int filter_type,
if (bpp == 4) {
p = *(int*)dst;
for (; i < size; i += bpp) {
- int s = *(int*)(src + i);
+ unsigned s = *(int*)(src + i);
p = ((s & 0x7f7f7f7f) + (p & 0x7f7f7f7f)) ^ ((s ^ p) & 0x80808080);
*(int*)(dst + i) = p;
}
@@ -328,6 +328,7 @@ static void png_handle_row(PNGDecContext *s)
png_filter_row(&s->dsp, s->tmp_row, s->crow_buf[0], s->crow_buf + 1,
s->last_row, s->pass_row_size, s->bpp);
FFSWAP(uint8_t*, s->last_row, s->tmp_row);
+ FFSWAP(unsigned int, s->last_row_size, s->tmp_row_size);
got_line = 1;
}
if ((png_pass_dsp_ymask[s->pass] << (s->y & 7)) & 0x80) {
@@ -370,8 +371,8 @@ static int png_decode_idat(PNGDecContext *s, int length)
while (s->zstream.avail_in > 0) {
ret = inflate(&s->zstream, Z_PARTIAL_FLUSH);
if (ret != Z_OK && ret != Z_STREAM_END) {
- av_log(s->avctx, AV_LOG_ERROR, "inflate returned %d\n", ret);
- return -1;
+ av_log(s->avctx, AV_LOG_ERROR, "inflate returned error %d\n", ret);
+ return AVERROR_EXTERNAL;
}
if (s->zstream.avail_out == 0) {
if (!(s->state & PNG_ALLIMAGE)) {
@@ -380,6 +381,10 @@ static int png_decode_idat(PNGDecContext *s, int length)
s->zstream.avail_out = s->crow_size;
s->zstream.next_out = s->crow_buf;
}
+ if (ret == Z_STREAM_END && s->zstream.avail_in > 0) {
+ av_log(NULL, AV_LOG_WARNING, "%d undecompressed bytes left in buffer\n", s->zstream.avail_in);
+ return 0;
+ }
}
return 0;
}
@@ -507,13 +512,16 @@ static int decode_frame(AVCodecContext *avctx,
PNGDecContext * const s = avctx->priv_data;
const uint8_t *buf = avpkt->data;
int buf_size = avpkt->size;
- AVFrame *p = data;
+ AVFrame *p;
AVDictionary *metadata = NULL;
- uint8_t *crow_buf_base = NULL;
uint32_t tag, length;
int64_t sig;
int ret;
+ ff_thread_release_buffer(avctx, &s->last_picture);
+ FFSWAP(ThreadFrame, s->picture, s->last_picture);
+ p = s->picture.f;
+
bytestream2_init(&s->gb, buf, buf_size);
/* check signature */
@@ -521,7 +529,7 @@ static int decode_frame(AVCodecContext *avctx,
if (sig != PNGSIG &&
sig != MNGSIG) {
av_log(avctx, AV_LOG_ERROR, "Missing png signature\n");
- return -1;
+ return AVERROR_INVALIDDATA;
}
s->y = s->state = 0;
@@ -532,8 +540,8 @@ static int decode_frame(AVCodecContext *avctx,
s->zstream.opaque = NULL;
ret = inflateInit(&s->zstream);
if (ret != Z_OK) {
- av_log(avctx, AV_LOG_ERROR, "inflateInit returned %d\n", ret);
- return -1;
+ av_log(avctx, AV_LOG_ERROR, "inflateInit returned error %d\n", ret);
+ return AVERROR_EXTERNAL;
}
for (;;) {
if (bytestream2_get_bytes_left(&s->gb) <= 0) {
@@ -637,8 +645,10 @@ static int decode_frame(AVCodecContext *avctx,
goto fail;
}
- if (ff_get_buffer(avctx, p, AV_GET_BUFFER_FLAG_REF) < 0)
+ if (ff_thread_get_buffer(avctx, &s->picture, AV_GET_BUFFER_FLAG_REF) < 0)
goto fail;
+ ff_thread_finish_setup(avctx);
+
p->pict_type = AV_PICTURE_TYPE_I;
p->key_frame = 1;
p->interlaced_frame = !!s->interlace_type;
@@ -661,22 +671,22 @@ static int decode_frame(AVCodecContext *avctx,
if (avctx->pix_fmt == AV_PIX_FMT_PAL8)
memcpy(p->data[1], s->palette, 256 * sizeof(uint32_t));
/* empty row is used if differencing to the first row */
- s->last_row = av_mallocz(s->row_size);
+ av_fast_padded_mallocz(&s->last_row, &s->last_row_size, s->row_size);
if (!s->last_row)
goto fail;
if (s->interlace_type ||
s->color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
- s->tmp_row = av_malloc(s->row_size);
+ av_fast_padded_malloc(&s->tmp_row, &s->tmp_row_size, s->row_size);
if (!s->tmp_row)
goto fail;
}
/* compressed row */
- crow_buf_base = av_malloc(s->row_size + 16);
- if (!crow_buf_base)
+ av_fast_padded_malloc(&s->buffer, &s->buffer_size, s->row_size + 16);
+ if (!s->buffer)
goto fail;
/* we want crow_buf+1 to be 16-byte aligned */
- s->crow_buf = crow_buf_base + 15;
+ s->crow_buf = s->buffer + 15;
s->zstream.avail_out = s->crow_size;
s->zstream.next_out = s->crow_buf;
}
@@ -822,16 +832,17 @@ static int decode_frame(AVCodecContext *avctx,
}
/* handle p-frames only if a predecessor frame is available */
- if (s->prev->data[0]) {
- if ( !(avpkt->flags & AV_PKT_FLAG_KEY)
- && s->prev->width == p->width
- && s->prev->height== p->height
- && s->prev->format== p->format
+ if (s->last_picture.f->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
) {
int i, j;
uint8_t *pd = p->data[0];
- uint8_t *pd_last = s->prev->data[0];
+ uint8_t *pd_last = s->last_picture.f->data[0];
+ ff_thread_await_progress(&s->last_picture, INT_MAX, 0);
for (j = 0; j < s->height; j++) {
for (i = 0; i < s->width * s->bpp; i++) {
pd[i] += pd_last[i];
@@ -841,41 +852,57 @@ static int decode_frame(AVCodecContext *avctx,
}
}
}
+ ff_thread_report_progress(&s->picture, INT_MAX, 0);
av_frame_set_metadata(p, metadata);
metadata = NULL;
- av_frame_unref(s->prev);
- if ((ret = av_frame_ref(s->prev, p)) < 0)
- goto fail;
+ if ((ret = av_frame_ref(data, s->picture.f)) < 0)
+ return ret;
*got_frame = 1;
ret = bytestream2_tell(&s->gb);
the_end:
inflateEnd(&s->zstream);
- av_free(crow_buf_base);
s->crow_buf = NULL;
- av_freep(&s->last_row);
- av_freep(&s->tmp_row);
return ret;
fail:
av_dict_free(&metadata);
- ret = -1;
+ ff_thread_report_progress(&s->picture, INT_MAX, 0);
+ ret = AVERROR_INVALIDDATA;
goto the_end;
}
+static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src)
+{
+ PNGDecContext *psrc = src->priv_data;
+ PNGDecContext *pdst = dst->priv_data;
+
+ if (dst == src)
+ return 0;
+
+ ff_thread_release_buffer(dst, &pdst->picture);
+ if (psrc->picture.f->data[0])
+ return ff_thread_ref_frame(&pdst->picture, &psrc->picture);
+
+ return 0;
+}
+
static av_cold int png_dec_init(AVCodecContext *avctx)
{
PNGDecContext *s = avctx->priv_data;
- s->prev = av_frame_alloc();
- if (!s->prev)
+ s->avctx = avctx;
+ s->last_picture.f = av_frame_alloc();
+ s->picture.f = av_frame_alloc();
+ if (!s->last_picture.f || !s->picture.f)
return AVERROR(ENOMEM);
- ff_pngdsp_init(&s->dsp);
-
- s->avctx = avctx;
+ if (!avctx->internal->is_copy) {
+ avctx->internal->allocate_progress = 1;
+ ff_pngdsp_init(&s->dsp);
+ }
return 0;
}
@@ -884,19 +911,30 @@ static av_cold int png_dec_end(AVCodecContext *avctx)
{
PNGDecContext *s = avctx->priv_data;
- av_frame_free(&s->prev);
+ ff_thread_release_buffer(avctx, &s->last_picture);
+ av_frame_free(&s->last_picture.f);
+ ff_thread_release_buffer(avctx, &s->picture);
+ av_frame_free(&s->picture.f);
+ av_freep(&s->buffer);
+ s->buffer_size = 0;
+ av_freep(&s->last_row);
+ s->last_row_size = 0;
+ av_freep(&s->tmp_row);
+ s->tmp_row_size = 0;
return 0;
}
AVCodec ff_png_decoder = {
.name = "png",
+ .long_name = NULL_IF_CONFIG_SMALL("PNG (Portable Network Graphics) image"),
.type = AVMEDIA_TYPE_VIDEO,
.id = AV_CODEC_ID_PNG,
.priv_data_size = sizeof(PNGDecContext),
.init = png_dec_init,
.close = png_dec_end,
.decode = decode_frame,
- .capabilities = CODEC_CAP_DR1 /*| CODEC_CAP_DRAW_HORIZ_BAND*/,
- .long_name = NULL_IF_CONFIG_SMALL("PNG (Portable Network Graphics) image"),
+ .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*/,
};