From b662acace688b10a7a6745b13c4872557e07fe96 Mon Sep 17 00:00:00 2001
From: Stanislav Dolganov <dolganov@qst.hk>
Date: Thu, 24 Mar 2016 13:53:43 +0300
Subject: [PATCH] simple ffv1 P frame support

---
 libavcodec/ffv1.c                                |  17 +++-
 libavcodec/ffv1.h                                |   5 +-
 libavcodec/ffv1dec.c                             | 108 ++++++++++++++++++++++-
 libavcodec/ffv1enc.c                             |  94 +++++++++++++++++++-
 tests/fate/vcodec.mak                            |  13 ++-
 tests/ref/vsynth/vsynth1-ffv1-v3-p-bgr0          |   4 +
 tests/ref/vsynth/vsynth1-ffv1-v3-p-yuv420p       |   4 +
 tests/ref/vsynth/vsynth1-ffv1-v3-p-yuv422p10     |   4 +
 tests/ref/vsynth/vsynth1-ffv1-v3-p-yuv444p16     |   4 +
 tests/ref/vsynth/vsynth2-ffv1-v3-p-bgr0          |   4 +
 tests/ref/vsynth/vsynth2-ffv1-v3-p-yuv420p       |   4 +
 tests/ref/vsynth/vsynth2-ffv1-v3-p-yuv422p10     |   4 +
 tests/ref/vsynth/vsynth2-ffv1-v3-p-yuv444p16     |   4 +
 tests/ref/vsynth/vsynth3-ffv1-v3-p-bgr0          |   4 +
 tests/ref/vsynth/vsynth3-ffv1-v3-p-yuv420p       |   4 +
 tests/ref/vsynth/vsynth3-ffv1-v3-p-yuv422p10     |   4 +
 tests/ref/vsynth/vsynth3-ffv1-v3-p-yuv444p16     |   4 +
 tests/ref/vsynth/vsynth_lena-ffv1-v3-p-bgr0      |   4 +
 tests/ref/vsynth/vsynth_lena-ffv1-v3-p-yuv420p   |   4 +
 tests/ref/vsynth/vsynth_lena-ffv1-v3-p-yuv422p10 |   4 +
 tests/ref/vsynth/vsynth_lena-ffv1-v3-p-yuv444p16 |   4 +
 21 files changed, 295 insertions(+), 6 deletions(-)
 create mode 100644 tests/ref/vsynth/vsynth1-ffv1-v3-p-bgr0
 create mode 100644 tests/ref/vsynth/vsynth1-ffv1-v3-p-yuv420p
 create mode 100644 tests/ref/vsynth/vsynth1-ffv1-v3-p-yuv422p10
 create mode 100644 tests/ref/vsynth/vsynth1-ffv1-v3-p-yuv444p16
 create mode 100644 tests/ref/vsynth/vsynth2-ffv1-v3-p-bgr0
 create mode 100644 tests/ref/vsynth/vsynth2-ffv1-v3-p-yuv420p
 create mode 100644 tests/ref/vsynth/vsynth2-ffv1-v3-p-yuv422p10
 create mode 100644 tests/ref/vsynth/vsynth2-ffv1-v3-p-yuv444p16
 create mode 100644 tests/ref/vsynth/vsynth3-ffv1-v3-p-bgr0
 create mode 100644 tests/ref/vsynth/vsynth3-ffv1-v3-p-yuv420p
 create mode 100644 tests/ref/vsynth/vsynth3-ffv1-v3-p-yuv422p10
 create mode 100644 tests/ref/vsynth/vsynth3-ffv1-v3-p-yuv444p16
 create mode 100644 tests/ref/vsynth/vsynth_lena-ffv1-v3-p-bgr0
 create mode 100644 tests/ref/vsynth/vsynth_lena-ffv1-v3-p-yuv420p
 create mode 100644 tests/ref/vsynth/vsynth_lena-ffv1-v3-p-yuv422p10
 create mode 100644 tests/ref/vsynth/vsynth_lena-ffv1-v3-p-yuv444p16

diff --git a/libavcodec/ffv1.c b/libavcodec/ffv1.c
index 537409e..d9f8881 100644
--- a/libavcodec/ffv1.c
+++ b/libavcodec/ffv1.c
@@ -51,12 +51,18 @@ av_cold int ff_ffv1_common_init(AVCodecContext *avctx)
 
     s->picture.f = av_frame_alloc();
     s->last_picture.f = av_frame_alloc();
-    if (!s->picture.f || !s->last_picture.f)
+    s->residual.f = av_frame_alloc();
+    if (!s->picture.f || !s->last_picture.f || !s->residual.f)
         return AVERROR(ENOMEM);
 
     s->width  = avctx->width;
     s->height = avctx->height;
 
