pngdec: frame multithreading support
authorPaul B Mahol <onemda@gmail.com>
Mon, 12 Aug 2013 10:56:20 +0000 (10:56 +0000)
committerPaul B Mahol <onemda@gmail.com>
Thu, 22 Aug 2013 13:14:25 +0000 (13:14 +0000)
Signed-off-by: Paul B Mahol <onemda@gmail.com>
libavcodec/pngdec.c

index 1358ac5..16225db 100644 (file)
@@ -28,6 +28,7 @@
 #include "internal.h"
 #include "png.h"
 #include "pngdsp.h"
+#include "thread.h"
 
 /* TODO:
  * - add 16 bit depth support
@@ -40,7 +41,8 @@ typedef struct PNGDecContext {
     AVCodecContext *avctx;
 
     GetByteContext gb;
-    AVFrame *prev;
+    ThreadFrame last_picture;
+    ThreadFrame picture;
 
     int state;
     int width, height;
@@ -505,13 +507,17 @@ 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 */
@@ -635,8 +641,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;
@@ -820,16 +828,17 @@ static int decode_frame(AVCodecContext *avctx,
     }
 
      /* handle p-frames only if a predecessor frame is available */
-     if (s->prev->data[0]) {
+     if (s->last_picture.f->data[0]) {
          if (   !(avpkt->flags & AV_PKT_FLAG_KEY) && avctx->codec_tag != AV_RL32("MPNG")
-            && s->prev->width == p->width
-            && s->prev->height== p->height
-            && s->prev->format== p->format
+            && 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];
@@ -839,13 +848,13 @@ 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;
 
@@ -860,20 +869,39 @@ static int decode_frame(AVCodecContext *avctx,
  fail:
     av_dict_free(&metadata);
     ret = AVERROR_INVALIDDATA;
+    ff_thread_release_buffer(avctx, &s->picture);
     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;
 }
@@ -882,7 +910,10 @@ 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);
 
     return 0;
 }
@@ -895,6 +926,8 @@ AVCodec ff_png_decoder = {
     .init           = png_dec_init,
     .close          = png_dec_end,
     .decode         = decode_frame,
-    .capabilities   = CODEC_CAP_DR1 /*| CODEC_CAP_DRAW_HORIZ_BAND*/,
+    .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*/,
     .long_name      = NULL_IF_CONFIG_SMALL("PNG (Portable Network Graphics) image"),
 };