Browse code

avcodec/pngdec: add APNG support.

Signed-off-by: Michael Niedermayer <michaelni@gmx.at>

Benoit Fouet authored on 2014/11/21 20:05:47
Showing 7 changed files
... ...
@@ -2068,6 +2068,7 @@ amrwb_decoder_select="lsp"
2068 2068
 amv_decoder_select="sp5x_decoder exif"
2069 2069
 amv_encoder_select="aandcttables mpegvideoenc"
2070 2070
 ape_decoder_select="bswapdsp llauddsp"
2071
+apng_decoder_select="zlib"
2071 2072
 asv1_decoder_select="blockdsp bswapdsp idctdsp"
2072 2073
 asv1_encoder_select="bswapdsp fdctdsp pixblockdsp"
2073 2074
 asv2_decoder_select="blockdsp bswapdsp idctdsp"
... ...
@@ -136,6 +136,7 @@ OBJS-$(CONFIG_AMV_ENCODER)             += mjpegenc.o mjpeg.o mjpegenc_common.o \
136 136
 OBJS-$(CONFIG_ANM_DECODER)             += anm.o
137 137
 OBJS-$(CONFIG_ANSI_DECODER)            += ansi.o cga_data.o
138 138
 OBJS-$(CONFIG_APE_DECODER)             += apedec.o
139
+OBJS-$(CONFIG_APNG_DECODER)            += png.o pngdec.o pngdsp.o
139 140
 OBJS-$(CONFIG_SSA_DECODER)             += assdec.o ass.o ass_split.o
140 141
 OBJS-$(CONFIG_SSA_ENCODER)             += assenc.o ass.o
141 142
 OBJS-$(CONFIG_ASS_DECODER)             += assdec.o ass.o ass_split.o
... ...
@@ -105,6 +105,7 @@ void avcodec_register_all(void)
105 105
     REGISTER_ENCDEC (AMV,               amv);
106 106
     REGISTER_DECODER(ANM,               anm);
107 107
     REGISTER_DECODER(ANSI,              ansi);
108
+    REGISTER_DECODER(APNG,              apng);
108 109
     REGISTER_ENCDEC (ASV1,              asv1);
109 110
     REGISTER_ENCDEC (ASV2,              asv2);
110 111
     REGISTER_DECODER(AURA,              aura);
... ...
@@ -319,6 +319,7 @@ enum AVCodecID {
319 319
     AV_CODEC_ID_HEVC       = MKBETAG('H','2','6','5'),
320 320
 #define AV_CODEC_ID_H265 AV_CODEC_ID_HEVC
321 321
     AV_CODEC_ID_VP7        = MKBETAG('V','P','7','0'),
322
+    AV_CODEC_ID_APNG       = MKBETAG('A','P','N','G'),
322 323
 
323 324
     /* various PCM "codecs" */
324 325
     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[] = {
1440 1440
         .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
1441 1441
         .mime_types= MT("image/x-xwindowdump"),
1442 1442
     },
1443
+    {
1444
+        .id        = AV_CODEC_ID_APNG,
1445
+        .type      = AVMEDIA_TYPE_VIDEO,
1446
+        .name      = "apng",
1447
+        .long_name = NULL_IF_CONFIG_SMALL("APNG (Animated Portable Network Graphics) image"),
1448
+        .props     = AV_CODEC_PROP_LOSSLESS,
1449
+        .mime_types= MT("image/png"),
1450
+    },
1443 1451
 
1444 1452
     /* various PCM "codecs" */
1445 1453
     {
... ...
@@ -786,15 +786,55 @@ static void handle_small_bpp(PNGDecContext *s, AVFrame *p)
786 786
     }
787 787
 }
788 788
 
