From: Michael Niedermayer <[email protected]>

In line with the reference implementation.
---
 libavcodec/ffv1.h    |   5 +-
 libavcodec/ffv1dec.c | 199 ++++++++++++++++++++++++++++++++++++++++++++++-----
 libavcodec/ffv1enc.c |   4 +-
 3 files changed, 187 insertions(+), 21 deletions(-)

diff --git a/libavcodec/ffv1.h b/libavcodec/ffv1.h
index 40fc393..32af924 100644
--- a/libavcodec/ffv1.h
+++ b/libavcodec/ffv1.h
@@ -30,6 +30,7 @@
 #include "get_bits.h"
 #include "put_bits.h"
 #include "rangecoder.h"
+#include "thread.h"
 
 #define MAX_PLANES 4
 #define CONTEXT_SIZE 32
@@ -79,8 +80,8 @@ typedef struct FFV1Context {
     int transparency;
     int flags;
     int picture_number;
-    AVFrame *frame;
-    AVFrame *last_picture;
+    ThreadFrame picture, last_picture;
+    struct FFV1Context *fsrc;
 
     AVFrame *cur;
     int plane_count;
diff --git a/libavcodec/ffv1dec.c b/libavcodec/ffv1dec.c
index dd31d89..88c34b1 100644
--- a/libavcodec/ffv1dec.c
+++ b/libavcodec/ffv1dec.c
@@ -37,6 +37,7 @@
 #include "golomb.h"
 #include "mathops.h"
 #include "rangecoder.h"
+#include "thread.h"
 
 static inline av_flatten int get_symbol_inline(RangeCoder *c, uint8_t *state,
                                                int is_signed)
@@ -353,6 +354,43 @@ static int decode_slice(AVCodecContext *c, void *arg)
                    ? (c->bits_per_raw_sample > 8) + 1
                    : 4;
     AVFrame *const p = f->cur;
+    int i, si;
+
+    for (si = 0; fs != f->slice_context[si]; si++);
+
+    if (f->fsrc && !p->key_frame)
+        ff_thread_await_progress(&f->last_picture, si, 0);
+
+    if (f->fsrc && !p->key_frame) {
+        FFV1Context *fssrc = f->fsrc->slice_context[si];
+        FFV1Context *fsdst = f->slice_context[si];
+
+        if (!p->key_frame)
+            fsdst->slice_damaged |= fssrc->slice_damaged;
+
+        for (i = 0; i < f->plane_count; i++) {
+            PlaneContext *psrc = &fssrc->plane[i];
+            PlaneContext *pdst = &fsdst->plane[i];
+
+            av_free(pdst->state);
+            av_free(pdst->vlc_state);
+            memcpy(pdst, psrc, sizeof(*pdst));
+            pdst->state = NULL;
+            pdst->vlc_state = NULL;
+
+            if (fssrc->ac) {
+                pdst->state = av_malloc(CONTEXT_SIZE * psrc->context_count);
+                memcpy(pdst->state, psrc->state,
+                       CONTEXT_SIZE * psrc->context_count);
+            } else {
+                pdst->vlc_state = av_malloc(sizeof(*pdst->vlc_state) *
+                                            psrc->context_count);
+                memcpy(pdst->vlc_state, psrc->vlc_state,
+                       sizeof(*pdst->vlc_state) * psrc->context_count);
+            }
+        }
+    }
+
 
     if (f->version > 2) {
         if (decode_slice_header(f, fs) < 0) {
@@ -425,6 +463,8 @@ static int decode_slice(AVCodecContext *c, void *arg)
 
     emms_c();
 
+    ff_thread_report_progress(&f->picture, si, 0);
+
     return 0;
 }
 
@@ -798,6 +838,23 @@ static int read_header(FFV1Context *f)
     return 0;
 }
 
+static av_cold int ffv1_decode_close(AVCodecContext *avctx)
+{
+    FFV1Context *s = avctx->priv_data;;
+
+    if (s->picture.f)
+        ff_thread_release_buffer(avctx, &s->picture);
+    av_frame_free(&s->picture.f);
+
+    if (s->last_picture.f)
+        ff_thread_release_buffer(avctx, &s->last_picture);
+    av_frame_free(&s->last_picture.f);
+
+    ffv1_close(avctx);
+
+    return 0;
+}
+
 static av_cold int ffv1_decode_init(AVCodecContext *avctx)
 {
     FFV1Context *f = avctx->priv_data;
@@ -813,12 +870,18 @@ static av_cold int ffv1_decode_init(AVCodecContext *avctx)
         return ret;
     }
 
-    f->last_picture = av_frame_alloc();
-    if (!f->last_picture) {
+    f->last_picture.f = av_frame_alloc();
+    if (!f->last_picture.f) {
         ffv1_close(avctx);
         return AVERROR(ENOMEM);
     }
 
+    f->picture.f = av_frame_alloc();
+    if (!f->picture.f) {
+        ffv1_decode_close(avctx);
+        return AVERROR(ENOMEM);
+    }
+
     return 0;
 }
 
@@ -832,9 +895,15 @@ static int ffv1_decode_frame(AVCodecContext *avctx, void 
*data,
     int i, ret;
     uint8_t keystate = 128;
     const uint8_t *buf_p;
-    AVFrame *const p    = data;
+    AVFrame *p;
+
+    if (f->last_picture.f)
+        ff_thread_release_buffer(avctx, &f->last_picture);
+    FFSWAP(ThreadFrame, f->picture, f->last_picture);
+
+    f->cur = p = f->picture.f;
 
-    f->cur = p;
+    f->avctx = avctx;
 
     ff_init_range_decoder(c, buf, buf_size);
     ff_build_rac_states(c, 0.05 * (1LL << 32), 256 - 8);
@@ -855,7 +924,7 @@ static int ffv1_decode_frame(AVCodecContext *avctx, void 
*data,
         p->key_frame = 0;
     }
 
-    if ((ret = ff_get_buffer(avctx, p, AV_GET_BUFFER_FLAG_REF)) < 0) {
+    if ((ret = ff_thread_get_buffer(avctx, &f->picture, 
AV_GET_BUFFER_FLAG_REF)) < 0) {
         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
         return ret;
     }
@@ -895,9 +964,12 @@ static int ffv1_decode_frame(AVCodecContext *avctx, void 
*data,
         } else
             fs->c.bytestream_end = (uint8_t *)(buf_p + v);
 
+        fs->avctx = avctx;
         fs->cur = p;
     }
 
+    ff_thread_finish_setup(avctx);
+
     avctx->execute(avctx, decode_slice, &f->slice_context[0], NULL,
                    f->slice_count,
                    sizeof(void *));
@@ -905,44 +977,135 @@ static int ffv1_decode_frame(AVCodecContext *avctx, void 
*data,
     for (i = f->slice_count - 1; i >= 0; i--) {
         FFV1Context *fs = f->slice_context[i];
         int j;
-        if (fs->slice_damaged && f->last_picture->data[0]) {
+        if (fs->slice_damaged && f->last_picture.f->data[0]) {
             const uint8_t *src[4];
             uint8_t *dst[4];
+            ff_thread_await_progress(&f->last_picture, INT_MAX, 0);
             for (j = 0; j < 4; j++) {
                 int sh = (j == 1 || j == 2) ? f->chroma_h_shift : 0;
                 int sv = (j == 1 || j == 2) ? f->chroma_v_shift : 0;
                 dst[j] = p->data[j] + p->linesize[j] *
                          (fs->slice_y >> sv) + (fs->slice_x >> sh);
-                src[j] = f->last_picture->data[j] +
-                         f->last_picture->linesize[j] *
+                src[j] = f->last_picture.f->data[j] +
+                         f->last_picture.f->linesize[j] *
                          (fs->slice_y >> sv) + (fs->slice_x >> sh);
             }
             av_image_copy(dst, p->linesize, (const uint8_t **)src,
-                          f->last_picture->linesize,
+                          f->last_picture.f->linesize,
                           avctx->pix_fmt, fs->slice_width,
                           fs->slice_height);
         }
     }
+    ff_thread_report_progress(&f->picture, INT_MAX, 0);
 
     f->picture_number++;
 
-    av_frame_unref(f->last_picture);
-    if ((ret = av_frame_ref(f->last_picture, p)) < 0)
-        return ret;
+    if (f->last_picture.f)
+        ff_thread_release_buffer(avctx, &f->last_picture);
+
     f->cur = NULL;
+    if ((ret = av_frame_ref(data, f->picture.f)) < 0)
+        return ret;
 
     *got_frame = 1;
 
     return buf_size;
 }
 
-static av_cold int ffv1_decode_close(AVCodecContext *avctx)
+static int init_thread_copy(AVCodecContext *avctx)
 {
-    FFV1Context *s = avctx->priv_data;;
+    FFV1Context *f = avctx->priv_data;
+    int i, ret;
 
-    av_frame_free(&s->last_picture);
+    f->picture.f      = NULL;
+    f->last_picture.f = NULL;
+    f->sample_buffer  = NULL;
+    f->slice_count = 0;
 
-    ffv1_close(avctx);
+    for (i = 0; i < f->quant_table_count; i++) {
+        int count = f->context_count[i];
+        void *p = av_malloc(count * sizeof(*f->initial_states[i]));
+
+        if (!p) {
+            int j;
+            for (j = 0; j < i; j++)
+                av_freep(f->initial_states + j);
+            for (; i < f->quant_table_count; i++)
+                f->initial_states[i] = NULL;
+            return AVERROR(ENOMEM);
+        }
+
+        memcpy(p, f->initial_states[i], count);
+
+        f->initial_states[i] = p;
+    }
+
+    f->picture.f      = av_frame_alloc();
+    f->last_picture.f = av_frame_alloc();
+
+    if ((ret = ffv1_init_slice_contexts(f)) < 0)
+        return ret;
+
+    return 0;
+}
+
+static void copy_fields(FFV1Context *fsdst, FFV1Context *fssrc, FFV1Context 
*fsrc)
+{
+    fsdst->version             = fsrc->version;
+    fsdst->minor_version       = fsrc->minor_version;
+    fsdst->chroma_planes       = fsrc->chroma_planes;
+    fsdst->chroma_h_shift      = fsrc->chroma_h_shift;
+    fsdst->chroma_v_shift      = fsrc->chroma_v_shift;
+    fsdst->transparency        = fsrc->transparency;
+    fsdst->plane_count         = fsrc->plane_count;
+    fsdst->ac                  = fsrc->ac;
+    fsdst->colorspace          = fsrc->colorspace;
+
+    fsdst->ec                  = fsrc->ec;
+    fsdst->slice_damaged       = fssrc->slice_damaged;
+    fsdst->key_frame_ok        = fsrc->key_frame_ok;
+
+    fsdst->bits_per_raw_sample = fsrc->bits_per_raw_sample;
+    fsdst->packed_at_lsb       = fsrc->packed_at_lsb;
+    fsdst->slice_count         = fsrc->slice_count;
+    if (fsrc->version<3){
+        fsdst->slice_x             = fssrc->slice_x;
+        fsdst->slice_y             = fssrc->slice_y;
+        fsdst->slice_width         = fssrc->slice_width;
+        fsdst->slice_height        = fssrc->slice_height;
+    }
+}
+
+static int update_thread_context(AVCodecContext *dst, const AVCodecContext 
*src)
+{
+    FFV1Context *fsrc = src->priv_data;
+    FFV1Context *fdst = dst->priv_data;
+    int i, ret;
+
+    if (dst == src)
+        return 0;
+
+    {
+        FFV1Context bak = *fdst;
+        memcpy(fdst, fsrc, sizeof(*fdst));
+        memcpy(fdst->initial_states, bak.initial_states, 
sizeof(fdst->initial_states));
+        memcpy(fdst->slice_context,  bak.slice_context , 
sizeof(fdst->slice_context));
+        fdst->picture      = bak.picture;
+        fdst->last_picture = bak.last_picture;
+        for (i = 0; i<fdst->num_h_slices * fdst->num_v_slices; i++) {
+            FFV1Context *fssrc = fsrc->slice_context[i];
+            FFV1Context *fsdst = fdst->slice_context[i];
+            copy_fields(fsdst, fssrc, fsrc);
+        }
+    }
+
+    ff_thread_release_buffer(dst, &fdst->picture);
+    if (fsrc->picture.f->data[0]) {
+        if ((ret = ff_thread_ref_frame(&fdst->picture, &fsrc->picture)) < 0)
+            return ret;
+    }
+
+    fdst->fsrc = fsrc;
 
     return 0;
 }
@@ -956,6 +1119,8 @@ AVCodec ff_ffv1_decoder = {
     .init           = ffv1_decode_init,
     .close          = ffv1_decode_close,
     .decode         = ffv1_decode_frame,
+    .init_thread_copy = ONLY_IF_THREADS_ENABLED(init_thread_copy),
+    .update_thread_context = ONLY_IF_THREADS_ENABLED(update_thread_context),
     .capabilities   = CODEC_CAP_DR1 /*| CODEC_CAP_DRAW_HORIZ_BAND*/ |
-                      CODEC_CAP_SLICE_THREADS,
+                      CODEC_CAP_FRAME_THREADS | CODEC_CAP_SLICE_THREADS,
 };
diff --git a/libavcodec/ffv1enc.c b/libavcodec/ffv1enc.c
index 179453d..b2410d4 100644
--- a/libavcodec/ffv1enc.c
+++ b/libavcodec/ffv1enc.c
@@ -879,7 +879,7 @@ static int encode_slice(AVCodecContext *c, void *arg)
     int height       = fs->slice_height;
     int x            = fs->slice_x;
     int y            = fs->slice_y;
-    const AVFrame *const p = f->frame;
+    const AVFrame *const p = f->cur;
     const int ps     = (av_pix_fmt_desc_get(c->pix_fmt)->flags & 
AV_PIX_FMT_FLAG_PLANAR)
                        ? (f->bits_per_raw_sample > 8) + 1
                        : 4;
@@ -937,7 +937,7 @@ static int ffv1_encode_frame(AVCodecContext *avctx, 
AVPacket *pkt,
     uint8_t *buf_p;
     int i, ret;
 
-    f->frame = pict;
+    f->cur = pict;
 
     if ((ret = ff_alloc_packet(pkt, avctx->width * avctx->height *
                              ((8 * 2 + 1 + 1) * 4) / 8 +
-- 
1.8.5.1

_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to