+    s->c_image_line_buf = av_mallocz_array(sizeof(*s->c_image_line_buf), s->width);
+    s->p_image_line_buf = av_mallocz_array(sizeof(*s->p_image_line_buf), s->width);
+    if (!s->c_image_line_buf || !s->p_image_line_buf)
+        return AVERROR(ENOMEM);
+
     // defaults
     s->num_h_slices = 1;
     s->num_v_slices = 1;
@@ -215,6 +221,10 @@ av_cold int ff_ffv1_close(AVCodecContext *avctx)
         ff_thread_release_buffer(avctx, &s->last_picture);
     av_frame_free(&s->last_picture.f);
 
+    if (s->residual.f)
+        ff_thread_release_buffer(avctx, &s->residual);
+    av_frame_free(&s->residual.f);
+
     for (j = 0; j < s->max_slice_count; j++) {
         FFV1Context *fs = s->slice_context[j];
         for (i = 0; i < s->plane_count; i++) {
@@ -226,6 +236,11 @@ av_cold int ff_ffv1_close(AVCodecContext *avctx)
         av_freep(&fs->sample_buffer);
     }
 
+    if (s->p_image_line_buf)
+        av_freep(&s->p_image_line_buf);
+    if (s->c_image_line_buf)
+        av_freep(&s->c_image_line_buf);
+
     av_freep(&avctx->stats_out);
     for (j = 0; j < s->quant_table_count; j++) {
         av_freep(&s->initial_states[j]);
diff --git a/libavcodec/ffv1.h b/libavcodec/ffv1.h
index d9398e5..0177992 100644
--- a/libavcodec/ffv1.h
+++ b/libavcodec/ffv1.h
@@ -93,7 +93,7 @@ typedef struct FFV1Context {
     int flags;
     int picture_number;
     int key_frame;
-    ThreadFrame picture, last_picture;
+    ThreadFrame picture, last_picture, residual;
     struct FFV1Context *fsrc;
 
     AVFrame *cur;
@@ -110,11 +110,14 @@ typedef struct FFV1Context {
     int colorspace;
     int16_t *sample_buffer;
 
+    uint16_t *p_image_line_buf, *c_image_line_buf;
+
     int ec;
     int intra;
     int slice_damaged;
     int key_frame_ok;
     int context_model;
+    int p_frame;
 
     int bits_per_raw_sample;
     int packed_at_lsb;
diff --git a/libavcodec/ffv1dec.c b/libavcodec/ffv1dec.c
index d2bf3a8..0465e6d 100644
--- a/libavcodec/ffv1dec.c
+++ b/libavcodec/ffv1dec.c
@@ -39,6 +39,69 @@
 #include "mathops.h"
 #include "ffv1.h"
 
+static int ff_predict_frame(AVCodecContext *avctx, FFV1Context *f)
+{
+    int ret, i, x, y;
+    AVFrame *curr     = f->picture.f;
+    AVFrame *prev     = f->last_picture.f;
+    AVFrame *residual = f->residual.f;
+    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(prev->format);
+    int width  = f->width;
+    int height = f->height;
+    int has_plane[4] = { 0 };
+    const int cw = AV_CEIL_RSHIFT(width, desc->log2_chroma_w);
+    const int ch = AV_CEIL_RSHIFT(height, desc->log2_chroma_h);
+
+    if (f->residual.f)
+        ff_thread_release_buffer(avctx, &f->residual);
+    if ((ret = ff_thread_ref_frame(&f->residual, &f->picture)) < 0)
+        return ret;
+    if ((ret = av_frame_make_writable(f->residual.f)) < 0) {
+        ff_thread_release_buffer(avctx, &f->residual);
+        return ret;
+    }
+
+    for (i = 0; i < desc->nb_components; i++)
+        has_plane[desc->comp[i].plane] = 1;
+
+    for (i = 0; i < desc->nb_components && has_plane[i]; i++)
+        memset(residual->buf[i]->data, 0, residual->buf[i]->size * sizeof(*residual->buf[i]->data));
+
+    for (i = 0; i < desc->nb_components; i++) {
+        const int w1 = (i == 1 || i == 2) ? cw : width;
+        const int h1 = (i == 1 || i == 2) ? ch : height;
+
+        const int depth = desc->comp[i].depth;
+        const int max_val = 1 << depth;
+
+        for (y = 0; y < h1; y++) {
+            memset(f->p_image_line_buf, 0, width * sizeof(*f->p_image_line_buf));
+            memset(f->c_image_line_buf, 0, width * sizeof(*f->c_image_line_buf));
+            av_read_image_line(f->c_image_line_buf,
+                               (void *)curr->data,
+                               curr->linesize,
+                               desc,
+                               0, y, i, w1, 0);
+            av_read_image_line(f->p_image_line_buf,
+                              (void *)prev->data,
+                              prev->linesize,
+                              desc,
+                              0, y, i, w1, 0);
+            for (x = 0; x < w1; ++x)
+                f->c_image_line_buf[x] = (f->c_image_line_buf[x] + f->p_image_line_buf[x] - (max_val >> 2)) & (max_val - 1);
+            av_write_image_line(f->c_image_line_buf,
+                                residual->data,
+                                residual->linesize,
+                                desc,
+                                0, y, i, w1);
+        }
+    }
+
+    av_image_copy(curr->data, curr->linesize, residual->data, residual->linesize, curr->format, f->width, f->height);
+
+    return 0;
+}
+
 static inline av_flatten int get_symbol_inline(RangeCoder *c, uint8_t *state,
                                                int is_signed)
 {
@@ -533,6 +596,7 @@ static int read_extra_header(FFV1Context *f)
     ff_build_rac_states(c, 0.05 * (1LL << 32), 256 - 8);
 
     f->version = get_symbol(c, state, 0);
+
     if (f->version < 2) {
         av_log(f->avctx, AV_LOG_ERROR, "Invalid version in global header\n");
         return AVERROR_INVALIDDATA;
@@ -543,6 +607,13 @@ static int read_extra_header(FFV1Context *f)
         if (f->micro_version < 0)
             return AVERROR_INVALIDDATA;
     }
+
+    if (f->version == 3 && f->micro_version > 4 || f->version == 4 && f->micro_version > 2) {
+        f->p_frame = 1;
+        f->micro_version--;
+    } else {
+        f->p_frame = 0;
+    }
     f->ac = get_symbol(c, state, 0);
 
     if (f->ac == AC_RANGE_CUSTOM_TAB) {
@@ -935,6 +1006,10 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac
         p->key_frame = 0;
     }
 
+    if (f->p_frame) {
+        p->pict_type = p->key_frame ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
+    }
+
     if ((ret = ff_thread_get_buffer(avctx, &f->picture, AV_GET_BUFFER_FLAG_REF)) < 0)
         return ret;
 
@@ -1018,6 +1093,17 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac
                           fs->slice_height);
         }
     }
+
+    if (f->p_frame) {
+        ff_thread_await_progress(&f->last_picture, INT_MAX, 0);
+
+        if (!p->key_frame) {
+            if ((ret = ff_predict_frame(avctx, f)) < 0) {
+                ff_thread_report_progress(&f->picture, INT_MAX, 0);
+                return ret;
+            }
+        }
+    }
     ff_thread_report_progress(&f->picture, INT_MAX, 0);
 
     f->picture_number++;
@@ -1025,6 +1111,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac
     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;
 
@@ -1041,10 +1128,14 @@ static int init_thread_copy(AVCodecContext *avctx)
 
     f->picture.f      = NULL;
     f->last_picture.f = NULL;
+    f->residual.f     = NULL;
     f->sample_buffer  = NULL;
     f->max_slice_count = 0;
     f->slice_count = 0;
 
+    f->p_image_line_buf = NULL;
+    f->c_image_line_buf = NULL;
+
     for (i = 0; i < f->quant_table_count; i++) {
         av_assert0(f->version > 1);
         f->initial_states[i] = av_memdup(f->initial_states[i],
@@ -1053,6 +1144,16 @@ static int init_thread_copy(AVCodecContext *avctx)
 
     f->picture.f      = av_frame_alloc();
     f->last_picture.f = av_frame_alloc();
+    f->residual.f     = av_frame_alloc();
+
+    if (!f->picture.f || !f->last_picture.f || !f->residual.f)
+        return AVERROR(ENOMEM);
+
+    f->p_image_line_buf = av_mallocz_array(sizeof(*f->p_image_line_buf), f->width);
+    f->c_image_line_buf = av_mallocz_array(sizeof(*f->c_image_line_buf), f->width);
+
+    if (!f->p_image_line_buf || !f->c_image_line_buf)
+        return AVERROR(ENOMEM);
 
     if ((ret = ff_ffv1_init_slice_contexts(f)) < 0)
         return ret;
@@ -1074,6 +1175,7 @@ static void copy_fields(FFV1Context *fsdst, FFV1Context *fssrc, FFV1Context *fsr
     fsdst->colorspace          = fsrc->colorspace;
 
     fsdst->ec                  = fsrc->ec;
+    fsdst->p_frame             = fsrc->p_frame;
     fsdst->intra               = fsrc->intra;
     fsdst->slice_damaged       = fssrc->slice_damaged;
     fsdst->key_frame_ok        = fsrc->key_frame_ok;
@@ -1100,7 +1202,8 @@ static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src)
         return 0;
 
     {
-        ThreadFrame picture = fdst->picture, last_picture = fdst->last_picture;
+        ThreadFrame picture = fdst->picture, last_picture = fdst->last_picture, residual = fdst->residual;
+        uint16_t *c_image_line_buf = fdst->c_image_line_buf, *p_image_line_buf = fdst->p_image_line_buf;
         uint8_t (*initial_states[MAX_QUANT_TABLES])[32];
         struct FFV1Context *slice_context[MAX_SLICES];
         memcpy(initial_states, fdst->initial_states, sizeof(fdst->initial_states));
@@ -1111,6 +1214,9 @@ static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src)
         memcpy(fdst->slice_context,  slice_context , sizeof(fdst->slice_context));
         fdst->picture      = picture;
         fdst->last_picture = last_picture;
+        fdst->residual     = residual;
+        fdst->p_image_line_buf = p_image_line_buf;
+        fdst->c_image_line_buf = c_image_line_buf;
         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];
diff --git a/libavcodec/ffv1enc.c b/libavcodec/ffv1enc.c
index 9ee9921..ed0a3ca 100644
--- a/libavcodec/ffv1enc.c
+++ b/libavcodec/ffv1enc.c
@@ -135,6 +135,72 @@ static const uint8_t ver2_state[256] = {
     241, 243, 242, 244, 245, 246, 247, 248, 249, 250, 251, 252, 252, 253, 254, 255,
 };
 
+static int ff_frame_diff(FFV1Context *f, const AVFrame *pict)
+{
+    int ret, i, x, y;
+    AVFrame *curr     = f->picture.f;
+    AVFrame *prev     = f->last_picture.f;
+    AVFrame *residual = f->residual.f;
+    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(prev->format);
+    int width  = f->width;
+    int height = f->height;
+    int has_plane[4] = { 0 };
+    const int cw = AV_CEIL_RSHIFT(width, desc->log2_chroma_w);
+    const int ch = AV_CEIL_RSHIFT(height, desc->log2_chroma_h);
+
+    if (f->picture.f)
+        av_frame_unref(f->picture.f);
+    if (f->residual.f)
+        av_frame_unref(f->residual.f);
+    if ((ret = av_frame_ref(f->residual.f, pict)) < 0)
+        return ret;
+    if ((ret = av_frame_make_writable(f->residual.f)) < 0) {
+        av_frame_unref(f->residual.f);
+        return ret;
+    }
+
+    for (i = 0; i < desc->nb_components; i++)
+        has_plane[desc->comp[i].plane] = 1;
+
+    for (i = 0; i < desc->nb_components && has_plane[i]; i++)
+        memset(residual->buf[i]->data, 0, residual->buf[i]->size * sizeof(*residual->buf[i]->data));
+
+    for (i = 0; i < desc->nb_components; i++) {
+        const int w1 = (i == 1 || i == 2) ? cw : width;
+        const int h1 = (i == 1 || i == 2) ? ch : height;
+
+        const int depth = desc->comp[i].depth;
+        const int max_val = 1 << depth;
+
+        for (y = 0; y < h1; y++) {
+            memset(f->p_image_line_buf, 0, width * sizeof(*f->p_image_line_buf));
+            memset(f->c_image_line_buf, 0, width * sizeof(*f->c_image_line_buf));
+            av_read_image_line(f->c_image_line_buf,
+                               (void *)pict->data,
+                               pict->linesize,
+                               desc,
+                               0, y, i, w1, 0);
+            av_read_image_line(f->p_image_line_buf,
+                              (void *)prev->data,
+                              prev->linesize,
+                              desc,
+                              0, y, i, w1, 0);
+            for (x = 0; x < w1; ++x)
+                f->c_image_line_buf[x] = (f->c_image_line_buf[x] - f->p_image_line_buf[x] + (max_val >> 2)) & (max_val - 1);
+            av_write_image_line(f->c_image_line_buf,
+                                residual->data,
+                                residual->linesize,
+                                desc,
+                                0, y, i, w1);
+        }
+    }
+
+    if ((ret = av_frame_ref(f->picture.f, f->residual.f)) < 0)
+        return ret;
+
+    return 0;
+}
+
 static void find_best_state(uint8_t best_state[256][256],
                             const uint8_t one_state[256])
 {
@@ -563,9 +629,9 @@ static int write_extradata(FFV1Context *f)
     put_symbol(c, state, f->version, 0);
     if (f->version > 2) {
         if (f->version == 3) {
-            f->micro_version = 4;
+            f->micro_version = 4 + f->p_frame;
         } else if (f->version == 4)
-            f->micro_version = 2;
+            f->micro_version = 2 + f->p_frame;
         put_symbol(c, state, f->micro_version, 0);
     }
 
@@ -1222,6 +1288,11 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
                         const AVFrame *pict, int *got_packet)
 {
     FFV1Context *f      = avctx->priv_data;
+    if (f->p_frame) {
+        if (f->last_picture.f)
+            av_frame_unref(f->last_picture.f);
+        FFSWAP(ThreadFrame, f->picture, f->last_picture);
+    }
     RangeCoder *const c = &f->slice_context[0]->c;
     AVFrame *const p    = f->picture.f;
     int used_count      = 0;
@@ -1301,6 +1372,15 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
         f->key_frame = 0;
     }
 
+    if (f->p_frame) {
+        avctx->coded_frame->pict_type = f->key_frame ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
+        if (!f->key_frame) {
+            if ((ret = ff_frame_diff(f, pict)) < 0) {
+                return ret;
+            }
+        }
+    }
+
     if (f->ac == AC_RANGE_CUSTOM_TAB) {
         int i;
         for (i = 1; i < 256; i++) {
@@ -1364,6 +1444,15 @@ FF_ENABLE_DEPRECATION_WARNINGS
     pkt->flags |= AV_PKT_FLAG_KEY * f->key_frame;
     *got_packet = 1;
 
+    if (f->p_frame) {
+        if (f->picture.f)
+            av_frame_unref(f->picture.f);
+        if ((ret = av_frame_ref(f->picture.f, pict)) < 0)
+            return ret;
+        if (f->last_picture.f)
+            av_frame_unref(f->last_picture.f);
+    }
+
     return 0;
 }
 
@@ -1377,6 +1466,7 @@ static av_cold int encode_close(AVCodecContext *avctx)
 #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
 static const AVOption options[] = {
     { "slicecrc", "Protect slices with CRCs", OFFSET(ec), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VE },
+    { "pframe", "Using P frames", OFFSET(p_frame), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE },
     { "coder", "Coder type", OFFSET(ac), AV_OPT_TYPE_INT,
             { .i64 = 0 }, -2, 2, VE, "coder" },
         { "rice", "Golomb rice", 0, AV_OPT_TYPE_CONST,
diff --git a/tests/fate/vcodec.mak b/tests/fate/vcodec.mak
index ccf88ce..77c84e8 100644
--- a/tests/fate/vcodec.mak
+++ b/tests/fate/vcodec.mak
@@ -75,7 +75,8 @@ fate-vsynth%-dv-50:              FMT     = dv
 
 FATE_VCODEC-$(call ENCDEC, FFV1, AVI)   += ffv1 ffv1-v0 \
                                            ffv1-v3-yuv420p ffv1-v3-yuv422p10 ffv1-v3-yuv444p16 \
-                                           ffv1-v3-bgr0
+                                           ffv1-v3-bgr0 ffv1-v3-p-yuv420p ffv1-v3-p-yuv422p10 \
+                                           ffv1-v3-p-yuv444p16 ffv1-v3-p-bgr0
 fate-vsynth%-ffv1:               ENCOPTS = -slices 4
 fate-vsynth%-ffv1-v0:            CODEC   = ffv1
 fate-vsynth%-ffv1-v3-yuv420p:    ENCOPTS = -level 3 -pix_fmt yuv420p
@@ -88,6 +89,16 @@ fate-vsynth%-ffv1-v3-yuv444p16:  DECOPTS = -sws_flags neighbor+bitexact
 fate-vsynth%-ffv1-v3-bgr0:       ENCOPTS = -level 3 -pix_fmt bgr0 \
                                            -sws_flags neighbor+bitexact
 fate-vsynth%-ffv1-v3-bgr0:       DECOPTS = -sws_flags neighbor+bitexact
+fate-vsynth%-ffv1-v3-p-yuv420p:  ENCOPTS = -level 3 -pframe 1 -pix_fmt yuv420p
+fate-vsynth%-ffv1-v3-p-yuv422p10: ENCOPTS = -level 3 -pframe 1 -pix_fmt yuv422p10 \
+                                           -sws_flags neighbor+bitexact
+fate-vsynth%-ffv1-v3-p-yuv422p10: DECOPTS = -sws_flags neighbor+bitexact
+fate-vsynth%-ffv1-v3-p-yuv444p16: ENCOPTS = -level 3 -pframe 1 -pix_fmt yuv444p16 \
+                                           -sws_flags neighbor+bitexact
+fate-vsynth%-ffv1-v3-p-yuv444p16: DECOPTS = -sws_flags neighbor+bitexact
+fate-vsynth%-ffv1-v3-p-bgr0:     ENCOPTS = -level 3 -pframe 1 -pix_fmt bgr0 \
+                                           -sws_flags neighbor+bitexact
+fate-vsynth%-ffv1-v3-p-bgr0:     DECOPTS = -sws_flags neighbor+bitexact
 
 FATE_VCODEC-$(call ENCDEC, FFVHUFF, AVI) += ffvhuff ffvhuff444 ffvhuff420p12 ffvhuff422p10left ffvhuff444p16
 fate-vsynth%-ffvhuff444:         ENCOPTS = -vcodec ffvhuff -pix_fmt yuv444p
diff --git a/tests/ref/vsynth/vsynth1-ffv1-v3-p-bgr0 b/tests/ref/vsynth/vsynth1-ffv1-v3-p-bgr0
new file mode 100644
index 0000000..c9a59f2
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-ffv1-v3-p-bgr0
@@ -0,0 +1,4 @@
+c7c587c45eeef13f367031f5938ff321 *tests/data/fate/vsynth1-ffv1-v3-p-bgr0.avi
+10007076 tests/data/fate/vsynth1-ffv1-v3-p-bgr0.avi
+49c03ab1b73b7cd3cabc3c77a9479c9e *tests/data/fate/vsynth1-ffv1-v3-p-bgr0.out.rawvideo
+stddev:    3.16 PSNR: 38.12 MAXDIFF:   50 bytes:  7603200/  7603200
diff --git a/tests/ref/vsynth/vsynth1-ffv1-v3-p-yuv420p b/tests/ref/vsynth/vsynth1-ffv1-v3-p-yuv420p
new file mode 100644
index 0000000..b3bd71f
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-ffv1-v3-p-yuv420p
@@ -0,0 +1,4 @@
+42cafe3650c907296ad1084ed219eff3 *tests/data/fate/vsynth1-ffv1-v3-p-yuv420p.avi
+3288706 tests/data/fate/vsynth1-ffv1-v3-p-yuv420p.avi
+c5ccac874dbf808e9088bc3107860042 *tests/data/fate/vsynth1-ffv1-v3-p-yuv420p.out.rawvideo
+stddev:    0.00 PSNR:999.99 MAXDIFF:    0 bytes:  7603200/  7603200
diff --git a/tests/ref/vsynth/vsynth1-ffv1-v3-p-yuv422p10 b/tests/ref/vsynth/vsynth1-ffv1-v3-p-yuv422p10
new file mode 100644
index 0000000..2d0e56c
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-ffv1-v3-p-yuv422p10
@@ -0,0 +1,4 @@
+316001a818e06e988f8be20f35058b36 *tests/data/fate/vsynth1-ffv1-v3-p-yuv422p10.avi
+3328804 tests/data/fate/vsynth1-ffv1-v3-p-yuv422p10.avi
+c5ccac874dbf808e9088bc3107860042 *tests/data/fate/vsynth1-ffv1-v3-p-yuv422p10.out.rawvideo
+stddev:    0.00 PSNR:999.99 MAXDIFF:    0 bytes:  7603200/  7603200
diff --git a/tests/ref/vsynth/vsynth1-ffv1-v3-p-yuv444p16 b/tests/ref/vsynth/vsynth1-ffv1-v3-p-yuv444p16
new file mode 100644
index 0000000..dad0b85
--- /dev/null
+++ b/tests/ref/vsynth/vsynth1-ffv1-v3-p-yuv444p16
@@ -0,0 +1,4 @@
+7a129548c4ecc0063032a4a9937d084b *tests/data/fate/vsynth1-ffv1-v3-p-yuv444p16.avi
+4857352 tests/data/fate/vsynth1-ffv1-v3-p-yuv444p16.avi
+c5ccac874dbf808e9088bc3107860042 *tests/data/fate/vsynth1-ffv1-v3-p-yuv444p16.out.rawvideo
+stddev:    0.00 PSNR:999.99 MAXDIFF:    0 bytes:  7603200/  7603200
diff --git a/tests/ref/vsynth/vsynth2-ffv1-v3-p-bgr0 b/tests/ref/vsynth/vsynth2-ffv1-v3-p-bgr0
new file mode 100644
index 0000000..91eb128
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-ffv1-v3-p-bgr0
@@ -0,0 +1,4 @@
+26ed95354c819a2901e83f569f54e268 *tests/data/fate/vsynth2-ffv1-v3-p-bgr0.avi
+8806728 tests/data/fate/vsynth2-ffv1-v3-p-bgr0.avi
+835a86f8dff88917c3e5f2776954c5b7 *tests/data/fate/vsynth2-ffv1-v3-p-bgr0.out.rawvideo
+stddev:    1.57 PSNR: 44.18 MAXDIFF:   20 bytes:  7603200/  7603200
diff --git a/tests/ref/vsynth/vsynth2-ffv1-v3-p-yuv420p b/tests/ref/vsynth/vsynth2-ffv1-v3-p-yuv420p
new file mode 100644
index 0000000..774e09a
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-ffv1-v3-p-yuv420p
@@ -0,0 +1,4 @@
+c2761578c47029ca020d08ad3aa7ce41 *tests/data/fate/vsynth2-ffv1-v3-p-yuv420p.avi
+4034942 tests/data/fate/vsynth2-ffv1-v3-p-yuv420p.avi
+36d7ca943916e1743cefa609eba0205c *tests/data/fate/vsynth2-ffv1-v3-p-yuv420p.out.rawvideo
+stddev:    0.00 PSNR:999.99 MAXDIFF:    0 bytes:  7603200/  7603200
diff --git a/tests/ref/vsynth/vsynth2-ffv1-v3-p-yuv422p10 b/tests/ref/vsynth/vsynth2-ffv1-v3-p-yuv422p10
new file mode 100644
index 0000000..f2fc677
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-ffv1-v3-p-yuv422p10
@@ -0,0 +1,4 @@
+79417dea01e6f33c4dda9c0135938ea5 *tests/data/fate/vsynth2-ffv1-v3-p-yuv422p10.avi
+4432290 tests/data/fate/vsynth2-ffv1-v3-p-yuv422p10.avi
+36d7ca943916e1743cefa609eba0205c *tests/data/fate/vsynth2-ffv1-v3-p-yuv422p10.out.rawvideo
+stddev:    0.00 PSNR:999.99 MAXDIFF:    0 bytes:  7603200/  7603200
diff --git a/tests/ref/vsynth/vsynth2-ffv1-v3-p-yuv444p16 b/tests/ref/vsynth/vsynth2-ffv1-v3-p-yuv444p16
new file mode 100644
index 0000000..f864687
--- /dev/null
+++ b/tests/ref/vsynth/vsynth2-ffv1-v3-p-yuv444p16
@@ -0,0 +1,4 @@
+cbc0646be79059ce6c9429cebede3b11 *tests/data/fate/vsynth2-ffv1-v3-p-yuv444p16.avi
+5398792 tests/data/fate/vsynth2-ffv1-v3-p-yuv444p16.avi
+36d7ca943916e1743cefa609eba0205c *tests/data/fate/vsynth2-ffv1-v3-p-yuv444p16.out.rawvideo
+stddev:    0.00 PSNR:999.99 MAXDIFF:    0 bytes:  7603200/  7603200
diff --git a/tests/ref/vsynth/vsynth3-ffv1-v3-p-bgr0 b/tests/ref/vsynth/vsynth3-ffv1-v3-p-bgr0
new file mode 100644
index 0000000..7d14650
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-ffv1-v3-p-bgr0
@@ -0,0 +1,4 @@
+79d4f439ebc94b9a84e3b46ef88246d1 *tests/data/fate/vsynth3-ffv1-v3-p-bgr0.avi
+151412 tests/data/fate/vsynth3-ffv1-v3-p-bgr0.avi
+5d031d2e891b13593b8cd79e63d083b4 *tests/data/fate/vsynth3-ffv1-v3-p-bgr0.out.rawvideo
+stddev:    3.23 PSNR: 37.92 MAXDIFF:   50 bytes:    86700/    86700
diff --git a/tests/ref/vsynth/vsynth3-ffv1-v3-p-yuv420p b/tests/ref/vsynth/vsynth3-ffv1-v3-p-yuv420p
new file mode 100644
index 0000000..31fffc0
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-ffv1-v3-p-yuv420p
@@ -0,0 +1,4 @@
+55f6e1292c963e87d2e8049245ef0980 *tests/data/fate/vsynth3-ffv1-v3-p-yuv420p.avi
+74022 tests/data/fate/vsynth3-ffv1-v3-p-yuv420p.avi
+a038ad7c3c09f776304ef7accdea9c74 *tests/data/fate/vsynth3-ffv1-v3-p-yuv420p.out.rawvideo
+stddev:    0.00 PSNR:999.99 MAXDIFF:    0 bytes:    86700/    86700
diff --git a/tests/ref/vsynth/vsynth3-ffv1-v3-p-yuv422p10 b/tests/ref/vsynth/vsynth3-ffv1-v3-p-yuv422p10
new file mode 100644
index 0000000..2e0cf4c
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-ffv1-v3-p-yuv422p10
@@ -0,0 +1,4 @@
+7cecc35c1715dbe52b7c0254ea93286a *tests/data/fate/vsynth3-ffv1-v3-p-yuv422p10.avi
+74144 tests/data/fate/vsynth3-ffv1-v3-p-yuv422p10.avi
+a038ad7c3c09f776304ef7accdea9c74 *tests/data/fate/vsynth3-ffv1-v3-p-yuv422p10.out.rawvideo
+stddev:    0.00 PSNR:999.99 MAXDIFF:    0 bytes:    86700/    86700
diff --git a/tests/ref/vsynth/vsynth3-ffv1-v3-p-yuv444p16 b/tests/ref/vsynth/vsynth3-ffv1-v3-p-yuv444p16
new file mode 100644
index 0000000..67d0249
--- /dev/null
+++ b/tests/ref/vsynth/vsynth3-ffv1-v3-p-yuv444p16
@@ -0,0 +1,4 @@
+15148eb9e73c174b41e6ddf0bdc5c843 *tests/data/fate/vsynth3-ffv1-v3-p-yuv444p16.avi
+79972 tests/data/fate/vsynth3-ffv1-v3-p-yuv444p16.avi
+a038ad7c3c09f776304ef7accdea9c74 *tests/data/fate/vsynth3-ffv1-v3-p-yuv444p16.out.rawvideo
+stddev:    0.00 PSNR:999.99 MAXDIFF:    0 bytes:    86700/    86700
diff --git a/tests/ref/vsynth/vsynth_lena-ffv1-v3-p-bgr0 b/tests/ref/vsynth/vsynth_lena-ffv1-v3-p-bgr0
new file mode 100644
index 0000000..21653a9
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-ffv1-v3-p-bgr0
@@ -0,0 +1,4 @@
+6b56677efc6cf078f8faa315beb3ad29 *tests/data/fate/vsynth_lena-ffv1-v3-p-bgr0.avi
+7974894 tests/data/fate/vsynth_lena-ffv1-v3-p-bgr0.avi
+0a8b7ddfec03622e37c869c5b552f9fc *tests/data/fate/vsynth_lena-ffv1-v3-p-bgr0.out.rawvideo
+stddev:    1.24 PSNR: 46.26 MAXDIFF:   17 bytes:  7603200/  7603200
diff --git a/tests/ref/vsynth/vsynth_lena-ffv1-v3-p-yuv420p b/tests/ref/vsynth/vsynth_lena-ffv1-v3-p-yuv420p
new file mode 100644
index 0000000..7033c52
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-ffv1-v3-p-yuv420p
@@ -0,0 +1,4 @@
+228ef585bcdfa8799729e735afa2ea72 *tests/data/fate/vsynth_lena-ffv1-v3-p-yuv420p.avi
+3838964 tests/data/fate/vsynth_lena-ffv1-v3-p-yuv420p.avi
+dde5895817ad9d219f79a52d0bdfb001 *tests/data/fate/vsynth_lena-ffv1-v3-p-yuv420p.out.rawvideo
+stddev:    0.00 PSNR:999.99 MAXDIFF:    0 bytes:  7603200/  7603200
diff --git a/tests/ref/vsynth/vsynth_lena-ffv1-v3-p-yuv422p10 b/tests/ref/vsynth/vsynth_lena-ffv1-v3-p-yuv422p10
new file mode 100644
index 0000000..78a81aa
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-ffv1-v3-p-yuv422p10
@@ -0,0 +1,4 @@
+034721b8b3de25e8ee6cfffd37367a7d *tests/data/fate/vsynth_lena-ffv1-v3-p-yuv422p10.avi
+4233142 tests/data/fate/vsynth_lena-ffv1-v3-p-yuv422p10.avi
+dde5895817ad9d219f79a52d0bdfb001 *tests/data/fate/vsynth_lena-ffv1-v3-p-yuv422p10.out.rawvideo
+stddev:    0.00 PSNR:999.99 MAXDIFF:    0 bytes:  7603200/  7603200
diff --git a/tests/ref/vsynth/vsynth_lena-ffv1-v3-p-yuv444p16 b/tests/ref/vsynth/vsynth_lena-ffv1-v3-p-yuv444p16
new file mode 100644
index 0000000..61c2557
--- /dev/null
+++ b/tests/ref/vsynth/vsynth_lena-ffv1-v3-p-yuv444p16
@@ -0,0 +1,4 @@
+61ac22e012a6e61189ea51003666fee3 *tests/data/fate/vsynth_lena-ffv1-v3-p-yuv444p16.avi
+5105946 tests/data/fate/vsynth_lena-ffv1-v3-p-yuv444p16.avi
+dde5895817ad9d219f79a52d0bdfb001 *tests/data/fate/vsynth_lena-ffv1-v3-p-yuv444p16.out.rawvideo
+stddev:    0.00 PSNR:999.99 MAXDIFF:    0 bytes:  7603200/  7603200
-- 
2.6.4 (Apple Git-63)

