]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/pngdec.c
DCA: ARM/NEON optimised lfe_fir
[ffmpeg] / libavcodec / pngdec.c
index fadbcd07c945ec0acd92dae487e544abc6afa6a6..aa05ff020b75cbc0dbd102746f3d016c2f9d2730 100644 (file)
@@ -37,7 +37,8 @@ typedef struct PNGDecContext {
     const uint8_t *bytestream;
     const uint8_t *bytestream_start;
     const uint8_t *bytestream_end;
-    AVFrame picture;
+    AVFrame picture1, picture2;
+    AVFrame *current_picture, *last_picture;
 
     int state;
     int width, height;
@@ -180,6 +181,13 @@ void ff_add_png_paeth_prediction(uint8_t *dst, uint8_t *src, uint8_t *top, int w
     else if(bpp == 2) UNROLL1(2, op)\
     else if(bpp == 3) UNROLL1(3, op)\
     else if(bpp == 4) UNROLL1(4, op)\
+    else {\
+        for (; i < size; i += bpp) {\
+            int j;\
+            for (j = 0; j < bpp; j++)\
+                dst[i+j] = op(dst[i+j-bpp], src[i+j], last[i+j]);\
+        }\
+    }
 
 /* NOTE: 'dst' can be equal to 'last' */
 static void png_filter_row(DSPContext *dsp, uint8_t *dst, int filter_type,
@@ -385,10 +393,15 @@ static int decode_frame(AVCodecContext *avctx,
     int buf_size = avpkt->size;
     PNGDecContext * const s = avctx->priv_data;
     AVFrame *picture = data;
-    AVFrame * const p= &s->picture;
+    AVFrame *p;
+    uint8_t *crow_buf_base = NULL;
     uint32_t tag, length;
     int ret, crc;
 
+    FFSWAP(AVFrame *, s->current_picture, s->last_picture);
+    avctx->coded_frame= s->current_picture;
+    p = s->current_picture;
+
     s->bytestream_start=
     s->bytestream= buf;
     s->bytestream_end= buf + buf_size;
@@ -417,13 +430,11 @@ static int decode_frame(AVCodecContext *avctx,
             goto fail;
         tag32 = bytestream_get_be32(&s->bytestream);
         tag = bswap_32(tag32);
-#ifdef DEBUG
-        av_log(avctx, AV_LOG_DEBUG, "png: tag=%c%c%c%c length=%u\n",
-               (tag & 0xff),
-               ((tag >> 8) & 0xff),
-               ((tag >> 16) & 0xff),
-               ((tag >> 24) & 0xff), length);
-#endif
+        dprintf(avctx, "png: tag=%c%c%c%c length=%u\n",
+                (tag & 0xff),
+                ((tag >> 8) & 0xff),
+                ((tag >> 16) & 0xff),
+                ((tag >> 24) & 0xff), length);
         switch(tag) {
         case MKTAG('I', 'H', 'D', 'R'):
             if (length != 13)
@@ -441,11 +452,9 @@ static int decode_frame(AVCodecContext *avctx,
             s->interlace_type = *s->bytestream++;
             crc = bytestream_get_be32(&s->bytestream);
             s->state |= PNG_IHDR;
-#ifdef DEBUG
-            av_log(avctx, AV_LOG_DEBUG, "width=%d height=%d depth=%d color_type=%d compression_type=%d filter_type=%d interlace_type=%d\n",
-                   s->width, s->height, s->bit_depth, s->color_type,
-                   s->compression_type, s->filter_type, s->interlace_type);
-#endif
+            dprintf(avctx, "width=%d height=%d depth=%d color_type=%d compression_type=%d filter_type=%d interlace_type=%d\n",
+                    s->width, s->height, s->bit_depth, s->color_type,
+                    s->compression_type, s->filter_type, s->interlace_type);
             break;
         case MKTAG('I', 'D', 'A', 'T'):
             if (!(s->state & PNG_IHDR))
@@ -472,6 +481,9 @@ static int decode_frame(AVCodecContext *avctx,
                 } else if (s->bit_depth == 16 &&
                            s->color_type == PNG_COLOR_TYPE_GRAY) {
                     avctx->pix_fmt = PIX_FMT_GRAY16BE;
+                } else if (s->bit_depth == 16 &&
+                           s->color_type == PNG_COLOR_TYPE_RGB) {
+                    avctx->pix_fmt = PIX_FMT_RGB48BE;
                 } else if (s->bit_depth == 1 &&
                            s->color_type == PNG_COLOR_TYPE_GRAY) {
                     avctx->pix_fmt = PIX_FMT_MONOBLACK;
@@ -502,10 +514,8 @@ static int decode_frame(AVCodecContext *avctx,
                                                          s->width);
                     s->crow_size = s->pass_row_size + 1;
                 }
-#ifdef DEBUG
-                av_log(avctx, AV_LOG_DEBUG, "row_size=%d crow_size =%d\n",
-                       s->row_size, s->crow_size);
-#endif
+                dprintf(avctx, "row_size=%d crow_size =%d\n",
+                        s->row_size, s->crow_size);
                 s->image_buf = p->data[0];
                 s->image_linesize = p->linesize[0];
                 /* copy the palette if needed */
@@ -522,9 +532,12 @@ static int decode_frame(AVCodecContext *avctx,
                         goto fail;
                 }
                 /* compressed row */
-                s->crow_buf = av_malloc(s->row_size + 1);
-                if (!s->crow_buf)
+                crow_buf_base = av_malloc(s->row_size + 16);
+                if (!crow_buf_base)
                     goto fail;
+
+                /* we want crow_buf+1 to be 16-byte aligned */
+                s->crow_buf = crow_buf_base + 15;
                 s->zstream.avail_out = s->crow_size;
                 s->zstream.next_out = s->crow_buf;
             }
@@ -584,13 +597,31 @@ static int decode_frame(AVCodecContext *avctx,
         }
     }
  exit_loop:
-    *picture= s->picture;
+     /* handle p-frames only if a predecessor frame is available */
+     if(s->last_picture->data[0] != NULL) {
+         if(!(avpkt->flags & AV_PKT_FLAG_KEY)) {
+            int i, j;
+            uint8_t *pd = s->current_picture->data[0];
+            uint8_t *pd_last = s->last_picture->data[0];
+
+            for(j=0; j < s->height; j++) {
+                for(i=0; i < s->width * s->bpp; i++) {
+                    pd[i] += pd_last[i];
+                }
+                pd += s->image_linesize;
+                pd_last += s->image_linesize;
+            }
+        }
+    }
+
+    *picture= *s->current_picture;
     *data_size = sizeof(AVFrame);
 
     ret = s->bytestream - s->bytestream_start;
  the_end:
     inflateEnd(&s->zstream);
-    av_freep(&s->crow_buf);
+    av_free(crow_buf_base);
+    s->crow_buf = NULL;
     av_freep(&s->last_row);
     av_freep(&s->tmp_row);
     return ret;
@@ -602,23 +633,37 @@ static int decode_frame(AVCodecContext *avctx,
 static av_cold int png_dec_init(AVCodecContext *avctx){
     PNGDecContext *s = avctx->priv_data;
 
-    avcodec_get_frame_defaults(&s->picture);
-    avctx->coded_frame= &s->picture;
+    s->current_picture = &s->picture1;
+    s->last_picture = &s->picture2;
+    avcodec_get_frame_defaults(&s->picture1);
+    avcodec_get_frame_defaults(&s->picture2);
     dsputil_init(&s->dsp, avctx);
 
     return 0;
 }
 
+static av_cold int png_dec_end(AVCodecContext *avctx)
+{
+    PNGDecContext *s = avctx->priv_data;
+
+    if (s->picture1.data[0])
+        avctx->release_buffer(avctx, &s->picture1);
+    if (s->picture2.data[0])
+        avctx->release_buffer(avctx, &s->picture2);
+
+    return 0;
+}
+
 AVCodec png_decoder = {
     "png",
-    CODEC_TYPE_VIDEO,
+    AVMEDIA_TYPE_VIDEO,
     CODEC_ID_PNG,
     sizeof(PNGDecContext),
     png_dec_init,
     NULL,
-    NULL, //decode_end,
+    png_dec_end,
     decode_frame,
-    0 /*CODEC_CAP_DR1*/ /*| CODEC_CAP_DRAW_HORIZ_BAND*/,
+    CODEC_CAP_DR1 /*| CODEC_CAP_DRAW_HORIZ_BAND*/,
     NULL,
     .long_name = NULL_IF_CONFIG_SMALL("PNG image"),
 };