789
+static int decode_fctl_chunk(AVCodecContext *avctx, PNGDecContext *s,
790
+                             uint32_t length)
791
+{
792
+    uint32_t sequence_number, width, height, x_offset, y_offset;
793
+
794
+    if (length != 26)
795
+        return AVERROR_INVALIDDATA;
796
+
797
+    sequence_number = bytestream2_get_be32(&s->gb);
798
+    width           = bytestream2_get_be32(&s->gb);
799
+    height          = bytestream2_get_be32(&s->gb);
800
+    x_offset        = bytestream2_get_be32(&s->gb);
801
+    y_offset        = bytestream2_get_be32(&s->gb);
802
+    bytestream2_skip(&s->gb, 10); /* delay_num  (2)
803
+                                   * delay_den  (2)
804
+                                   * dispose_op (1)
805
+                                   * blend_op   (1)
806
+                                   * crc        (4)
807
+                                   */
808
+
809
+    if (width != s->width || height != s->height ||
810
+        x_offset != 0 || y_offset != 0) {
811
+        if (sequence_number == 0)
812
+            return AVERROR_INVALIDDATA;
813
+        avpriv_request_sample(avctx, "non key frames");
814
+        return AVERROR_PATCHWELCOME;
815
+    }
816
+
817
+    return 0;
818
+}
819
+
789 820
 static int decode_frame_common(AVCodecContext *avctx, PNGDecContext *s,
790 821
                                AVFrame *p, AVPacket *avpkt)
