avcodec/pngdec: add APNG support.
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
This commit is contained in:
parent
367c9d33d6
commit
33acebd3cc
1
configure
vendored
1
configure
vendored
@ -2068,6 +2068,7 @@ amrwb_decoder_select="lsp"
|
|||||||
amv_decoder_select="sp5x_decoder exif"
|
amv_decoder_select="sp5x_decoder exif"
|
||||||
amv_encoder_select="aandcttables mpegvideoenc"
|
amv_encoder_select="aandcttables mpegvideoenc"
|
||||||
ape_decoder_select="bswapdsp llauddsp"
|
ape_decoder_select="bswapdsp llauddsp"
|
||||||
|
apng_decoder_select="zlib"
|
||||||
asv1_decoder_select="blockdsp bswapdsp idctdsp"
|
asv1_decoder_select="blockdsp bswapdsp idctdsp"
|
||||||
asv1_encoder_select="bswapdsp fdctdsp pixblockdsp"
|
asv1_encoder_select="bswapdsp fdctdsp pixblockdsp"
|
||||||
asv2_decoder_select="blockdsp bswapdsp idctdsp"
|
asv2_decoder_select="blockdsp bswapdsp idctdsp"
|
||||||
|
@ -136,6 +136,7 @@ OBJS-$(CONFIG_AMV_ENCODER) += mjpegenc.o mjpeg.o mjpegenc_common.o \
|
|||||||
OBJS-$(CONFIG_ANM_DECODER) += anm.o
|
OBJS-$(CONFIG_ANM_DECODER) += anm.o
|
||||||
OBJS-$(CONFIG_ANSI_DECODER) += ansi.o cga_data.o
|
OBJS-$(CONFIG_ANSI_DECODER) += ansi.o cga_data.o
|
||||||
OBJS-$(CONFIG_APE_DECODER) += apedec.o
|
OBJS-$(CONFIG_APE_DECODER) += apedec.o
|
||||||
|
OBJS-$(CONFIG_APNG_DECODER) += png.o pngdec.o pngdsp.o
|
||||||
OBJS-$(CONFIG_SSA_DECODER) += assdec.o ass.o ass_split.o
|
OBJS-$(CONFIG_SSA_DECODER) += assdec.o ass.o ass_split.o
|
||||||
OBJS-$(CONFIG_SSA_ENCODER) += assenc.o ass.o
|
OBJS-$(CONFIG_SSA_ENCODER) += assenc.o ass.o
|
||||||
OBJS-$(CONFIG_ASS_DECODER) += assdec.o ass.o ass_split.o
|
OBJS-$(CONFIG_ASS_DECODER) += assdec.o ass.o ass_split.o
|
||||||
|
@ -105,6 +105,7 @@ void avcodec_register_all(void)
|
|||||||
REGISTER_ENCDEC (AMV, amv);
|
REGISTER_ENCDEC (AMV, amv);
|
||||||
REGISTER_DECODER(ANM, anm);
|
REGISTER_DECODER(ANM, anm);
|
||||||
REGISTER_DECODER(ANSI, ansi);
|
REGISTER_DECODER(ANSI, ansi);
|
||||||
|
REGISTER_DECODER(APNG, apng);
|
||||||
REGISTER_ENCDEC (ASV1, asv1);
|
REGISTER_ENCDEC (ASV1, asv1);
|
||||||
REGISTER_ENCDEC (ASV2, asv2);
|
REGISTER_ENCDEC (ASV2, asv2);
|
||||||
REGISTER_DECODER(AURA, aura);
|
REGISTER_DECODER(AURA, aura);
|
||||||
|
@ -319,6 +319,7 @@ enum AVCodecID {
|
|||||||
AV_CODEC_ID_HEVC = MKBETAG('H','2','6','5'),
|
AV_CODEC_ID_HEVC = MKBETAG('H','2','6','5'),
|
||||||
#define AV_CODEC_ID_H265 AV_CODEC_ID_HEVC
|
#define AV_CODEC_ID_H265 AV_CODEC_ID_HEVC
|
||||||
AV_CODEC_ID_VP7 = MKBETAG('V','P','7','0'),
|
AV_CODEC_ID_VP7 = MKBETAG('V','P','7','0'),
|
||||||
|
AV_CODEC_ID_APNG = MKBETAG('A','P','N','G'),
|
||||||
|
|
||||||
/* various PCM "codecs" */
|
/* various PCM "codecs" */
|
||||||
AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs
|
AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs
|
||||||
|
@ -1440,6 +1440,14 @@ static const AVCodecDescriptor codec_descriptors[] = {
|
|||||||
.props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
|
.props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
|
||||||
.mime_types= MT("image/x-xwindowdump"),
|
.mime_types= MT("image/x-xwindowdump"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.id = AV_CODEC_ID_APNG,
|
||||||
|
.type = AVMEDIA_TYPE_VIDEO,
|
||||||
|
.name = "apng",
|
||||||
|
.long_name = NULL_IF_CONFIG_SMALL("APNG (Animated Portable Network Graphics) image"),
|
||||||
|
.props = AV_CODEC_PROP_LOSSLESS,
|
||||||
|
.mime_types= MT("image/png"),
|
||||||
|
},
|
||||||
|
|
||||||
/* various PCM "codecs" */
|
/* various PCM "codecs" */
|
||||||
{
|
{
|
||||||
|
@ -786,15 +786,55 @@ static void handle_small_bpp(PNGDecContext *s, AVFrame *p)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int decode_fctl_chunk(AVCodecContext *avctx, PNGDecContext *s,
|
||||||
|
uint32_t length)
|
||||||
|
{
|
||||||
|
uint32_t sequence_number, width, height, x_offset, y_offset;
|
||||||
|
|
||||||
|
if (length != 26)
|
||||||
|
return AVERROR_INVALIDDATA;
|
||||||
|
|
||||||
|
sequence_number = bytestream2_get_be32(&s->gb);
|
||||||
|
width = bytestream2_get_be32(&s->gb);
|
||||||
|
height = bytestream2_get_be32(&s->gb);
|
||||||
|
x_offset = bytestream2_get_be32(&s->gb);
|
||||||
|
y_offset = bytestream2_get_be32(&s->gb);
|
||||||
|
bytestream2_skip(&s->gb, 10); /* delay_num (2)
|
||||||
|
* delay_den (2)
|
||||||
|
* dispose_op (1)
|
||||||
|
* blend_op (1)
|
||||||
|
* crc (4)
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (width != s->width || height != s->height ||
|
||||||
|
x_offset != 0 || y_offset != 0) {
|
||||||
|
if (sequence_number == 0)
|
||||||
|
return AVERROR_INVALIDDATA;
|
||||||
|
avpriv_request_sample(avctx, "non key frames");
|
||||||
|
return AVERROR_PATCHWELCOME;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int decode_frame_common(AVCodecContext *avctx, PNGDecContext *s,
|
static int decode_frame_common(AVCodecContext *avctx, PNGDecContext *s,
|
||||||
AVFrame *p, AVPacket *avpkt)
|
AVFrame *p, AVPacket *avpkt)
|
||||||
{
|
{
|
||||||
AVDictionary *metadata = NULL;
|
AVDictionary *metadata = NULL;
|
||||||
uint32_t tag, length;
|
uint32_t tag, length;
|
||||||
|
int decode_next_dat = 0;
|
||||||
|
int ret = AVERROR_INVALIDDATA;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (bytestream2_get_bytes_left(&s->gb) <= 0) {
|
length = bytestream2_get_bytes_left(&s->gb);
|
||||||
av_log(avctx, AV_LOG_ERROR, "%d bytes left\n", bytestream2_get_bytes_left(&s->gb));
|
if (length <= 0) {
|
||||||
|
if (avctx->codec_id == AV_CODEC_ID_APNG && length == 0) {
|
||||||
|
if (!(s->state & PNG_IDAT))
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
goto exit_loop;
|
||||||
|
}
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "%d bytes left\n", length);
|
||||||
if ( s->state & PNG_ALLIMAGE
|
if ( s->state & PNG_ALLIMAGE
|
||||||
&& avctx->strict_std_compliance <= FF_COMPLIANCE_NORMAL)
|
&& avctx->strict_std_compliance <= FF_COMPLIANCE_NORMAL)
|
||||||
goto exit_loop;
|
goto exit_loop;
|
||||||
@ -822,7 +862,24 @@ static int decode_frame_common(AVCodecContext *avctx, PNGDecContext *s,
|
|||||||
if (decode_phys_chunk(avctx, s) < 0)
|
if (decode_phys_chunk(avctx, s) < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
break;
|
break;
|
||||||
|
case MKTAG('f', 'c', 'T', 'L'):
|
||||||
|
if (avctx->codec_id != AV_CODEC_ID_APNG)
|
||||||
|
goto skip_tag;
|
||||||
|
if ((ret = decode_fctl_chunk(avctx, s, length)) < 0)
|
||||||
|
goto fail;
|
||||||
|
decode_next_dat = 1;
|
||||||
|
break;
|
||||||
|
case MKTAG('f', 'd', 'A', 'T'):
|
||||||
|
if (avctx->codec_id != AV_CODEC_ID_APNG)
|
||||||
|
goto skip_tag;
|
||||||
|
if (!decode_next_dat)
|
||||||
|
goto fail;
|
||||||
|
bytestream2_get_be32(&s->gb);
|
||||||
|
length -= 4;
|
||||||
|
/* fallthrough */
|
||||||
case MKTAG('I', 'D', 'A', 'T'):
|
case MKTAG('I', 'D', 'A', 'T'):
|
||||||
|
if (avctx->codec_id == AV_CODEC_ID_APNG && !decode_next_dat)
|
||||||
|
goto skip_tag;
|
||||||
if (decode_idat_chunk(avctx, s, length, p) < 0)
|
if (decode_idat_chunk(avctx, s, length, p) < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
break;
|
break;
|
||||||
@ -894,9 +951,10 @@ exit_loop:
|
|||||||
fail:
|
fail:
|
||||||
av_dict_free(&metadata);
|
av_dict_free(&metadata);
|
||||||
ff_thread_report_progress(&s->picture, INT_MAX, 0);
|
ff_thread_report_progress(&s->picture, INT_MAX, 0);
|
||||||
return AVERROR_INVALIDDATA;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CONFIG_PNG_DECODER
|
||||||
static int decode_frame_png(AVCodecContext *avctx,
|
static int decode_frame_png(AVCodecContext *avctx,
|
||||||
void *data, int *got_frame,
|
void *data, int *got_frame,
|
||||||
AVPacket *avpkt)
|
AVPacket *avpkt)
|
||||||
@ -948,6 +1006,63 @@ the_end:
|
|||||||
s->crow_buf = NULL;
|
s->crow_buf = NULL;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_APNG_DECODER
|
||||||
|
static int decode_frame_apng(AVCodecContext *avctx,
|
||||||
|
void *data, int *got_frame,
|
||||||
|
AVPacket *avpkt)
|
||||||
|
{
|
||||||
|
PNGDecContext *const s = avctx->priv_data;
|
||||||
|
int ret;
|
||||||
|
AVFrame *p;
|
||||||
|
|
||||||
|
ff_thread_release_buffer(avctx, &s->last_picture);
|
||||||
|
FFSWAP(ThreadFrame, s->picture, s->last_picture);
|
||||||
|
p = s->picture.f;
|
||||||
|
|
||||||
|
if (!(s->state & PNG_IHDR)) {
|
||||||
|
if (!avctx->extradata_size)
|
||||||
|
return AVERROR_INVALIDDATA;
|
||||||
|
|
||||||
|
/* only init fields, there is no zlib use in extradata */
|
||||||
|
s->zstream.zalloc = ff_png_zalloc;
|
||||||
|
s->zstream.zfree = ff_png_zfree;
|
||||||
|
|
||||||
|
bytestream2_init(&s->gb, avctx->extradata, avctx->extradata_size);
|
||||||
|
if ((ret = decode_frame_common(avctx, s, p, avpkt)) < 0)
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* reset state for a new frame */
|
||||||
|
if ((ret = inflateInit(&s->zstream)) != Z_OK) {
|
||||||
|
av_log(avctx, AV_LOG_ERROR, "inflateInit returned error %d\n", ret);
|
||||||
|
ret = AVERROR_EXTERNAL;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
s->y = 0;
|
||||||
|
s->state &= ~(PNG_IDAT | PNG_ALLIMAGE);
|
||||||
|
bytestream2_init(&s->gb, avpkt->data, avpkt->size);
|
||||||
|
if ((ret = decode_frame_common(avctx, s, p, avpkt)) < 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
if (!(s->state & PNG_ALLIMAGE))
|
||||||
|
av_log(avctx, AV_LOG_WARNING, "Frame did not contain a complete image\n");
|
||||||
|
if (!(s->state & (PNG_ALLIMAGE|PNG_IDAT))) {
|
||||||
|
ret = AVERROR_INVALIDDATA;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
if ((ret = av_frame_ref(data, s->picture.f)) < 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
*got_frame = 1;
|
||||||
|
ret = bytestream2_tell(&s->gb);
|
||||||
|
|
||||||
|
end:
|
||||||
|
inflateEnd(&s->zstream);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src)
|
static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src)
|
||||||
{
|
{
|
||||||
@ -1000,6 +1115,23 @@ static av_cold int png_dec_end(AVCodecContext *avctx)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CONFIG_APNG_DECODER
|
||||||
|
AVCodec ff_apng_decoder = {
|
||||||
|
.name = "apng",
|
||||||
|
.long_name = NULL_IF_CONFIG_SMALL("APNG (Animated Portable Network Graphics) image"),
|
||||||
|
.type = AVMEDIA_TYPE_VIDEO,
|
||||||
|
.id = AV_CODEC_ID_APNG,
|
||||||
|
.priv_data_size = sizeof(PNGDecContext),
|
||||||
|
.init = png_dec_init,
|
||||||
|
.close = png_dec_end,
|
||||||
|
.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*/,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_PNG_DECODER
|
||||||
AVCodec ff_png_decoder = {
|
AVCodec ff_png_decoder = {
|
||||||
.name = "png",
|
.name = "png",
|
||||||
.long_name = NULL_IF_CONFIG_SMALL("PNG (Portable Network Graphics) image"),
|
.long_name = NULL_IF_CONFIG_SMALL("PNG (Portable Network Graphics) image"),
|
||||||
@ -1013,3 +1145,4 @@ AVCodec ff_png_decoder = {
|
|||||||
.update_thread_context = ONLY_IF_THREADS_ENABLED(update_thread_context),
|
.update_thread_context = ONLY_IF_THREADS_ENABLED(update_thread_context),
|
||||||
.capabilities = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS /*| CODEC_CAP_DRAW_HORIZ_BAND*/,
|
.capabilities = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS /*| CODEC_CAP_DRAW_HORIZ_BAND*/,
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
@ -29,8 +29,8 @@
|
|||||||
#include "libavutil/version.h"
|
#include "libavutil/version.h"
|
||||||
|
|
||||||
#define LIBAVCODEC_VERSION_MAJOR 56
|
#define LIBAVCODEC_VERSION_MAJOR 56
|
||||||
#define LIBAVCODEC_VERSION_MINOR 12
|
#define LIBAVCODEC_VERSION_MINOR 13
|
||||||
#define LIBAVCODEC_VERSION_MICRO 101
|
#define LIBAVCODEC_VERSION_MICRO 100
|
||||||
|
|
||||||
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
|
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
|
||||||
LIBAVCODEC_VERSION_MINOR, \
|
LIBAVCODEC_VERSION_MINOR, \
|
||||||
|
Loading…
x
Reference in New Issue
Block a user