791 822
 {
792 823
     AVDictionary *metadata  = NULL;
793 824
     uint32_t tag, length;
825
+    int decode_next_dat = 0;
826
+    int ret = AVERROR_INVALIDDATA;
794 827
 
795 828
     for (;;) {
796
-        if (bytestream2_get_bytes_left(&s->gb) <= 0) {
797
-            av_log(avctx, AV_LOG_ERROR, "%d bytes left\n", bytestream2_get_bytes_left(&s->gb));
829
+        length = bytestream2_get_bytes_left(&s->gb);
830
+        if (length <= 0) {
831
+            if (avctx->codec_id == AV_CODEC_ID_APNG && length == 0) {
832
+                if (!(s->state & PNG_IDAT))
833
+                    return 0;
834
+                else
835
+                    goto exit_loop;
836
+            }
837
+            av_log(avctx, AV_LOG_ERROR, "%d bytes left\n", length);
798 838
             if (   s->state & PNG_ALLIMAGE
799 839
                 && avctx->strict_std_compliance <= FF_COMPLIANCE_NORMAL)
800 840
                 goto exit_loop;
... ...
@@ -822,7 +862,24 @@ static int decode_frame_common(AVCodecContext *avctx, PNGDecContext *s,
822 822
             if (decode_phys_chunk(avctx, s) < 0)
823 823
                 goto fail;
824 824
             break;
825
+        case MKTAG('f', 'c', 'T', 'L'):
826
+            if (avctx->codec_id != AV_CODEC_ID_APNG)
827
+                goto skip_tag;
828
+            if ((ret = decode_fctl_chunk(avctx, s, length)) < 0)
829
+                goto fail;
830
+            decode_next_dat = 1;
831
+            break;
832
+        case MKTAG('f', 'd', 'A', 'T'):
833
+            if (avctx->codec_id != AV_CODEC_ID_APNG)
834
+                goto skip_tag;
835
+            if (!decode_next_dat)
836
+                goto fail;
837
+            bytestream2_get_be32(&s->gb);
838
+            length -= 4;
839
+            /* fallthrough */
825 840
         case MKTAG('I', 'D', 'A', 'T'):
841
+            if (avctx->codec_id == AV_CODEC_ID_APNG && !decode_next_dat)
842
+                goto skip_tag;
826 843
             if (decode_idat_chunk(avctx, s, length, p) < 0)
827 844
                 goto fail;
828 845
             break;
... ...
@@ -894,9 +951,10 @@ exit_loop:
894 894
 fail:
895 895
     av_dict_free(&metadata);
896 896
     ff_thread_report_progress(&s->picture, INT_MAX, 0);
897
-    return AVERROR_INVALIDDATA;
897
+    return ret;
898 898
 }
899 899
 
900
+#if CONFIG_PNG_DECODER
900 901
 static int decode_frame_png(AVCodecContext *avctx,
901 902
                         void *data, int *got_frame,
902 903
                         AVPacket *avpkt)
... ...
@@ -948,6 +1006,63 @@ the_end:
948 948
     s->crow_buf = NULL;
949 949
     return ret;
950 950
 }
951
+#endif
952
+
953
+#if CONFIG_APNG_DECODER
954
+static int decode_frame_apng(AVCodecContext *avctx,
955
+                        void *data, int *got_frame,
956
+                        AVPacket *avpkt)
957
+{
958
+    PNGDecContext *const s = avctx->priv_data;
959
+    int ret;
960
+    AVFrame *p;
961
+
962
+    ff_thread_release_buffer(avctx, &s->last_picture);
963
+    FFSWAP(ThreadFrame, s->picture, s->last_picture);
964
+    p = s->picture.f;
965
+
966
+    if (!(s->state & PNG_IHDR)) {
967
+        if (!avctx->extradata_size)
968
+            return AVERROR_INVALIDDATA;
969
+
970
+        /* only init fields, there is no zlib use in extradata */
971
+        s->zstream.zalloc = ff_png_zalloc;
972
+        s->zstream.zfree  = ff_png_zfree;
973
+
974
+        bytestream2_init(&s->gb, avctx->extradata, avctx->extradata_size);
975
+        if ((ret = decode_frame_common(avctx, s, p, avpkt)) < 0)
976
+            goto end;
977
+    }
978
+
979
+    /* reset state for a new frame */
980
+    if ((ret = inflateInit(&s->zstream)) != Z_OK) {
981
+        av_log(avctx, AV_LOG_ERROR, "inflateInit returned error %d\n", ret);
982
+        ret = AVERROR_EXTERNAL;
983
+        goto end;
984
+    }
985
+    s->y = 0;
986
+    s->state &= ~(PNG_IDAT | PNG_ALLIMAGE);
987
+    bytestream2_init(&s->gb, avpkt->data, avpkt->size);
988
+    if ((ret = decode_frame_common(avctx, s, p, avpkt)) < 0)
989
+        goto end;
990
+
991
+    if (!(s->state & PNG_ALLIMAGE))
992
+        av_log(avctx, AV_LOG_WARNING, "Frame did not contain a complete image\n");
993
+    if (!(s->state & (PNG_ALLIMAGE|PNG_IDAT))) {
994
+        ret = AVERROR_INVALIDDATA;
995
+        goto end;
996
+    }
997
+    if ((ret = av_frame_ref(data, s->picture.f)) < 0)
998
+        goto end;
999
+
1000
+    *got_frame = 1;
1001
+    ret = bytestream2_tell(&s->gb);
1002
+
1003
+end:
1004
+    inflateEnd(&s->zstream);
1005
+    return ret;
1006
+}
1007
+#endif
951 1008
 
952 1009
 static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src)
953 1010
 {
... ...
@@ -1000,6 +1115,23 @@ static av_cold int png_dec_end(AVCodecContext *avctx)
1000 1000
     return 0;
1001 1001
 }
1002 1002
 
1003
+#if CONFIG_APNG_DECODER
1004
+AVCodec ff_apng_decoder = {
1005
+    .name           = "apng",
1006
+    .long_name      = NULL_IF_CONFIG_SMALL("APNG (Animated Portable Network Graphics) image"),
1007
+    .type           = AVMEDIA_TYPE_VIDEO,
1008
+    .id             = AV_CODEC_ID_APNG,
1009
+    .priv_data_size = sizeof(PNGDecContext),
1010
+    .init           = png_dec_init,
1011
+    .close          = png_dec_end,
1012
+    .decode         = decode_frame_apng,
1013
+    .init_thread_copy = ONLY_IF_THREADS_ENABLED(png_dec_init),
1014
+    .update_thread_context = ONLY_IF_THREADS_ENABLED(update_thread_context),
1015
+    .capabilities   = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS /*| CODEC_CAP_DRAW_HORIZ_BAND*/,
1016
+};
1017
+#endif
1018
+
1019
+#if CONFIG_PNG_DECODER
1003 1020
 AVCodec ff_png_decoder = {
1004 1021
     .name           = "png",
1005 1022
     .long_name      = NULL_IF_CONFIG_SMALL("PNG (Portable Network Graphics) image"),
... ...
@@ -1013,3 +1145,4 @@ AVCodec ff_png_decoder = {
1013 1013
     .update_thread_context = ONLY_IF_THREADS_ENABLED(update_thread_context),
1014 1014
     .capabilities   = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS /*| CODEC_CAP_DRAW_HORIZ_BAND*/,
1015 1015
 };
1016
+#endif
... ...
@@ -29,8 +29,8 @@
29 29
 #include "libavutil/version.h"
30 30
 
31 31
 #define LIBAVCODEC_VERSION_MAJOR 56
32
-#define LIBAVCODEC_VERSION_MINOR  12
33
-#define LIBAVCODEC_VERSION_MICRO 101
32
+#define LIBAVCODEC_VERSION_MINOR  13
33
+#define LIBAVCODEC_VERSION_MICRO 100
34 34
 
35 35
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
36 36
                                                LIBAVCODEC_VERSION_MINOR, \